// 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 };
}