79 lines
3.4 KiB
JavaScript
79 lines
3.4 KiB
JavaScript
#!/usr/bin/env node
|
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
import { dirname, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { compile } from "json-schema-to-typescript";
|
|
|
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
const repoRoot = resolve(packageRoot, "..", "..");
|
|
const generatedRoot = resolve(packageRoot, "src", "generated");
|
|
const contracts = [
|
|
["providerAdvertisement", "EveProviderAdvertisement", "provider-advertisement.ts", "gamecult.eve.provider_advertisement.v1.schema.json"],
|
|
["surface", "EveSurfaceDocument", "surface.ts", "gamecult.eve.surface.v1.schema.json"],
|
|
["commandDescriptor", "EveCommandDescriptor", "command-descriptor.ts", "gamecult.eve.command.v1.schema.json"],
|
|
["commandInvocation", "EveCommandInvocation", "command-invocation.ts", "gamecult.eve.command_invocation.v1.schema.json"],
|
|
["commandReceipt", "EveCommandReceipt", "command-receipt.ts", "gamecult.eve.command_receipt.v1.schema.json"],
|
|
["commandResult", "EveCommandResult", "command-result.ts", "gamecult.eve.command_result.v1.schema.json"],
|
|
["inputCapability", "EveInputCapability", "input-capability.ts", "gamecult.eve.input_capability.v1.schema.json"],
|
|
];
|
|
|
|
const loaded = [];
|
|
for (const [key, typeName, generatedFileName, schemaFileName] of contracts) {
|
|
const path = resolve(repoRoot, "schemas", schemaFileName);
|
|
const source = await readFile(path, "utf8");
|
|
const schema = JSON.parse(source);
|
|
loaded.push({ key, typeName, generatedFileName, schemaFileName, schema });
|
|
}
|
|
|
|
const schemasById = new Map(loaded.map(({ schema }) => [schema.$id, schema]));
|
|
for (const contract of loaded) {
|
|
const typeSchema = inlineKnownRefs(contract.schema);
|
|
contract.typeSource = (await compile(typeSchema, contract.typeName, {
|
|
bannerComment: "",
|
|
format: false,
|
|
unknownAny: false,
|
|
})).trim();
|
|
}
|
|
|
|
const schemasOutput = `${generatedHeader()}\nexport const eveContractSchemas = ${JSON.stringify(
|
|
Object.fromEntries(loaded.map(({ key, schema }) => [key, schema])),
|
|
null,
|
|
2,
|
|
)} as const;\n\nexport type EveContractSchemaName = keyof typeof eveContractSchemas;\n`;
|
|
|
|
await mkdir(generatedRoot, { recursive: true });
|
|
for (const { generatedFileName, schemaFileName, typeSource } of loaded) {
|
|
await checkOrWrite(
|
|
resolve(generatedRoot, generatedFileName),
|
|
`${generatedHeader()}\n// Source: schemas/${schemaFileName}\n${typeSource}\n`,
|
|
);
|
|
}
|
|
await checkOrWrite(resolve(generatedRoot, "schemas.ts"), schemasOutput);
|
|
|
|
function generatedHeader() {
|
|
return "// Generated by scripts/generate-contracts.mjs. Do not edit by hand.";
|
|
}
|
|
|
|
async function checkOrWrite(path, expected) {
|
|
if (process.argv.includes("--check")) {
|
|
const actual = await readFile(path, "utf8").catch(() => "");
|
|
if (normalizeNewlines(actual) !== normalizeNewlines(expected)) {
|
|
throw new Error(`${path} is stale. Run npm run generate in ${packageRoot}.`);
|
|
}
|
|
return;
|
|
}
|
|
await writeFile(path, expected, "utf8");
|
|
}
|
|
|
|
function normalizeNewlines(value) {
|
|
return value.replace(/\r\n/g, "\n");
|
|
}
|
|
|
|
function inlineKnownRefs(value) {
|
|
if (Array.isArray(value)) return value.map(inlineKnownRefs);
|
|
if (!value || typeof value !== "object") return value;
|
|
if (typeof value.$ref === "string" && schemasById.has(value.$ref)) {
|
|
return inlineKnownRefs(schemasById.get(value.$ref));
|
|
}
|
|
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, inlineKnownRefs(child)]));
|
|
}
|