import fs from "node:fs" import path from "node:path" import { fileURLToPath } from "node:url" import Ajv from "ajv" import addFormats from "ajv-formats" import { globSync } from "glob" import yaml from "js-yaml" const __dirname = path.dirname(fileURLToPath(import.meta.url)) const repoRoot = path.resolve(__dirname, "..") const schemaDir = path.join(repoRoot, "schemas", "config") const includeType = new yaml.Type("!include", { kind: "scalar", construct(data) { return data ?? "" }, }) const yamlSchema = yaml.DEFAULT_SCHEMA.extend([includeType]) const ajv = new Ajv({ allErrors: true, strict: false, }) addFormats(ajv) const schemaFiles = globSync("*.schema.json", { cwd: schemaDir, absolute: true, }).sort() if (schemaFiles.length === 0) { console.error("No schema files found in", schemaDir) process.exit(1) } for (const filePath of schemaFiles) { const schema = JSON.parse(fs.readFileSync(filePath, "utf8")) ajv.addSchema(schema, schema.$id || path.basename(filePath)) } for (const filePath of schemaFiles) { const schema = JSON.parse(fs.readFileSync(filePath, "utf8")) ajv.getSchema(schema.$id || path.basename(filePath)) } const validations = [ { schema: "project.schema.json", pattern: "demo-api/config.y*ml" }, { schema: "collection.schema.json", pattern: "demo-api/collections/*.y*ml", }, { schema: "field.schema.json", pattern: "demo-api/collections/fields/*.y*ml", }, { schema: "field-list.schema.json", pattern: "demo-api/collections/fieldLists/*.y*ml", }, { schema: "job.schema.json", pattern: "demo-api/jobs/*.y*ml" }, { schema: "action.schema.json", pattern: "demo-api/actions/*.y*ml" }, { schema: "asset.schema.json", pattern: "demo-api/assets/*.y*ml" }, ] let hasErrors = false let validatedCount = 0 for (const { schema, pattern } of validations) { const validate = ajv.getSchema(schema) if (!validate) { console.error(`Schema not registered: ${schema}`) hasErrors = true continue } const files = globSync(pattern, { cwd: repoRoot, absolute: true, }).sort() for (const filePath of files) { const raw = fs.readFileSync(filePath, "utf8") const parsed = yaml.load(raw, { schema: yamlSchema }) const valid = validate(parsed) validatedCount += 1 if (!valid) { hasErrors = true console.error( `\nValidation failed: ${path.relative(repoRoot, filePath)}` ) for (const error of validate.errors || []) { const location = error.instancePath || "/" console.error(` ${location} ${error.message}`) } } } } if (hasErrors) { process.exit(1) } console.log( `Validated ${validatedCount} YAML file(s) against ${schemaFiles.length} schema file(s).` )