UNPKG

@ai2070/l0

Version:

L0: The Missing Reliability Substrate for AI

185 lines 7.1 kB
let jsonSchemaAdapter = null; export function registerJSONSchemaAdapter(adapter) { jsonSchemaAdapter = adapter; } export function unregisterJSONSchemaAdapter() { jsonSchemaAdapter = null; } export function hasJSONSchemaAdapter() { return jsonSchemaAdapter !== null; } export function getJSONSchemaAdapter() { if (!jsonSchemaAdapter) { throw new Error("JSON Schema adapter not registered. Call registerJSONSchemaAdapter() first."); } return jsonSchemaAdapter; } export function isJSONSchema(value) { if (!value || typeof value !== "object") return false; const schema = value; return ("$schema" in schema || "type" in schema || "properties" in schema || "$ref" in schema || "allOf" in schema || "anyOf" in schema || "oneOf" in schema); } export function validateJSONSchema(schema, data) { const adapter = getJSONSchemaAdapter(); const result = adapter.validate(schema, data); if (result.valid) { return { success: true, data: result.data }; } else { const message = adapter.formatErrors(result.errors); return { success: false, error: new Error(message) }; } } export function wrapJSONSchema(schema) { return { _tag: "jsonschema", parse(data) { const result = validateJSONSchema(schema, data); if (result.success) { return result.data; } throw result.error; }, safeParse(data) { return validateJSONSchema(schema, data); }, }; } export function createSimpleJSONSchemaAdapter() { return { validate: (schema, data) => { const errors = []; function validateValue(s, value, path) { if (s.type) { const types = Array.isArray(s.type) ? s.type : [s.type]; const actualType = getJSONType(value); const typeMatches = types.some((t) => { if (t === actualType) return true; if (t === "integer" && actualType === "number") { return Number.isInteger(value); } return false; }); if (!typeMatches) { errors.push({ path, message: `Expected ${types.join(" or ")}, got ${actualType}`, keyword: "type", }); return; } } if (s.enum && !s.enum.includes(value)) { errors.push({ path, message: `Value must be one of: ${s.enum.join(", ")}`, keyword: "enum", }); } if (s.const !== undefined && value !== s.const) { errors.push({ path, message: `Value must be ${JSON.stringify(s.const)}`, keyword: "const", }); } if (s.type === "object" && typeof value === "object" && value !== null) { const obj = value; if (s.required) { for (const prop of s.required) { if (!(prop in obj)) { errors.push({ path: `${path}/${prop}`, message: `Missing required property: ${prop}`, keyword: "required", }); } } } if (s.properties) { for (const [key, propSchema] of Object.entries(s.properties)) { if (key in obj) { validateValue(propSchema, obj[key], `${path}/${key}`); } } } } if (s.type === "array" && Array.isArray(value)) { if (s.items && !Array.isArray(s.items)) { value.forEach((item, index) => { validateValue(s.items, item, `${path}/${index}`); }); } } if (s.type === "string" && typeof value === "string") { if (s.minLength !== undefined && value.length < s.minLength) { errors.push({ path, message: `String must be at least ${s.minLength} characters`, keyword: "minLength", }); } if (s.maxLength !== undefined && value.length > s.maxLength) { errors.push({ path, message: `String must be at most ${s.maxLength} characters`, keyword: "maxLength", }); } if (s.pattern) { const regex = new RegExp(s.pattern); if (!regex.test(value)) { errors.push({ path, message: `String must match pattern: ${s.pattern}`, keyword: "pattern", }); } } } if (s.type === "number" && typeof value === "number") { if (s.minimum !== undefined && value < s.minimum) { errors.push({ path, message: `Number must be >= ${s.minimum}`, keyword: "minimum", }); } if (s.maximum !== undefined && value > s.maximum) { errors.push({ path, message: `Number must be <= ${s.maximum}`, keyword: "maximum", }); } } } validateValue(schema, data, ""); if (errors.length === 0) { return { valid: true, data: data }; } return { valid: false, errors }; }, formatErrors: (errors) => { return errors.map((e) => `${e.path || "/"}: ${e.message}`).join("; "); }, }; } function getJSONType(value) { if (value === null) return "null"; if (Array.isArray(value)) return "array"; return typeof value; } //# sourceMappingURL=jsonSchemaCompat.js.map