json-schema-compatibility-checker 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -151
- package/dist/cjs/condition-resolver.js.map +1 -1
- package/dist/cjs/data-narrowing.d.ts +31 -0
- package/dist/cjs/data-narrowing.js +2 -0
- package/dist/cjs/data-narrowing.js.map +1 -0
- package/dist/cjs/index.d.ts +2 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/json-schema-compatibility-checker.d.ts +39 -26
- package/dist/cjs/json-schema-compatibility-checker.js +1 -1
- package/dist/cjs/json-schema-compatibility-checker.js.map +1 -1
- package/dist/cjs/merge-engine.js.map +1 -1
- package/dist/cjs/types.d.ts +19 -3
- package/dist/esm/condition-resolver.js.map +1 -1
- package/dist/esm/data-narrowing.d.ts +31 -0
- package/dist/esm/data-narrowing.js +2 -0
- package/dist/esm/data-narrowing.js.map +1 -0
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/json-schema-compatibility-checker.d.ts +39 -26
- package/dist/esm/json-schema-compatibility-checker.js +1 -1
- package/dist/esm/json-schema-compatibility-checker.js.map +1 -1
- package/dist/esm/merge-engine.js.map +1 -1
- package/dist/esm/types.d.ts +19 -3
- package/dist/esm/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/condition-resolver.ts"],"sourcesContent":["import type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\nimport { validateFormat } from \"./format-validator\";\nimport type { MergeEngine } from \"./merge-engine\";\nimport { inferType } from \"./normalizer\";\nimport type { ResolvedConditionResult } from \"./types\";\nimport { deepEqual, hasOwn, isPlainObj, omitKeys, unionStrings } from \"./utils\";\n\n// ─── Condition Resolver ──────────────────────────────────────────────────────\n//\n// Résout les `if/then/else` d'un schema en évaluant le `if` contre\n// des données partielles (discriminants).\n//\n// Stratégie :\n// 1. Évaluer si les données partielles satisfont le `if`\n// 2. Merger la branche applicable (`then` ou `else`) dans le schema de base\n// 3. Supprimer les mots-clés `if/then/else` du résultat\n// 4. Récurser dans les `properties` pour résoudre les conditions imbriquées\n//\n// L'évaluation du `if` (via `evaluateCondition`) gère :\n// - `properties` avec `const`, `enum`, `type`, contraintes numériques/string/array\n// - `required` (vérification de présence des clés)\n// - `allOf` (toutes les entrées doivent matcher — récursion) [2.1]\n// - `anyOf` (au moins une entrée doit matcher — récursion) [2.2]\n// - `oneOf` (exactement une entrée doit matcher — récursion) [2.3]\n// - `not` (inversion du résultat — récursion) [2.4]\n// - Propriétés imbriquées (nested objects — récursion) [2.5]\n// - `format` via `validateFormat` de `format-validator.ts` [2.6]\n//\n// Utilise lodash massivement :\n// - `_.has` / `_.get` pour l'accès sûr aux propriétés\n// - `_.every` / `_.some` pour les prédicats sur les collections\n// - `_.union` / `_.uniq` pour la fusion de tableaux (required, deps)\n// - `_.isArray` / `_.isPlainObject` pour le typage des valeurs\n// - `_.mapValues` pour transformer les propriétés\n// - `_.omit` / `_.pick` pour sélectionner/exclure des clés\n// - `_.keys` / `_.forEach` pour l'itération\n// - `_.reduce` pour accumuler les résultats\n// - `_.isEqual` pour la comparaison profonde\n// - `_.size` / `_.filter` pour le comptage (oneOf)\n\n// ─── Keywords classification ─────────────────────────────────────────────────\n\n/** Mots-clés qui ne doivent pas être traités par la boucle générique de mergeBranchInto */\nconst SPECIAL_MERGE_KEYS = new Set([\"required\", \"properties\", \"dependencies\"]);\n\n/** Mots-clés contenant un sous-schema unique (mergeable via engine.merge) */\nconst SUB_SCHEMA_KEYS = new Set([\n\t\"additionalProperties\",\n\t\"items\",\n\t\"contains\",\n\t\"propertyNames\",\n\t\"not\",\n]);\n\n/** Mots-clés numériques de type \"minimum\" (prendre le max pour être plus restrictif) */\nconst MIN_KEYS = new Set([\n\t\"minimum\",\n\t\"exclusiveMinimum\",\n\t\"minLength\",\n\t\"minItems\",\n\t\"minProperties\",\n]);\n\n/** Mots-clés numériques de type \"maximum\" (prendre le min pour être plus restrictif) */\nconst MAX_KEYS = new Set([\n\t\"maximum\",\n\t\"exclusiveMaximum\",\n\t\"maxLength\",\n\t\"maxItems\",\n\t\"maxProperties\",\n]);\n\n// ─── Condition evaluation (internal) ─────────────────────────────────────────\n\n/**\n * Vérifie si `value` correspond à un type JSON Schema.\n */\nfunction matchesType(value: unknown, type: JSONSchema7[\"type\"]): boolean {\n\tif (type === undefined) return true;\n\n\tconst types = Array.isArray(type) ? type : [type];\n\tconst actualType = inferType(value);\n\n\treturn types.some(\n\t\t(t) => t === actualType || (t === \"number\" && actualType === \"integer\"),\n\t);\n}\n\n/**\n * Évalue une contrainte numérique sur une valeur.\n * Point 5 — Enrichissement de evaluateCondition.\n */\nfunction evaluateNumericConstraints(value: number, prop: JSONSchema7): boolean {\n\tif (prop.minimum !== undefined && !(value >= prop.minimum)) return false;\n\tif (prop.maximum !== undefined && !(value <= prop.maximum)) return false;\n\tif (\n\t\tprop.exclusiveMinimum !== undefined &&\n\t\t!(value > (prop.exclusiveMinimum as number))\n\t)\n\t\treturn false;\n\tif (\n\t\tprop.exclusiveMaximum !== undefined &&\n\t\t!(value < (prop.exclusiveMaximum as number))\n\t)\n\t\treturn false;\n\tif (prop.multipleOf !== undefined && value % prop.multipleOf !== 0)\n\t\treturn false;\n\treturn true;\n}\n\n/**\n * Évalue une contrainte string sur une valeur.\n * Point 5 — Enrichissement de evaluateCondition.\n */\n/** Cache for compiled RegExp patterns used in evaluateStringConstraints */\nconst patternRegexCache = new Map<string, RegExp>();\n\nfunction getOrCompileRegex(pattern: string): RegExp {\n\tlet regex = patternRegexCache.get(pattern);\n\tif (regex === undefined) {\n\t\tregex = new RegExp(pattern);\n\t\tpatternRegexCache.set(pattern, regex);\n\t}\n\treturn regex;\n}\n\nfunction evaluateStringConstraints(value: string, prop: JSONSchema7): boolean {\n\tif (prop.minLength !== undefined && !(value.length >= prop.minLength))\n\t\treturn false;\n\tif (prop.maxLength !== undefined && !(value.length <= prop.maxLength))\n\t\treturn false;\n\tif (\n\t\tprop.pattern !== undefined &&\n\t\t!getOrCompileRegex(prop.pattern).test(value)\n\t)\n\t\treturn false;\n\treturn true;\n}\n\n/**\n * Évalue une contrainte array sur une valeur.\n * Point 5 — Enrichissement de evaluateCondition.\n */\nfunction evaluateArrayConstraints(\n\tvalue: unknown[],\n\tprop: JSONSchema7,\n): boolean {\n\tif (prop.minItems !== undefined && !(value.length >= prop.minItems))\n\t\treturn false;\n\tif (prop.maxItems !== undefined && !(value.length <= prop.maxItems))\n\t\treturn false;\n\tif (prop.uniqueItems === true) {\n\t\t// Vérifier l'unicité via deepEqual pour les éléments non-primitifs\n\t\t// Optimisation : double boucle sans slice pour éviter les allocations\n\t\tconst len = value.length;\n\t\tfor (let i = 0; i < len; i++) {\n\t\t\tfor (let j = i + 1; j < len; j++) {\n\t\t\t\tif (deepEqual(value[i], value[j])) return false;\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\n\n/**\n * Évalue si des données partielles satisfont un `if` schema.\n *\n * Stratégie pragmatique (pas un validateur complet) :\n * - Vérifie les `properties` avec `const`, `enum`, `type`\n * - Point 5 : Vérifie aussi minimum/maximum, minLength/maxLength,\n * pattern, multipleOf, minItems/maxItems, uniqueItems\n * - Vérifie les `required`\n * - 2.1 : `allOf` → toutes les entrées doivent matcher (récursion)\n * - 2.2 : `anyOf` → au moins une entrée doit matcher (récursion)\n * - 2.3 : `oneOf` → exactement une entrée doit matcher (récursion)\n * - 2.4 : `not` → inversion du résultat (récursion)\n * - 2.5 : Propriétés imbriquées → récursion sur les sous-objets\n * - 2.6 : `format` → validation via `validateFormat`\n *\n * Utilise `_.forEach` / `_.every` / `_.has` pour une itération idiomatique.\n */\nfunction evaluateCondition(\n\tifSchema: JSONSchema7,\n\tdata: Record<string, unknown>,\n): boolean {\n\tif (isPlainObj(ifSchema.properties)) {\n\t\tconst propsOk = Object.keys(ifSchema.properties).every((key) => {\n\t\t\tconst propDef = ifSchema.properties?.[key];\n\t\t\tif (typeof propDef === \"boolean\") return true;\n\t\t\tconst prop = propDef as JSONSchema7;\n\t\t\tconst value = data[key];\n\n\t\t\t// ── Propriété absente → skip ──\n\t\t\t// Selon la spec JSON Schema Draft-07, le keyword `properties` ne valide\n\t\t\t// une propriété que si elle est **présente** dans l'instance.\n\t\t\t// C'est le keyword `required` qui gère la présence obligatoire.\n\t\t\tif (value === undefined) return true;\n\n\t\t\t// ── const ──\n\t\t\tif (hasOwn(prop, \"const\")) {\n\t\t\t\tif (!deepEqual(value, prop.const)) return false;\n\t\t\t}\n\n\t\t\t// ── enum ──\n\t\t\tif (hasOwn(prop, \"enum\")) {\n\t\t\t\tif (!prop.enum?.some((v) => deepEqual(v, value))) return false;\n\t\t\t}\n\n\t\t\t// ── type ──\n\t\t\tif (hasOwn(prop, \"type\") && value !== undefined) {\n\t\t\t\tif (!matchesType(value, prop.type)) return false;\n\t\t\t}\n\n\t\t\t// ── Point 5 : Contraintes numériques/string/array ──\n\t\t\t// Quand `value` est `undefined`, aucun de ces blocs ne s'exécute\n\t\t\t// (`typeof undefined` vaut `\"undefined\"`, pas `\"number\"` ni `\"string\"`,\n\t\t\t// et `isArray(undefined)` retourne `false`).\n\t\t\t// C'est le comportement voulu : on ne peut pas évaluer une contrainte\n\t\t\t// sur une donnée absente → on skip, cohérent avec la logique pragmatique.\n\t\t\tif (typeof value === \"number\") {\n\t\t\t\tif (!evaluateNumericConstraints(value, prop)) return false;\n\t\t\t}\n\n\t\t\tif (typeof value === \"string\") {\n\t\t\t\tif (!evaluateStringConstraints(value, prop)) return false;\n\t\t\t}\n\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tif (!evaluateArrayConstraints(value as unknown[], prop)) return false;\n\t\t\t}\n\n\t\t\t// ── 2.6 — format ──\n\t\t\t// Valide la valeur contre le format via class-validator.\n\t\t\t// Le format ne s'applique qu'aux strings en Draft-07.\n\t\t\t// Si le format est inconnu → skip (retourne null → on continue).\n\t\t\tif (prop.format !== undefined && typeof value === \"string\") {\n\t\t\t\tconst formatResult = validateFormat(value, prop.format);\n\t\t\t\tif (formatResult === false) return false;\n\t\t\t\t// null (format inconnu) → skip, cohérent avec l'approche pragmatique\n\t\t\t}\n\n\t\t\t// ── 2.5 — Propriétés imbriquées (nested objects) ──\n\t\t\t// Si la propriété elle-même a des `properties` ou un `required`,\n\t\t\t// et que la valeur dans data est un objet, récurser dans evaluateCondition\n\t\t\t// en passant la sous-donnée comme nouveau `data`.\n\t\t\t// Si data[key] n'est pas un objet, on skip (retourne true pour cette prop,\n\t\t\t// cohérent avec \"absence = pas de contrainte\").\n\t\t\tif (isPlainObj(prop.properties) || Array.isArray(prop.required)) {\n\t\t\t\tif (isPlainObj(value)) {\n\t\t\t\t\tif (!evaluateCondition(prop, value as Record<string, unknown>)) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// value n'est pas un objet → skip, on ne peut pas évaluer les sous-props\n\t\t\t}\n\n\t\t\treturn true;\n\t\t});\n\t\tif (!propsOk) return false;\n\t}\n\n\t// ── required ──\n\tif (Array.isArray(ifSchema.required)) {\n\t\tconst allRequired = ifSchema.required.every((key) =>\n\t\t\thasOwn(data, key as string),\n\t\t);\n\t\tif (!allRequired) return false;\n\t}\n\n\t// ── 2.1 — allOf ──\n\t// Toutes les entrées du allOf doivent matcher (évaluation récursive).\n\tif (Array.isArray(ifSchema.allOf)) {\n\t\tconst allMatch = ifSchema.allOf.every((entry) => {\n\t\t\tif (typeof entry === \"boolean\") return entry;\n\t\t\treturn evaluateCondition(entry as JSONSchema7, data);\n\t\t});\n\t\tif (!allMatch) return false;\n\t}\n\n\t// ── 2.2 — anyOf ──\n\t// Au moins une entrée du anyOf doit matcher (évaluation récursive).\n\tif (Array.isArray(ifSchema.anyOf)) {\n\t\tconst anyMatch = ifSchema.anyOf.some((entry) => {\n\t\t\tif (typeof entry === \"boolean\") return entry;\n\t\t\treturn evaluateCondition(entry as JSONSchema7, data);\n\t\t});\n\t\tif (!anyMatch) return false;\n\t}\n\n\t// ── 2.3 — oneOf ──\n\t// Exactement une entrée du oneOf doit matcher (évaluation récursive).\n\tif (Array.isArray(ifSchema.oneOf)) {\n\t\tlet matchCount = 0;\n\t\tfor (const entry of ifSchema.oneOf) {\n\t\t\tconst matches =\n\t\t\t\ttypeof entry === \"boolean\"\n\t\t\t\t\t? entry\n\t\t\t\t\t: evaluateCondition(entry as JSONSchema7, data);\n\t\t\tif (matches) matchCount++;\n\t\t\tif (matchCount > 1) break;\n\t\t}\n\t\tif (matchCount !== 1) return false;\n\t}\n\n\t// ── 2.4 — not ──\n\t// Inverser le résultat de l'évaluation du contenu du `not`.\n\tif (\n\t\thasOwn(ifSchema, \"not\") &&\n\t\tisPlainObj(ifSchema.not) &&\n\t\ttypeof ifSchema.not !== \"boolean\"\n\t) {\n\t\tconst notResult = evaluateCondition(ifSchema.not as JSONSchema7, data);\n\t\tif (notResult) return false; // Le not matche → la condition not ne matche pas\n\t}\n\n\treturn true;\n}\n\n// ─── Discriminant extraction ─────────────────────────────────────────────────\n\n/**\n * Mots-clés qui indiquent qu'une propriété est un discriminant\n * (sa valeur dans les données est utilisée pour la résolution).\n *\n * Point 5 — Étendu avec les contraintes numériques/string/pattern.\n */\nconst DISCRIMINANT_INDICATORS = [\n\t\"const\",\n\t\"enum\",\n\t\"minimum\",\n\t\"maximum\",\n\t\"exclusiveMinimum\",\n\t\"exclusiveMaximum\",\n\t\"pattern\",\n\t\"minLength\",\n\t\"maxLength\",\n\t\"multipleOf\",\n\t\"minItems\",\n\t\"maxItems\",\n\t\"format\",\n] as const;\n\n/**\n * Extrait les valeurs discriminantes utilisées dans un `if` schema\n * depuis les données partielles.\n *\n * Point 5 — Collecte aussi les discriminants pour les nouvelles contraintes\n * (minimum, maximum, pattern, etc.).\n *\n * Utilise `_.some` pour vérifier qu'au moins un indicateur est présent,\n * et `_.has` pour un accès sûr.\n */\nfunction extractDiscriminants(\n\tifSchema: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tout: Record<string, unknown>,\n): void {\n\tif (!isPlainObj(ifSchema.properties)) return;\n\n\tconst props = ifSchema.properties as Record<string, JSONSchema7Definition>;\n\tfor (const key of Object.keys(props)) {\n\t\tconst propDef = props[key];\n\t\tif (typeof propDef === \"boolean\") continue;\n\t\tconst prop = propDef as JSONSchema7;\n\n\t\t// Collecter si au moins un indicateur de discriminant est présent\n\t\tconst hasIndicator = DISCRIMINANT_INDICATORS.some((indicator) =>\n\t\t\thasOwn(prop, indicator),\n\t\t);\n\n\t\tif (hasIndicator && hasOwn(data, key)) {\n\t\t\tout[key] = data[key];\n\t\t}\n\t}\n}\n\n// ─── Branch merging (deduplicated) ───────────────────────────────────────────\n\n/**\n * Merge une branche conditionnelle (`then` ou `else`) dans le schema résolu.\n *\n * Point 4 — Fix first-writer-wins :\n * Au lieu d'ignorer les keywords déjà présents dans `resolved`,\n * on tente un merge intelligent selon le type de keyword :\n *\n * - `required` → union dédupliquée via `_.union`\n * - `properties` → merge individuel via engine.merge\n * - `dependencies` → Point 3 : union des tableaux (forme 1),\n * merge des schemas (forme 2) via `_.mapValues`\n * - Sub-schema keys → merge via engine.merge\n * - Min keys → `Math.max` (plus restrictif)\n * - Max keys → `Math.min` (plus restrictif)\n * - `uniqueItems` → `true` gagne sur `false`\n * - `pattern` / `format` → la branche gagne (plus spécifique)\n * - Autres → tentative de merge via engine, sinon la branche gagne\n *\n * Utilise lodash massivement pour chaque opération de merge.\n */\nfunction mergeBranchInto(\n\tresolved: JSONSchema7,\n\tbranchDef: JSONSchema7Definition,\n\tengine: MergeEngine,\n): void {\n\tif (typeof branchDef === \"boolean\") return;\n\n\tconst branchSchema = branchDef as JSONSchema7;\n\n\t// ── Merger required via _.union (dédupliquée automatiquement) ──\n\tif (Array.isArray(branchSchema.required)) {\n\t\tresolved.required = unionStrings(\n\t\t\tresolved.required ?? [],\n\t\t\tbranchSchema.required,\n\t\t);\n\t}\n\n\t// ── Merger properties ──\n\tif (isPlainObj(branchSchema.properties)) {\n\t\tconst branchProps = branchSchema.properties as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tconst mergedProps: Record<string, JSONSchema7Definition> = {\n\t\t\t...(resolved.properties ?? {}),\n\t\t};\n\t\tfor (const key of Object.keys(branchProps)) {\n\t\t\tconst branchProp = branchProps[key];\n\t\t\tif (branchProp === undefined) continue;\n\t\t\tconst existing = resolved.properties?.[key];\n\t\t\tif (\n\t\t\t\texisting !== undefined &&\n\t\t\t\ttypeof existing !== \"boolean\" &&\n\t\t\t\ttypeof branchProp !== \"boolean\"\n\t\t\t) {\n\t\t\t\tconst merged = engine.merge(\n\t\t\t\t\texisting as JSONSchema7Definition,\n\t\t\t\t\tbranchProp as JSONSchema7Definition,\n\t\t\t\t);\n\t\t\t\tmergedProps[key] = (merged ?? branchProp) as JSONSchema7Definition;\n\t\t\t} else {\n\t\t\t\tmergedProps[key] = branchProp;\n\t\t\t}\n\t\t}\n\t\tresolved.properties = mergedProps;\n\t}\n\n\t// ── Merger dependencies (Point 3) ──\n\tif (isPlainObj(branchSchema.dependencies)) {\n\t\tconst resolvedDeps = (resolved.dependencies ?? {}) as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t\tconst branchDeps = branchSchema.dependencies as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\n\t\tconst acc = { ...resolvedDeps };\n\t\tfor (const depKey of Object.keys(branchDeps)) {\n\t\t\tconst branchVal = branchDeps[depKey] as\n\t\t\t\t| JSONSchema7Definition\n\t\t\t\t| string[]\n\t\t\t\t| undefined;\n\t\t\tif (branchVal === undefined) continue;\n\t\t\tconst existingVal = acc[depKey] as\n\t\t\t\t| JSONSchema7Definition\n\t\t\t\t| string[]\n\t\t\t\t| undefined;\n\n\t\t\tif (existingVal === undefined) {\n\t\t\t\t// Pas de valeur existante → copier directement\n\t\t\t\tacc[depKey] = branchVal;\n\t\t\t} else if (Array.isArray(existingVal) && Array.isArray(branchVal)) {\n\t\t\t\t// Forme 1 : union dédupliquée des tableaux de strings\n\t\t\t\tacc[depKey] = unionStrings(\n\t\t\t\t\texistingVal as string[],\n\t\t\t\t\tbranchVal as string[],\n\t\t\t\t);\n\t\t\t} else if (isPlainObj(existingVal) && isPlainObj(branchVal)) {\n\t\t\t\t// Forme 2 : merge des sous-schemas\n\t\t\t\tconst merged = engine.merge(\n\t\t\t\t\texistingVal as JSONSchema7Definition,\n\t\t\t\t\tbranchVal as JSONSchema7Definition,\n\t\t\t\t);\n\t\t\t\tacc[depKey] = (merged ?? branchVal) as JSONSchema7Definition;\n\t\t\t} else {\n\t\t\t\t// Types incompatibles (tableau vs schema) → la branche gagne\n\t\t\t\tacc[depKey] = branchVal;\n\t\t\t}\n\t\t}\n\t\tresolved.dependencies = acc as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t}\n\n\t// ── Merger les autres mots-clés (Point 4 — fix first-writer-wins) ──\n\tfor (const key of Object.keys(branchSchema) as (keyof JSONSchema7)[]) {\n\t\t// Skip les clés déjà traitées ci-dessus\n\t\tif (SPECIAL_MERGE_KEYS.has(key)) return;\n\n\t\tconst branchVal = branchSchema[key];\n\t\tconst resolvedVal = resolved[key];\n\n\t\t// Si le resolved n'a pas cette clé → copier directement\n\t\tif (resolvedVal === undefined) {\n\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\treturn;\n\t\t}\n\n\t\t// Si les deux ont la même valeur → rien à faire\n\t\tif (deepEqual(resolvedVal, branchVal)) return;\n\n\t\t// ── Sub-schema keys → merge via engine ──\n\t\tif (SUB_SCHEMA_KEYS.has(key)) {\n\t\t\tconst merged = engine.merge(\n\t\t\t\tresolvedVal as JSONSchema7Definition,\n\t\t\t\tbranchVal as JSONSchema7Definition,\n\t\t\t);\n\t\t\tif (merged !== null) {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = merged;\n\t\t\t} else {\n\t\t\t\t// Merge impossible → la branche gagne (contexte conditionnel)\n\t\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// ── Min keys → Math.max (plus restrictif) ──\n\t\tif (MIN_KEYS.has(key)) {\n\t\t\tif (typeof resolvedVal === \"number\" && typeof branchVal === \"number\") {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = Math.max(\n\t\t\t\t\tresolvedVal,\n\t\t\t\t\tbranchVal,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// ── Max keys → Math.min (plus restrictif) ──\n\t\tif (MAX_KEYS.has(key)) {\n\t\t\tif (typeof resolvedVal === \"number\" && typeof branchVal === \"number\") {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = Math.min(\n\t\t\t\t\tresolvedVal,\n\t\t\t\t\tbranchVal,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// ── uniqueItems → true gagne sur false ──\n\t\tif (key === \"uniqueItems\") {\n\t\t\t(resolved as Record<string, unknown>)[key] =\n\t\t\t\tresolvedVal === true || branchVal === true;\n\t\t\treturn;\n\t\t}\n\n\t\t// ── pattern / format → la branche gagne (plus spécifique au contexte) ──\n\t\tif (key === \"pattern\" || key === \"format\") {\n\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\treturn;\n\t\t}\n\n\t\t// ── Fallback : tentative de merge via engine pour les cas restants ──\n\t\tconst base = { [key]: resolvedVal } as JSONSchema7Definition;\n\t\tconst branch = { [key]: branchVal } as JSONSchema7Definition;\n\t\tconst merged = engine.merge(base, branch);\n\t\tif (\n\t\t\tmerged &&\n\t\t\ttypeof merged !== \"boolean\" &&\n\t\t\thasOwn(merged as object, key)\n\t\t) {\n\t\t\t(resolved as Record<string, unknown>)[key] = (\n\t\t\t\tmerged as unknown as Record<string, unknown>\n\t\t\t)[key];\n\t\t} else {\n\t\t\t// Merge échoué → la branche gagne (contexte conditionnel applicable)\n\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t}\n\t}\n}\n\n// ─── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Résout les `if/then/else` d'un schema en évaluant le `if` contre\n * des données partielles (discriminants).\n *\n * @param schema Le schema contenant potentiellement des if/then/else\n * @param data Données partielles utilisées pour évaluer les conditions\n * @param engine Le MergeEngine pour merger les branches\n *\n * @example\n * ```ts\n * const form = {\n * type: \"object\",\n * properties: { accountType: { type: \"string\" }, ... },\n * if: { properties: { accountType: { const: \"business\" } } },\n * then: { required: [\"companyName\"] },\n * else: { required: [\"firstName\"] },\n * };\n *\n * const { resolved } = resolveConditions(form, { accountType: \"business\" }, engine);\n * // → resolved n'a plus de if/then/else, mais a required: [\"companyName\"]\n * ```\n */\nexport function resolveConditions(\n\tschema: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tengine: MergeEngine,\n): ResolvedConditionResult {\n\tlet branch: \"then\" | \"else\" | null = null;\n\tconst discriminant: Record<string, unknown> = {};\n\n\t// ── Fast path: no conditions at all ──\n\t// If there's no `if` and no `allOf` with conditions, skip the copy entirely.\n\tconst hasTopLevelIf = schema.if !== undefined;\n\tconst hasAllOfConditions =\n\t\tArray.isArray(schema.allOf) &&\n\t\tschema.allOf.some(\n\t\t\t(e) => typeof e !== \"boolean\" && hasOwn(e as object, \"if\"),\n\t\t);\n\n\tif (!hasTopLevelIf && !hasAllOfConditions) {\n\t\t// Phase 3 only: check nested properties (resolveNestedProperties\n\t\t// already returns the original if nothing changes)\n\t\tconst resolved = resolveNestedProperties(\n\t\t\tschema,\n\t\t\tdata,\n\t\t\tengine,\n\t\t\tdiscriminant,\n\t\t);\n\t\treturn { resolved, branch, discriminant };\n\t}\n\n\t// ── Copy-on-write: only copy when mutations are needed ──\n\tlet resolved = { ...schema };\n\n\t// ── Phase 1 : Résoudre les if/then/else dans allOf ──\n\tif (hasAllOfConditions) {\n\t\tresolved = resolveAllOfConditions(resolved, data, engine, discriminant);\n\t}\n\n\t// ── Phase 2 : Résoudre le if/then/else de ce niveau ──\n\tif (resolved.if !== undefined) {\n\t\tconst ifSchema = resolved.if as JSONSchema7;\n\t\tconst matches = evaluateCondition(ifSchema, data);\n\n\t\textractDiscriminants(ifSchema, data, discriminant);\n\n\t\tconst applicableBranch = matches ? resolved.then : resolved.else;\n\t\tbranch = matches ? \"then\" : \"else\";\n\n\t\tif (applicableBranch) {\n\t\t\tmergeBranchInto(\n\t\t\t\tresolved,\n\t\t\t\tapplicableBranch as JSONSchema7Definition,\n\t\t\t\tengine,\n\t\t\t);\n\t\t}\n\n\t\tdelete resolved.if;\n\t\tdelete resolved.then;\n\t\tdelete resolved.else;\n\t}\n\n\t// ── Phase 3 : Récurser dans les properties ──\n\tresolved = resolveNestedProperties(resolved, data, engine, discriminant);\n\n\treturn { resolved, branch, discriminant };\n}\n\n// ─── Internal phases ─────────────────────────────────────────────────────────\n\n/**\n * Phase 1 : Parcourt les entrées `allOf` et résout celles qui contiennent\n * un `if/then/else`. Les entrées non-conditionnelles sont préservées.\n *\n * Utilise `_.reduce` pour accumuler les entrées restantes et `_.filter`\n * pour séparer les clés conditionnelles des non-conditionnelles.\n */\nfunction resolveAllOfConditions(\n\tresolved: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tengine: MergeEngine,\n\tdiscriminant: Record<string, unknown>,\n): JSONSchema7 {\n\tif (!Array.isArray(resolved.allOf)) return resolved;\n\n\tconst remainingAllOf: JSONSchema7Definition[] = [];\n\n\tfor (const entry of resolved.allOf) {\n\t\tif (typeof entry === \"boolean\") {\n\t\t\tremainingAllOf.push(entry);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst subSchema = entry as JSONSchema7;\n\n\t\tif (subSchema.if === undefined) {\n\t\t\tremainingAllOf.push(entry);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Résoudre la condition de cette entrée allOf\n\t\tconst ifSchema = subSchema.if as JSONSchema7;\n\t\tconst matches = evaluateCondition(ifSchema, data);\n\n\t\textractDiscriminants(ifSchema, data, discriminant);\n\n\t\tconst applicableBranch = matches ? subSchema.then : subSchema.else;\n\n\t\tif (applicableBranch) {\n\t\t\tmergeBranchInto(\n\t\t\t\tresolved,\n\t\t\t\tapplicableBranch as JSONSchema7Definition,\n\t\t\t\tengine,\n\t\t\t);\n\t\t}\n\n\t\t// Garder les parties non-conditionnelles de l'entrée allOf\n\t\tconst remaining = omitKeys(\n\t\t\tsubSchema as unknown as Record<string, unknown>,\n\t\t\t[\"if\", \"then\", \"else\"],\n\t\t);\n\t\tif (Object.keys(remaining).length > 0) {\n\t\t\tremainingAllOf.push(remaining as JSONSchema7);\n\t\t}\n\t}\n\n\tresolved = { ...resolved };\n\tif (remainingAllOf.length === 0) {\n\t\tdelete resolved.allOf;\n\t} else {\n\t\tresolved.allOf = remainingAllOf;\n\t}\n\n\treturn resolved;\n}\n\n/**\n * Phase 3 : Récurse dans les `properties` du schema résolu pour résoudre\n * les conditions imbriquées (ex: un objet dont une propriété a un if/then/else).\n *\n * Utilise `_.mapValues` pour transformer chaque propriété en une seule passe,\n * et `_.forEach` pour remonter les discriminants imbriqués.\n */\nfunction resolveNestedProperties(\n\tresolved: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tengine: MergeEngine,\n\tdiscriminant: Record<string, unknown>,\n): JSONSchema7 {\n\tif (!isPlainObj(resolved.properties)) return resolved;\n\n\tconst props = resolved.properties as Record<string, JSONSchema7Definition>;\n\tconst propKeys = Object.keys(props);\n\tlet changed = false;\n\tconst resolvedProps: Record<string, JSONSchema7Definition> = {};\n\n\tfor (const key of propKeys) {\n\t\tconst propDef = props[key];\n\t\tif (propDef === undefined) continue;\n\t\tif (typeof propDef === \"boolean\") {\n\t\t\tresolvedProps[key] = propDef;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst propSchema = propDef as JSONSchema7;\n\t\tconst hasConditions =\n\t\t\tpropSchema.if !== undefined ||\n\t\t\t(Array.isArray(propSchema.allOf) &&\n\t\t\t\tpropSchema.allOf.some(\n\t\t\t\t\t(e) => typeof e !== \"boolean\" && hasOwn(e as object, \"if\"),\n\t\t\t\t));\n\n\t\tif (!hasConditions) {\n\t\t\tresolvedProps[key] = propDef;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Données imbriquées disponibles → résoudre récursivement\n\t\tconst nestedData = isPlainObj(data[key])\n\t\t\t? (data[key] as Record<string, unknown>)\n\t\t\t: {};\n\n\t\tconst nested = resolveConditions(propSchema, nestedData, engine);\n\n\t\t// Remonter les discriminants imbriqués avec prefix\n\t\tfor (const dk of Object.keys(nested.discriminant)) {\n\t\t\tdiscriminant[`${key}.${dk}`] = nested.discriminant[dk];\n\t\t}\n\n\t\tresolvedProps[key] = nested.resolved;\n\t\tchanged = true;\n\t}\n\n\treturn changed ? { ...resolved, properties: resolvedProps } : resolved;\n}\n"],"names":["resolveConditions","SPECIAL_MERGE_KEYS","Set","SUB_SCHEMA_KEYS","MIN_KEYS","MAX_KEYS","matchesType","value","type","undefined","types","Array","isArray","actualType","inferType","some","t","evaluateNumericConstraints","prop","minimum","maximum","exclusiveMinimum","exclusiveMaximum","multipleOf","patternRegexCache","Map","getOrCompileRegex","pattern","regex","get","RegExp","set","evaluateStringConstraints","minLength","length","maxLength","test","evaluateArrayConstraints","minItems","maxItems","uniqueItems","len","i","j","deepEqual","evaluateCondition","ifSchema","data","isPlainObj","properties","propsOk","Object","keys","every","key","propDef","hasOwn","const","enum","v","format","formatResult","validateFormat","required","allRequired","allOf","allMatch","entry","anyOf","anyMatch","oneOf","matchCount","matches","not","notResult","DISCRIMINANT_INDICATORS","extractDiscriminants","out","props","hasIndicator","indicator","mergeBranchInto","resolved","branchDef","engine","branchSchema","unionStrings","branchProps","mergedProps","branchProp","existing","merged","merge","dependencies","resolvedDeps","branchDeps","acc","depKey","branchVal","existingVal","has","resolvedVal","Math","max","min","base","branch","schema","discriminant","hasTopLevelIf","if","hasAllOfConditions","e","resolveNestedProperties","resolveAllOfConditions","applicableBranch","then","else","remainingAllOf","push","subSchema","remaining","omitKeys","propKeys","changed","resolvedProps","propSchema","hasConditions","nestedData","nested","dk"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/condition-resolver.ts"],"sourcesContent":["import type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\nimport { validateFormat } from \"./format-validator\";\nimport type { MergeEngine } from \"./merge-engine\";\nimport { inferType } from \"./normalizer\";\nimport type { ResolvedConditionResult } from \"./types\";\nimport { deepEqual, hasOwn, isPlainObj, omitKeys, unionStrings } from \"./utils\";\n\n// ─── Condition Resolver ──────────────────────────────────────────────────────\n//\n// Résout les `if/then/else` d'un schema en évaluant le `if` contre\n// des données partielles (discriminants).\n//\n// Stratégie :\n// 1. Évaluer si les données partielles satisfont le `if`\n// 2. Merger la branche applicable (`then` ou `else`) dans le schema de base\n// 3. Supprimer les mots-clés `if/then/else` du résultat\n// 4. Récurser dans les `properties` pour résoudre les conditions imbriquées\n//\n// L'évaluation du `if` (via `evaluateCondition`) gère :\n// - `properties` avec `const`, `enum`, `type`, contraintes numériques/string/array\n// - `required` (vérification de présence des clés)\n// - `allOf` (toutes les entrées doivent matcher — récursion) [2.1]\n// - `anyOf` (au moins une entrée doit matcher — récursion) [2.2]\n// - `oneOf` (exactement une entrée doit matcher — récursion) [2.3]\n// - `not` (inversion du résultat — récursion) [2.4]\n// - Propriétés imbriquées (nested objects — récursion) [2.5]\n// - `format` via `validateFormat` de `format-validator.ts` [2.6]\n//\n// Uses custom utilities from `utils.ts`:\n// - `hasOwn` / `isPlainObj` for safe property access and type checks\n// - `deepEqual` for deep structural comparison\n// - `unionStrings` for merging string arrays (required, deps)\n// - `omitKeys` for excluding keys from objects\n\n// ─── Keywords classification ─────────────────────────────────────────────────\n\n/** Mots-clés qui ne doivent pas être traités par la boucle générique de mergeBranchInto */\nconst SPECIAL_MERGE_KEYS = new Set([\"required\", \"properties\", \"dependencies\"]);\n\n/** Mots-clés contenant un sous-schema unique (mergeable via engine.merge) */\nconst SUB_SCHEMA_KEYS = new Set([\n\t\"additionalProperties\",\n\t\"items\",\n\t\"contains\",\n\t\"propertyNames\",\n\t\"not\",\n]);\n\n/** Mots-clés numériques de type \"minimum\" (prendre le max pour être plus restrictif) */\nconst MIN_KEYS = new Set([\n\t\"minimum\",\n\t\"exclusiveMinimum\",\n\t\"minLength\",\n\t\"minItems\",\n\t\"minProperties\",\n]);\n\n/** Mots-clés numériques de type \"maximum\" (prendre le min pour être plus restrictif) */\nconst MAX_KEYS = new Set([\n\t\"maximum\",\n\t\"exclusiveMaximum\",\n\t\"maxLength\",\n\t\"maxItems\",\n\t\"maxProperties\",\n]);\n\n// ─── Condition evaluation (internal) ─────────────────────────────────────────\n\n/**\n * Vérifie si `value` correspond à un type JSON Schema.\n */\nfunction matchesType(value: unknown, type: JSONSchema7[\"type\"]): boolean {\n\tif (type === undefined) return true;\n\n\tconst types = Array.isArray(type) ? type : [type];\n\tconst actualType = inferType(value);\n\n\treturn types.some(\n\t\t(t) => t === actualType || (t === \"number\" && actualType === \"integer\"),\n\t);\n}\n\n/**\n * Évalue une contrainte numérique sur une valeur.\n * Point 5 — Enrichissement de evaluateCondition.\n */\nfunction evaluateNumericConstraints(value: number, prop: JSONSchema7): boolean {\n\tif (prop.minimum !== undefined && !(value >= prop.minimum)) return false;\n\tif (prop.maximum !== undefined && !(value <= prop.maximum)) return false;\n\tif (\n\t\tprop.exclusiveMinimum !== undefined &&\n\t\t!(value > (prop.exclusiveMinimum as number))\n\t)\n\t\treturn false;\n\tif (\n\t\tprop.exclusiveMaximum !== undefined &&\n\t\t!(value < (prop.exclusiveMaximum as number))\n\t)\n\t\treturn false;\n\tif (prop.multipleOf !== undefined && value % prop.multipleOf !== 0)\n\t\treturn false;\n\treturn true;\n}\n\n/**\n * Évalue une contrainte string sur une valeur.\n * Point 5 — Enrichissement de evaluateCondition.\n */\n/** Cache for compiled RegExp patterns used in evaluateStringConstraints */\nconst patternRegexCache = new Map<string, RegExp>();\n\nfunction getOrCompileRegex(pattern: string): RegExp {\n\tlet regex = patternRegexCache.get(pattern);\n\tif (regex === undefined) {\n\t\tregex = new RegExp(pattern);\n\t\tpatternRegexCache.set(pattern, regex);\n\t}\n\treturn regex;\n}\n\nfunction evaluateStringConstraints(value: string, prop: JSONSchema7): boolean {\n\tif (prop.minLength !== undefined && !(value.length >= prop.minLength))\n\t\treturn false;\n\tif (prop.maxLength !== undefined && !(value.length <= prop.maxLength))\n\t\treturn false;\n\tif (\n\t\tprop.pattern !== undefined &&\n\t\t!getOrCompileRegex(prop.pattern).test(value)\n\t)\n\t\treturn false;\n\treturn true;\n}\n\n/**\n * Évalue une contrainte array sur une valeur.\n * Point 5 — Enrichissement de evaluateCondition.\n */\nfunction evaluateArrayConstraints(\n\tvalue: unknown[],\n\tprop: JSONSchema7,\n): boolean {\n\tif (prop.minItems !== undefined && !(value.length >= prop.minItems))\n\t\treturn false;\n\tif (prop.maxItems !== undefined && !(value.length <= prop.maxItems))\n\t\treturn false;\n\tif (prop.uniqueItems === true) {\n\t\t// Vérifier l'unicité via deepEqual pour les éléments non-primitifs\n\t\t// Optimisation : double boucle sans slice pour éviter les allocations\n\t\tconst len = value.length;\n\t\tfor (let i = 0; i < len; i++) {\n\t\t\tfor (let j = i + 1; j < len; j++) {\n\t\t\t\tif (deepEqual(value[i], value[j])) return false;\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\n\n/**\n * Évalue si des données partielles satisfont un `if` schema.\n *\n * Stratégie pragmatique (pas un validateur complet) :\n * - Vérifie les `properties` avec `const`, `enum`, `type`\n * - Point 5 : Vérifie aussi minimum/maximum, minLength/maxLength,\n * pattern, multipleOf, minItems/maxItems, uniqueItems\n * - Vérifie les `required`\n * - 2.1 : `allOf` → toutes les entrées doivent matcher (récursion)\n * - 2.2 : `anyOf` → au moins une entrée doit matcher (récursion)\n * - 2.3 : `oneOf` → exactement une entrée doit matcher (récursion)\n * - 2.4 : `not` → inversion du résultat (récursion)\n * - 2.5 : Propriétés imbriquées → récursion sur les sous-objets\n * - 2.6 : `format` → validation via `validateFormat`\n *\n * Utilise `_.forEach` / `_.every` / `_.has` pour une itération idiomatique.\n */\nfunction evaluateCondition(\n\tifSchema: JSONSchema7,\n\tdata: Record<string, unknown>,\n): boolean {\n\tif (isPlainObj(ifSchema.properties)) {\n\t\tconst propsOk = Object.keys(ifSchema.properties).every((key) => {\n\t\t\tconst propDef = ifSchema.properties?.[key];\n\t\t\tif (typeof propDef === \"boolean\") return true;\n\t\t\tconst prop = propDef as JSONSchema7;\n\t\t\tconst value = data[key];\n\n\t\t\t// ── Propriété absente → skip ──\n\t\t\t// Selon la spec JSON Schema Draft-07, le keyword `properties` ne valide\n\t\t\t// une propriété que si elle est **présente** dans l'instance.\n\t\t\t// C'est le keyword `required` qui gère la présence obligatoire.\n\t\t\tif (value === undefined) return true;\n\n\t\t\t// ── const ──\n\t\t\tif (hasOwn(prop, \"const\")) {\n\t\t\t\tif (!deepEqual(value, prop.const)) return false;\n\t\t\t}\n\n\t\t\t// ── enum ──\n\t\t\tif (hasOwn(prop, \"enum\")) {\n\t\t\t\tif (!prop.enum?.some((v) => deepEqual(v, value))) return false;\n\t\t\t}\n\n\t\t\t// ── type ──\n\t\t\tif (hasOwn(prop, \"type\") && value !== undefined) {\n\t\t\t\tif (!matchesType(value, prop.type)) return false;\n\t\t\t}\n\n\t\t\t// ── Point 5 : Contraintes numériques/string/array ──\n\t\t\t// Quand `value` est `undefined`, aucun de ces blocs ne s'exécute\n\t\t\t// (`typeof undefined` vaut `\"undefined\"`, pas `\"number\"` ni `\"string\"`,\n\t\t\t// et `isArray(undefined)` retourne `false`).\n\t\t\t// C'est le comportement voulu : on ne peut pas évaluer une contrainte\n\t\t\t// sur une donnée absente → on skip, cohérent avec la logique pragmatique.\n\t\t\tif (typeof value === \"number\") {\n\t\t\t\tif (!evaluateNumericConstraints(value, prop)) return false;\n\t\t\t}\n\n\t\t\tif (typeof value === \"string\") {\n\t\t\t\tif (!evaluateStringConstraints(value, prop)) return false;\n\t\t\t}\n\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tif (!evaluateArrayConstraints(value as unknown[], prop)) return false;\n\t\t\t}\n\n\t\t\t// ── 2.6 — format ──\n\t\t\t// Valide la valeur contre le format via class-validator.\n\t\t\t// Le format ne s'applique qu'aux strings en Draft-07.\n\t\t\t// Si le format est inconnu → skip (retourne null → on continue).\n\t\t\tif (prop.format !== undefined && typeof value === \"string\") {\n\t\t\t\tconst formatResult = validateFormat(value, prop.format);\n\t\t\t\tif (formatResult === false) return false;\n\t\t\t\t// null (format inconnu) → skip, cohérent avec l'approche pragmatique\n\t\t\t}\n\n\t\t\t// ── 2.5 — Propriétés imbriquées (nested objects) ──\n\t\t\t// Si la propriété elle-même a des `properties` ou un `required`,\n\t\t\t// et que la valeur dans data est un objet, récurser dans evaluateCondition\n\t\t\t// en passant la sous-donnée comme nouveau `data`.\n\t\t\t// Si data[key] n'est pas un objet, on skip (retourne true pour cette prop,\n\t\t\t// cohérent avec \"absence = pas de contrainte\").\n\t\t\tif (isPlainObj(prop.properties) || Array.isArray(prop.required)) {\n\t\t\t\tif (isPlainObj(value)) {\n\t\t\t\t\tif (!evaluateCondition(prop, value as Record<string, unknown>)) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// value n'est pas un objet → skip, on ne peut pas évaluer les sous-props\n\t\t\t}\n\n\t\t\treturn true;\n\t\t});\n\t\tif (!propsOk) return false;\n\t}\n\n\t// ── required ──\n\tif (Array.isArray(ifSchema.required)) {\n\t\tconst allRequired = ifSchema.required.every((key) =>\n\t\t\thasOwn(data, key as string),\n\t\t);\n\t\tif (!allRequired) return false;\n\t}\n\n\t// ── 2.1 — allOf ──\n\t// Toutes les entrées du allOf doivent matcher (évaluation récursive).\n\tif (Array.isArray(ifSchema.allOf)) {\n\t\tconst allMatch = ifSchema.allOf.every((entry) => {\n\t\t\tif (typeof entry === \"boolean\") return entry;\n\t\t\treturn evaluateCondition(entry as JSONSchema7, data);\n\t\t});\n\t\tif (!allMatch) return false;\n\t}\n\n\t// ── 2.2 — anyOf ──\n\t// Au moins une entrée du anyOf doit matcher (évaluation récursive).\n\tif (Array.isArray(ifSchema.anyOf)) {\n\t\tconst anyMatch = ifSchema.anyOf.some((entry) => {\n\t\t\tif (typeof entry === \"boolean\") return entry;\n\t\t\treturn evaluateCondition(entry as JSONSchema7, data);\n\t\t});\n\t\tif (!anyMatch) return false;\n\t}\n\n\t// ── 2.3 — oneOf ──\n\t// Exactement une entrée du oneOf doit matcher (évaluation récursive).\n\tif (Array.isArray(ifSchema.oneOf)) {\n\t\tlet matchCount = 0;\n\t\tfor (const entry of ifSchema.oneOf) {\n\t\t\tconst matches =\n\t\t\t\ttypeof entry === \"boolean\"\n\t\t\t\t\t? entry\n\t\t\t\t\t: evaluateCondition(entry as JSONSchema7, data);\n\t\t\tif (matches) matchCount++;\n\t\t\tif (matchCount > 1) break;\n\t\t}\n\t\tif (matchCount !== 1) return false;\n\t}\n\n\t// ── 2.4 — not ──\n\t// Inverser le résultat de l'évaluation du contenu du `not`.\n\tif (\n\t\thasOwn(ifSchema, \"not\") &&\n\t\tisPlainObj(ifSchema.not) &&\n\t\ttypeof ifSchema.not !== \"boolean\"\n\t) {\n\t\tconst notResult = evaluateCondition(ifSchema.not as JSONSchema7, data);\n\t\tif (notResult) return false; // Le not matche → la condition not ne matche pas\n\t}\n\n\treturn true;\n}\n\n// ─── Discriminant extraction ─────────────────────────────────────────────────\n\n/**\n * Mots-clés qui indiquent qu'une propriété est un discriminant\n * (sa valeur dans les données est utilisée pour la résolution).\n *\n * Point 5 — Étendu avec les contraintes numériques/string/pattern.\n */\nconst DISCRIMINANT_INDICATORS = [\n\t\"const\",\n\t\"enum\",\n\t\"minimum\",\n\t\"maximum\",\n\t\"exclusiveMinimum\",\n\t\"exclusiveMaximum\",\n\t\"pattern\",\n\t\"minLength\",\n\t\"maxLength\",\n\t\"multipleOf\",\n\t\"minItems\",\n\t\"maxItems\",\n\t\"format\",\n] as const;\n\n/**\n * Extrait les valeurs discriminantes utilisées dans un `if` schema\n * depuis les données partielles.\n *\n * Point 5 — Collecte aussi les discriminants pour les nouvelles contraintes\n * (minimum, maximum, pattern, etc.).\n *\n * Utilise `_.some` pour vérifier qu'au moins un indicateur est présent,\n * et `_.has` pour un accès sûr.\n */\nfunction extractDiscriminants(\n\tifSchema: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tout: Record<string, unknown>,\n): void {\n\tif (!isPlainObj(ifSchema.properties)) return;\n\n\tconst props = ifSchema.properties as Record<string, JSONSchema7Definition>;\n\tfor (const key of Object.keys(props)) {\n\t\tconst propDef = props[key];\n\t\tif (typeof propDef === \"boolean\") continue;\n\t\tconst prop = propDef as JSONSchema7;\n\n\t\t// Collecter si au moins un indicateur de discriminant est présent\n\t\tconst hasIndicator = DISCRIMINANT_INDICATORS.some((indicator) =>\n\t\t\thasOwn(prop, indicator),\n\t\t);\n\n\t\tif (hasIndicator && hasOwn(data, key)) {\n\t\t\tout[key] = data[key];\n\t\t}\n\t}\n}\n\n// ─── Branch merging (deduplicated) ───────────────────────────────────────────\n\n/**\n * Merge une branche conditionnelle (`then` ou `else`) dans le schema résolu.\n *\n * Point 4 — Fix first-writer-wins :\n * Au lieu d'ignorer les keywords déjà présents dans `resolved`,\n * on tente un merge intelligent selon le type de keyword :\n *\n * - `required` → union dédupliquée via `_.union`\n * - `properties` → merge individuel via engine.merge\n * - `dependencies` → Point 3 : union des tableaux (forme 1),\n * merge des schemas (forme 2) via `_.mapValues`\n * - Sub-schema keys → merge via engine.merge\n * - Min keys → `Math.max` (plus restrictif)\n * - Max keys → `Math.min` (plus restrictif)\n * - `uniqueItems` → `true` gagne sur `false`\n * - `pattern` / `format` → la branche gagne (plus spécifique)\n * - Autres → tentative de merge via engine, sinon la branche gagne\n *\n * Uses custom utilities from `utils.ts` for each merge operation.\n */\nfunction mergeBranchInto(\n\tresolved: JSONSchema7,\n\tbranchDef: JSONSchema7Definition,\n\tengine: MergeEngine,\n): void {\n\tif (typeof branchDef === \"boolean\") return;\n\n\tconst branchSchema = branchDef as JSONSchema7;\n\n\t// ── Merge required via unionStrings (deduplicated automatically) ──\n\tif (Array.isArray(branchSchema.required)) {\n\t\tresolved.required = unionStrings(\n\t\t\tresolved.required ?? [],\n\t\t\tbranchSchema.required,\n\t\t);\n\t}\n\n\t// ── Merger properties ──\n\tif (isPlainObj(branchSchema.properties)) {\n\t\tconst branchProps = branchSchema.properties as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tconst mergedProps: Record<string, JSONSchema7Definition> = {\n\t\t\t...(resolved.properties ?? {}),\n\t\t};\n\t\tfor (const key of Object.keys(branchProps)) {\n\t\t\tconst branchProp = branchProps[key];\n\t\t\tif (branchProp === undefined) continue;\n\t\t\tconst existing = resolved.properties?.[key];\n\t\t\tif (\n\t\t\t\texisting !== undefined &&\n\t\t\t\ttypeof existing !== \"boolean\" &&\n\t\t\t\ttypeof branchProp !== \"boolean\"\n\t\t\t) {\n\t\t\t\tconst merged = engine.merge(\n\t\t\t\t\texisting as JSONSchema7Definition,\n\t\t\t\t\tbranchProp as JSONSchema7Definition,\n\t\t\t\t);\n\t\t\t\tmergedProps[key] = (merged ?? branchProp) as JSONSchema7Definition;\n\t\t\t} else {\n\t\t\t\tmergedProps[key] = branchProp;\n\t\t\t}\n\t\t}\n\t\tresolved.properties = mergedProps;\n\t}\n\n\t// ── Merger dependencies (Point 3) ──\n\tif (isPlainObj(branchSchema.dependencies)) {\n\t\tconst resolvedDeps = (resolved.dependencies ?? {}) as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t\tconst branchDeps = branchSchema.dependencies as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\n\t\tconst acc = { ...resolvedDeps };\n\t\tfor (const depKey of Object.keys(branchDeps)) {\n\t\t\tconst branchVal = branchDeps[depKey] as\n\t\t\t\t| JSONSchema7Definition\n\t\t\t\t| string[]\n\t\t\t\t| undefined;\n\t\t\tif (branchVal === undefined) continue;\n\t\t\tconst existingVal = acc[depKey] as\n\t\t\t\t| JSONSchema7Definition\n\t\t\t\t| string[]\n\t\t\t\t| undefined;\n\n\t\t\tif (existingVal === undefined) {\n\t\t\t\t// Pas de valeur existante → copier directement\n\t\t\t\tacc[depKey] = branchVal;\n\t\t\t} else if (Array.isArray(existingVal) && Array.isArray(branchVal)) {\n\t\t\t\t// Forme 1 : union dédupliquée des tableaux de strings\n\t\t\t\tacc[depKey] = unionStrings(\n\t\t\t\t\texistingVal as string[],\n\t\t\t\t\tbranchVal as string[],\n\t\t\t\t);\n\t\t\t} else if (isPlainObj(existingVal) && isPlainObj(branchVal)) {\n\t\t\t\t// Forme 2 : merge des sous-schemas\n\t\t\t\tconst merged = engine.merge(\n\t\t\t\t\texistingVal as JSONSchema7Definition,\n\t\t\t\t\tbranchVal as JSONSchema7Definition,\n\t\t\t\t);\n\t\t\t\tacc[depKey] = (merged ?? branchVal) as JSONSchema7Definition;\n\t\t\t} else {\n\t\t\t\t// Types incompatibles (tableau vs schema) → la branche gagne\n\t\t\t\tacc[depKey] = branchVal;\n\t\t\t}\n\t\t}\n\t\tresolved.dependencies = acc as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t}\n\n\t// ── Merger les autres mots-clés (Point 4 — fix first-writer-wins) ──\n\tfor (const key of Object.keys(branchSchema) as (keyof JSONSchema7)[]) {\n\t\t// Skip les clés déjà traitées ci-dessus\n\t\tif (SPECIAL_MERGE_KEYS.has(key)) return;\n\n\t\tconst branchVal = branchSchema[key];\n\t\tconst resolvedVal = resolved[key];\n\n\t\t// Si le resolved n'a pas cette clé → copier directement\n\t\tif (resolvedVal === undefined) {\n\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\treturn;\n\t\t}\n\n\t\t// Si les deux ont la même valeur → rien à faire\n\t\tif (deepEqual(resolvedVal, branchVal)) return;\n\n\t\t// ── Sub-schema keys → merge via engine ──\n\t\tif (SUB_SCHEMA_KEYS.has(key)) {\n\t\t\tconst merged = engine.merge(\n\t\t\t\tresolvedVal as JSONSchema7Definition,\n\t\t\t\tbranchVal as JSONSchema7Definition,\n\t\t\t);\n\t\t\tif (merged !== null) {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = merged;\n\t\t\t} else {\n\t\t\t\t// Merge impossible → la branche gagne (contexte conditionnel)\n\t\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// ── Min keys → Math.max (plus restrictif) ──\n\t\tif (MIN_KEYS.has(key)) {\n\t\t\tif (typeof resolvedVal === \"number\" && typeof branchVal === \"number\") {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = Math.max(\n\t\t\t\t\tresolvedVal,\n\t\t\t\t\tbranchVal,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// ── Max keys → Math.min (plus restrictif) ──\n\t\tif (MAX_KEYS.has(key)) {\n\t\t\tif (typeof resolvedVal === \"number\" && typeof branchVal === \"number\") {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = Math.min(\n\t\t\t\t\tresolvedVal,\n\t\t\t\t\tbranchVal,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// ── uniqueItems → true gagne sur false ──\n\t\tif (key === \"uniqueItems\") {\n\t\t\t(resolved as Record<string, unknown>)[key] =\n\t\t\t\tresolvedVal === true || branchVal === true;\n\t\t\treturn;\n\t\t}\n\n\t\t// ── pattern / format → la branche gagne (plus spécifique au contexte) ──\n\t\tif (key === \"pattern\" || key === \"format\") {\n\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\treturn;\n\t\t}\n\n\t\t// ── Fallback : tentative de merge via engine pour les cas restants ──\n\t\tconst base = { [key]: resolvedVal } as JSONSchema7Definition;\n\t\tconst branch = { [key]: branchVal } as JSONSchema7Definition;\n\t\tconst merged = engine.merge(base, branch);\n\t\tif (\n\t\t\tmerged &&\n\t\t\ttypeof merged !== \"boolean\" &&\n\t\t\thasOwn(merged as object, key)\n\t\t) {\n\t\t\t(resolved as Record<string, unknown>)[key] = (\n\t\t\t\tmerged as unknown as Record<string, unknown>\n\t\t\t)[key];\n\t\t} else {\n\t\t\t// Merge échoué → la branche gagne (contexte conditionnel applicable)\n\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t}\n\t}\n}\n\n// ─── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Résout les `if/then/else` d'un schema en évaluant le `if` contre\n * des données partielles (discriminants).\n *\n * @param schema Le schema contenant potentiellement des if/then/else\n * @param data Données partielles utilisées pour évaluer les conditions\n * @param engine Le MergeEngine pour merger les branches\n *\n * @example\n * ```ts\n * const form = {\n * type: \"object\",\n * properties: { accountType: { type: \"string\" }, ... },\n * if: { properties: { accountType: { const: \"business\" } } },\n * then: { required: [\"companyName\"] },\n * else: { required: [\"firstName\"] },\n * };\n *\n * const { resolved } = resolveConditions(form, { accountType: \"business\" }, engine);\n * // → resolved n'a plus de if/then/else, mais a required: [\"companyName\"]\n * ```\n */\nexport function resolveConditions(\n\tschema: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tengine: MergeEngine,\n): ResolvedConditionResult {\n\tlet branch: \"then\" | \"else\" | null = null;\n\tconst discriminant: Record<string, unknown> = {};\n\n\t// ── Fast path: no conditions at all ──\n\t// If there's no `if` and no `allOf` with conditions, skip the copy entirely.\n\tconst hasTopLevelIf = schema.if !== undefined;\n\tconst hasAllOfConditions =\n\t\tArray.isArray(schema.allOf) &&\n\t\tschema.allOf.some(\n\t\t\t(e) => typeof e !== \"boolean\" && hasOwn(e as object, \"if\"),\n\t\t);\n\n\tif (!hasTopLevelIf && !hasAllOfConditions) {\n\t\t// Phase 3 only: check nested properties (resolveNestedProperties\n\t\t// already returns the original if nothing changes)\n\t\tconst resolved = resolveNestedProperties(\n\t\t\tschema,\n\t\t\tdata,\n\t\t\tengine,\n\t\t\tdiscriminant,\n\t\t);\n\t\treturn { resolved, branch, discriminant };\n\t}\n\n\t// ── Copy-on-write: only copy when mutations are needed ──\n\tlet resolved = { ...schema };\n\n\t// ── Phase 1 : Résoudre les if/then/else dans allOf ──\n\tif (hasAllOfConditions) {\n\t\tresolved = resolveAllOfConditions(resolved, data, engine, discriminant);\n\t}\n\n\t// ── Phase 2 : Résoudre le if/then/else de ce niveau ──\n\tif (resolved.if !== undefined) {\n\t\tconst ifSchema = resolved.if as JSONSchema7;\n\t\tconst matches = evaluateCondition(ifSchema, data);\n\n\t\textractDiscriminants(ifSchema, data, discriminant);\n\n\t\tconst applicableBranch = matches ? resolved.then : resolved.else;\n\t\tbranch = matches ? \"then\" : \"else\";\n\n\t\tif (applicableBranch) {\n\t\t\tmergeBranchInto(\n\t\t\t\tresolved,\n\t\t\t\tapplicableBranch as JSONSchema7Definition,\n\t\t\t\tengine,\n\t\t\t);\n\t\t}\n\n\t\tdelete resolved.if;\n\t\tdelete resolved.then;\n\t\tdelete resolved.else;\n\t}\n\n\t// ── Phase 3 : Récurser dans les properties ──\n\tresolved = resolveNestedProperties(resolved, data, engine, discriminant);\n\n\treturn { resolved, branch, discriminant };\n}\n\n// ─── Internal phases ─────────────────────────────────────────────────────────\n\n/**\n * Phase 1 : Parcourt les entrées `allOf` et résout celles qui contiennent\n * un `if/then/else`. Les entrées non-conditionnelles sont préservées.\n *\n * Utilise `_.reduce` pour accumuler les entrées restantes et `_.filter`\n * pour séparer les clés conditionnelles des non-conditionnelles.\n */\nfunction resolveAllOfConditions(\n\tresolved: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tengine: MergeEngine,\n\tdiscriminant: Record<string, unknown>,\n): JSONSchema7 {\n\tif (!Array.isArray(resolved.allOf)) return resolved;\n\n\tconst remainingAllOf: JSONSchema7Definition[] = [];\n\n\tfor (const entry of resolved.allOf) {\n\t\tif (typeof entry === \"boolean\") {\n\t\t\tremainingAllOf.push(entry);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst subSchema = entry as JSONSchema7;\n\n\t\tif (subSchema.if === undefined) {\n\t\t\tremainingAllOf.push(entry);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Résoudre la condition de cette entrée allOf\n\t\tconst ifSchema = subSchema.if as JSONSchema7;\n\t\tconst matches = evaluateCondition(ifSchema, data);\n\n\t\textractDiscriminants(ifSchema, data, discriminant);\n\n\t\tconst applicableBranch = matches ? subSchema.then : subSchema.else;\n\n\t\tif (applicableBranch) {\n\t\t\tmergeBranchInto(\n\t\t\t\tresolved,\n\t\t\t\tapplicableBranch as JSONSchema7Definition,\n\t\t\t\tengine,\n\t\t\t);\n\t\t}\n\n\t\t// Garder les parties non-conditionnelles de l'entrée allOf\n\t\tconst remaining = omitKeys(\n\t\t\tsubSchema as unknown as Record<string, unknown>,\n\t\t\t[\"if\", \"then\", \"else\"],\n\t\t);\n\t\tif (Object.keys(remaining).length > 0) {\n\t\t\tremainingAllOf.push(remaining as JSONSchema7);\n\t\t}\n\t}\n\n\tresolved = { ...resolved };\n\tif (remainingAllOf.length === 0) {\n\t\tdelete resolved.allOf;\n\t} else {\n\t\tresolved.allOf = remainingAllOf;\n\t}\n\n\treturn resolved;\n}\n\n/**\n * Phase 3 : Récurse dans les `properties` du schema résolu pour résoudre\n * les conditions imbriquées (ex: un objet dont une propriété a un if/then/else).\n *\n * Utilise `_.mapValues` pour transformer chaque propriété en une seule passe,\n * et `_.forEach` pour remonter les discriminants imbriqués.\n */\nfunction resolveNestedProperties(\n\tresolved: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tengine: MergeEngine,\n\tdiscriminant: Record<string, unknown>,\n): JSONSchema7 {\n\tif (!isPlainObj(resolved.properties)) return resolved;\n\n\tconst props = resolved.properties as Record<string, JSONSchema7Definition>;\n\tconst propKeys = Object.keys(props);\n\tlet changed = false;\n\tconst resolvedProps: Record<string, JSONSchema7Definition> = {};\n\n\tfor (const key of propKeys) {\n\t\tconst propDef = props[key];\n\t\tif (propDef === undefined) continue;\n\t\tif (typeof propDef === \"boolean\") {\n\t\t\tresolvedProps[key] = propDef;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst propSchema = propDef as JSONSchema7;\n\t\tconst hasConditions =\n\t\t\tpropSchema.if !== undefined ||\n\t\t\t(Array.isArray(propSchema.allOf) &&\n\t\t\t\tpropSchema.allOf.some(\n\t\t\t\t\t(e) => typeof e !== \"boolean\" && hasOwn(e as object, \"if\"),\n\t\t\t\t));\n\n\t\tif (!hasConditions) {\n\t\t\tresolvedProps[key] = propDef;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Données imbriquées disponibles → résoudre récursivement\n\t\tconst nestedData = isPlainObj(data[key])\n\t\t\t? (data[key] as Record<string, unknown>)\n\t\t\t: {};\n\n\t\tconst nested = resolveConditions(propSchema, nestedData, engine);\n\n\t\t// Remonter les discriminants imbriqués avec prefix\n\t\tfor (const dk of Object.keys(nested.discriminant)) {\n\t\t\tdiscriminant[`${key}.${dk}`] = nested.discriminant[dk];\n\t\t}\n\n\t\tresolvedProps[key] = nested.resolved;\n\t\tchanged = true;\n\t}\n\n\treturn changed ? { ...resolved, properties: resolvedProps } : resolved;\n}\n"],"names":["resolveConditions","SPECIAL_MERGE_KEYS","Set","SUB_SCHEMA_KEYS","MIN_KEYS","MAX_KEYS","matchesType","value","type","undefined","types","Array","isArray","actualType","inferType","some","t","evaluateNumericConstraints","prop","minimum","maximum","exclusiveMinimum","exclusiveMaximum","multipleOf","patternRegexCache","Map","getOrCompileRegex","pattern","regex","get","RegExp","set","evaluateStringConstraints","minLength","length","maxLength","test","evaluateArrayConstraints","minItems","maxItems","uniqueItems","len","i","j","deepEqual","evaluateCondition","ifSchema","data","isPlainObj","properties","propsOk","Object","keys","every","key","propDef","hasOwn","const","enum","v","format","formatResult","validateFormat","required","allRequired","allOf","allMatch","entry","anyOf","anyMatch","oneOf","matchCount","matches","not","notResult","DISCRIMINANT_INDICATORS","extractDiscriminants","out","props","hasIndicator","indicator","mergeBranchInto","resolved","branchDef","engine","branchSchema","unionStrings","branchProps","mergedProps","branchProp","existing","merged","merge","dependencies","resolvedDeps","branchDeps","acc","depKey","branchVal","existingVal","has","resolvedVal","Math","max","min","base","branch","schema","discriminant","hasTopLevelIf","if","hasAllOfConditions","e","resolveNestedProperties","resolveAllOfConditions","applicableBranch","then","else","remainingAllOf","push","subSchema","remaining","omitKeys","propKeys","changed","resolvedProps","propSchema","hasConditions","nestedData","nested","dk"],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { JSONSchema7 } from "json-schema";
|
|
2
|
+
/**
|
|
3
|
+
* Narrows a schema using runtime data when the target schema has enum
|
|
4
|
+
* constraints that match the data values.
|
|
5
|
+
*
|
|
6
|
+
* This enables runtime-aware subset checking: when a schema is generic
|
|
7
|
+
* (e.g. `{ type: "string" }`) but the actual runtime value matches an
|
|
8
|
+
* enum constraint in the target schema, the source schema is narrowed
|
|
9
|
+
* to reflect the concrete value.
|
|
10
|
+
*
|
|
11
|
+
* @param schema - The resolved source schema to potentially narrow
|
|
12
|
+
* @param data - The runtime data value (primitive or object)
|
|
13
|
+
* @param targetSchema - The target schema containing potential enum constraints
|
|
14
|
+
* @returns The narrowed schema or the original if no narrowing applies
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* // Primitive narrowing
|
|
19
|
+
* const sub = { type: "string" };
|
|
20
|
+
* const sup = { type: "string", enum: ["red", "green", "blue"] };
|
|
21
|
+
* narrowSchemaWithData(sub, "red", sup);
|
|
22
|
+
* // → { type: "string", enum: ["red"] }
|
|
23
|
+
*
|
|
24
|
+
* // Object property narrowing
|
|
25
|
+
* const sub = { type: "object", properties: { color: { type: "string" } } };
|
|
26
|
+
* const sup = { type: "object", properties: { color: { type: "string", enum: ["red", "green"] } } };
|
|
27
|
+
* narrowSchemaWithData(sub, { color: "red" }, sup);
|
|
28
|
+
* // → { type: "object", properties: { color: { type: "string", enum: ["red"] } } }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function narrowSchemaWithData(schema: JSONSchema7, data: unknown, targetSchema: JSONSchema7): JSONSchema7;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"narrowSchemaWithData",{enumerable:true,get:function(){return narrowSchemaWithData}});const _utilsts=require("./utils.js");function isValueInEnum(value,enumValues){if(!Array.isArray(enumValues))return false;return enumValues.some(v=>(0,_utilsts.deepEqual)(v,value))}function getTargetEnum(schema){if(Array.isArray(schema.enum))return schema.enum;if("const"in schema)return[schema.const];return undefined}function narrowPrimitive(schema,data,targetSchema){const targetEnum=getTargetEnum(targetSchema);if(targetEnum===undefined)return schema;if(Array.isArray(schema.enum)||"const"in schema)return schema;if(!isValueInEnum(data,targetEnum))return schema;return{...schema,enum:[data]}}function narrowObjectProperties(schema,data,targetSchema){if(!(0,_utilsts.isPlainObj)(schema.properties))return schema;if(!(0,_utilsts.isPlainObj)(targetSchema.properties))return schema;const props=schema.properties;const targetProps=targetSchema.properties;let changed=false;const narrowedProps={};for(const key of Object.keys(props)){const propDef=props[key];if(propDef===undefined)continue;if(typeof propDef==="boolean"){narrowedProps[key]=propDef;continue}const targetPropDef=targetProps[key];const propData=data[key];if(targetPropDef===undefined||typeof targetPropDef==="boolean"||propData===undefined){narrowedProps[key]=propDef;continue}const narrowed=narrowSchemaWithData(propDef,propData,targetPropDef);if(narrowed!==propDef){changed=true}narrowedProps[key]=narrowed}if(!changed)return schema;return{...schema,properties:narrowedProps}}function narrowSchemaWithData(schema,data,targetSchema){if(schema===targetSchema||data===undefined||data===null){return schema}if((0,_utilsts.isPlainObj)(data)&&schema.type==="object"){return narrowObjectProperties(schema,data,targetSchema)}if(!(0,_utilsts.isPlainObj)(data)){return narrowPrimitive(schema,data,targetSchema)}return schema}
|
|
2
|
+
//# sourceMappingURL=data-narrowing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/data-narrowing.ts"],"sourcesContent":["import type {\n\tJSONSchema7,\n\tJSONSchema7Definition,\n\tJSONSchema7Type,\n} from \"json-schema\";\nimport { deepEqual, isPlainObj } from \"./utils.ts\";\n\n// ─── Data Narrowing ──────────────────────────────────────────────────────────\n//\n// Narrows a resolved schema using runtime data when the target schema\n// contains enum constraints that match the data values.\n//\n// Use case: when `sub` is `{ type: \"string\" }` and `sup` is\n// `{ type: \"string\", enum: [\"red\", \"green\", \"blue\"] }`, and\n// `subData = \"red\"`, the sub schema is narrowed to\n// `{ type: \"string\", enum: [\"red\"] }` so that the subset check succeeds.\n//\n// Rules:\n// - Only narrows when the target schema has an `enum` (or `const`)\n// - Only narrows when the runtime value is present in the target enum\n// - If the value is NOT in the target enum, the schema is unchanged\n// - If the target has no enum/const, the schema is unchanged\n// - Recurses into object properties for complex schemas\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n/**\n * Checks if a value is present in an enum array using deep equality.\n */\nfunction isValueInEnum(\n\tvalue: unknown,\n\tenumValues: JSONSchema7[\"enum\"],\n): boolean {\n\tif (!Array.isArray(enumValues)) return false;\n\treturn enumValues.some((v) => deepEqual(v, value));\n}\n\n/**\n * Extracts the effective enum values from a schema.\n * Handles both `enum` and `const` keywords.\n * Returns undefined if the schema has no enum constraint.\n */\nfunction getTargetEnum(schema: JSONSchema7): JSONSchema7Type[] | undefined {\n\tif (Array.isArray(schema.enum)) return schema.enum;\n\tif (\"const\" in schema) return [schema.const as JSONSchema7Type];\n\treturn undefined;\n}\n\n// ─── Core Narrowing ──────────────────────────────────────────────────────────\n\n/**\n * Narrows a primitive schema by adding an enum constraint matching the\n * runtime data value, if that value is present in the target schema's enum.\n *\n * @param schema - The resolved schema to potentially narrow\n * @param data - The runtime data value\n * @param targetSchema - The opposite schema containing potential enum constraints\n * @returns The narrowed schema (new object) or the original if no narrowing occurred\n */\nfunction narrowPrimitive(\n\tschema: JSONSchema7,\n\tdata: unknown,\n\ttargetSchema: JSONSchema7,\n): JSONSchema7 {\n\tconst targetEnum = getTargetEnum(targetSchema);\n\tif (targetEnum === undefined) return schema;\n\n\t// Only narrow if the schema doesn't already have enum/const constraints\n\tif (Array.isArray(schema.enum) || \"const\" in schema) return schema;\n\n\t// Only narrow if the runtime value matches the target enum\n\tif (!isValueInEnum(data, targetEnum)) return schema;\n\n\t// Narrow: add enum: [data] to the schema\n\treturn { ...schema, enum: [data as JSONSchema7Type] };\n}\n\n/**\n * Narrows object properties recursively by matching runtime data values\n * against the target schema's property enum constraints.\n *\n * @param schema - The resolved object schema to potentially narrow\n * @param data - The runtime data (must be a plain object)\n * @param targetSchema - The opposite schema containing potential enum constraints\n * @returns The narrowed schema (new object) or the original if no narrowing occurred\n */\nfunction narrowObjectProperties(\n\tschema: JSONSchema7,\n\tdata: Record<string, unknown>,\n\ttargetSchema: JSONSchema7,\n): JSONSchema7 {\n\tif (!isPlainObj(schema.properties)) return schema;\n\tif (!isPlainObj(targetSchema.properties)) return schema;\n\n\tconst props = schema.properties as Record<string, JSONSchema7Definition>;\n\tconst targetProps = targetSchema.properties as Record<\n\t\tstring,\n\t\tJSONSchema7Definition\n\t>;\n\n\tlet changed = false;\n\tconst narrowedProps: Record<string, JSONSchema7Definition> = {};\n\n\tfor (const key of Object.keys(props)) {\n\t\tconst propDef = props[key];\n\t\tif (propDef === undefined) continue;\n\n\t\t// Skip boolean schemas — they can't be narrowed\n\t\tif (typeof propDef === \"boolean\") {\n\t\t\tnarrowedProps[key] = propDef;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst targetPropDef = targetProps[key];\n\t\tconst propData = data[key];\n\n\t\t// No matching target property or no runtime data for this key — skip\n\t\tif (\n\t\t\ttargetPropDef === undefined ||\n\t\t\ttypeof targetPropDef === \"boolean\" ||\n\t\t\tpropData === undefined\n\t\t) {\n\t\t\tnarrowedProps[key] = propDef;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Recursively narrow this property\n\t\tconst narrowed = narrowSchemaWithData(propDef, propData, targetPropDef);\n\n\t\tif (narrowed !== propDef) {\n\t\t\tchanged = true;\n\t\t}\n\t\tnarrowedProps[key] = narrowed;\n\t}\n\n\tif (!changed) return schema;\n\treturn { ...schema, properties: narrowedProps };\n}\n\n// ─── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Narrows a schema using runtime data when the target schema has enum\n * constraints that match the data values.\n *\n * This enables runtime-aware subset checking: when a schema is generic\n * (e.g. `{ type: \"string\" }`) but the actual runtime value matches an\n * enum constraint in the target schema, the source schema is narrowed\n * to reflect the concrete value.\n *\n * @param schema - The resolved source schema to potentially narrow\n * @param data - The runtime data value (primitive or object)\n * @param targetSchema - The target schema containing potential enum constraints\n * @returns The narrowed schema or the original if no narrowing applies\n *\n * @example\n * ```ts\n * // Primitive narrowing\n * const sub = { type: \"string\" };\n * const sup = { type: \"string\", enum: [\"red\", \"green\", \"blue\"] };\n * narrowSchemaWithData(sub, \"red\", sup);\n * // → { type: \"string\", enum: [\"red\"] }\n *\n * // Object property narrowing\n * const sub = { type: \"object\", properties: { color: { type: \"string\" } } };\n * const sup = { type: \"object\", properties: { color: { type: \"string\", enum: [\"red\", \"green\"] } } };\n * narrowSchemaWithData(sub, { color: \"red\" }, sup);\n * // → { type: \"object\", properties: { color: { type: \"string\", enum: [\"red\"] } } }\n * ```\n */\nexport function narrowSchemaWithData(\n\tschema: JSONSchema7,\n\tdata: unknown,\n\ttargetSchema: JSONSchema7,\n): JSONSchema7 {\n\t// Fast path: if schemas are identical or data is undefined/null, no narrowing\n\tif (schema === targetSchema || data === undefined || data === null) {\n\t\treturn schema;\n\t}\n\n\t// Object case: recurse into properties\n\tif (isPlainObj(data) && schema.type === \"object\") {\n\t\treturn narrowObjectProperties(schema, data, targetSchema);\n\t}\n\n\t// Primitive case: try to narrow with enum from target\n\tif (!isPlainObj(data)) {\n\t\treturn narrowPrimitive(schema, data, targetSchema);\n\t}\n\n\treturn schema;\n}\n"],"names":["narrowSchemaWithData","isValueInEnum","value","enumValues","Array","isArray","some","v","deepEqual","getTargetEnum","schema","enum","const","undefined","narrowPrimitive","data","targetSchema","targetEnum","narrowObjectProperties","isPlainObj","properties","props","targetProps","changed","narrowedProps","key","Object","keys","propDef","targetPropDef","propData","narrowed","type"],"mappings":"oGA0KgBA,8DAAAA,+CArKsB,cAwBtC,SAASC,cACRC,KAAc,CACdC,UAA+B,EAE/B,GAAI,CAACC,MAAMC,OAAO,CAACF,YAAa,OAAO,MACvC,OAAOA,WAAWG,IAAI,CAAC,AAACC,GAAMC,GAAAA,kBAAS,EAACD,EAAGL,OAC5C,CAOA,SAASO,cAAcC,MAAmB,EACzC,GAAIN,MAAMC,OAAO,CAACK,OAAOC,IAAI,EAAG,OAAOD,OAAOC,IAAI,CAClD,GAAI,UAAWD,OAAQ,MAAO,CAACA,OAAOE,KAAK,CAAoB,CAC/D,OAAOC,SACR,CAaA,SAASC,gBACRJ,MAAmB,CACnBK,IAAa,CACbC,YAAyB,EAEzB,MAAMC,WAAaR,cAAcO,cACjC,GAAIC,aAAeJ,UAAW,OAAOH,OAGrC,GAAIN,MAAMC,OAAO,CAACK,OAAOC,IAAI,GAAK,UAAWD,OAAQ,OAAOA,OAG5D,GAAI,CAACT,cAAcc,KAAME,YAAa,OAAOP,OAG7C,MAAO,CAAE,GAAGA,MAAM,CAAEC,KAAM,CAACI,KAAwB,AAAC,CACrD,CAWA,SAASG,uBACRR,MAAmB,CACnBK,IAA6B,CAC7BC,YAAyB,EAEzB,GAAI,CAACG,GAAAA,mBAAU,EAACT,OAAOU,UAAU,EAAG,OAAOV,OAC3C,GAAI,CAACS,GAAAA,mBAAU,EAACH,aAAaI,UAAU,EAAG,OAAOV,OAEjD,MAAMW,MAAQX,OAAOU,UAAU,CAC/B,MAAME,YAAcN,aAAaI,UAAU,CAK3C,IAAIG,QAAU,MACd,MAAMC,cAAuD,CAAC,EAE9D,IAAK,MAAMC,OAAOC,OAAOC,IAAI,CAACN,OAAQ,CACrC,MAAMO,QAAUP,KAAK,CAACI,IAAI,CAC1B,GAAIG,UAAYf,UAAW,SAG3B,GAAI,OAAOe,UAAY,UAAW,CACjCJ,aAAa,CAACC,IAAI,CAAGG,QACrB,QACD,CAEA,MAAMC,cAAgBP,WAAW,CAACG,IAAI,CACtC,MAAMK,SAAWf,IAAI,CAACU,IAAI,CAG1B,GACCI,gBAAkBhB,WAClB,OAAOgB,gBAAkB,WACzBC,WAAajB,UACZ,CACDW,aAAa,CAACC,IAAI,CAAGG,QACrB,QACD,CAGA,MAAMG,SAAW/B,qBAAqB4B,QAASE,SAAUD,eAEzD,GAAIE,WAAaH,QAAS,CACzBL,QAAU,IACX,CACAC,aAAa,CAACC,IAAI,CAAGM,QACtB,CAEA,GAAI,CAACR,QAAS,OAAOb,OACrB,MAAO,CAAE,GAAGA,MAAM,CAAEU,WAAYI,aAAc,CAC/C,CAiCO,SAASxB,qBACfU,MAAmB,CACnBK,IAAa,CACbC,YAAyB,EAGzB,GAAIN,SAAWM,cAAgBD,OAASF,WAAaE,OAAS,KAAM,CACnE,OAAOL,MACR,CAGA,GAAIS,GAAAA,mBAAU,EAACJ,OAASL,OAAOsB,IAAI,GAAK,SAAU,CACjD,OAAOd,uBAAuBR,OAAQK,KAAMC,aAC7C,CAGA,GAAI,CAACG,GAAAA,mBAAU,EAACJ,MAAO,CACtB,OAAOD,gBAAgBJ,OAAQK,KAAMC,aACtC,CAEA,OAAON,MACR"}
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
export { resolveConditions } from "./condition-resolver.js";
|
|
1
2
|
export { JsonSchemaCompatibilityChecker } from "./json-schema-compatibility-checker.js";
|
|
2
3
|
export { MergeEngine } from "./merge-engine.js";
|
|
3
4
|
export { arePatternsEquivalent, isPatternSubset, isTrivialPattern, } from "./pattern-subset.js";
|
|
4
5
|
export { formatSchemaType } from "./semantic-errors.js";
|
|
5
|
-
export type {
|
|
6
|
+
export type { CheckConditionsOptions, ResolvedConditionResult, ResolvedSubsetResult, SchemaError, SubsetResult, } from "./types.js";
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get JsonSchemaCompatibilityChecker(){return
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get JsonSchemaCompatibilityChecker(){return _jsonschemacompatibilitycheckerts.JsonSchemaCompatibilityChecker},get MergeEngine(){return _mergeenginets.MergeEngine},get arePatternsEquivalent(){return _patternsubsetts.arePatternsEquivalent},get formatSchemaType(){return _semanticerrorsts.formatSchemaType},get isPatternSubset(){return _patternsubsetts.isPatternSubset},get isTrivialPattern(){return _patternsubsetts.isTrivialPattern},get resolveConditions(){return _conditionresolverts.resolveConditions}});const _conditionresolverts=require("./condition-resolver.js");const _jsonschemacompatibilitycheckerts=require("./json-schema-compatibility-checker.js");const _mergeenginets=require("./merge-engine.js");const _patternsubsetts=require("./pattern-subset.js");const _semanticerrorsts=require("./semantic-errors.js");
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export { JsonSchemaCompatibilityChecker } from \"./json-schema-compatibility-checker\";\nexport { MergeEngine } from \"./merge-engine\";\nexport {\n\tarePatternsEquivalent,\n\tisPatternSubset,\n\tisTrivialPattern,\n} from \"./pattern-subset\";\nexport { formatSchemaType } from \"./semantic-errors\";\nexport type {\n\
|
|
1
|
+
{"version":3,"sources":["../../src/index.ts"],"sourcesContent":["export { resolveConditions } from \"./condition-resolver.ts\";\nexport { JsonSchemaCompatibilityChecker } from \"./json-schema-compatibility-checker.ts\";\nexport { MergeEngine } from \"./merge-engine.ts\";\nexport {\n\tarePatternsEquivalent,\n\tisPatternSubset,\n\tisTrivialPattern,\n} from \"./pattern-subset.ts\";\nexport { formatSchemaType } from \"./semantic-errors.ts\";\nexport type {\n\tCheckConditionsOptions,\n\tResolvedConditionResult,\n\tResolvedSubsetResult,\n\tSchemaError,\n\tSubsetResult,\n} from \"./types.ts\";\n"],"names":["JsonSchemaCompatibilityChecker","MergeEngine","arePatternsEquivalent","formatSchemaType","isPatternSubset","isTrivialPattern","resolveConditions"],"mappings":"mPACSA,wCAAAA,gEAA8B,MAC9BC,qBAAAA,0BAAW,MAEnBC,+BAAAA,sCAAqB,MAIbC,0BAAAA,kCAAgB,MAHxBC,yBAAAA,gCAAe,MACfC,0BAAAA,iCAAgB,MANRC,2BAAAA,sCAAiB,uCAAQ,2EACa,uEACnB,oDAKrB,uDAC0B"}
|
|
@@ -5,8 +5,8 @@ import { MergeEngine } from "./merge-engine.js";
|
|
|
5
5
|
import { normalize } from "./normalizer.js";
|
|
6
6
|
import { arePatternsEquivalent, isPatternSubset, isTrivialPattern } from "./pattern-subset.js";
|
|
7
7
|
import type { BranchResult, BranchType } from "./subset-checker.js";
|
|
8
|
-
import type {
|
|
9
|
-
export type { SchemaError, SubsetResult,
|
|
8
|
+
import type { CheckConditionsOptions, ResolvedConditionResult, ResolvedSubsetResult, SchemaError, SubsetResult } from "./types.js";
|
|
9
|
+
export type { SchemaError, SubsetResult, ResolvedConditionResult, ResolvedSubsetResult, CheckConditionsOptions, BranchType, BranchResult, };
|
|
10
10
|
export { normalize, resolveConditions, formatResult, MergeEngine, isPatternSubset, arePatternsEquivalent, isTrivialPattern, };
|
|
11
11
|
export declare class JsonSchemaCompatibilityChecker {
|
|
12
12
|
private readonly engine;
|
|
@@ -23,17 +23,30 @@ export declare class JsonSchemaCompatibilityChecker {
|
|
|
23
23
|
* Vérifie `sub ⊆ sup` et retourne un diagnostic complet
|
|
24
24
|
* avec des erreurs sémantiques lisibles.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
*
|
|
26
|
+
* Si `options` est fourni avec `subData`, les conditions `if/then/else`
|
|
27
|
+
* des deux schemas sont résolues avant le check :
|
|
28
|
+
* - `subData` est utilisé pour résoudre les conditions du sub
|
|
29
|
+
* - `supData` (ou `subData` par défaut) est utilisé pour résoudre le sup
|
|
30
|
+
*
|
|
31
|
+
* @param sub - Le schema source (candidat subset)
|
|
32
|
+
* @param sup - Le schema cible (superset attendu)
|
|
33
|
+
* @param options - Options de résolution de conditions (optionnel)
|
|
34
|
+
* @returns SubsetResult si pas d'options, ResolvedSubsetResult si options fournies
|
|
32
35
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```ts
|
|
38
|
+
* // Sans résolution de conditions
|
|
39
|
+
* checker.check(sub, sup);
|
|
40
|
+
*
|
|
41
|
+
* // Avec résolution de conditions (subData pour les deux)
|
|
42
|
+
* checker.check(sub, sup, { subData: { kind: "text" } });
|
|
43
|
+
*
|
|
44
|
+
* // Avec résolution séparée pour sub et sup
|
|
45
|
+
* checker.check(sub, sup, { subData: { kind: "text" }, supData: { kind: "other" } });
|
|
46
|
+
* ```
|
|
35
47
|
*/
|
|
36
|
-
|
|
48
|
+
check(sub: JSONSchema7Definition, sup: JSONSchema7Definition, options: CheckConditionsOptions): ResolvedSubsetResult;
|
|
49
|
+
check(sub: JSONSchema7Definition, sup: JSONSchema7Definition): SubsetResult;
|
|
37
50
|
/**
|
|
38
51
|
* Vérifie l'égalité structurelle entre deux schemas.
|
|
39
52
|
*/
|
|
@@ -46,21 +59,6 @@ export declare class JsonSchemaCompatibilityChecker {
|
|
|
46
59
|
* du merge (ex: `enum` redondant quand `const` est présent).
|
|
47
60
|
*/
|
|
48
61
|
intersect(a: JSONSchema7Definition, b: JSONSchema7Definition): JSONSchema7Definition | null;
|
|
49
|
-
/**
|
|
50
|
-
* Résout les `if/then/else` d'un schema en évaluant le `if` contre
|
|
51
|
-
* des données partielles (discriminants).
|
|
52
|
-
*/
|
|
53
|
-
resolveConditions(schema: JSONSchema7, data: Record<string, unknown>): ResolvedConditionResult;
|
|
54
|
-
/**
|
|
55
|
-
* Raccourci : résout les conditions des deux schemas puis vérifie sub ⊆ sup.
|
|
56
|
-
*
|
|
57
|
-
* Utile quand le superset contient des if/then/else et que tu connais
|
|
58
|
-
* les valeurs discriminantes que le subset va produire.
|
|
59
|
-
*/
|
|
60
|
-
checkResolved(sub: JSONSchema7, sup: JSONSchema7, subData: Record<string, unknown>, supData?: Record<string, unknown>): SubsetResult & {
|
|
61
|
-
resolvedSub: ResolvedConditionResult;
|
|
62
|
-
resolvedSup: ResolvedConditionResult;
|
|
63
|
-
};
|
|
64
62
|
/**
|
|
65
63
|
* Normalise un schema : infère `type` depuis `const`/`enum`,
|
|
66
64
|
* et normalise récursivement tous les sous-schemas.
|
|
@@ -70,4 +68,19 @@ export declare class JsonSchemaCompatibilityChecker {
|
|
|
70
68
|
* Formate un SubsetResult en chaîne lisible (utile pour logs/debug).
|
|
71
69
|
*/
|
|
72
70
|
formatResult(label: string, result: SubsetResult): string;
|
|
71
|
+
/**
|
|
72
|
+
* Resolves `if/then/else` conditions in a schema by evaluating the `if`
|
|
73
|
+
* against partial data (discriminants).
|
|
74
|
+
*
|
|
75
|
+
* @param schema - The schema containing conditions to resolve
|
|
76
|
+
* @param data - The runtime data used to evaluate conditions
|
|
77
|
+
* @returns The resolved schema with branch info and discriminants
|
|
78
|
+
*/
|
|
79
|
+
resolveConditions(schema: JSONSchema7, data: Record<string, unknown>): ResolvedConditionResult;
|
|
80
|
+
/**
|
|
81
|
+
* Logique interne de check sans résolution de conditions.
|
|
82
|
+
* Factorise le pipeline normalize → branch → atomic pour éviter
|
|
83
|
+
* la duplication entre les deux chemins de `check()`.
|
|
84
|
+
*/
|
|
85
|
+
private checkInternal;
|
|
73
86
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get JsonSchemaCompatibilityChecker(){return JsonSchemaCompatibilityChecker},get MergeEngine(){return
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get JsonSchemaCompatibilityChecker(){return JsonSchemaCompatibilityChecker},get MergeEngine(){return _mergeenginets.MergeEngine},get arePatternsEquivalent(){return _patternsubsetts.arePatternsEquivalent},get formatResult(){return _formatterts.formatResult},get isPatternSubset(){return _patternsubsetts.isPatternSubset},get isTrivialPattern(){return _patternsubsetts.isTrivialPattern},get normalize(){return _normalizerts.normalize},get resolveConditions(){return _conditionresolverts.resolveConditions}});const _conditionresolverts=require("./condition-resolver.js");const _datanarrowingts=require("./data-narrowing.js");const _formatterts=require("./formatter.js");const _mergeenginets=require("./merge-engine.js");const _normalizerts=require("./normalizer.js");const _patternsubsetts=require("./pattern-subset.js");const _subsetcheckerts=require("./subset-checker.js");const _utilsts=require("./utils.js");function _define_property(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}class JsonSchemaCompatibilityChecker{isSubset(sub,sup){if(sub===sup)return true;if((0,_utilsts.deepEqual)(sub,sup))return true;const nSub=(0,_normalizerts.normalize)(sub);const nSup=(0,_normalizerts.normalize)(sup);if(nSub!==sub&&nSup!==sup&&(0,_utilsts.deepEqual)(nSub,nSup))return true;if(nSub!==nSup&&(0,_utilsts.deepEqual)(nSub,nSup))return true;const{branches:subBranches}=(0,_subsetcheckerts.getBranchesTyped)(nSub);if(subBranches.length>1||subBranches[0]!==nSub){return subBranches.every(branch=>(0,_subsetcheckerts.isAtomicSubsetOf)(branch,nSup,this.engine))}return(0,_subsetcheckerts.isAtomicSubsetOf)(nSub,nSup,this.engine)}check(sub,sup,options){if(options){const subData=options.subData;const supData=options.supData??options.subData;const subDataForConditions=(0,_utilsts.isPlainObj)(subData)?subData:{};const supDataForConditions=(0,_utilsts.isPlainObj)(supData)?supData:{};const resolvedSub=(0,_conditionresolverts.resolveConditions)(sub,subDataForConditions,this.engine);const resolvedSup=(0,_conditionresolverts.resolveConditions)(sup,supDataForConditions,this.engine);const narrowedSubResolved=subData!==undefined?(0,_datanarrowingts.narrowSchemaWithData)(resolvedSub.resolved,subData,resolvedSup.resolved):resolvedSub.resolved;const narrowedSupResolved=supData!==undefined?(0,_datanarrowingts.narrowSchemaWithData)(resolvedSup.resolved,supData,resolvedSub.resolved):resolvedSup.resolved;const result=this.checkInternal(narrowedSubResolved,narrowedSupResolved);return{...result,resolvedSub:{...resolvedSub,resolved:narrowedSubResolved},resolvedSup:{...resolvedSup,resolved:narrowedSupResolved}}}return this.checkInternal(sub,sup)}isEqual(a,b){return this.engine.isEqual((0,_normalizerts.normalize)(a),(0,_normalizerts.normalize)(b))}intersect(a,b){if(a===b||(0,_utilsts.deepEqual)(a,b))return(0,_normalizerts.normalize)(a);const nA=(0,_normalizerts.normalize)(a);const nB=(0,_normalizerts.normalize)(b);if((0,_utilsts.deepEqual)(nA,nB))return nA;const merged=this.engine.merge(nA,nB);if(merged===null)return null;if((0,_utilsts.deepEqual)(merged,nA)||(0,_utilsts.deepEqual)(merged,nB))return merged;return(0,_normalizerts.normalize)(merged)}normalize(def){return(0,_normalizerts.normalize)(def)}formatResult(label,result){return(0,_formatterts.formatResult)(label,result)}resolveConditions(schema,data){return(0,_conditionresolverts.resolveConditions)(schema,data,this.engine)}checkInternal(sub,sup){if(sub===sup){return{isSubset:true,merged:sub,errors:[]}}if((0,_utilsts.deepEqual)(sub,sup)){return{isSubset:true,merged:sub,errors:[]}}const nSub=(0,_normalizerts.normalize)(sub);const nSup=(0,_normalizerts.normalize)(sup);if((0,_utilsts.deepEqual)(nSub,nSup)){return{isSubset:true,merged:nSub,errors:[]}}const{branches:subBranches,type:subBranchType}=(0,_subsetcheckerts.getBranchesTyped)(nSub);const{branches:supBranches,type:supBranchType}=(0,_subsetcheckerts.getBranchesTyped)(nSup);if(subBranches.length>1||subBranches[0]!==nSub){return(0,_subsetcheckerts.checkBranchedSub)(subBranches,nSup,this.engine,subBranchType)}if(supBranches.length>1||supBranches[0]!==nSup){return(0,_subsetcheckerts.checkBranchedSup)(nSub,supBranches,this.engine,supBranchType)}return(0,_subsetcheckerts.checkAtomic)(nSub,nSup,this.engine)}constructor(){_define_property(this,"engine",void 0);this.engine=new _mergeenginets.MergeEngine}}
|
|
2
2
|
//# sourceMappingURL=json-schema-compatibility-checker.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/json-schema-compatibility-checker.ts"],"sourcesContent":["import type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\nimport { resolveConditions } from \"./condition-resolver\";\nimport { formatResult } from \"./formatter\";\nimport { MergeEngine } from \"./merge-engine\";\nimport { normalize } from \"./normalizer\";\nimport {\n\tarePatternsEquivalent,\n\tisPatternSubset,\n\tisTrivialPattern,\n} from \"./pattern-subset\";\nimport type { BranchResult, BranchType } from \"./subset-checker\";\nimport {\n\tcheckAtomic,\n\tcheckBranchedSub,\n\tcheckBranchedSup,\n\tgetBranchesTyped,\n\tisAtomicSubsetOf,\n} from \"./subset-checker\";\nimport type {\n\tConnectionResult,\n\tResolvedConditionResult,\n\tSchemaError,\n\tSubsetResult,\n} from \"./types\";\nimport { deepEqual } from \"./utils\";\n\n// ─── Re-exports ──────────────────────────────────────────────────────────────\n\nexport type {\n\tSchemaError,\n\tSubsetResult,\n\tConnectionResult,\n\tResolvedConditionResult,\n\tBranchType,\n\tBranchResult,\n};\n\nexport {\n\tnormalize,\n\tresolveConditions,\n\tformatResult,\n\tMergeEngine,\n\tisPatternSubset,\n\tarePatternsEquivalent,\n\tisTrivialPattern,\n};\n\n// ─── Main Class ──────────────────────────────────────────────────────────────\n//\n// Façade légère qui orchestre les sous-modules pour vérifier la compatibilité\n// entre JSON Schemas (Draft-07).\n//\n// Principe mathématique :\n// A ⊆ B ⟺ A ∩ B ≡ A\n//\n// En JSON Schema :\n// - A ∩ B = allOf([A, B]) résolu via merge\n// - ≡ = comparaison structurelle\n//\n// @example\n// ```ts\n// const checker = new JsonSchemaCompatibilityChecker();\n//\n// checker.isSubset(strict, loose); // true\n// checker.check(loose, strict); // { isSubset: false, diffs: [...] }\n// checker.canConnect(nodeA.output, nodeB.input); // ConnectionResult\n// ```\n\nexport class JsonSchemaCompatibilityChecker {\n\tprivate readonly engine: MergeEngine;\n\n\tconstructor() {\n\t\tthis.engine = new MergeEngine();\n\t}\n\n\t// ── Subset check (boolean) ─────────────────────────────────────────────\n\n\t/**\n\t * Vérifie si `sub ⊆ sup`.\n\t * Toute valeur valide pour sub est-elle aussi valide pour sup ?\n\t *\n\t * Point 6 — Utilise `getBranchesTyped` pour distinguer `anyOf` de `oneOf`\n\t * en interne, bien que le résultat boolean ne reflète pas la distinction.\n\t */\n\tisSubset(sub: JSONSchema7Definition, sup: JSONSchema7Definition): boolean {\n\t\t// ── Identity short-circuit ──\n\t\t// If sub and sup are the same reference, sub ⊆ sup is trivially true.\n\t\t// This avoids the entire normalize + merge + compare pipeline.\n\t\tif (sub === sup) return true;\n\n\t\t// ── Pre-normalize structural equality ──\n\t\t// If sub and sup are structurally identical before normalization,\n\t\t// they represent the same schema → sub ⊆ sup trivially.\n\t\t// This avoids the WeakMap overhead of normalize() for common cases\n\t\t// like {} ⊆ {} or identical schema objects with different references.\n\t\tif (deepEqual(sub, sup)) return true;\n\n\t\tconst nSub = normalize(sub);\n\t\tconst nSup = normalize(sup);\n\n\t\t// ── Post-normalize structural identity ──\n\t\t// After normalization, schemas that were syntactically different\n\t\t// but semantically equivalent become structurally equal\n\t\t// (e.g. {const:1} vs {const:1, type:\"integer\"}).\n\t\tif (nSub !== sub && nSup !== sup && deepEqual(nSub, nSup)) return true;\n\t\tif (nSub !== nSup && deepEqual(nSub, nSup)) return true;\n\n\t\tconst { branches: subBranches } = getBranchesTyped(nSub);\n\n\t\tif (subBranches.length > 1 || subBranches[0] !== nSub) {\n\t\t\treturn subBranches.every((branch) =>\n\t\t\t\tisAtomicSubsetOf(branch, nSup, this.engine),\n\t\t\t);\n\t\t}\n\n\t\treturn isAtomicSubsetOf(nSub, nSup, this.engine);\n\t}\n\n\t// ── Subset check (detailed) ────────────────────────────────────────────\n\n\t/**\n\t * Vérifie `sub ⊆ sup` et retourne un diagnostic complet\n\t * avec des erreurs sémantiques lisibles.\n\t *\n\t * Point 6 — Utilise `getBranchesTyped` pour distinguer `anyOf` de `oneOf`\n\t * dans les paths d'erreur.\n\t */\n\tcheck(sub: JSONSchema7Definition, sup: JSONSchema7Definition): SubsetResult {\n\t\t// ── Identity short-circuit ──\n\t\t// Same reference → no errors, no merge needed.\n\t\tif (sub === sup) {\n\t\t\treturn { isSubset: true, merged: sub, errors: [] };\n\t\t}\n\n\t\t// ── Pre-normalize structural equality ──\n\t\t// Avoids WeakMap overhead for identical schemas ({} ⊆ {}, etc.).\n\t\tif (deepEqual(sub, sup)) {\n\t\t\treturn { isSubset: true, merged: sub, errors: [] };\n\t\t}\n\n\t\tconst nSub = normalize(sub);\n\t\tconst nSup = normalize(sup);\n\n\t\t// ── Post-normalize structural identity ──\n\t\t// Catches semantically equivalent schemas after normalization.\n\t\tif (deepEqual(nSub, nSup)) {\n\t\t\treturn { isSubset: true, merged: nSub, errors: [] };\n\t\t}\n\n\t\tconst { branches: subBranches, type: subBranchType } =\n\t\t\tgetBranchesTyped(nSub);\n\t\tconst { branches: supBranches, type: supBranchType } =\n\t\t\tgetBranchesTyped(nSup);\n\n\t\t// anyOf/oneOf dans sub\n\t\tif (subBranches.length > 1 || subBranches[0] !== nSub) {\n\t\t\treturn checkBranchedSub(subBranches, nSup, this.engine, subBranchType);\n\t\t}\n\n\t\t// anyOf/oneOf dans sup uniquement\n\t\tif (supBranches.length > 1 || supBranches[0] !== nSup) {\n\t\t\treturn checkBranchedSup(nSub, supBranches, this.engine, supBranchType);\n\t\t}\n\n\t\t// Cas standard\n\t\treturn checkAtomic(nSub, nSup, this.engine);\n\t}\n\n\t// ── Connection check ───────────────────────────────────────────────────\n\n\t/**\n\t * Vérifie si la sortie d'un nœud source peut alimenter l'entrée d'un nœud cible.\n\t *\n\t * Sémantique : `sourceOutput ⊆ targetInput`\n\t * → Toute donnée produite par source sera acceptée par target.\n\t */\n\tcanConnect(\n\t\tsourceOutput: JSONSchema7Definition,\n\t\ttargetInput: JSONSchema7Definition,\n\t): ConnectionResult {\n\t\tconst result = this.check(sourceOutput, targetInput);\n\t\treturn { ...result, direction: \"sourceOutput ⊆ targetInput\" };\n\t}\n\n\t// ── Equality ───────────────────────────────────────────────────────────\n\n\t/**\n\t * Vérifie l'égalité structurelle entre deux schemas.\n\t */\n\tisEqual(a: JSONSchema7Definition, b: JSONSchema7Definition): boolean {\n\t\treturn this.engine.isEqual(normalize(a), normalize(b));\n\t}\n\n\t// ── Intersection ───────────────────────────────────────────────────────\n\n\t/**\n\t * Calcule l'intersection de deux schemas (allOf merge).\n\t * Retourne null si les schemas sont incompatibles.\n\t *\n\t * Le résultat est normalisé pour éliminer les artefacts structurels\n\t * du merge (ex: `enum` redondant quand `const` est présent).\n\t */\n\tintersect(\n\t\ta: JSONSchema7Definition,\n\t\tb: JSONSchema7Definition,\n\t): JSONSchema7Definition | null {\n\t\t// ── Identity short-circuit ──\n\t\t// If a and b are the same reference or structurally equal,\n\t\t// intersection is just normalize(a) — skip the merge entirely.\n\t\tif (a === b || deepEqual(a, b)) return normalize(a);\n\n\t\tconst nA = normalize(a);\n\t\tconst nB = normalize(b);\n\n\t\t// ── Post-normalize identity ──\n\t\tif (deepEqual(nA, nB)) return nA;\n\n\t\tconst merged = this.engine.merge(nA, nB);\n\t\tif (merged === null) return null;\n\t\t// Fast path: if merge result equals one of the normalized inputs,\n\t\t// it's already normalized — skip redundant normalize call.\n\t\tif (deepEqual(merged, nA) || deepEqual(merged, nB)) return merged;\n\t\treturn normalize(merged);\n\t}\n\n\t// ── Condition resolution ───────────────────────────────────────────────\n\n\t/**\n\t * Résout les `if/then/else` d'un schema en évaluant le `if` contre\n\t * des données partielles (discriminants).\n\t */\n\tresolveConditions(\n\t\tschema: JSONSchema7,\n\t\tdata: Record<string, unknown>,\n\t): ResolvedConditionResult {\n\t\treturn resolveConditions(schema, data, this.engine);\n\t}\n\n\t// ── Resolved check ────────────────────────────────────────────────────\n\n\t/**\n\t * Raccourci : résout les conditions des deux schemas puis vérifie sub ⊆ sup.\n\t *\n\t * Utile quand le superset contient des if/then/else et que tu connais\n\t * les valeurs discriminantes que le subset va produire.\n\t */\n\tcheckResolved(\n\t\tsub: JSONSchema7,\n\t\tsup: JSONSchema7,\n\t\tsubData: Record<string, unknown>,\n\t\tsupData?: Record<string, unknown>,\n\t): SubsetResult & {\n\t\tresolvedSub: ResolvedConditionResult;\n\t\tresolvedSup: ResolvedConditionResult;\n\t} {\n\t\tconst resolvedSub = resolveConditions(sub, subData, this.engine);\n\t\tconst resolvedSup = resolveConditions(sup, supData ?? subData, this.engine);\n\t\tconst result = this.check(resolvedSub.resolved, resolvedSup.resolved);\n\n\t\treturn { ...result, resolvedSub, resolvedSup };\n\t}\n\n\t// ── Normalization ──────────────────────────────────────────────────────\n\n\t/**\n\t * Normalise un schema : infère `type` depuis `const`/`enum`,\n\t * et normalise récursivement tous les sous-schemas.\n\t */\n\tnormalize(def: JSONSchema7Definition): JSONSchema7Definition {\n\t\treturn normalize(def);\n\t}\n\n\t// ── Formatting ─────────────────────────────────────────────────────────\n\n\t/**\n\t * Formate un SubsetResult en chaîne lisible (utile pour logs/debug).\n\t */\n\tformatResult(label: string, result: SubsetResult): string {\n\t\treturn formatResult(label, result);\n\t}\n}\n"],"names":["JsonSchemaCompatibilityChecker","MergeEngine","arePatternsEquivalent","formatResult","isPatternSubset","isTrivialPattern","normalize","resolveConditions","isSubset","sub","sup","deepEqual","nSub","nSup","branches","subBranches","getBranchesTyped","length","every","branch","isAtomicSubsetOf","engine","check","merged","errors","type","subBranchType","supBranches","supBranchType","checkBranchedSub","checkBranchedSup","checkAtomic","canConnect","sourceOutput","targetInput","result","direction","isEqual","a","b","intersect","nA","nB","merge","schema","data","checkResolved","subData","supData","resolvedSub","resolvedSup","resolved","def","label"],"mappings":"mPAoEaA,wCAAAA,oCA3BZC,qBAAAA,wBAAW,MAEXC,+BAAAA,oCAAqB,MAHrBC,sBAAAA,uBAAY,MAEZC,yBAAAA,8BAAe,MAEfC,0BAAAA,+BAAgB,MANhBC,mBAAAA,qBAAS,MACTC,2BAAAA,oCAAiB,qCAtCgB,iDACL,0CACD,4CACF,6CAKnB,iDAQA,yCAOmB,+LA4CnB,MAAMP,+BAgBZQ,SAASC,GAA0B,CAAEC,GAA0B,CAAW,CAIzE,GAAID,MAAQC,IAAK,OAAO,KAOxB,GAAIC,GAAAA,gBAAS,EAACF,IAAKC,KAAM,OAAO,KAEhC,MAAME,KAAON,GAAAA,qBAAS,EAACG,KACvB,MAAMI,KAAOP,GAAAA,qBAAS,EAACI,KAMvB,GAAIE,OAASH,KAAOI,OAASH,KAAOC,GAAAA,gBAAS,EAACC,KAAMC,MAAO,OAAO,KAClE,GAAID,OAASC,MAAQF,GAAAA,gBAAS,EAACC,KAAMC,MAAO,OAAO,KAEnD,KAAM,CAAEC,SAAUC,WAAW,CAAE,CAAGC,GAAAA,+BAAgB,EAACJ,MAEnD,GAAIG,YAAYE,MAAM,CAAG,GAAKF,WAAW,CAAC,EAAE,GAAKH,KAAM,CACtD,OAAOG,YAAYG,KAAK,CAAC,AAACC,QACzBC,GAAAA,+BAAgB,EAACD,OAAQN,KAAM,IAAI,CAACQ,MAAM,EAE5C,CAEA,MAAOD,GAAAA,+BAAgB,EAACR,KAAMC,KAAM,IAAI,CAACQ,MAAM,CAChD,CAWAC,MAAMb,GAA0B,CAAEC,GAA0B,CAAgB,CAG3E,GAAID,MAAQC,IAAK,CAChB,MAAO,CAAEF,SAAU,KAAMe,OAAQd,IAAKe,OAAQ,EAAE,AAAC,CAClD,CAIA,GAAIb,GAAAA,gBAAS,EAACF,IAAKC,KAAM,CACxB,MAAO,CAAEF,SAAU,KAAMe,OAAQd,IAAKe,OAAQ,EAAE,AAAC,CAClD,CAEA,MAAMZ,KAAON,GAAAA,qBAAS,EAACG,KACvB,MAAMI,KAAOP,GAAAA,qBAAS,EAACI,KAIvB,GAAIC,GAAAA,gBAAS,EAACC,KAAMC,MAAO,CAC1B,MAAO,CAAEL,SAAU,KAAMe,OAAQX,KAAMY,OAAQ,EAAE,AAAC,CACnD,CAEA,KAAM,CAAEV,SAAUC,WAAW,CAAEU,KAAMC,aAAa,CAAE,CACnDV,GAAAA,+BAAgB,EAACJ,MAClB,KAAM,CAAEE,SAAUa,WAAW,CAAEF,KAAMG,aAAa,CAAE,CACnDZ,GAAAA,+BAAgB,EAACH,MAGlB,GAAIE,YAAYE,MAAM,CAAG,GAAKF,WAAW,CAAC,EAAE,GAAKH,KAAM,CACtD,MAAOiB,GAAAA,+BAAgB,EAACd,YAAaF,KAAM,IAAI,CAACQ,MAAM,CAAEK,cACzD,CAGA,GAAIC,YAAYV,MAAM,CAAG,GAAKU,WAAW,CAAC,EAAE,GAAKd,KAAM,CACtD,MAAOiB,GAAAA,+BAAgB,EAAClB,KAAMe,YAAa,IAAI,CAACN,MAAM,CAAEO,cACzD,CAGA,MAAOG,GAAAA,0BAAW,EAACnB,KAAMC,KAAM,IAAI,CAACQ,MAAM,CAC3C,CAUAW,WACCC,YAAmC,CACnCC,WAAkC,CACf,CACnB,MAAMC,OAAS,IAAI,CAACb,KAAK,CAACW,aAAcC,aACxC,MAAO,CAAE,GAAGC,MAAM,CAAEC,UAAW,4BAA6B,CAC7D,CAOAC,QAAQC,CAAwB,CAAEC,CAAwB,CAAW,CACpE,OAAO,IAAI,CAAClB,MAAM,CAACgB,OAAO,CAAC/B,GAAAA,qBAAS,EAACgC,GAAIhC,GAAAA,qBAAS,EAACiC,GACpD,CAWAC,UACCF,CAAwB,CACxBC,CAAwB,CACO,CAI/B,GAAID,IAAMC,GAAK5B,GAAAA,gBAAS,EAAC2B,EAAGC,GAAI,MAAOjC,GAAAA,qBAAS,EAACgC,GAEjD,MAAMG,GAAKnC,GAAAA,qBAAS,EAACgC,GACrB,MAAMI,GAAKpC,GAAAA,qBAAS,EAACiC,GAGrB,GAAI5B,GAAAA,gBAAS,EAAC8B,GAAIC,IAAK,OAAOD,GAE9B,MAAMlB,OAAS,IAAI,CAACF,MAAM,CAACsB,KAAK,CAACF,GAAIC,IACrC,GAAInB,SAAW,KAAM,OAAO,KAG5B,GAAIZ,GAAAA,gBAAS,EAACY,OAAQkB,KAAO9B,GAAAA,gBAAS,EAACY,OAAQmB,IAAK,OAAOnB,OAC3D,MAAOjB,GAAAA,qBAAS,EAACiB,OAClB,CAQAhB,kBACCqC,MAAmB,CACnBC,IAA6B,CACH,CAC1B,MAAOtC,GAAAA,oCAAiB,EAACqC,OAAQC,KAAM,IAAI,CAACxB,MAAM,CACnD,CAUAyB,cACCrC,GAAgB,CAChBC,GAAgB,CAChBqC,OAAgC,CAChCC,OAAiC,CAIhC,CACD,MAAMC,YAAc1C,GAAAA,oCAAiB,EAACE,IAAKsC,QAAS,IAAI,CAAC1B,MAAM,EAC/D,MAAM6B,YAAc3C,GAAAA,oCAAiB,EAACG,IAAKsC,SAAWD,QAAS,IAAI,CAAC1B,MAAM,EAC1E,MAAMc,OAAS,IAAI,CAACb,KAAK,CAAC2B,YAAYE,QAAQ,CAAED,YAAYC,QAAQ,EAEpE,MAAO,CAAE,GAAGhB,MAAM,CAAEc,YAAaC,WAAY,CAC9C,CAQA5C,UAAU8C,GAA0B,CAAyB,CAC5D,MAAO9C,GAAAA,qBAAS,EAAC8C,IAClB,CAOAjD,aAAakD,KAAa,CAAElB,MAAoB,CAAU,CACzD,MAAOhC,GAAAA,uBAAY,EAACkD,MAAOlB,OAC5B,CAhNA,aAAc,CAFd,sBAAiBd,SAAjB,KAAA,EAGC,CAAA,IAAI,CAACA,MAAM,CAAG,IAAIpB,wBAAW,AAC9B,CA+MD"}
|
|
1
|
+
{"version":3,"sources":["../../src/json-schema-compatibility-checker.ts"],"sourcesContent":["import type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\nimport { resolveConditions } from \"./condition-resolver.ts\";\nimport { narrowSchemaWithData } from \"./data-narrowing.ts\";\nimport { formatResult } from \"./formatter.ts\";\nimport { MergeEngine } from \"./merge-engine.ts\";\nimport { normalize } from \"./normalizer.ts\";\nimport {\n\tarePatternsEquivalent,\n\tisPatternSubset,\n\tisTrivialPattern,\n} from \"./pattern-subset.ts\";\nimport type { BranchResult, BranchType } from \"./subset-checker.ts\";\nimport {\n\tcheckAtomic,\n\tcheckBranchedSub,\n\tcheckBranchedSup,\n\tgetBranchesTyped,\n\tisAtomicSubsetOf,\n} from \"./subset-checker.ts\";\nimport type {\n\tCheckConditionsOptions,\n\tResolvedConditionResult,\n\tResolvedSubsetResult,\n\tSchemaError,\n\tSubsetResult,\n} from \"./types.ts\";\nimport { deepEqual, isPlainObj } from \"./utils.ts\";\n\n// ─── Re-exports ──────────────────────────────────────────────────────────────\n\nexport type {\n\tSchemaError,\n\tSubsetResult,\n\tResolvedConditionResult,\n\tResolvedSubsetResult,\n\tCheckConditionsOptions,\n\tBranchType,\n\tBranchResult,\n};\n\nexport {\n\tnormalize,\n\tresolveConditions,\n\tformatResult,\n\tMergeEngine,\n\tisPatternSubset,\n\tarePatternsEquivalent,\n\tisTrivialPattern,\n};\n\n// ─── Main Class ──────────────────────────────────────────────────────────────\n//\n// Façade légère qui orchestre les sous-modules pour vérifier la compatibilité\n// entre JSON Schemas (Draft-07).\n//\n// Principe mathématique :\n// A ⊆ B ⟺ A ∩ B ≡ A\n//\n// En JSON Schema :\n// - A ∩ B = allOf([A, B]) résolu via merge\n// - ≡ = comparaison structurelle\n//\n// @example\n// ```ts\n// const checker = new JsonSchemaCompatibilityChecker();\n//\n// checker.isSubset(strict, loose); // true\n// checker.check(loose, strict); // { isSubset: false, diffs: [...] }\n// checker.check(sub, sup, { subData: {...} }); // resolves conditions then checks\n// ```\n\nexport class JsonSchemaCompatibilityChecker {\n\tprivate readonly engine: MergeEngine;\n\n\tconstructor() {\n\t\tthis.engine = new MergeEngine();\n\t}\n\n\t// ── Subset check (boolean) ─────────────────────────────────────────────\n\n\t/**\n\t * Vérifie si `sub ⊆ sup`.\n\t * Toute valeur valide pour sub est-elle aussi valide pour sup ?\n\t *\n\t * Point 6 — Utilise `getBranchesTyped` pour distinguer `anyOf` de `oneOf`\n\t * en interne, bien que le résultat boolean ne reflète pas la distinction.\n\t */\n\tisSubset(sub: JSONSchema7Definition, sup: JSONSchema7Definition): boolean {\n\t\t// ── Identity short-circuit ──\n\t\t// If sub and sup are the same reference, sub ⊆ sup is trivially true.\n\t\t// This avoids the entire normalize + merge + compare pipeline.\n\t\tif (sub === sup) return true;\n\n\t\t// ── Pre-normalize structural equality ──\n\t\t// If sub and sup are structurally identical before normalization,\n\t\t// they represent the same schema → sub ⊆ sup trivially.\n\t\t// This avoids the WeakMap overhead of normalize() for common cases\n\t\t// like {} ⊆ {} or identical schema objects with different references.\n\t\tif (deepEqual(sub, sup)) return true;\n\n\t\tconst nSub = normalize(sub);\n\t\tconst nSup = normalize(sup);\n\n\t\t// ── Post-normalize structural identity ──\n\t\t// After normalization, schemas that were syntactically different\n\t\t// but semantically equivalent become structurally equal\n\t\t// (e.g. {const:1} vs {const:1, type:\"integer\"}).\n\t\tif (nSub !== sub && nSup !== sup && deepEqual(nSub, nSup)) return true;\n\t\tif (nSub !== nSup && deepEqual(nSub, nSup)) return true;\n\n\t\tconst { branches: subBranches } = getBranchesTyped(nSub);\n\n\t\tif (subBranches.length > 1 || subBranches[0] !== nSub) {\n\t\t\treturn subBranches.every((branch) =>\n\t\t\t\tisAtomicSubsetOf(branch, nSup, this.engine),\n\t\t\t);\n\t\t}\n\n\t\treturn isAtomicSubsetOf(nSub, nSup, this.engine);\n\t}\n\n\t// ── Subset check (detailed) ────────────────────────────────────────────\n\n\t/**\n\t * Vérifie `sub ⊆ sup` et retourne un diagnostic complet\n\t * avec des erreurs sémantiques lisibles.\n\t *\n\t * Si `options` est fourni avec `subData`, les conditions `if/then/else`\n\t * des deux schemas sont résolues avant le check :\n\t * - `subData` est utilisé pour résoudre les conditions du sub\n\t * - `supData` (ou `subData` par défaut) est utilisé pour résoudre le sup\n\t *\n\t * @param sub - Le schema source (candidat subset)\n\t * @param sup - Le schema cible (superset attendu)\n\t * @param options - Options de résolution de conditions (optionnel)\n\t * @returns SubsetResult si pas d'options, ResolvedSubsetResult si options fournies\n\t *\n\t * @example\n\t * ```ts\n\t * // Sans résolution de conditions\n\t * checker.check(sub, sup);\n\t *\n\t * // Avec résolution de conditions (subData pour les deux)\n\t * checker.check(sub, sup, { subData: { kind: \"text\" } });\n\t *\n\t * // Avec résolution séparée pour sub et sup\n\t * checker.check(sub, sup, { subData: { kind: \"text\" }, supData: { kind: \"other\" } });\n\t * ```\n\t */\n\tcheck(\n\t\tsub: JSONSchema7Definition,\n\t\tsup: JSONSchema7Definition,\n\t\toptions: CheckConditionsOptions,\n\t): ResolvedSubsetResult;\n\tcheck(sub: JSONSchema7Definition, sup: JSONSchema7Definition): SubsetResult;\n\tcheck(\n\t\tsub: JSONSchema7Definition,\n\t\tsup: JSONSchema7Definition,\n\t\toptions?: CheckConditionsOptions,\n\t): SubsetResult | ResolvedSubsetResult {\n\t\t// ── Condition resolution path ──\n\t\tif (options) {\n\t\t\tconst subData = options.subData;\n\t\t\tconst supData = options.supData ?? options.subData;\n\n\t\t\t// resolveConditions expects Record<string, unknown> for property access;\n\t\t\t// coerce non-object data to empty object (no conditions to resolve for primitives)\n\t\t\tconst subDataForConditions = isPlainObj(subData)\n\t\t\t\t? subData\n\t\t\t\t: ({} as Record<string, unknown>);\n\t\t\tconst supDataForConditions = isPlainObj(supData)\n\t\t\t\t? supData\n\t\t\t\t: ({} as Record<string, unknown>);\n\n\t\t\tconst resolvedSub = resolveConditions(\n\t\t\t\tsub as JSONSchema7,\n\t\t\t\tsubDataForConditions,\n\t\t\t\tthis.engine,\n\t\t\t);\n\t\t\tconst resolvedSup = resolveConditions(\n\t\t\t\tsup as JSONSchema7,\n\t\t\t\tsupDataForConditions,\n\t\t\t\tthis.engine,\n\t\t\t);\n\n\t\t\t// ── Data narrowing ──\n\t\t\t// When runtime data is available, narrow the resolved schema by\n\t\t\t// constraining generic types to enum values when the data matches\n\t\t\t// the opposite schema's enum constraints.\n\t\t\tconst narrowedSubResolved =\n\t\t\t\tsubData !== undefined\n\t\t\t\t\t? narrowSchemaWithData(\n\t\t\t\t\t\t\tresolvedSub.resolved,\n\t\t\t\t\t\t\tsubData,\n\t\t\t\t\t\t\tresolvedSup.resolved,\n\t\t\t\t\t\t)\n\t\t\t\t\t: resolvedSub.resolved;\n\n\t\t\tconst narrowedSupResolved =\n\t\t\t\tsupData !== undefined\n\t\t\t\t\t? narrowSchemaWithData(\n\t\t\t\t\t\t\tresolvedSup.resolved,\n\t\t\t\t\t\t\tsupData,\n\t\t\t\t\t\t\tresolvedSub.resolved,\n\t\t\t\t\t\t)\n\t\t\t\t\t: resolvedSup.resolved;\n\n\t\t\tconst result = this.checkInternal(\n\t\t\t\tnarrowedSubResolved,\n\t\t\t\tnarrowedSupResolved,\n\t\t\t);\n\t\t\treturn {\n\t\t\t\t...result,\n\t\t\t\tresolvedSub: { ...resolvedSub, resolved: narrowedSubResolved },\n\t\t\t\tresolvedSup: { ...resolvedSup, resolved: narrowedSupResolved },\n\t\t\t};\n\t\t}\n\n\t\t// ── Standard path (no condition resolution) ──\n\t\treturn this.checkInternal(sub, sup);\n\t}\n\n\t// ── Equality ───────────────────────────────────────────────────────────\n\n\t/**\n\t * Vérifie l'égalité structurelle entre deux schemas.\n\t */\n\tisEqual(a: JSONSchema7Definition, b: JSONSchema7Definition): boolean {\n\t\treturn this.engine.isEqual(normalize(a), normalize(b));\n\t}\n\n\t// ── Intersection ───────────────────────────────────────────────────────\n\n\t/**\n\t * Calcule l'intersection de deux schemas (allOf merge).\n\t * Retourne null si les schemas sont incompatibles.\n\t *\n\t * Le résultat est normalisé pour éliminer les artefacts structurels\n\t * du merge (ex: `enum` redondant quand `const` est présent).\n\t */\n\tintersect(\n\t\ta: JSONSchema7Definition,\n\t\tb: JSONSchema7Definition,\n\t): JSONSchema7Definition | null {\n\t\t// ── Identity short-circuit ──\n\t\t// If a and b are the same reference or structurally equal,\n\t\t// intersection is just normalize(a) — skip the merge entirely.\n\t\tif (a === b || deepEqual(a, b)) return normalize(a);\n\n\t\tconst nA = normalize(a);\n\t\tconst nB = normalize(b);\n\n\t\t// ── Post-normalize identity ──\n\t\tif (deepEqual(nA, nB)) return nA;\n\n\t\tconst merged = this.engine.merge(nA, nB);\n\t\tif (merged === null) return null;\n\t\t// Fast path: if merge result equals one of the normalized inputs,\n\t\t// it's already normalized — skip redundant normalize call.\n\t\tif (deepEqual(merged, nA) || deepEqual(merged, nB)) return merged;\n\t\treturn normalize(merged);\n\t}\n\n\t// ── Normalization ──────────────────────────────────────────────────────\n\n\t/**\n\t * Normalise un schema : infère `type` depuis `const`/`enum`,\n\t * et normalise récursivement tous les sous-schemas.\n\t */\n\tnormalize(def: JSONSchema7Definition): JSONSchema7Definition {\n\t\treturn normalize(def);\n\t}\n\n\t// ── Formatting ─────────────────────────────────────────────────────────\n\n\t/**\n\t * Formate un SubsetResult en chaîne lisible (utile pour logs/debug).\n\t */\n\tformatResult(label: string, result: SubsetResult): string {\n\t\treturn formatResult(label, result);\n\t}\n\n\t// ── Condition Resolution ────────────────────────────────────────────────\n\n\t/**\n\t * Resolves `if/then/else` conditions in a schema by evaluating the `if`\n\t * against partial data (discriminants).\n\t *\n\t * @param schema - The schema containing conditions to resolve\n\t * @param data - The runtime data used to evaluate conditions\n\t * @returns The resolved schema with branch info and discriminants\n\t */\n\tresolveConditions(\n\t\tschema: JSONSchema7,\n\t\tdata: Record<string, unknown>,\n\t): ResolvedConditionResult {\n\t\treturn resolveConditions(schema, data, this.engine);\n\t}\n\n\t// ── Private ────────────────────────────────────────────────────────────\n\n\t/**\n\t * Logique interne de check sans résolution de conditions.\n\t * Factorise le pipeline normalize → branch → atomic pour éviter\n\t * la duplication entre les deux chemins de `check()`.\n\t */\n\tprivate checkInternal(\n\t\tsub: JSONSchema7Definition,\n\t\tsup: JSONSchema7Definition,\n\t): SubsetResult {\n\t\t// ── Identity short-circuit ──\n\t\t// Same reference → no errors, no merge needed.\n\t\tif (sub === sup) {\n\t\t\treturn { isSubset: true, merged: sub, errors: [] };\n\t\t}\n\n\t\t// ── Pre-normalize structural equality ──\n\t\t// Avoids WeakMap overhead for identical schemas ({} ⊆ {}, etc.).\n\t\tif (deepEqual(sub, sup)) {\n\t\t\treturn { isSubset: true, merged: sub, errors: [] };\n\t\t}\n\n\t\tconst nSub = normalize(sub);\n\t\tconst nSup = normalize(sup);\n\n\t\t// ── Post-normalize structural identity ──\n\t\t// Catches semantically equivalent schemas after normalization.\n\t\tif (deepEqual(nSub, nSup)) {\n\t\t\treturn { isSubset: true, merged: nSub, errors: [] };\n\t\t}\n\n\t\tconst { branches: subBranches, type: subBranchType } =\n\t\t\tgetBranchesTyped(nSub);\n\t\tconst { branches: supBranches, type: supBranchType } =\n\t\t\tgetBranchesTyped(nSup);\n\n\t\t// anyOf/oneOf dans sub\n\t\tif (subBranches.length > 1 || subBranches[0] !== nSub) {\n\t\t\treturn checkBranchedSub(subBranches, nSup, this.engine, subBranchType);\n\t\t}\n\n\t\t// anyOf/oneOf dans sup uniquement\n\t\tif (supBranches.length > 1 || supBranches[0] !== nSup) {\n\t\t\treturn checkBranchedSup(nSub, supBranches, this.engine, supBranchType);\n\t\t}\n\n\t\t// Cas standard\n\t\treturn checkAtomic(nSub, nSup, this.engine);\n\t}\n}\n"],"names":["JsonSchemaCompatibilityChecker","MergeEngine","arePatternsEquivalent","formatResult","isPatternSubset","isTrivialPattern","normalize","resolveConditions","isSubset","sub","sup","deepEqual","nSub","nSup","branches","subBranches","getBranchesTyped","length","every","branch","isAtomicSubsetOf","engine","check","options","subData","supData","subDataForConditions","isPlainObj","supDataForConditions","resolvedSub","resolvedSup","narrowedSubResolved","undefined","narrowSchemaWithData","resolved","narrowedSupResolved","result","checkInternal","isEqual","a","b","intersect","nA","nB","merged","merge","def","label","schema","data","errors","type","subBranchType","supBranches","supBranchType","checkBranchedSub","checkBranchedSup","checkAtomic"],"mappings":"mPAuEaA,wCAAAA,oCA3BZC,qBAAAA,0BAAW,MAEXC,+BAAAA,sCAAqB,MAHrBC,sBAAAA,yBAAY,MAEZC,yBAAAA,gCAAe,MAEfC,0BAAAA,iCAAgB,MANhBC,mBAAAA,uBAAS,MACTC,2BAAAA,sCAAiB,uCAzCgB,0DACG,kDACR,+CACD,iDACF,kDAKnB,sDAQA,8CAQ+B,kMA6C/B,MAAMP,+BAgBZQ,SAASC,GAA0B,CAAEC,GAA0B,CAAW,CAIzE,GAAID,MAAQC,IAAK,OAAO,KAOxB,GAAIC,GAAAA,kBAAS,EAACF,IAAKC,KAAM,OAAO,KAEhC,MAAME,KAAON,GAAAA,uBAAS,EAACG,KACvB,MAAMI,KAAOP,GAAAA,uBAAS,EAACI,KAMvB,GAAIE,OAASH,KAAOI,OAASH,KAAOC,GAAAA,kBAAS,EAACC,KAAMC,MAAO,OAAO,KAClE,GAAID,OAASC,MAAQF,GAAAA,kBAAS,EAACC,KAAMC,MAAO,OAAO,KAEnD,KAAM,CAAEC,SAAUC,WAAW,CAAE,CAAGC,GAAAA,iCAAgB,EAACJ,MAEnD,GAAIG,YAAYE,MAAM,CAAG,GAAKF,WAAW,CAAC,EAAE,GAAKH,KAAM,CACtD,OAAOG,YAAYG,KAAK,CAAC,AAACC,QACzBC,GAAAA,iCAAgB,EAACD,OAAQN,KAAM,IAAI,CAACQ,MAAM,EAE5C,CAEA,MAAOD,GAAAA,iCAAgB,EAACR,KAAMC,KAAM,IAAI,CAACQ,MAAM,CAChD,CAoCAC,MACCb,GAA0B,CAC1BC,GAA0B,CAC1Ba,OAAgC,CACM,CAEtC,GAAIA,QAAS,CACZ,MAAMC,QAAUD,QAAQC,OAAO,CAC/B,MAAMC,QAAUF,QAAQE,OAAO,EAAIF,QAAQC,OAAO,CAIlD,MAAME,qBAAuBC,GAAAA,mBAAU,EAACH,SACrCA,QACC,CAAC,EACL,MAAMI,qBAAuBD,GAAAA,mBAAU,EAACF,SACrCA,QACC,CAAC,EAEL,MAAMI,YAActB,GAAAA,sCAAiB,EACpCE,IACAiB,qBACA,IAAI,CAACL,MAAM,EAEZ,MAAMS,YAAcvB,GAAAA,sCAAiB,EACpCG,IACAkB,qBACA,IAAI,CAACP,MAAM,EAOZ,MAAMU,oBACLP,UAAYQ,UACTC,GAAAA,qCAAoB,EACpBJ,YAAYK,QAAQ,CACpBV,QACAM,YAAYI,QAAQ,EAEpBL,YAAYK,QAAQ,CAExB,MAAMC,oBACLV,UAAYO,UACTC,GAAAA,qCAAoB,EACpBH,YAAYI,QAAQ,CACpBT,QACAI,YAAYK,QAAQ,EAEpBJ,YAAYI,QAAQ,CAExB,MAAME,OAAS,IAAI,CAACC,aAAa,CAChCN,oBACAI,qBAED,MAAO,CACN,GAAGC,MAAM,CACTP,YAAa,CAAE,GAAGA,WAAW,CAAEK,SAAUH,mBAAoB,EAC7DD,YAAa,CAAE,GAAGA,WAAW,CAAEI,SAAUC,mBAAoB,CAC9D,CACD,CAGA,OAAO,IAAI,CAACE,aAAa,CAAC5B,IAAKC,IAChC,CAOA4B,QAAQC,CAAwB,CAAEC,CAAwB,CAAW,CACpE,OAAO,IAAI,CAACnB,MAAM,CAACiB,OAAO,CAAChC,GAAAA,uBAAS,EAACiC,GAAIjC,GAAAA,uBAAS,EAACkC,GACpD,CAWAC,UACCF,CAAwB,CACxBC,CAAwB,CACO,CAI/B,GAAID,IAAMC,GAAK7B,GAAAA,kBAAS,EAAC4B,EAAGC,GAAI,MAAOlC,GAAAA,uBAAS,EAACiC,GAEjD,MAAMG,GAAKpC,GAAAA,uBAAS,EAACiC,GACrB,MAAMI,GAAKrC,GAAAA,uBAAS,EAACkC,GAGrB,GAAI7B,GAAAA,kBAAS,EAAC+B,GAAIC,IAAK,OAAOD,GAE9B,MAAME,OAAS,IAAI,CAACvB,MAAM,CAACwB,KAAK,CAACH,GAAIC,IACrC,GAAIC,SAAW,KAAM,OAAO,KAG5B,GAAIjC,GAAAA,kBAAS,EAACiC,OAAQF,KAAO/B,GAAAA,kBAAS,EAACiC,OAAQD,IAAK,OAAOC,OAC3D,MAAOtC,GAAAA,uBAAS,EAACsC,OAClB,CAQAtC,UAAUwC,GAA0B,CAAyB,CAC5D,MAAOxC,GAAAA,uBAAS,EAACwC,IAClB,CAOA3C,aAAa4C,KAAa,CAAEX,MAAoB,CAAU,CACzD,MAAOjC,GAAAA,yBAAY,EAAC4C,MAAOX,OAC5B,CAYA7B,kBACCyC,MAAmB,CACnBC,IAA6B,CACH,CAC1B,MAAO1C,GAAAA,sCAAiB,EAACyC,OAAQC,KAAM,IAAI,CAAC5B,MAAM,CACnD,CASA,AAAQgB,cACP5B,GAA0B,CAC1BC,GAA0B,CACX,CAGf,GAAID,MAAQC,IAAK,CAChB,MAAO,CAAEF,SAAU,KAAMoC,OAAQnC,IAAKyC,OAAQ,EAAE,AAAC,CAClD,CAIA,GAAIvC,GAAAA,kBAAS,EAACF,IAAKC,KAAM,CACxB,MAAO,CAAEF,SAAU,KAAMoC,OAAQnC,IAAKyC,OAAQ,EAAE,AAAC,CAClD,CAEA,MAAMtC,KAAON,GAAAA,uBAAS,EAACG,KACvB,MAAMI,KAAOP,GAAAA,uBAAS,EAACI,KAIvB,GAAIC,GAAAA,kBAAS,EAACC,KAAMC,MAAO,CAC1B,MAAO,CAAEL,SAAU,KAAMoC,OAAQhC,KAAMsC,OAAQ,EAAE,AAAC,CACnD,CAEA,KAAM,CAAEpC,SAAUC,WAAW,CAAEoC,KAAMC,aAAa,CAAE,CACnDpC,GAAAA,iCAAgB,EAACJ,MAClB,KAAM,CAAEE,SAAUuC,WAAW,CAAEF,KAAMG,aAAa,CAAE,CACnDtC,GAAAA,iCAAgB,EAACH,MAGlB,GAAIE,YAAYE,MAAM,CAAG,GAAKF,WAAW,CAAC,EAAE,GAAKH,KAAM,CACtD,MAAO2C,GAAAA,iCAAgB,EAACxC,YAAaF,KAAM,IAAI,CAACQ,MAAM,CAAE+B,cACzD,CAGA,GAAIC,YAAYpC,MAAM,CAAG,GAAKoC,WAAW,CAAC,EAAE,GAAKxC,KAAM,CACtD,MAAO2C,GAAAA,iCAAgB,EAAC5C,KAAMyC,YAAa,IAAI,CAAChC,MAAM,CAAEiC,cACzD,CAGA,MAAOG,GAAAA,4BAAW,EAAC7C,KAAMC,KAAM,IAAI,CAACQ,MAAM,CAC3C,CAlRA,aAAc,CAFd,sBAAiBA,SAAjB,KAAA,EAGC,CAAA,IAAI,CAACA,MAAM,CAAG,IAAIpB,0BAAW,AAC9B,CAiRD"}
|