#!/usr/bin/env node /** * Generates a JSON Schema file from the template schema, see source/template/schemas.ts for the schema definition. * * To provide support for types that JSON Schema cannot natively represent (e.g. bigint, Uint8Array), this script uses * Zod's override functionality. * * The generated schema file (source/template/xo-template.schema.json) is not directly used anywhere in the xo project, but can be consumed by other JSON Schema validators * to perform validations and help development of xo templates but it is important to note that they do not guarantee the support for bigint and * other types support in the future. Hence, for XO compatible templates, it's a requirement that the provided template (json or typescript) is validated against * the current template schema (source/template/schemas.ts) and validator. */ import { writeFileSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { dirname, join } from 'node:path'; import { ZodBigInt } from 'zod'; import { xoTemplateSchema, uint8ArraySchema } from '../source/template/schemas.ts'; // Gets the directory of this script file. const scriptDirectory = dirname(fileURLToPath(import.meta.url)); // Gets the root directory of the package. const rootDirectory = join(scriptDirectory, '..'); // The output path for the generated JSON Schema file, placed alongside the template schemas. const schemaOutputPath = join(rootDirectory, 'source/template/xo-template.schema.json'); /** * Generates the JSON Schema from the zod's template validation schema. * * - Bigint fields are mapped to `{ "type": "integer", "format": "bigint" }` because JSON Schema has no native bigint type. * - Uint8Array fields are mapped to `{ "type": "string", "format": "uint8array" }` because JSON Schema has no byte array type. * * @returns The generated JSON Schema object. */ const generateSchema = (): Record => { return xoTemplateSchema.toJSONSchema({ // With "throw", Zod throws for any type it cannot represent in JSON Schema natively, unless the // override below handles it first. This ensures new unrepresentable types added to the schema are // caught immediately rather than silently producing an empty schema node. unrepresentable: 'throw', override: ({ zodSchema, jsonSchema: schemaNode }): void => { // Override for bigint if (zodSchema instanceof ZodBigInt) { Object.assign(schemaNode, { type: 'integer', format: 'bigint' }); } // Override for Uint8Array if (zodSchema === uint8ArraySchema) { Object.assign(schemaNode, { type: 'string', format: 'uint8array' }); } }, }); }; try { const schema = generateSchema(); writeFileSync(schemaOutputPath, JSON.stringify(schema, null, 4) + '\n', 'utf8'); console.log('Schema generated:', schemaOutputPath); } catch (thrownValue) { const errorMessage = thrownValue instanceof Error ? thrownValue.message : String(thrownValue); console.error('Schema generation failed:', errorMessage); process.exit(1); }