// valider.ts — validation structurelle d'un JSON de données contre le schéma // de sa table (schemas/.schema.json, incarné par schemas.ts). Sans // dépendance, sans I/O. Ce n'est pas un validateur JSON Schema complet : type, // required, properties, items, enum, minItems. import { SCHEMAS } from './schemas.js'; const MAX_ERREURS = 20; function typeDe(v) { if (v === null) return 'null'; if (Array.isArray(v)) return 'array'; if (typeof v === 'number') return Number.isInteger(v) ? 'integer' : 'number'; if (typeof v === 'string') return 'string'; if (typeof v === 'boolean') return 'boolean'; return 'object'; } function typeAccepte(attendu, reel) { const liste = Array.isArray(attendu) ? attendu : [attendu]; return liste.some((t) => t === reel || (t === 'number' && reel === 'integer')); } function verifie(schema, valeur, chemin, erreurs) { if (erreurs.length >= MAX_ERREURS) return; const reel = typeDe(valeur); if (!typeAccepte(schema.type, reel)) { erreurs.push(`${chemin} : type ${reel}, attendu ${Array.isArray(schema.type) ? schema.type.join('|') : schema.type}`); return; } if (schema.enum && !schema.enum.includes(valeur)) { erreurs.push(`${chemin} : valeur « ${String(valeur)} » hors de ${schema.enum.map(String).join(', ')}`); } if (reel === 'array') { const tableau = valeur; if (schema.minItems != null && tableau.length < schema.minItems) { erreurs.push(`${chemin} : ${tableau.length} élément(s), minimum ${schema.minItems}`); } if (schema.items) { for (let i = 0; i < tableau.length && erreurs.length < MAX_ERREURS; i++) { verifie(schema.items, tableau[i], `${chemin}[${i}]`, erreurs); } } } else if (reel === 'object') { const objet = valeur; for (const cle of schema.required ?? []) { if (!(cle in objet) || objet[cle] === undefined) erreurs.push(`${chemin}.${cle} : requis, absent`); } if (schema.properties) { for (const [cle, sous] of Object.entries(schema.properties)) { if (cle in objet && objet[cle] !== undefined) verifie(sous, objet[cle], `${chemin}.${cle}`, erreurs); } } } } /** * Valide un JSON de données contre le schéma de sa table. Renvoie au plus * vingt erreurs, chacune avec son chemin. */ export function valider(table, json) { const schema = SCHEMAS[table]; if (!schema) return { ok: false, erreurs: [`table inconnue : ${String(table)}`] }; const erreurs = []; verifie(schema, json, table, erreurs); return { ok: erreurs.length === 0, erreurs }; } /** Valide un objet contre un schéma arbitraire (même sous-ensemble). */ export function validerContre(schema, json, nom = '$') { const erreurs = []; verifie(schema, json, nom, erreurs); return { ok: erreurs.length === 0, erreurs }; }