import type { Schema, ReferenceSchema, ReverseReferenceSchema, UnionSchema, } from "./types"; export function schemaToTypeString( schema: Schema, resourceNames?: Map, ): string { switch (schema.type) { case "string": return "string"; case "number": case "int": case "float": return "number"; case "boolean": return "boolean"; case "stringLiteral": return `"${schema.value}"`; case "union": return schema.members .map((m) => schemaToTypeString(m, resourceNames)) .join(" | "); case "reference": { const typeName = resourceNames?.get(schema.tableName) || schema.tableName.charAt(0).toUpperCase() + schema.tableName.slice(1); const baseType = schema.isArray ? `${typeName}[]` : typeName; return schema.isOptional ? `${baseType} | null` : baseType; } case "reverseReference": { const typeName = resourceNames?.get(schema.tableName) || schema.tableName.charAt(0).toUpperCase() + schema.tableName.slice(1); const baseType = `${typeName}[]`; return schema.isOptional ? `${baseType} | null` : baseType; } case "array": if (schema.element.type === "tuple") { const tupleElements = schema.element.elements.map((el) => { const typeStr = schemaToTypeString(el.schema, resourceNames); return el.name ? `${el.name}: ${typeStr}` : typeStr; }); return `[${tupleElements.join(", ")}][]`; } const elementType = schemaToTypeString(schema.element, resourceNames); if (schema.element.type === "union") { return `(${elementType})[]`; } return `${elementType}[]`; case "tuple": const tupleElements = schema.elements.map((el) => { const typeStr = schemaToTypeString(el.schema, resourceNames); return el.name ? `${el.name}: ${typeStr}` : typeStr; }); return `[${tupleElements.join(", ")}]`; default: return "unknown"; } } export function createValidator(schema: Schema): (value: unknown) => boolean { return function validate(value: unknown): boolean { switch (schema.type) { case "string": return typeof value === "string"; case "number": return typeof value === "number" && !isNaN(value); case "int": return ( typeof value === "number" && !isNaN(value) && Number.isInteger(value) ); case "float": return typeof value === "number" && !isNaN(value); case "boolean": return typeof value === "boolean"; case "stringLiteral": return typeof value === "string" && value === schema.value; case "union": return schema.members.some((member) => createValidator(member)(value)); case "tuple": if (!Array.isArray(value)) return false; if (value.length !== schema.elements.length) return false; return schema.elements.every((elementSchema, index) => createValidator(elementSchema.schema)(value[index]), ); case "array": if (!Array.isArray(value)) return false; return value.every((item) => createValidator(schema.element)(item)); case "reference": if (schema.isOptional && value === null) return true; if (schema.isArray) { return ( Array.isArray(value) && value.every((id) => typeof id === "string") ); } return ( typeof value === "string" || (Array.isArray(value) && value.every((id) => typeof id === "string")) ); case "reverseReference": if (schema.isOptional && value === null) return true; return Array.isArray(value); default: return false; } }; }