← Files Vocabloot Deck KitARCHIVED FILE
scripts/lib/jsonschema.mjs
2.01 KB · Oct 2, 2026 · 00:34 UTC
// The subset of JSON Schema the kit's answer schemas use: type (one or several),
// enum, required, properties with additionalProperties false, items, min/maxItems.
// Enough to tell an agent exactly which field of its answer is wrong.
function typeOf(v) {
if (v === null) return "null";
if (Array.isArray(v)) return "array";
if (typeof v === "number") return Number.isInteger(v) ? "integer" : "number";
return typeof v;
}
function typeOk(v, type) {
const types = Array.isArray(type) ? type : [type];
const actual = typeOf(v);
return types.some((t) => t === actual || (t === "number" && actual === "integer"));
}
/** Returns a list of problems; empty when the value matches the schema. */
export function validateAgainst(schema, value, where = "answer") {
const p = [];
if (!schema || typeof schema !== "object") return p;
if (schema.type && !typeOk(value, schema.type)) {
p.push(`${where}: expected ${[].concat(schema.type).join(" or ")}, got ${typeOf(value)}`);
return p;
}
if (schema.enum && !schema.enum.includes(value))
p.push(`${where}: must be one of ${schema.enum.map((e) => JSON.stringify(e)).join(", ")}`);
if (typeOf(value) === "object" && schema.properties) {
for (const k of schema.required ?? []) if (!(k in value)) p.push(`${where}.${k}: missing`);
for (const [k, v] of Object.entries(value)) {
if (schema.properties[k]) p.push(...validateAgainst(schema.properties[k], v, `${where}.${k}`));
else if (schema.additionalProperties === false) p.push(`${where}.${k}: not a field of this schema`);
}
}
if (typeOf(value) === "array") {
if (schema.minItems != null && value.length < schema.minItems)
p.push(`${where}: at least ${schema.minItems} items required, got ${value.length}`);
if (schema.maxItems != null && value.length > schema.maxItems)
p.push(`${where}: at most ${schema.maxItems} items allowed, got ${value.length}`);
if (schema.items) value.forEach((v, i) => p.push(...validateAgainst(schema.items, v, `${where}[${i}]`)));
}
return p;
}
SHA-256: b65bad5ab37b4fb616018d1c3be3c32c5cc0e656a31fcee20ee40e0f28e09127