cesium-native/tools/generate-classes/index.js

234 lines
6.4 KiB
JavaScript

const yargs = require("yargs");
const path = require("path");
const fs = require("fs");
const SchemaCache = require("./SchemaCache");
const generate = require("./generate");
const generateCombinedWriter = require("./generateCombinedWriter");
const generateRegisterExtensions = require("./generateRegisterExtensions");
const getNameFromTitle = require("./getNameFromTitle");
const argv = yargs.options({
schemas: {
description: "The paths to the JSON schemas.",
demandOption: true,
type: "array",
},
output: {
description: "The output directory for the generated class files.",
demandOption: true,
type: "string",
},
readerOutput: {
description: "The output directory for the generated reader files.",
demandOption: true,
type: "string",
},
writerOutput: {
description: "The output directory for the generated writer files.",
demandOption: true,
type: "string",
},
extensions: {
description: "The extension directories.",
demandOption: true,
type: "array",
},
config: {
description:
"The path to the configuration options controlling code generation, expressed in a JSON file.",
demandOption: true,
type: "string",
},
namespace: {
description: "Namespace to put the generated classes in.",
demandOption: true,
type: "string",
},
readerNamespace: {
description: "Namespace to put the generated reader files in.",
demandOption: true,
type: "string",
},
writerNamespace: {
description: "Namespace to put the generated writer files in.",
demandOption: true,
type: "string",
},
oneHandlerFile: {
description:
"Generate all the JSON handler implementations into a single file, GeneratedJsonHandlers.cpp.",
type: "bool",
default: true,
},
}).argv;
function splitSchemaPath(schemaPath) {
const schemaNameIndex = schemaPath.lastIndexOf("/") + 1;
const schemaName = schemaPath.slice(schemaNameIndex);
const schemaBasePath = schemaPath.slice(0, schemaNameIndex);
return { schemaName, schemaBasePath };
}
const schemaBasePaths = [];
for (const schemaPath of argv.schemas) {
const { _, schemaBasePath } = splitSchemaPath(schemaPath);
schemaBasePaths.push(schemaBasePath);
}
const schemaCache = new SchemaCache(schemaBasePaths, argv.extensions);
let schemas = [];
for (const schemaPath of argv.schemas) {
const { schemaName, _ } = splitSchemaPath(schemaPath);
const schema = schemaCache.load(schemaName);
schemas.push(schema);
}
const rootSchema = schemas[0];
const config = JSON.parse(fs.readFileSync(argv.config, "utf-8"));
if (argv.oneHandlerFile) {
// Clear the handler implementation file, and then we'll append to it in `generate`.
const readerHeaderOutputDir = path.join(
argv.readerOutput,
"generated",
"src"
);
fs.mkdirSync(readerHeaderOutputDir, { recursive: true });
const readerSourceOutputPath = path.join(
readerHeaderOutputDir,
"GeneratedJsonHandlers.cpp"
);
fs.writeFileSync(readerSourceOutputPath, "", "utf-8");
}
const options = {
schemaCache,
oneHandlerFile: argv.oneHandlerFile,
outputDir: argv.output,
readerOutputDir: argv.readerOutput,
config: config,
namespace: argv.namespace,
readerNamespace: argv.readerNamespace,
writerNamespace: argv.writerNamespace,
// key: Title of the element name that is extended (e.g. "Mesh Primitive")
// value: Array of extension type names.
extensions: {},
};
const writers = [];
function getObjectToExtend(schema, extensionName) {
const parts = schema.split("/");
const last = parts[parts.length - 1];
const subParts = last.split(".");
const extensionNameIndex = subParts.indexOf(extensionName);
if (extensionNameIndex == -1 || extensionNameIndex == 0) {
return undefined;
}
const objectToExtend = subParts.slice(0, extensionNameIndex).join(".");
return objectToExtend;
}
for (const extension of config.extensions) {
const extensionSchema = schemaCache.loadExtension(
extension.schema,
extension.extensionName
);
const extensionClassName = getNameFromTitle(config, extensionSchema.title);
if (!extensionSchema) {
console.warn(
`Could not load schema ${extension.schema} for extension class ${extensionClassName}.`
);
continue;
}
if (!config.classes[extensionSchema.title]) {
config.classes[extensionSchema.title] = {};
}
config.classes[extensionSchema.title].overrideName = extensionClassName;
config.classes[extensionSchema.title].extensionName = extension.extensionName;
schemas.push(...generate(options, extensionSchema, writers));
var objectsToExtend = [];
if (extension.attachTo !== undefined) {
objectsToExtend = objectsToExtend.concat(extension.attachTo);
} else {
const attachTo = getObjectToExtend(
extension.schema,
extension.extensionName,
extensionClassName
);
if (attachTo !== undefined) {
objectsToExtend.push(attachTo);
}
}
if (objectsToExtend.length === 0) {
console.warn(
`Could not find object to extend for extension class ${extensionClassName}`
);
continue;
}
for (const objectToExtend of objectsToExtend) {
const objectToExtendSchema = schemaCache.load(
`${objectToExtend}.schema.json`
);
if (!objectToExtendSchema) {
console.warn(`Could not load schema for ${objectToExtend}.`);
continue;
}
if (!options.extensions[objectToExtendSchema.title]) {
options.extensions[objectToExtendSchema.title] = [];
}
options.extensions[objectToExtendSchema.title].push({
name: extension.extensionName,
className: extensionClassName,
});
}
}
function processSchemas() {
const processed = {};
while (schemas.length > 0) {
const schema = schemas.pop();
if (processed[schema.sourcePath]) {
continue;
}
processed[schema.sourcePath] = true;
if ((options.config.classes[schema.title] || {}).manuallyDefined) {
continue;
}
schemas.push(...generate(options, schema, writers));
}
}
processSchemas();
generateRegisterExtensions({
readerOutputDir: argv.readerOutput,
writerOutputDir: argv.writerOutput,
config: config,
namespace: argv.namespace,
readerNamespace: argv.readerNamespace,
writerNamespace: argv.writerNamespace,
rootSchema: rootSchema,
extensions: options.extensions,
});
generateCombinedWriter({
writerOutputDir: argv.writerOutput,
config: config,
namespace: argv.namespace,
writerNamespace: argv.writerNamespace,
rootSchema: rootSchema,
writers: writers,
extensions: options.extensions,
});