60 lines
2.0 KiB
TypeScript
60 lines
2.0 KiB
TypeScript
import fs from "fs";
|
|
import path from "path";
|
|
import Ajv2020, { type ErrorObject, type ValidateFunction } from "ajv/dist/2020";
|
|
import { SCHEMAS_DIR } from "../config";
|
|
import type { NormalizedPayload, ValidationResult } from "../types/normalizer";
|
|
|
|
type SchemaVersion = "v1" | "v2" | "v2_0_1" | "v2_0_2";
|
|
|
|
const validators = new Map<SchemaVersion, ValidateFunction>();
|
|
|
|
function schemaPath(version: SchemaVersion): string {
|
|
if (version === "v1") {
|
|
return path.resolve(SCHEMAS_DIR, "normalized_query_v1.json");
|
|
}
|
|
if (version === "v2_0_1") {
|
|
return path.resolve(SCHEMAS_DIR, "normalized_query_v2_0_1.json");
|
|
}
|
|
if (version === "v2_0_2") {
|
|
return path.resolve(SCHEMAS_DIR, "normalized_query_v2_0_2.json");
|
|
}
|
|
return path.resolve(SCHEMAS_DIR, "normalized_query_v2.json");
|
|
}
|
|
|
|
function loadValidator(version: SchemaVersion): ValidateFunction {
|
|
const cached = validators.get(version);
|
|
if (cached) {
|
|
return cached;
|
|
}
|
|
const raw = fs.readFileSync(schemaPath(version), "utf-8");
|
|
const schema = JSON.parse(raw);
|
|
const ajv = new Ajv2020({ allErrors: true, strict: false });
|
|
const compiled = ajv.compile(schema);
|
|
validators.set(version, compiled);
|
|
return compiled;
|
|
}
|
|
|
|
function normalizeAjvErrors(errors: ErrorObject[] | null | undefined): string[] {
|
|
if (!errors || errors.length === 0) {
|
|
return [];
|
|
}
|
|
return errors.map((item) => `${item.instancePath || "/"} ${item.message ?? "validation error"}`.trim());
|
|
}
|
|
|
|
export function validateNormalized(payload: unknown, schemaVersion: SchemaVersion = "v1"): ValidationResult {
|
|
const check = loadValidator(schemaVersion);
|
|
const passed = check(payload);
|
|
return {
|
|
passed: Boolean(passed),
|
|
errors: passed ? [] : normalizeAjvErrors(check.errors)
|
|
};
|
|
}
|
|
|
|
export function assertNormalized(payload: unknown, schemaVersion: SchemaVersion = "v1"): NormalizedPayload {
|
|
const validation = validateNormalized(payload, schemaVersion);
|
|
if (!validation.passed) {
|
|
throw new Error(`Invalid normalized JSON: ${validation.errors.join("; ")}`);
|
|
}
|
|
return payload as NormalizedPayload;
|
|
}
|