Files
moteurs/dist/commun/valider.js
T
JulesandClaude Fable 5.1 69809df5d1 LOT P1.0 : paquet @transformer/moteurs v0.1.0
Extraction du cœur autonomie de calculs.trans-former.fr (12 modules, sans
singleton, couplages sans mutation, console derrière debug), découpage en trois
moteurs d'axe + intégrateur (mode global = calculs, mode par_axe = plateforme),
moteurs commun.contexte (Corse 2A/2B, DOM 97x corrigés) et commun.geometrie,
table des coefficients harmonisés (docs/CONSTANTES.md pour Jules, R-7),
validation structurelle des données (schemas/), tests hors ligne : 28 assertions
d'origine + épingle générée depuis le code d'astro-pro + écarts d'harmonisation
figés + contrat des moteurs. dist/ committé.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019UBHYPdeQYy2m1GVJp6b12
2026-09-28 17:06:49 +02:00

78 lines
3.0 KiB
JavaScript

// valider.ts — validation structurelle d'un JSON de données contre le schéma
// de sa table (schemas/<table>.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 };
}