json-schema-compatibility-checker 1.0.6 → 1.0.8
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 +40 -1869
- 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/merge-engine.ts"],"sourcesContent":["import {\n\tcreateComparator,\n\tcreateMerger,\n\tcreateShallowAllOfMerge,\n} from \"@x0k/json-schema-merge\";\nimport {\n\tcreateDeduplicator,\n\tcreateIntersector,\n} from \"@x0k/json-schema-merge/lib/array\";\n\nimport type {\n\tJSONSchema7,\n\tJSONSchema7Definition,\n\tJSONSchema7Type,\n} from \"json-schema\";\n\nimport { isFormatSubset } from \"./format-validator\";\nimport { deepEqual, hasOwn, isPlainObj } from \"./utils\";\n\n// ─── Merge Engine ────────────────────────────────────────────────────────────\n//\n// Encapsule la librairie `@x0k/json-schema-merge` et expose une API simple\n// pour merger et comparer des JSON Schemas.\n//\n// Principe mathématique :\n// A ∩ B = allOf([A, B]) résolu via shallow merge\n// A ≡ B ⟺ compare(A, B) === 0\n//\n// Pré-checks avant merge :\n// - `hasDeepConstConflict` : détecte les conflits de `const`/`enum`\n// - `hasAdditionalPropertiesConflict` : détecte les conflits `additionalProperties`\n// - `hasFormatConflict` : détecte les conflits de `format` entre deux schemas\n\n// ─── Const conflict detection ────────────────────────────────────────────────\n\n/**\n * Détecte un conflit de `const` entre deux schemas.\n *\n * Cas 1 — const vs const : les deux schemas ont un `const` avec des valeurs\n * différentes → intersection vide.\n *\n * Cas 2 — const vs enum : un schema a `const`, l'autre a `enum`.\n * Si la valeur de `const` n'est pas dans l'`enum` → intersection vide.\n *\n * Utilise `lodash/isEqual` pour la comparaison profonde (objets, tableaux).\n */\nfunction hasConstConflict(\n\ta: JSONSchema7Definition,\n\tb: JSONSchema7Definition,\n): boolean {\n\tif (typeof a === \"boolean\" || typeof b === \"boolean\") return false;\n\n\tconst aHasConst = hasOwn(a, \"const\");\n\tconst bHasConst = hasOwn(b, \"const\");\n\tconst aConst = (a as Record<string, unknown>).const;\n\tconst bConst = (b as Record<string, unknown>).const;\n\tconst aEnum = a.enum as unknown[] | undefined;\n\tconst bEnum = b.enum as unknown[] | undefined;\n\n\t// Cas 1 — const vs const\n\tif (aHasConst && bHasConst) {\n\t\treturn !deepEqual(aConst, bConst);\n\t}\n\n\t// Cas 2 — const vs enum\n\tif (aHasConst && Array.isArray(bEnum)) {\n\t\treturn !bEnum.some((v) => deepEqual(v, aConst));\n\t}\n\tif (bHasConst && Array.isArray(aEnum)) {\n\t\treturn !aEnum.some((v) => deepEqual(v, bConst));\n\t}\n\n\treturn false;\n}\n\n/** Mots-clés contenant un unique sous-schema à vérifier récursivement */\nconst SINGLE_SCHEMA_CONFLICT_KEYS = [\n\t\"items\",\n\t\"additionalProperties\",\n\t\"contains\",\n\t\"propertyNames\",\n\t\"not\",\n] as const;\n\n/** Mots-clés contenant un Record<string, JSONSchema7Definition> */\nconst PROPERTIES_MAP_CONFLICT_KEYS = [\n\t\"properties\",\n\t\"patternProperties\",\n] as const;\n\n/**\n * Détecte récursivement les conflits de `const` dans les sous-schemas.\n *\n * Quand la librairie de merge fait un shallow merge, les sous-schemas\n * imbriqués peuvent aussi avoir des conflits de `const` masqués\n * (elle utilise `identity` pour `const`).\n *\n * Récurse dans :\n * - `properties`, `patternProperties` (clés communes)\n * - `items` (single schema), tuple `items` (par index)\n * - `additionalProperties`, `contains`, `propertyNames`, `not`\n */\nfunction hasDeepConstConflict(\n\ta: JSONSchema7Definition,\n\tb: JSONSchema7Definition,\n): boolean {\n\tif (hasConstConflict(a, b)) return true;\n\n\tif (typeof a === \"boolean\" || typeof b === \"boolean\") return false;\n\n\t// ── Single sub-schema keywords ──\n\tfor (const key of SINGLE_SCHEMA_CONFLICT_KEYS) {\n\t\tconst aVal = (a as Record<string, unknown>)[key] as\n\t\t\t| JSONSchema7Definition\n\t\t\t| undefined;\n\t\tconst bVal = (b as Record<string, unknown>)[key] as\n\t\t\t| JSONSchema7Definition\n\t\t\t| undefined;\n\t\tif (\n\t\t\tisPlainObj(aVal) &&\n\t\t\tisPlainObj(bVal) &&\n\t\t\thasDeepConstConflict(\n\t\t\t\taVal as JSONSchema7Definition,\n\t\t\t\tbVal as JSONSchema7Definition,\n\t\t\t)\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// ── Properties-like maps (properties, patternProperties) ──\n\tfor (const key of PROPERTIES_MAP_CONFLICT_KEYS) {\n\t\tconst aMap = (a as Record<string, unknown>)[key] as\n\t\t\t| Record<string, JSONSchema7Definition>\n\t\t\t| undefined;\n\t\tconst bMap = (b as Record<string, unknown>)[key] as\n\t\t\t| Record<string, JSONSchema7Definition>\n\t\t\t| undefined;\n\t\tif (!isPlainObj(aMap) || !isPlainObj(bMap)) continue;\n\t\tconst aMapSafe = aMap as Record<string, JSONSchema7Definition>;\n\t\tconst bMapSafe = bMap as Record<string, JSONSchema7Definition>;\n\t\tfor (const propKey of Object.keys(aMapSafe)) {\n\t\t\tconst aVal = aMapSafe[propKey];\n\t\t\tconst bVal = bMapSafe[propKey];\n\t\t\tif (\n\t\t\t\taVal !== undefined &&\n\t\t\t\tbVal !== undefined &&\n\t\t\t\thasOwn(bMapSafe, propKey) &&\n\t\t\t\thasDeepConstConflict(aVal, bVal)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Tuple items (array of schemas, compared by index) ──\n\tif (Array.isArray(a.items) && Array.isArray(b.items)) {\n\t\tconst aItems = a.items as JSONSchema7Definition[];\n\t\tconst bItems = b.items as JSONSchema7Definition[];\n\t\tconst len = Math.min(aItems.length, bItems.length);\n\t\tfor (let i = 0; i < len; i++) {\n\t\t\tconst aItem = aItems[i];\n\t\t\tconst bItem = bItems[i];\n\t\t\tif (aItem === undefined || bItem === undefined) continue;\n\t\t\tif (hasDeepConstConflict(aItem, bItem)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false;\n}\n\n// ─── additionalProperties conflict detection ─────────────────────────────────\n\n/**\n * Détecte un conflit entre `additionalProperties` et les propriétés extra\n * **requises** de l'autre schema.\n *\n * ⚠️ Cette fonction est **ultra-conservatrice** : elle ne détecte que les\n * conflits où une propriété est à la fois :\n * - INTERDITE par `additionalProperties: false` d'un côté\n * - REQUISE (`required`) par l'autre côté\n * - ABSENTE des `properties` du côté restrictif\n * - ET le côté restrictif AUSSI a un `required` qui rend l'objet non-vide\n * (sinon la librairie gère déjà le cas en excluant les propriétés extra)\n *\n * La librairie de merge (`@x0k/json-schema-merge`) gère DÉJÀ correctement\n * le cas `additionalProperties: false` avec des propriétés simplement DÉFINIES\n * (non requises) dans l'autre schema — elle les exclut du résultat.\n * On ne détecte donc QUE les contradictions `required` impossibles à résoudre.\n *\n * Cas gérés :\n * 1. `a` a `additionalProperties: false` et `b` REQUIERT des propriétés\n * absentes de `a.properties`, ET ces propriétés sont dans `b.properties`\n * → conflit certain (intersection vide car b exige, a interdit)\n * 2. Symétrique pour `b.additionalProperties: false`\n * 3. `additionalProperties` comme schema → vérifier la compatibilité de type\n * des propriétés extra REQUISES uniquement\n * 4. Récursion dans les propriétés communes (sous-objets)\n *\n * ⚠️ Ne vérifie que les clés de `properties`, pas les `patternProperties`\n * (trop complexe à résoudre statiquement).\n *\n * Retourne `true` si un conflit évident est détecté, `false` sinon.\n * En cas de doute → `false` (conservateur, laisser le merge décider).\n *\n * Utilise `_.keys`, `_.some`, `_.every`, `_.has`, `_.get`, `_.isPlainObject`,\n * `_.includes` pour des vérifications concises.\n */\nfunction hasAdditionalPropertiesConflict(\n\ta: JSONSchema7Definition,\n\tb: JSONSchema7Definition,\n): boolean {\n\tif (typeof a === \"boolean\" || typeof b === \"boolean\") return false;\n\n\tconst aProps = isPlainObj(a.properties)\n\t\t? (a.properties as Record<string, JSONSchema7Definition>)\n\t\t: undefined;\n\tconst bProps = isPlainObj(b.properties)\n\t\t? (b.properties as Record<string, JSONSchema7Definition>)\n\t\t: undefined;\n\n\t// Si aucun des deux n'a de properties, on ne peut rien déterminer\n\tif (!aProps && !bProps) return false;\n\n\tconst aKeys = aProps ? Object.keys(aProps) : [];\n\tconst bKeys = bProps ? Object.keys(bProps) : [];\n\tconst aRequired = Array.isArray(a.required) ? (a.required as string[]) : [];\n\tconst bRequired = Array.isArray(b.required) ? (b.required as string[]) : [];\n\n\t// ── Vérifier additionalProperties: false de a vs propriétés REQUISES extra de b ──\n\t// Condition stricte : b doit DÉFINIR la propriété dans b.properties ET la\n\t// REQUÉRIR dans b.required, ET cette propriété doit être ABSENTE de a.properties.\n\t// De plus, a doit lui-même avoir des propriétés (sinon on ne peut rien dire).\n\tif (a.additionalProperties === false && aProps && bProps) {\n\t\tconst hasRequiredExtra = bRequired.some(\n\t\t\t(k) => !hasOwn(aProps, k) && hasOwn(bProps, k),\n\t\t);\n\t\t// Ne détecter le conflit que si a a aussi un required qui rend l'objet\n\t\t// structurellement contraint (pas un schema vague)\n\t\tif (hasRequiredExtra && aKeys.length > 0) return true;\n\t}\n\n\t// ── Vérification du cas additionalProperties comme schema ──\n\t// Si a.additionalProperties est un schema avec un type, et que b REQUIERT\n\t// une propriété extra dont le type est incompatible → conflit\n\tif (\n\t\tisPlainObj(a.additionalProperties) &&\n\t\ttypeof a.additionalProperties !== \"boolean\" &&\n\t\taProps &&\n\t\tbProps\n\t) {\n\t\tconst addPropsSchema = a.additionalProperties as JSONSchema7;\n\t\tif (hasOwn(addPropsSchema, \"type\")) {\n\t\t\tconst addPropsType = addPropsSchema.type;\n\t\t\tconst hasTypeConflict = bRequired.some((k) => {\n\t\t\t\tif (hasOwn(aProps, k)) return false;\n\t\t\t\tif (!hasOwn(bProps, k)) return false;\n\t\t\t\tconst bPropDef = bProps[k];\n\t\t\t\tif (typeof bPropDef === \"boolean\") return false;\n\t\t\t\tconst bProp = bPropDef as JSONSchema7;\n\t\t\t\tif (!hasOwn(bProp, \"type\")) return false;\n\t\t\t\tif (\n\t\t\t\t\ttypeof addPropsType === \"string\" &&\n\t\t\t\t\ttypeof bProp.type === \"string\"\n\t\t\t\t) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\taddPropsType !== bProp.type &&\n\t\t\t\t\t\t!(addPropsType === \"number\" && bProp.type === \"integer\") &&\n\t\t\t\t\t\t!(addPropsType === \"integer\" && bProp.type === \"number\")\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\tif (hasTypeConflict) return true;\n\t\t}\n\t}\n\n\t// ── Vérification symétrique : additionalProperties de b vs propriétés REQUISES extra de a ──\n\tif (b.additionalProperties === false && bProps && aProps) {\n\t\tconst hasRequiredExtra = aRequired.some(\n\t\t\t(k) => !hasOwn(bProps, k) && hasOwn(aProps, k),\n\t\t);\n\t\tif (hasRequiredExtra && bKeys.length > 0) return true;\n\t}\n\n\t// Symétrique pour additionalProperties comme schema\n\tif (\n\t\tisPlainObj(b.additionalProperties) &&\n\t\ttypeof b.additionalProperties !== \"boolean\" &&\n\t\tbProps &&\n\t\taProps\n\t) {\n\t\tconst addPropsSchema = b.additionalProperties as JSONSchema7;\n\t\tif (hasOwn(addPropsSchema, \"type\")) {\n\t\t\tconst addPropsType = addPropsSchema.type;\n\t\t\tconst hasTypeConflict = aRequired.some((k) => {\n\t\t\t\tif (hasOwn(bProps, k)) return false;\n\t\t\t\tif (!hasOwn(aProps, k)) return false;\n\t\t\t\tconst aPropDef = aProps[k];\n\t\t\t\tif (typeof aPropDef === \"boolean\") return false;\n\t\t\t\tconst aProp = aPropDef as JSONSchema7;\n\t\t\t\tif (!hasOwn(aProp, \"type\")) return false;\n\t\t\t\tif (\n\t\t\t\t\ttypeof addPropsType === \"string\" &&\n\t\t\t\t\ttypeof aProp.type === \"string\"\n\t\t\t\t) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\taddPropsType !== aProp.type &&\n\t\t\t\t\t\t!(addPropsType === \"number\" && aProp.type === \"integer\") &&\n\t\t\t\t\t\t!(addPropsType === \"integer\" && aProp.type === \"number\")\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\tif (hasTypeConflict) return true;\n\t\t}\n\t}\n\n\t// ── Récursion dans les propriétés communes ──\n\t// Si les deux schemas ont des propriétés communes qui sont des objets,\n\t// vérifier récursivement les conflits additionalProperties\n\tif (aProps && bProps) {\n\t\tfor (const k of aKeys) {\n\t\t\tif (!hasOwn(bProps, k)) continue;\n\t\t\tconst aPropDef = aProps[k];\n\t\t\tconst bPropDef = bProps[k];\n\t\t\tif (typeof aPropDef === \"boolean\" || typeof bPropDef === \"boolean\")\n\t\t\t\tcontinue;\n\t\t\tif (\n\t\t\t\thasAdditionalPropertiesConflict(\n\t\t\t\t\taPropDef as JSONSchema7Definition,\n\t\t\t\t\tbPropDef as JSONSchema7Definition,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false;\n}\n\n// ─── Format conflict detection ───────────────────────────────────────────────\n\n/**\n * Détecte un conflit de format entre deux schemas.\n *\n * ⚠️ Ne se déclenche QUE quand les DEUX schemas ont un `format`.\n * Si un seul schema a un `format`, il n'y a PAS de conflit — le merge\n * engine gère nativement ce cas (le format est conservé dans l'intersection,\n * et la comparaison `merged ≡ sub` détermine correctement la relation ⊆).\n *\n * Deux schemas avec des formats différents et sans relation d'inclusion\n * connue ont une intersection vide (ex: \"email\" ∩ \"ipv4\" = ∅).\n *\n * Utilise `isFormatSubset` de `format-validator.ts` pour vérifier la hiérarchie.\n *\n * Récurse dans les sous-schemas (`properties`, `items`, etc.) pour détecter\n * les conflits de format imbriqués.\n *\n * @returns `true` si un conflit de format est détecté, `false` sinon\n */\nfunction hasFormatConflict(\n\ta: JSONSchema7Definition,\n\tb: JSONSchema7Definition,\n): boolean {\n\tif (typeof a === \"boolean\" || typeof b === \"boolean\") return false;\n\n\t// ── Seulement quand LES DEUX ont un format ──\n\t// Si un seul a un format → pas de conflit, le merge gère nativement\n\tif (hasOwn(a, \"format\") && hasOwn(b, \"format\")) {\n\t\tconst aFormat = a.format as string;\n\t\tconst bFormat = b.format as string;\n\n\t\t// Même format → pas de conflit\n\t\tif (aFormat !== bFormat) {\n\t\t\t// Vérifier si l'un est un sous-ensemble de l'autre via la hiérarchie\n\t\t\tconst subsetCheck = isFormatSubset(aFormat, bFormat);\n\t\t\tif (subsetCheck !== true) {\n\t\t\t\tconst reverseCheck = isFormatSubset(bFormat, aFormat);\n\t\t\t\tif (reverseCheck !== true) {\n\t\t\t\t\t// Formats différents sans relation connue → conflit\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Récursion dans les sous-schemas ──\n\t// Vérifier les conflits de format dans les propriétés communes\n\tif (isPlainObj(a.properties) && isPlainObj(b.properties)) {\n\t\tconst aMap = a.properties as Record<string, JSONSchema7Definition>;\n\t\tconst bMap = b.properties as Record<string, JSONSchema7Definition>;\n\t\tfor (const k of Object.keys(aMap)) {\n\t\t\tconst aVal = aMap[k];\n\t\t\tconst bVal = bMap[k];\n\t\t\tif (\n\t\t\t\taVal !== undefined &&\n\t\t\t\tbVal !== undefined &&\n\t\t\t\thasOwn(bMap, k) &&\n\t\t\t\thasFormatConflict(aVal, bVal)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Vérifier items (single schema)\n\tif (isPlainObj(a.items) && isPlainObj(b.items)) {\n\t\tif (\n\t\t\thasFormatConflict(\n\t\t\t\ta.items as JSONSchema7Definition,\n\t\t\t\tb.items as JSONSchema7Definition,\n\t\t\t)\n\t\t)\n\t\t\treturn true;\n\t}\n\n\t// Vérifier additionalProperties\n\tif (\n\t\tisPlainObj(a.additionalProperties) &&\n\t\tisPlainObj(b.additionalProperties)\n\t) {\n\t\tif (\n\t\t\thasFormatConflict(\n\t\t\t\ta.additionalProperties as JSONSchema7Definition,\n\t\t\t\tb.additionalProperties as JSONSchema7Definition,\n\t\t\t)\n\t\t)\n\t\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// ─── MergeEngine class ───────────────────────────────────────────────────────\n\nexport class MergeEngine {\n\tprivate readonly compareFn: (\n\t\ta: JSONSchema7Definition,\n\t\tb: JSONSchema7Definition,\n\t) => number;\n\n\tprivate readonly shallowAllOfMergeFn: (\n\t\tschema: JSONSchema7 & { allOf: JSONSchema7Definition[] },\n\t) => JSONSchema7Definition;\n\n\tconstructor() {\n\t\tconst { compareSchemaDefinitions, compareSchemaValues } =\n\t\t\tcreateComparator();\n\n\t\t// ── Null-safe wrapper for compareSchemaValues ──\n\t\t// The library's compareSchemaValues has a bug: when both a and b are null,\n\t\t// it returns -1 instead of 0 (the null check for `a` fires before checking\n\t\t// if `b` is also null). This causes createIntersector to lose null values\n\t\t// during enum intersection (the sort-merge join relies on compare(x,x)===0).\n\t\tconst safeCompareSchemaValues = (\n\t\t\ta: JSONSchema7Type,\n\t\t\tb: JSONSchema7Type,\n\t\t): number => {\n\t\t\tif (a === null && b === null) return 0;\n\t\t\treturn compareSchemaValues(a, b);\n\t\t};\n\n\t\tconst { mergeArrayOfSchemaDefinitions } = createMerger({\n\t\t\tintersectJson: createIntersector(safeCompareSchemaValues),\n\t\t\tdeduplicateJsonSchemaDef: createDeduplicator(compareSchemaDefinitions),\n\t\t});\n\n\t\tthis.compareFn = compareSchemaDefinitions;\n\t\tthis.shallowAllOfMergeFn = createShallowAllOfMerge(\n\t\t\tmergeArrayOfSchemaDefinitions,\n\t\t);\n\t}\n\n\t/**\n\t * Merge deux schemas via `allOf([a, b])`.\n\t * Retourne `null` si les schemas sont incompatibles.\n\t *\n\t * Post-merge : détecte les conflits de `const` que la librairie\n\t * ne capture pas (elle utilise `identity` pour `const`).\n\t */\n\tmerge(\n\t\ta: JSONSchema7Definition,\n\t\tb: JSONSchema7Definition,\n\t): JSONSchema7Definition | null {\n\t\t// Pré-check : conflit de const détectable avant le merge\n\t\tif (hasDeepConstConflict(a, b)) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Pré-check : conflit de format (les DEUX ont un format incompatible)\n\t\tif (hasFormatConflict(a, b)) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Pré-check : conflit additionalProperties vs propriétés REQUISES extra\n\t\t// Ne détecte que les cas où une propriété est à la fois interdite\n\t\t// (additionalProperties: false) et requise (required) → intersection vide.\n\t\t// Les cas où les propriétés sont simplement définies sans être requises\n\t\t// sont gérés correctement par la librairie de merge elle-même.\n\t\tif (hasAdditionalPropertiesConflict(a, b)) {\n\t\t\treturn null;\n\t\t}\n\n\t\ttry {\n\t\t\treturn this.shallowAllOfMergeFn({ allOf: [a, b] });\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Merge via `shallowAllOfMerge` — lève une exception si incompatible.\n\t * Utile quand on veut capturer l'erreur pour le diagnostic.\n\t *\n\t * Post-merge : détecte les conflits de `const` et lève une exception.\n\t */\n\tmergeOrThrow(\n\t\ta: JSONSchema7Definition,\n\t\tb: JSONSchema7Definition,\n\t): JSONSchema7Definition {\n\t\t// Pré-check : conflit de const\n\t\tif (hasDeepConstConflict(a, b)) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Incompatible const values: schemas have conflicting const constraints\",\n\t\t\t);\n\t\t}\n\n\t\t// Pré-check : conflit de format\n\t\tif (hasFormatConflict(a, b)) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Incompatible format values: schemas have conflicting format constraints\",\n\t\t\t);\n\t\t}\n\n\t\t// Pré-check : conflit additionalProperties vs propriétés REQUISES extra\n\t\tif (hasAdditionalPropertiesConflict(a, b)) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Incompatible additionalProperties: required properties conflict with additionalProperties constraint\",\n\t\t\t);\n\t\t}\n\n\t\treturn this.shallowAllOfMergeFn({ allOf: [a, b] });\n\t}\n\n\t/**\n\t * Compare structurellement deux schema definitions.\n\t * Retourne 0 si elles sont identiques, sinon un entier non nul.\n\t */\n\tcompare(a: JSONSchema7Definition, b: JSONSchema7Definition): number {\n\t\treturn this.compareFn(a, b);\n\t}\n\n\t/**\n\t * Vérifie l'égalité structurelle entre deux schema definitions.\n\t */\n\tisEqual(a: JSONSchema7Definition, b: JSONSchema7Definition): boolean {\n\t\treturn this.compareFn(a, b) === 0;\n\t}\n}\n"],"names":["MergeEngine","hasConstConflict","a","b","aHasConst","hasOwn","bHasConst","aConst","const","bConst","aEnum","enum","bEnum","deepEqual","Array","isArray","some","v","SINGLE_SCHEMA_CONFLICT_KEYS","PROPERTIES_MAP_CONFLICT_KEYS","hasDeepConstConflict","key","aVal","bVal","isPlainObj","aMap","bMap","aMapSafe","bMapSafe","propKey","Object","keys","undefined","items","aItems","bItems","len","Math","min","length","i","aItem","bItem","hasAdditionalPropertiesConflict","aProps","properties","bProps","aKeys","bKeys","aRequired","required","bRequired","additionalProperties","hasRequiredExtra","k","addPropsSchema","addPropsType","type","hasTypeConflict","bPropDef","bProp","aPropDef","aProp","hasFormatConflict","aFormat","format","bFormat","subsetCheck","isFormatSubset","reverseCheck","merge","shallowAllOfMergeFn","allOf","mergeOrThrow","Error","compare","compareFn","isEqual","compareSchemaDefinitions","compareSchemaValues","createComparator","safeCompareSchemaValues","mergeArrayOfSchemaDefinitions","createMerger","intersectJson","createIntersector","deduplicateJsonSchemaDef","createDeduplicator","createShallowAllOfMerge"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/merge-engine.ts"],"sourcesContent":["import {\n\tcreateComparator,\n\tcreateMerger,\n\tcreateShallowAllOfMerge,\n} from \"@x0k/json-schema-merge\";\nimport {\n\tcreateDeduplicator,\n\tcreateIntersector,\n} from \"@x0k/json-schema-merge/lib/array\";\n\nimport type {\n\tJSONSchema7,\n\tJSONSchema7Definition,\n\tJSONSchema7Type,\n} from \"json-schema\";\n\nimport { isFormatSubset } from \"./format-validator\";\nimport { deepEqual, hasOwn, isPlainObj } from \"./utils\";\n\n// ─── Merge Engine ────────────────────────────────────────────────────────────\n//\n// Encapsule la librairie `@x0k/json-schema-merge` et expose une API simple\n// pour merger et comparer des JSON Schemas.\n//\n// Principe mathématique :\n// A ∩ B = allOf([A, B]) résolu via shallow merge\n// A ≡ B ⟺ compare(A, B) === 0\n//\n// Pré-checks avant merge :\n// - `hasDeepConstConflict` : détecte les conflits de `const`/`enum`\n// - `hasAdditionalPropertiesConflict` : détecte les conflits `additionalProperties`\n// - `hasFormatConflict` : détecte les conflits de `format` entre deux schemas\n\n// ─── Const conflict detection ────────────────────────────────────────────────\n\n/**\n * Détecte un conflit de `const` entre deux schemas.\n *\n * Cas 1 — const vs const : les deux schemas ont un `const` avec des valeurs\n * différentes → intersection vide.\n *\n * Cas 2 — const vs enum : un schema a `const`, l'autre a `enum`.\n * Si la valeur de `const` n'est pas dans l'`enum` → intersection vide.\n *\n * Uses `deepEqual` from `utils.ts` for deep comparison (objects, arrays).\n */\nfunction hasConstConflict(\n\ta: JSONSchema7Definition,\n\tb: JSONSchema7Definition,\n): boolean {\n\tif (typeof a === \"boolean\" || typeof b === \"boolean\") return false;\n\n\tconst aHasConst = hasOwn(a, \"const\");\n\tconst bHasConst = hasOwn(b, \"const\");\n\tconst aConst = (a as Record<string, unknown>).const;\n\tconst bConst = (b as Record<string, unknown>).const;\n\tconst aEnum = a.enum as unknown[] | undefined;\n\tconst bEnum = b.enum as unknown[] | undefined;\n\n\t// Cas 1 — const vs const\n\tif (aHasConst && bHasConst) {\n\t\treturn !deepEqual(aConst, bConst);\n\t}\n\n\t// Cas 2 — const vs enum\n\tif (aHasConst && Array.isArray(bEnum)) {\n\t\treturn !bEnum.some((v) => deepEqual(v, aConst));\n\t}\n\tif (bHasConst && Array.isArray(aEnum)) {\n\t\treturn !aEnum.some((v) => deepEqual(v, bConst));\n\t}\n\n\treturn false;\n}\n\n/** Mots-clés contenant un unique sous-schema à vérifier récursivement */\nconst SINGLE_SCHEMA_CONFLICT_KEYS = [\n\t\"items\",\n\t\"additionalProperties\",\n\t\"contains\",\n\t\"propertyNames\",\n\t\"not\",\n] as const;\n\n/** Mots-clés contenant un Record<string, JSONSchema7Definition> */\nconst PROPERTIES_MAP_CONFLICT_KEYS = [\n\t\"properties\",\n\t\"patternProperties\",\n] as const;\n\n/**\n * Détecte récursivement les conflits de `const` dans les sous-schemas.\n *\n * Quand la librairie de merge fait un shallow merge, les sous-schemas\n * imbriqués peuvent aussi avoir des conflits de `const` masqués\n * (elle utilise `identity` pour `const`).\n *\n * Récurse dans :\n * - `properties`, `patternProperties` (clés communes)\n * - `items` (single schema), tuple `items` (par index)\n * - `additionalProperties`, `contains`, `propertyNames`, `not`\n */\nfunction hasDeepConstConflict(\n\ta: JSONSchema7Definition,\n\tb: JSONSchema7Definition,\n): boolean {\n\tif (hasConstConflict(a, b)) return true;\n\n\tif (typeof a === \"boolean\" || typeof b === \"boolean\") return false;\n\n\t// ── Single sub-schema keywords ──\n\tfor (const key of SINGLE_SCHEMA_CONFLICT_KEYS) {\n\t\tconst aVal = (a as Record<string, unknown>)[key] as\n\t\t\t| JSONSchema7Definition\n\t\t\t| undefined;\n\t\tconst bVal = (b as Record<string, unknown>)[key] as\n\t\t\t| JSONSchema7Definition\n\t\t\t| undefined;\n\t\tif (\n\t\t\tisPlainObj(aVal) &&\n\t\t\tisPlainObj(bVal) &&\n\t\t\thasDeepConstConflict(\n\t\t\t\taVal as JSONSchema7Definition,\n\t\t\t\tbVal as JSONSchema7Definition,\n\t\t\t)\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\t// ── Properties-like maps (properties, patternProperties) ──\n\tfor (const key of PROPERTIES_MAP_CONFLICT_KEYS) {\n\t\tconst aMap = (a as Record<string, unknown>)[key] as\n\t\t\t| Record<string, JSONSchema7Definition>\n\t\t\t| undefined;\n\t\tconst bMap = (b as Record<string, unknown>)[key] as\n\t\t\t| Record<string, JSONSchema7Definition>\n\t\t\t| undefined;\n\t\tif (!isPlainObj(aMap) || !isPlainObj(bMap)) continue;\n\t\tconst aMapSafe = aMap as Record<string, JSONSchema7Definition>;\n\t\tconst bMapSafe = bMap as Record<string, JSONSchema7Definition>;\n\t\tfor (const propKey of Object.keys(aMapSafe)) {\n\t\t\tconst aVal = aMapSafe[propKey];\n\t\t\tconst bVal = bMapSafe[propKey];\n\t\t\tif (\n\t\t\t\taVal !== undefined &&\n\t\t\t\tbVal !== undefined &&\n\t\t\t\thasOwn(bMapSafe, propKey) &&\n\t\t\t\thasDeepConstConflict(aVal, bVal)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Tuple items (array of schemas, compared by index) ──\n\tif (Array.isArray(a.items) && Array.isArray(b.items)) {\n\t\tconst aItems = a.items as JSONSchema7Definition[];\n\t\tconst bItems = b.items as JSONSchema7Definition[];\n\t\tconst len = Math.min(aItems.length, bItems.length);\n\t\tfor (let i = 0; i < len; i++) {\n\t\t\tconst aItem = aItems[i];\n\t\t\tconst bItem = bItems[i];\n\t\t\tif (aItem === undefined || bItem === undefined) continue;\n\t\t\tif (hasDeepConstConflict(aItem, bItem)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false;\n}\n\n// ─── additionalProperties conflict detection ─────────────────────────────────\n\n/**\n * Détecte un conflit entre `additionalProperties` et les propriétés extra\n * **requises** de l'autre schema.\n *\n * ⚠️ Cette fonction est **ultra-conservatrice** : elle ne détecte que les\n * conflits où une propriété est à la fois :\n * - INTERDITE par `additionalProperties: false` d'un côté\n * - REQUISE (`required`) par l'autre côté\n * - ABSENTE des `properties` du côté restrictif\n * - ET le côté restrictif AUSSI a un `required` qui rend l'objet non-vide\n * (sinon la librairie gère déjà le cas en excluant les propriétés extra)\n *\n * La librairie de merge (`@x0k/json-schema-merge`) gère DÉJÀ correctement\n * le cas `additionalProperties: false` avec des propriétés simplement DÉFINIES\n * (non requises) dans l'autre schema — elle les exclut du résultat.\n * On ne détecte donc QUE les contradictions `required` impossibles à résoudre.\n *\n * Cas gérés :\n * 1. `a` a `additionalProperties: false` et `b` REQUIERT des propriétés\n * absentes de `a.properties`, ET ces propriétés sont dans `b.properties`\n * → conflit certain (intersection vide car b exige, a interdit)\n * 2. Symétrique pour `b.additionalProperties: false`\n * 3. `additionalProperties` comme schema → vérifier la compatibilité de type\n * des propriétés extra REQUISES uniquement\n * 4. Récursion dans les propriétés communes (sous-objets)\n *\n * ⚠️ Ne vérifie que les clés de `properties`, pas les `patternProperties`\n * (trop complexe à résoudre statiquement).\n *\n * Retourne `true` si un conflit évident est détecté, `false` sinon.\n * En cas de doute → `false` (conservateur, laisser le merge décider).\n *\n * Utilise `_.keys`, `_.some`, `_.every`, `_.has`, `_.get`, `_.isPlainObject`,\n * `_.includes` pour des vérifications concises.\n */\nfunction hasAdditionalPropertiesConflict(\n\ta: JSONSchema7Definition,\n\tb: JSONSchema7Definition,\n): boolean {\n\tif (typeof a === \"boolean\" || typeof b === \"boolean\") return false;\n\n\tconst aProps = isPlainObj(a.properties)\n\t\t? (a.properties as Record<string, JSONSchema7Definition>)\n\t\t: undefined;\n\tconst bProps = isPlainObj(b.properties)\n\t\t? (b.properties as Record<string, JSONSchema7Definition>)\n\t\t: undefined;\n\n\t// Si aucun des deux n'a de properties, on ne peut rien déterminer\n\tif (!aProps && !bProps) return false;\n\n\tconst aKeys = aProps ? Object.keys(aProps) : [];\n\tconst bKeys = bProps ? Object.keys(bProps) : [];\n\tconst aRequired = Array.isArray(a.required) ? (a.required as string[]) : [];\n\tconst bRequired = Array.isArray(b.required) ? (b.required as string[]) : [];\n\n\t// ── Vérifier additionalProperties: false de a vs propriétés REQUISES extra de b ──\n\t// Condition stricte : b doit DÉFINIR la propriété dans b.properties ET la\n\t// REQUÉRIR dans b.required, ET cette propriété doit être ABSENTE de a.properties.\n\t// De plus, a doit lui-même avoir des propriétés (sinon on ne peut rien dire).\n\tif (a.additionalProperties === false && aProps && bProps) {\n\t\tconst hasRequiredExtra = bRequired.some(\n\t\t\t(k) => !hasOwn(aProps, k) && hasOwn(bProps, k),\n\t\t);\n\t\t// Ne détecter le conflit que si a a aussi un required qui rend l'objet\n\t\t// structurellement contraint (pas un schema vague)\n\t\tif (hasRequiredExtra && aKeys.length > 0) return true;\n\t}\n\n\t// ── Vérification du cas additionalProperties comme schema ──\n\t// Si a.additionalProperties est un schema avec un type, et que b REQUIERT\n\t// une propriété extra dont le type est incompatible → conflit\n\tif (\n\t\tisPlainObj(a.additionalProperties) &&\n\t\ttypeof a.additionalProperties !== \"boolean\" &&\n\t\taProps &&\n\t\tbProps\n\t) {\n\t\tconst addPropsSchema = a.additionalProperties as JSONSchema7;\n\t\tif (hasOwn(addPropsSchema, \"type\")) {\n\t\t\tconst addPropsType = addPropsSchema.type;\n\t\t\tconst hasTypeConflict = bRequired.some((k) => {\n\t\t\t\tif (hasOwn(aProps, k)) return false;\n\t\t\t\tif (!hasOwn(bProps, k)) return false;\n\t\t\t\tconst bPropDef = bProps[k];\n\t\t\t\tif (typeof bPropDef === \"boolean\") return false;\n\t\t\t\tconst bProp = bPropDef as JSONSchema7;\n\t\t\t\tif (!hasOwn(bProp, \"type\")) return false;\n\t\t\t\tif (\n\t\t\t\t\ttypeof addPropsType === \"string\" &&\n\t\t\t\t\ttypeof bProp.type === \"string\"\n\t\t\t\t) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\taddPropsType !== bProp.type &&\n\t\t\t\t\t\t!(addPropsType === \"number\" && bProp.type === \"integer\") &&\n\t\t\t\t\t\t!(addPropsType === \"integer\" && bProp.type === \"number\")\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\tif (hasTypeConflict) return true;\n\t\t}\n\t}\n\n\t// ── Vérification symétrique : additionalProperties de b vs propriétés REQUISES extra de a ──\n\tif (b.additionalProperties === false && bProps && aProps) {\n\t\tconst hasRequiredExtra = aRequired.some(\n\t\t\t(k) => !hasOwn(bProps, k) && hasOwn(aProps, k),\n\t\t);\n\t\tif (hasRequiredExtra && bKeys.length > 0) return true;\n\t}\n\n\t// Symétrique pour additionalProperties comme schema\n\tif (\n\t\tisPlainObj(b.additionalProperties) &&\n\t\ttypeof b.additionalProperties !== \"boolean\" &&\n\t\tbProps &&\n\t\taProps\n\t) {\n\t\tconst addPropsSchema = b.additionalProperties as JSONSchema7;\n\t\tif (hasOwn(addPropsSchema, \"type\")) {\n\t\t\tconst addPropsType = addPropsSchema.type;\n\t\t\tconst hasTypeConflict = aRequired.some((k) => {\n\t\t\t\tif (hasOwn(bProps, k)) return false;\n\t\t\t\tif (!hasOwn(aProps, k)) return false;\n\t\t\t\tconst aPropDef = aProps[k];\n\t\t\t\tif (typeof aPropDef === \"boolean\") return false;\n\t\t\t\tconst aProp = aPropDef as JSONSchema7;\n\t\t\t\tif (!hasOwn(aProp, \"type\")) return false;\n\t\t\t\tif (\n\t\t\t\t\ttypeof addPropsType === \"string\" &&\n\t\t\t\t\ttypeof aProp.type === \"string\"\n\t\t\t\t) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\taddPropsType !== aProp.type &&\n\t\t\t\t\t\t!(addPropsType === \"number\" && aProp.type === \"integer\") &&\n\t\t\t\t\t\t!(addPropsType === \"integer\" && aProp.type === \"number\")\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\tif (hasTypeConflict) return true;\n\t\t}\n\t}\n\n\t// ── Récursion dans les propriétés communes ──\n\t// Si les deux schemas ont des propriétés communes qui sont des objets,\n\t// vérifier récursivement les conflits additionalProperties\n\tif (aProps && bProps) {\n\t\tfor (const k of aKeys) {\n\t\t\tif (!hasOwn(bProps, k)) continue;\n\t\t\tconst aPropDef = aProps[k];\n\t\t\tconst bPropDef = bProps[k];\n\t\t\tif (typeof aPropDef === \"boolean\" || typeof bPropDef === \"boolean\")\n\t\t\t\tcontinue;\n\t\t\tif (\n\t\t\t\thasAdditionalPropertiesConflict(\n\t\t\t\t\taPropDef as JSONSchema7Definition,\n\t\t\t\t\tbPropDef as JSONSchema7Definition,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false;\n}\n\n// ─── Format conflict detection ───────────────────────────────────────────────\n\n/**\n * Détecte un conflit de format entre deux schemas.\n *\n * ⚠️ Ne se déclenche QUE quand les DEUX schemas ont un `format`.\n * Si un seul schema a un `format`, il n'y a PAS de conflit — le merge\n * engine gère nativement ce cas (le format est conservé dans l'intersection,\n * et la comparaison `merged ≡ sub` détermine correctement la relation ⊆).\n *\n * Deux schemas avec des formats différents et sans relation d'inclusion\n * connue ont une intersection vide (ex: \"email\" ∩ \"ipv4\" = ∅).\n *\n * Utilise `isFormatSubset` de `format-validator.ts` pour vérifier la hiérarchie.\n *\n * Récurse dans les sous-schemas (`properties`, `items`, etc.) pour détecter\n * les conflits de format imbriqués.\n *\n * @returns `true` si un conflit de format est détecté, `false` sinon\n */\nfunction hasFormatConflict(\n\ta: JSONSchema7Definition,\n\tb: JSONSchema7Definition,\n): boolean {\n\tif (typeof a === \"boolean\" || typeof b === \"boolean\") return false;\n\n\t// ── Seulement quand LES DEUX ont un format ──\n\t// Si un seul a un format → pas de conflit, le merge gère nativement\n\tif (hasOwn(a, \"format\") && hasOwn(b, \"format\")) {\n\t\tconst aFormat = a.format as string;\n\t\tconst bFormat = b.format as string;\n\n\t\t// Même format → pas de conflit\n\t\tif (aFormat !== bFormat) {\n\t\t\t// Vérifier si l'un est un sous-ensemble de l'autre via la hiérarchie\n\t\t\tconst subsetCheck = isFormatSubset(aFormat, bFormat);\n\t\t\tif (subsetCheck !== true) {\n\t\t\t\tconst reverseCheck = isFormatSubset(bFormat, aFormat);\n\t\t\t\tif (reverseCheck !== true) {\n\t\t\t\t\t// Formats différents sans relation connue → conflit\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Récursion dans les sous-schemas ──\n\t// Vérifier les conflits de format dans les propriétés communes\n\tif (isPlainObj(a.properties) && isPlainObj(b.properties)) {\n\t\tconst aMap = a.properties as Record<string, JSONSchema7Definition>;\n\t\tconst bMap = b.properties as Record<string, JSONSchema7Definition>;\n\t\tfor (const k of Object.keys(aMap)) {\n\t\t\tconst aVal = aMap[k];\n\t\t\tconst bVal = bMap[k];\n\t\t\tif (\n\t\t\t\taVal !== undefined &&\n\t\t\t\tbVal !== undefined &&\n\t\t\t\thasOwn(bMap, k) &&\n\t\t\t\thasFormatConflict(aVal, bVal)\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Vérifier items (single schema)\n\tif (isPlainObj(a.items) && isPlainObj(b.items)) {\n\t\tif (\n\t\t\thasFormatConflict(\n\t\t\t\ta.items as JSONSchema7Definition,\n\t\t\t\tb.items as JSONSchema7Definition,\n\t\t\t)\n\t\t)\n\t\t\treturn true;\n\t}\n\n\t// Vérifier additionalProperties\n\tif (\n\t\tisPlainObj(a.additionalProperties) &&\n\t\tisPlainObj(b.additionalProperties)\n\t) {\n\t\tif (\n\t\t\thasFormatConflict(\n\t\t\t\ta.additionalProperties as JSONSchema7Definition,\n\t\t\t\tb.additionalProperties as JSONSchema7Definition,\n\t\t\t)\n\t\t)\n\t\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n// ─── MergeEngine class ───────────────────────────────────────────────────────\n\nexport class MergeEngine {\n\tprivate readonly compareFn: (\n\t\ta: JSONSchema7Definition,\n\t\tb: JSONSchema7Definition,\n\t) => number;\n\n\tprivate readonly shallowAllOfMergeFn: (\n\t\tschema: JSONSchema7 & { allOf: JSONSchema7Definition[] },\n\t) => JSONSchema7Definition;\n\n\tconstructor() {\n\t\tconst { compareSchemaDefinitions, compareSchemaValues } =\n\t\t\tcreateComparator();\n\n\t\t// ── Null-safe wrapper for compareSchemaValues ──\n\t\t// The library's compareSchemaValues has a bug: when both a and b are null,\n\t\t// it returns -1 instead of 0 (the null check for `a` fires before checking\n\t\t// if `b` is also null). This causes createIntersector to lose null values\n\t\t// during enum intersection (the sort-merge join relies on compare(x,x)===0).\n\t\tconst safeCompareSchemaValues = (\n\t\t\ta: JSONSchema7Type,\n\t\t\tb: JSONSchema7Type,\n\t\t): number => {\n\t\t\tif (a === null && b === null) return 0;\n\t\t\treturn compareSchemaValues(a, b);\n\t\t};\n\n\t\tconst { mergeArrayOfSchemaDefinitions } = createMerger({\n\t\t\tintersectJson: createIntersector(safeCompareSchemaValues),\n\t\t\tdeduplicateJsonSchemaDef: createDeduplicator(compareSchemaDefinitions),\n\t\t});\n\n\t\tthis.compareFn = compareSchemaDefinitions;\n\t\tthis.shallowAllOfMergeFn = createShallowAllOfMerge(\n\t\t\tmergeArrayOfSchemaDefinitions,\n\t\t);\n\t}\n\n\t/**\n\t * Merge deux schemas via `allOf([a, b])`.\n\t * Retourne `null` si les schemas sont incompatibles.\n\t *\n\t * Post-merge : détecte les conflits de `const` que la librairie\n\t * ne capture pas (elle utilise `identity` pour `const`).\n\t */\n\tmerge(\n\t\ta: JSONSchema7Definition,\n\t\tb: JSONSchema7Definition,\n\t): JSONSchema7Definition | null {\n\t\t// Pré-check : conflit de const détectable avant le merge\n\t\tif (hasDeepConstConflict(a, b)) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Pré-check : conflit de format (les DEUX ont un format incompatible)\n\t\tif (hasFormatConflict(a, b)) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Pré-check : conflit additionalProperties vs propriétés REQUISES extra\n\t\t// Ne détecte que les cas où une propriété est à la fois interdite\n\t\t// (additionalProperties: false) et requise (required) → intersection vide.\n\t\t// Les cas où les propriétés sont simplement définies sans être requises\n\t\t// sont gérés correctement par la librairie de merge elle-même.\n\t\tif (hasAdditionalPropertiesConflict(a, b)) {\n\t\t\treturn null;\n\t\t}\n\n\t\ttry {\n\t\t\treturn this.shallowAllOfMergeFn({ allOf: [a, b] });\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Merge via `shallowAllOfMerge` — lève une exception si incompatible.\n\t * Utile quand on veut capturer l'erreur pour le diagnostic.\n\t *\n\t * Post-merge : détecte les conflits de `const` et lève une exception.\n\t */\n\tmergeOrThrow(\n\t\ta: JSONSchema7Definition,\n\t\tb: JSONSchema7Definition,\n\t): JSONSchema7Definition {\n\t\t// Pré-check : conflit de const\n\t\tif (hasDeepConstConflict(a, b)) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Incompatible const values: schemas have conflicting const constraints\",\n\t\t\t);\n\t\t}\n\n\t\t// Pré-check : conflit de format\n\t\tif (hasFormatConflict(a, b)) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Incompatible format values: schemas have conflicting format constraints\",\n\t\t\t);\n\t\t}\n\n\t\t// Pré-check : conflit additionalProperties vs propriétés REQUISES extra\n\t\tif (hasAdditionalPropertiesConflict(a, b)) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Incompatible additionalProperties: required properties conflict with additionalProperties constraint\",\n\t\t\t);\n\t\t}\n\n\t\treturn this.shallowAllOfMergeFn({ allOf: [a, b] });\n\t}\n\n\t/**\n\t * Compare structurellement deux schema definitions.\n\t * Retourne 0 si elles sont identiques, sinon un entier non nul.\n\t */\n\tcompare(a: JSONSchema7Definition, b: JSONSchema7Definition): number {\n\t\treturn this.compareFn(a, b);\n\t}\n\n\t/**\n\t * Vérifie l'égalité structurelle entre deux schema definitions.\n\t */\n\tisEqual(a: JSONSchema7Definition, b: JSONSchema7Definition): boolean {\n\t\treturn this.compareFn(a, b) === 0;\n\t}\n}\n"],"names":["MergeEngine","hasConstConflict","a","b","aHasConst","hasOwn","bHasConst","aConst","const","bConst","aEnum","enum","bEnum","deepEqual","Array","isArray","some","v","SINGLE_SCHEMA_CONFLICT_KEYS","PROPERTIES_MAP_CONFLICT_KEYS","hasDeepConstConflict","key","aVal","bVal","isPlainObj","aMap","bMap","aMapSafe","bMapSafe","propKey","Object","keys","undefined","items","aItems","bItems","len","Math","min","length","i","aItem","bItem","hasAdditionalPropertiesConflict","aProps","properties","bProps","aKeys","bKeys","aRequired","required","bRequired","additionalProperties","hasRequiredExtra","k","addPropsSchema","addPropsType","type","hasTypeConflict","bPropDef","bProp","aPropDef","aProp","hasFormatConflict","aFormat","format","bFormat","subsetCheck","isFormatSubset","reverseCheck","merge","shallowAllOfMergeFn","allOf","mergeOrThrow","Error","compare","compareFn","isEqual","compareSchemaDefinitions","compareSchemaValues","createComparator","safeCompareSchemaValues","mergeArrayOfSchemaDefinitions","createMerger","intersectJson","createIntersector","deduplicateJsonSchemaDef","createDeduplicator","createShallowAllOfMerge"],"mappings":"oGAubaA,qDAAAA,8CAnbN,+CAIA,mEAQwB,2CACe,+LA6B9C,SAASC,iBACRC,CAAwB,CACxBC,CAAwB,EAExB,GAAI,OAAOD,IAAM,WAAa,OAAOC,IAAM,UAAW,OAAO,MAE7D,MAAMC,UAAYC,GAAAA,aAAM,EAACH,EAAG,SAC5B,MAAMI,UAAYD,GAAAA,aAAM,EAACF,EAAG,SAC5B,MAAMI,OAAS,AAACL,EAA8BM,KAAK,CACnD,MAAMC,OAAS,AAACN,EAA8BK,KAAK,CACnD,MAAME,MAAQR,EAAES,IAAI,CACpB,MAAMC,MAAQT,EAAEQ,IAAI,CAGpB,GAAIP,WAAaE,UAAW,CAC3B,MAAO,CAACO,GAAAA,gBAAS,EAACN,OAAQE,OAC3B,CAGA,GAAIL,WAAaU,MAAMC,OAAO,CAACH,OAAQ,CACtC,MAAO,CAACA,MAAMI,IAAI,CAAC,AAACC,GAAMJ,GAAAA,gBAAS,EAACI,EAAGV,QACxC,CACA,GAAID,WAAaQ,MAAMC,OAAO,CAACL,OAAQ,CACtC,MAAO,CAACA,MAAMM,IAAI,CAAC,AAACC,GAAMJ,GAAAA,gBAAS,EAACI,EAAGR,QACxC,CAEA,OAAO,KACR,CAGA,MAAMS,4BAA8B,CACnC,QACA,uBACA,WACA,gBACA,MACA,CAGD,MAAMC,6BAA+B,CACpC,aACA,oBACA,CAcD,SAASC,qBACRlB,CAAwB,CACxBC,CAAwB,EAExB,GAAIF,iBAAiBC,EAAGC,GAAI,OAAO,KAEnC,GAAI,OAAOD,IAAM,WAAa,OAAOC,IAAM,UAAW,OAAO,MAG7D,IAAK,MAAMkB,OAAOH,4BAA6B,CAC9C,MAAMI,KAAO,AAACpB,CAA6B,CAACmB,IAAI,CAGhD,MAAME,KAAO,AAACpB,CAA6B,CAACkB,IAAI,CAGhD,GACCG,GAAAA,iBAAU,EAACF,OACXE,GAAAA,iBAAU,EAACD,OACXH,qBACCE,KACAC,MAEA,CACD,OAAO,IACR,CACD,CAGA,IAAK,MAAMF,OAAOF,6BAA8B,CAC/C,MAAMM,KAAO,AAACvB,CAA6B,CAACmB,IAAI,CAGhD,MAAMK,KAAO,AAACvB,CAA6B,CAACkB,IAAI,CAGhD,GAAI,CAACG,GAAAA,iBAAU,EAACC,OAAS,CAACD,GAAAA,iBAAU,EAACE,MAAO,SAC5C,MAAMC,SAAWF,KACjB,MAAMG,SAAWF,KACjB,IAAK,MAAMG,WAAWC,OAAOC,IAAI,CAACJ,UAAW,CAC5C,MAAML,KAAOK,QAAQ,CAACE,QAAQ,CAC9B,MAAMN,KAAOK,QAAQ,CAACC,QAAQ,CAC9B,GACCP,OAASU,WACTT,OAASS,WACT3B,GAAAA,aAAM,EAACuB,SAAUC,UACjBT,qBAAqBE,KAAMC,MAC1B,CACD,OAAO,IACR,CACD,CACD,CAGA,GAAIT,MAAMC,OAAO,CAACb,EAAE+B,KAAK,GAAKnB,MAAMC,OAAO,CAACZ,EAAE8B,KAAK,EAAG,CACrD,MAAMC,OAAShC,EAAE+B,KAAK,CACtB,MAAME,OAAShC,EAAE8B,KAAK,CACtB,MAAMG,IAAMC,KAAKC,GAAG,CAACJ,OAAOK,MAAM,CAAEJ,OAAOI,MAAM,EACjD,IAAK,IAAIC,EAAI,EAAGA,EAAIJ,IAAKI,IAAK,CAC7B,MAAMC,MAAQP,MAAM,CAACM,EAAE,CACvB,MAAME,MAAQP,MAAM,CAACK,EAAE,CACvB,GAAIC,QAAUT,WAAaU,QAAUV,UAAW,SAChD,GAAIZ,qBAAqBqB,MAAOC,OAAQ,CACvC,OAAO,IACR,CACD,CACD,CAEA,OAAO,KACR,CAuCA,SAASC,gCACRzC,CAAwB,CACxBC,CAAwB,EAExB,GAAI,OAAOD,IAAM,WAAa,OAAOC,IAAM,UAAW,OAAO,MAE7D,MAAMyC,OAASpB,GAAAA,iBAAU,EAACtB,EAAE2C,UAAU,EAClC3C,EAAE2C,UAAU,CACbb,UACH,MAAMc,OAAStB,GAAAA,iBAAU,EAACrB,EAAE0C,UAAU,EAClC1C,EAAE0C,UAAU,CACbb,UAGH,GAAI,CAACY,QAAU,CAACE,OAAQ,OAAO,MAE/B,MAAMC,MAAQH,OAASd,OAAOC,IAAI,CAACa,QAAU,EAAE,CAC/C,MAAMI,MAAQF,OAAShB,OAAOC,IAAI,CAACe,QAAU,EAAE,CAC/C,MAAMG,UAAYnC,MAAMC,OAAO,CAACb,EAAEgD,QAAQ,EAAKhD,EAAEgD,QAAQ,CAAgB,EAAE,CAC3E,MAAMC,UAAYrC,MAAMC,OAAO,CAACZ,EAAE+C,QAAQ,EAAK/C,EAAE+C,QAAQ,CAAgB,EAAE,CAM3E,GAAIhD,EAAEkD,oBAAoB,GAAK,OAASR,QAAUE,OAAQ,CACzD,MAAMO,iBAAmBF,UAAUnC,IAAI,CACtC,AAACsC,GAAM,CAACjD,GAAAA,aAAM,EAACuC,OAAQU,IAAMjD,GAAAA,aAAM,EAACyC,OAAQQ,IAI7C,GAAID,kBAAoBN,MAAMR,MAAM,CAAG,EAAG,OAAO,IAClD,CAKA,GACCf,GAAAA,iBAAU,EAACtB,EAAEkD,oBAAoB,GACjC,OAAOlD,EAAEkD,oBAAoB,GAAK,WAClCR,QACAE,OACC,CACD,MAAMS,eAAiBrD,EAAEkD,oBAAoB,CAC7C,GAAI/C,GAAAA,aAAM,EAACkD,eAAgB,QAAS,CACnC,MAAMC,aAAeD,eAAeE,IAAI,CACxC,MAAMC,gBAAkBP,UAAUnC,IAAI,CAAC,AAACsC,IACvC,GAAIjD,GAAAA,aAAM,EAACuC,OAAQU,GAAI,OAAO,MAC9B,GAAI,CAACjD,GAAAA,aAAM,EAACyC,OAAQQ,GAAI,OAAO,MAC/B,MAAMK,SAAWb,MAAM,CAACQ,EAAE,CAC1B,GAAI,OAAOK,WAAa,UAAW,OAAO,MAC1C,MAAMC,MAAQD,SACd,GAAI,CAACtD,GAAAA,aAAM,EAACuD,MAAO,QAAS,OAAO,MACnC,GACC,OAAOJ,eAAiB,UACxB,OAAOI,MAAMH,IAAI,GAAK,SACrB,CACD,OACCD,eAAiBI,MAAMH,IAAI,EAC3B,CAAED,CAAAA,eAAiB,UAAYI,MAAMH,IAAI,GAAK,SAAQ,GACtD,CAAED,CAAAA,eAAiB,WAAaI,MAAMH,IAAI,GAAK,QAAO,CAExD,CACA,OAAO,KACR,GACA,GAAIC,gBAAiB,OAAO,IAC7B,CACD,CAGA,GAAIvD,EAAEiD,oBAAoB,GAAK,OAASN,QAAUF,OAAQ,CACzD,MAAMS,iBAAmBJ,UAAUjC,IAAI,CACtC,AAACsC,GAAM,CAACjD,GAAAA,aAAM,EAACyC,OAAQQ,IAAMjD,GAAAA,aAAM,EAACuC,OAAQU,IAE7C,GAAID,kBAAoBL,MAAMT,MAAM,CAAG,EAAG,OAAO,IAClD,CAGA,GACCf,GAAAA,iBAAU,EAACrB,EAAEiD,oBAAoB,GACjC,OAAOjD,EAAEiD,oBAAoB,GAAK,WAClCN,QACAF,OACC,CACD,MAAMW,eAAiBpD,EAAEiD,oBAAoB,CAC7C,GAAI/C,GAAAA,aAAM,EAACkD,eAAgB,QAAS,CACnC,MAAMC,aAAeD,eAAeE,IAAI,CACxC,MAAMC,gBAAkBT,UAAUjC,IAAI,CAAC,AAACsC,IACvC,GAAIjD,GAAAA,aAAM,EAACyC,OAAQQ,GAAI,OAAO,MAC9B,GAAI,CAACjD,GAAAA,aAAM,EAACuC,OAAQU,GAAI,OAAO,MAC/B,MAAMO,SAAWjB,MAAM,CAACU,EAAE,CAC1B,GAAI,OAAOO,WAAa,UAAW,OAAO,MAC1C,MAAMC,MAAQD,SACd,GAAI,CAACxD,GAAAA,aAAM,EAACyD,MAAO,QAAS,OAAO,MACnC,GACC,OAAON,eAAiB,UACxB,OAAOM,MAAML,IAAI,GAAK,SACrB,CACD,OACCD,eAAiBM,MAAML,IAAI,EAC3B,CAAED,CAAAA,eAAiB,UAAYM,MAAML,IAAI,GAAK,SAAQ,GACtD,CAAED,CAAAA,eAAiB,WAAaM,MAAML,IAAI,GAAK,QAAO,CAExD,CACA,OAAO,KACR,GACA,GAAIC,gBAAiB,OAAO,IAC7B,CACD,CAKA,GAAId,QAAUE,OAAQ,CACrB,IAAK,MAAMQ,KAAKP,MAAO,CACtB,GAAI,CAAC1C,GAAAA,aAAM,EAACyC,OAAQQ,GAAI,SACxB,MAAMO,SAAWjB,MAAM,CAACU,EAAE,CAC1B,MAAMK,SAAWb,MAAM,CAACQ,EAAE,CAC1B,GAAI,OAAOO,WAAa,WAAa,OAAOF,WAAa,UACxD,SACD,GACChB,gCACCkB,SACAF,UAEA,CACD,OAAO,IACR,CACD,CACD,CAEA,OAAO,KACR,CAsBA,SAASI,kBACR7D,CAAwB,CACxBC,CAAwB,EAExB,GAAI,OAAOD,IAAM,WAAa,OAAOC,IAAM,UAAW,OAAO,MAI7D,GAAIE,GAAAA,aAAM,EAACH,EAAG,WAAaG,GAAAA,aAAM,EAACF,EAAG,UAAW,CAC/C,MAAM6D,QAAU9D,EAAE+D,MAAM,CACxB,MAAMC,QAAU/D,EAAE8D,MAAM,CAGxB,GAAID,UAAYE,QAAS,CAExB,MAAMC,YAAcC,GAAAA,+BAAc,EAACJ,QAASE,SAC5C,GAAIC,cAAgB,KAAM,CACzB,MAAME,aAAeD,GAAAA,+BAAc,EAACF,QAASF,SAC7C,GAAIK,eAAiB,KAAM,CAE1B,OAAO,IACR,CACD,CACD,CACD,CAIA,GAAI7C,GAAAA,iBAAU,EAACtB,EAAE2C,UAAU,GAAKrB,GAAAA,iBAAU,EAACrB,EAAE0C,UAAU,EAAG,CACzD,MAAMpB,KAAOvB,EAAE2C,UAAU,CACzB,MAAMnB,KAAOvB,EAAE0C,UAAU,CACzB,IAAK,MAAMS,KAAKxB,OAAOC,IAAI,CAACN,MAAO,CAClC,MAAMH,KAAOG,IAAI,CAAC6B,EAAE,CACpB,MAAM/B,KAAOG,IAAI,CAAC4B,EAAE,CACpB,GACChC,OAASU,WACTT,OAASS,WACT3B,GAAAA,aAAM,EAACqB,KAAM4B,IACbS,kBAAkBzC,KAAMC,MACvB,CACD,OAAO,IACR,CACD,CACD,CAGA,GAAIC,GAAAA,iBAAU,EAACtB,EAAE+B,KAAK,GAAKT,GAAAA,iBAAU,EAACrB,EAAE8B,KAAK,EAAG,CAC/C,GACC8B,kBACC7D,EAAE+B,KAAK,CACP9B,EAAE8B,KAAK,EAGR,OAAO,IACT,CAGA,GACCT,GAAAA,iBAAU,EAACtB,EAAEkD,oBAAoB,GACjC5B,GAAAA,iBAAU,EAACrB,EAAEiD,oBAAoB,EAChC,CACD,GACCW,kBACC7D,EAAEkD,oBAAoB,CACtBjD,EAAEiD,oBAAoB,EAGvB,OAAO,IACT,CAEA,OAAO,KACR,CAIO,MAAMpD,YA6CZsE,MACCpE,CAAwB,CACxBC,CAAwB,CACO,CAE/B,GAAIiB,qBAAqBlB,EAAGC,GAAI,CAC/B,OAAO,IACR,CAGA,GAAI4D,kBAAkB7D,EAAGC,GAAI,CAC5B,OAAO,IACR,CAOA,GAAIwC,gCAAgCzC,EAAGC,GAAI,CAC1C,OAAO,IACR,CAEA,GAAI,CACH,OAAO,IAAI,CAACoE,mBAAmB,CAAC,CAAEC,MAAO,CAACtE,EAAGC,EAAE,AAAC,EACjD,CAAE,KAAM,CACP,OAAO,IACR,CACD,CAQAsE,aACCvE,CAAwB,CACxBC,CAAwB,CACA,CAExB,GAAIiB,qBAAqBlB,EAAGC,GAAI,CAC/B,MAAM,IAAIuE,MACT,wEAEF,CAGA,GAAIX,kBAAkB7D,EAAGC,GAAI,CAC5B,MAAM,IAAIuE,MACT,0EAEF,CAGA,GAAI/B,gCAAgCzC,EAAGC,GAAI,CAC1C,MAAM,IAAIuE,MACT,uGAEF,CAEA,OAAO,IAAI,CAACH,mBAAmB,CAAC,CAAEC,MAAO,CAACtE,EAAGC,EAAE,AAAC,EACjD,CAMAwE,QAAQzE,CAAwB,CAAEC,CAAwB,CAAU,CACnE,OAAO,IAAI,CAACyE,SAAS,CAAC1E,EAAGC,EAC1B,CAKA0E,QAAQ3E,CAAwB,CAAEC,CAAwB,CAAW,CACpE,OAAO,IAAI,CAACyE,SAAS,CAAC1E,EAAGC,KAAO,CACjC,CAhHA,aAAc,CATd,sBAAiByE,YAAjB,KAAA,GAKA,sBAAiBL,sBAAjB,KAAA,GAKC,KAAM,CAAEO,wBAAwB,CAAEC,mBAAmB,CAAE,CACtDC,GAAAA,iCAAgB,IAOjB,MAAMC,wBAA0B,CAC/B/E,EACAC,KAEA,GAAID,IAAM,MAAQC,IAAM,KAAM,OAAO,EACrC,OAAO4E,oBAAoB7E,EAAGC,EAC/B,EAEA,KAAM,CAAE+E,6BAA6B,CAAE,CAAGC,GAAAA,6BAAY,EAAC,CACtDC,cAAeC,GAAAA,wBAAiB,EAACJ,yBACjCK,yBAA0BC,GAAAA,yBAAkB,EAACT,yBAC9C,EAEA,CAAA,IAAI,CAACF,SAAS,CAAGE,wBACjB,CAAA,IAAI,CAACP,mBAAmB,CAAGiB,GAAAA,wCAAuB,EACjDN,8BAEF,CAuFD"}
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -15,9 +15,25 @@ export interface SubsetResult {
|
|
|
15
15
|
/** Erreurs sémantiques décrivant les incompatibilités entre les deux schemas */
|
|
16
16
|
errors: SchemaError[];
|
|
17
17
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
/**
|
|
19
|
+
* Options pour résoudre les if/then/else avant un check de subset.
|
|
20
|
+
* Si `subData` est fourni, les conditions du sub sont résolues.
|
|
21
|
+
* Si `supData` est aussi fourni, il est utilisé pour résoudre le sup ;
|
|
22
|
+
* sinon `subData` est utilisé pour les deux.
|
|
23
|
+
*/
|
|
24
|
+
export interface CheckConditionsOptions {
|
|
25
|
+
/** Runtime data for the sub schema — used for condition resolution and enum narrowing */
|
|
26
|
+
subData: unknown;
|
|
27
|
+
/** Runtime data for the sup schema (defaults to subData) — used for condition resolution and enum narrowing */
|
|
28
|
+
supData?: unknown;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Résultat étendu de `check()` quand des options de conditions sont fournies.
|
|
32
|
+
* Inclut les résultats de résolution pour sub et sup en plus du SubsetResult.
|
|
33
|
+
*/
|
|
34
|
+
export interface ResolvedSubsetResult extends SubsetResult {
|
|
35
|
+
resolvedSub: ResolvedConditionResult;
|
|
36
|
+
resolvedSup: ResolvedConditionResult;
|
|
21
37
|
}
|
|
22
38
|
export interface ResolvedConditionResult {
|
|
23
39
|
/** Le schema avec les if/then/else résolus (aplatis) */
|
|
@@ -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":["validateFormat","inferType","deepEqual","hasOwn","isPlainObj","omitKeys","unionStrings","SPECIAL_MERGE_KEYS","Set","SUB_SCHEMA_KEYS","MIN_KEYS","MAX_KEYS","matchesType","value","type","undefined","types","Array","isArray","actualType","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","evaluateCondition","ifSchema","data","properties","propsOk","Object","keys","every","key","propDef","const","enum","v","format","formatResult","required","allRequired","allOf","allMatch","entry","anyOf","anyMatch","oneOf","matchCount","matches","not","notResult","DISCRIMINANT_INDICATORS","extractDiscriminants","out","props","hasIndicator","indicator","mergeBranchInto","resolved","branchDef","engine","branchSchema","branchProps","mergedProps","branchProp","existing","merged","merge","dependencies","resolvedDeps","branchDeps","acc","depKey","branchVal","existingVal","has","resolvedVal","Math","max","min","base","branch","resolveConditions","schema","discriminant","hasTopLevelIf","if","hasAllOfConditions","e","resolveNestedProperties","resolveAllOfConditions","applicableBranch","then","else","remainingAllOf","push","subSchema","remaining","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":["validateFormat","inferType","deepEqual","hasOwn","isPlainObj","omitKeys","unionStrings","SPECIAL_MERGE_KEYS","Set","SUB_SCHEMA_KEYS","MIN_KEYS","MAX_KEYS","matchesType","value","type","undefined","types","Array","isArray","actualType","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","evaluateCondition","ifSchema","data","properties","propsOk","Object","keys","every","key","propDef","const","enum","v","format","formatResult","required","allRequired","allOf","allMatch","entry","anyOf","anyMatch","oneOf","matchCount","matches","not","notResult","DISCRIMINANT_INDICATORS","extractDiscriminants","out","props","hasIndicator","indicator","mergeBranchInto","resolved","branchDef","engine","branchSchema","branchProps","mergedProps","branchProp","existing","merged","merge","dependencies","resolvedDeps","branchDeps","acc","depKey","branchVal","existingVal","has","resolvedVal","Math","max","min","base","branch","resolveConditions","schema","discriminant","hasTopLevelIf","if","hasAllOfConditions","e","resolveNestedProperties","resolveAllOfConditions","applicableBranch","then","else","remainingAllOf","push","subSchema","remaining","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
|
+
import{deepEqual,isPlainObj}from"./utils.js";function isValueInEnum(value,enumValues){if(!Array.isArray(enumValues))return false;return enumValues.some(v=>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(!isPlainObj(schema.properties))return schema;if(!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}}export function narrowSchemaWithData(schema,data,targetSchema){if(schema===targetSchema||data===undefined||data===null){return schema}if(isPlainObj(data)&&schema.type==="object"){return narrowObjectProperties(schema,data,targetSchema)}if(!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":["deepEqual","isPlainObj","isValueInEnum","value","enumValues","Array","isArray","some","v","getTargetEnum","schema","enum","const","undefined","narrowPrimitive","data","targetSchema","targetEnum","narrowObjectProperties","properties","props","targetProps","changed","narrowedProps","key","Object","keys","propDef","targetPropDef","propData","narrowed","narrowSchemaWithData","type"],"mappings":"AAKA,OAASA,SAAS,CAAEC,UAAU,KAAQ,YAAa,CAwBnD,SAASC,cACRC,KAAc,CACdC,UAA+B,EAE/B,GAAI,CAACC,MAAMC,OAAO,CAACF,YAAa,OAAO,MACvC,OAAOA,WAAWG,IAAI,CAAC,AAACC,GAAMR,UAAUQ,EAAGL,OAC5C,CAOA,SAASM,cAAcC,MAAmB,EACzC,GAAIL,MAAMC,OAAO,CAACI,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,GAAIL,MAAMC,OAAO,CAACI,OAAOC,IAAI,GAAK,UAAWD,OAAQ,OAAOA,OAG5D,GAAI,CAACR,cAAca,KAAME,YAAa,OAAOP,OAG7C,MAAO,CAAE,GAAGA,MAAM,CAAEC,KAAM,CAACI,KAAwB,AAAC,CACrD,CAWA,SAASG,uBACRR,MAAmB,CACnBK,IAA6B,CAC7BC,YAAyB,EAEzB,GAAI,CAACf,WAAWS,OAAOS,UAAU,EAAG,OAAOT,OAC3C,GAAI,CAACT,WAAWe,aAAaG,UAAU,EAAG,OAAOT,OAEjD,MAAMU,MAAQV,OAAOS,UAAU,CAC/B,MAAME,YAAcL,aAAaG,UAAU,CAK3C,IAAIG,QAAU,MACd,MAAMC,cAAuD,CAAC,EAE9D,IAAK,MAAMC,OAAOC,OAAOC,IAAI,CAACN,OAAQ,CACrC,MAAMO,QAAUP,KAAK,CAACI,IAAI,CAC1B,GAAIG,UAAYd,UAAW,SAG3B,GAAI,OAAOc,UAAY,UAAW,CACjCJ,aAAa,CAACC,IAAI,CAAGG,QACrB,QACD,CAEA,MAAMC,cAAgBP,WAAW,CAACG,IAAI,CACtC,MAAMK,SAAWd,IAAI,CAACS,IAAI,CAG1B,GACCI,gBAAkBf,WAClB,OAAOe,gBAAkB,WACzBC,WAAahB,UACZ,CACDU,aAAa,CAACC,IAAI,CAAGG,QACrB,QACD,CAGA,MAAMG,SAAWC,qBAAqBJ,QAASE,SAAUD,eAEzD,GAAIE,WAAaH,QAAS,CACzBL,QAAU,IACX,CACAC,aAAa,CAACC,IAAI,CAAGM,QACtB,CAEA,GAAI,CAACR,QAAS,OAAOZ,OACrB,MAAO,CAAE,GAAGA,MAAM,CAAES,WAAYI,aAAc,CAC/C,CAiCA,OAAO,SAASQ,qBACfrB,MAAmB,CACnBK,IAAa,CACbC,YAAyB,EAGzB,GAAIN,SAAWM,cAAgBD,OAASF,WAAaE,OAAS,KAAM,CACnE,OAAOL,MACR,CAGA,GAAIT,WAAWc,OAASL,OAAOsB,IAAI,GAAK,SAAU,CACjD,OAAOd,uBAAuBR,OAAQK,KAAMC,aAC7C,CAGA,GAAI,CAACf,WAAWc,MAAO,CACtB,OAAOD,gBAAgBJ,OAAQK,KAAMC,aACtC,CAEA,OAAON,MACR"}
|
package/dist/esm/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/esm/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export{JsonSchemaCompatibilityChecker}from"./json-schema-compatibility-checker.js";export{MergeEngine}from"./merge-engine.js";export{arePatternsEquivalent,isPatternSubset,isTrivialPattern}from"./pattern-subset.js";export{formatSchemaType}from"./semantic-errors.js";
|
|
1
|
+
export{resolveConditions}from"./condition-resolver.js";export{JsonSchemaCompatibilityChecker}from"./json-schema-compatibility-checker.js";export{MergeEngine}from"./merge-engine.js";export{arePatternsEquivalent,isPatternSubset,isTrivialPattern}from"./pattern-subset.js";export{formatSchemaType}from"./semantic-errors.js";
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/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":["resolveConditions","JsonSchemaCompatibilityChecker","MergeEngine","arePatternsEquivalent","isPatternSubset","isTrivialPattern","formatSchemaType"],"mappings":"AAAA,OAASA,iBAAiB,KAAQ,yBAA0B,AAC5D,QAASC,8BAA8B,KAAQ,wCAAyC,AACxF,QAASC,WAAW,KAAQ,mBAAoB,AAChD,QACCC,qBAAqB,CACrBC,eAAe,CACfC,gBAAgB,KACV,qBAAsB,AAC7B,QAASC,gBAAgB,KAAQ,sBAAuB"}
|
|
@@ -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
|
-
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}import{resolveConditions}from"./condition-resolver.js";import{formatResult}from"./formatter.js";import{MergeEngine}from"./merge-engine.js";import{normalize}from"./normalizer.js";import{arePatternsEquivalent,isPatternSubset,isTrivialPattern}from"./pattern-subset.js";import{checkAtomic,checkBranchedSub,checkBranchedSup,getBranchesTyped,isAtomicSubsetOf}from"./subset-checker.js";import{deepEqual}from"./utils.js";export{normalize,resolveConditions,formatResult,MergeEngine,isPatternSubset,arePatternsEquivalent,isTrivialPattern};export class JsonSchemaCompatibilityChecker{isSubset(sub,sup){if(sub===sup)return true;if(deepEqual(sub,sup))return true;const nSub=normalize(sub);const nSup=normalize(sup);if(nSub!==sub&&nSup!==sup&&deepEqual(nSub,nSup))return true;if(nSub!==nSup&&deepEqual(nSub,nSup))return true;const{branches:subBranches}=getBranchesTyped(nSub);if(subBranches.length>1||subBranches[0]!==nSub){return subBranches.every(branch=>isAtomicSubsetOf(branch,nSup,this.engine))}return isAtomicSubsetOf(nSub,nSup,this.engine)}check(sub,sup){if(
|
|
1
|
+
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}import{resolveConditions}from"./condition-resolver.js";import{narrowSchemaWithData}from"./data-narrowing.js";import{formatResult}from"./formatter.js";import{MergeEngine}from"./merge-engine.js";import{normalize}from"./normalizer.js";import{arePatternsEquivalent,isPatternSubset,isTrivialPattern}from"./pattern-subset.js";import{checkAtomic,checkBranchedSub,checkBranchedSup,getBranchesTyped,isAtomicSubsetOf}from"./subset-checker.js";import{deepEqual,isPlainObj}from"./utils.js";export{normalize,resolveConditions,formatResult,MergeEngine,isPatternSubset,arePatternsEquivalent,isTrivialPattern};export class JsonSchemaCompatibilityChecker{isSubset(sub,sup){if(sub===sup)return true;if(deepEqual(sub,sup))return true;const nSub=normalize(sub);const nSup=normalize(sup);if(nSub!==sub&&nSup!==sup&&deepEqual(nSub,nSup))return true;if(nSub!==nSup&&deepEqual(nSub,nSup))return true;const{branches:subBranches}=getBranchesTyped(nSub);if(subBranches.length>1||subBranches[0]!==nSub){return subBranches.every(branch=>isAtomicSubsetOf(branch,nSup,this.engine))}return isAtomicSubsetOf(nSub,nSup,this.engine)}check(sub,sup,options){if(options){const subData=options.subData;const supData=options.supData??options.subData;const subDataForConditions=isPlainObj(subData)?subData:{};const supDataForConditions=isPlainObj(supData)?supData:{};const resolvedSub=resolveConditions(sub,subDataForConditions,this.engine);const resolvedSup=resolveConditions(sup,supDataForConditions,this.engine);const narrowedSubResolved=subData!==undefined?narrowSchemaWithData(resolvedSub.resolved,subData,resolvedSup.resolved):resolvedSub.resolved;const narrowedSupResolved=supData!==undefined?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(normalize(a),normalize(b))}intersect(a,b){if(a===b||deepEqual(a,b))return normalize(a);const nA=normalize(a);const nB=normalize(b);if(deepEqual(nA,nB))return nA;const merged=this.engine.merge(nA,nB);if(merged===null)return null;if(deepEqual(merged,nA)||deepEqual(merged,nB))return merged;return normalize(merged)}normalize(def){return normalize(def)}formatResult(label,result){return formatResult(label,result)}resolveConditions(schema,data){return resolveConditions(schema,data,this.engine)}checkInternal(sub,sup){if(sub===sup){return{isSubset:true,merged:sub,errors:[]}}if(deepEqual(sub,sup)){return{isSubset:true,merged:sub,errors:[]}}const nSub=normalize(sub);const nSup=normalize(sup);if(deepEqual(nSub,nSup)){return{isSubset:true,merged:nSub,errors:[]}}const{branches:subBranches,type:subBranchType}=getBranchesTyped(nSub);const{branches:supBranches,type:supBranchType}=getBranchesTyped(nSup);if(subBranches.length>1||subBranches[0]!==nSub){return checkBranchedSub(subBranches,nSup,this.engine,subBranchType)}if(supBranches.length>1||supBranches[0]!==nSup){return checkBranchedSup(nSub,supBranches,this.engine,supBranchType)}return checkAtomic(nSub,nSup,this.engine)}constructor(){_define_property(this,"engine",void 0);this.engine=new MergeEngine}}
|
|
2
2
|
//# sourceMappingURL=json-schema-compatibility-checker.js.map
|