FP_POC / packages /shared /src /validation.ts
github-actions[bot]
Space-Deploy aus GitHub main
9de795a
Raw History Blame Contribute Delete
1.81 kB
/**
* Schema-Validierung (Ajv, JSON Schema draft 2020-12) über alle Verträge.
* Wird vom Schema-Check, den Tests und später vom Frontend (Import-Pfade)
* genutzt. Python-Gegenstück: fp_engines.validation (jsonschema).
*/
import Ajv2020 from "ajv/dist/2020.js";
import addFormats from "ajv-formats";
import { readdirSync, readFileSync } from "node:fs";
import { join, dirname, resolve, basename } from "node:path";
import { fileURLToPath } from "node:url";
const schemasDir = resolve(dirname(fileURLToPath(import.meta.url)), "../schemas");
export interface ValidationResult {
ok: boolean;
errors: string[];
}
export interface ContractValidator {
/** Validiert eine Instanz gegen einen Vertrag (Schema-Name ohne Endung). */
validate(schemaName: string, instance: unknown): ValidationResult;
schemaNames: string[];
}
export function createValidator(): ContractValidator {
// allowUnionTypes: Verträge nutzen bewusst Union-Typen (z.B. params: number|string).
const ajv = new Ajv2020({ allErrors: true, strict: true, allowUnionTypes: true });
addFormats(ajv);
const names: string[] = [];
for (const file of readdirSync(schemasDir).filter((f) => f.endsWith(".schema.json"))) {
const schema: unknown = JSON.parse(readFileSync(join(schemasDir, file), "utf-8"));
const name = basename(file, ".schema.json");
ajv.addSchema(schema as object, name);
names.push(name);
}
return {
schemaNames: names,
validate(schemaName, instance) {
const validate = ajv.getSchema(schemaName);
if (!validate) throw new Error(`Unbekanntes Schema: ${schemaName}`);
const ok = validate(instance) as boolean;
return {
ok,
errors: (validate.errors ?? []).map((e) => `${e.instancePath || "/"} ${e.message ?? ""}`),
};
},
};
}