json-schema-compatibility-checker 1.0.8 → 1.0.9

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 CHANGED
@@ -35,7 +35,8 @@ Cette librairie répond à cette question en vérifiant si un schema est un **so
35
35
 
36
36
  - ✅ Vérifie si un schema est un sous-ensemble d'un autre (`sub ⊆ sup`)
37
37
  - ✅ Produit un diagnostic détaillé avec les différences structurelles
38
- - ✅ Calcule l'intersection de deux schemas
38
+ - ✅ Calcule l'intersection de deux schemas (`allOf` merge)
39
+ - ✅ Accumule des schemas séquentiellement via deep spread (`overlay`)
39
40
  - ✅ Résout les conditions `if/then/else` avec des données discriminantes
40
41
  - ✅ Gère `anyOf`, `oneOf`, `not`, `format`, `pattern`, `dependencies`, etc.
41
42
  - ✅ Compare des patterns regex par échantillonnage
@@ -116,7 +117,9 @@ console.log(checker.isSubset(loose, strict)); // false ❌
116
117
 
117
118
  ## API Reference
118
119
 
119
- Toutes les méthodes sont exposées par la classe `JsonSchemaCompatibilityChecker`.
120
+ ### `JsonSchemaCompatibilityChecker`
121
+
122
+ Toutes les méthodes de vérification de compatibilité sont exposées par la classe `JsonSchemaCompatibilityChecker`.
120
123
 
121
124
  ```ts
122
125
  const checker = new JsonSchemaCompatibilityChecker();
@@ -133,6 +136,24 @@ const checker = new JsonSchemaCompatibilityChecker();
133
136
  | `normalize(schema)` | Normalise un schema (infère types, résout double négation) | `JSONSchema7Definition` |
134
137
  | `formatResult(label, result)` | Formate un résultat pour le debug | `string` |
135
138
 
139
+ ### `MergeEngine`
140
+
141
+ Opérations bas-niveau sur les schemas : intersection (`allOf` merge) et overlay (deep spread séquentiel).
142
+
143
+ ```ts
144
+ import { MergeEngine } from "json-schema-compatibility-checker";
145
+
146
+ const engine = new MergeEngine();
147
+ ```
148
+
149
+ | Méthode | Description | Retour |
150
+ |---|---|---|
151
+ | `merge(a, b)` | Intersection `allOf([a, b])` — retourne `null` si incompatible | `JSONSchema7Definition \| null` |
152
+ | `mergeOrThrow(a, b)` | Comme `merge`, mais lève une exception si incompatible | `JSONSchema7Definition` |
153
+ | `overlay(base, override)` | Deep spread séquentiel — last writer wins par propriété | `JSONSchema7Definition` |
154
+ | `compare(a, b)` | Comparaison structurelle (0 = identique) | `number` |
155
+ | `isEqual(a, b)` | Égalité structurelle | `boolean` |
156
+
136
157
  **Exemple rapide — `check` avec diagnostic :**
137
158
 
138
159
  ```ts
@@ -156,6 +177,36 @@ console.log(result.isSubset); // true ✅
156
177
  console.log(result.resolvedSup.branch); // "then"
157
178
  ```
158
179
 
180
+ **Exemple rapide — `overlay` pour accumulation séquentielle :**
181
+
182
+ ```ts
183
+ import { MergeEngine } from "json-schema-compatibility-checker";
184
+
185
+ const engine = new MergeEngine();
186
+
187
+ // Node1 produit accountId avec enum
188
+ const node1Output = {
189
+ type: "object",
190
+ properties: { accountId: { type: "string", enum: ["a", "b"] } },
191
+ required: ["accountId"],
192
+ };
193
+
194
+ // Node2 redéfinit accountId en string simple (plus large)
195
+ const node2Output = {
196
+ type: "object",
197
+ properties: { accountId: { type: "string" } },
198
+ required: ["accountId"],
199
+ };
200
+
201
+ // ❌ merge (intersection) : garde l'enum — FAUX pour un pipeline séquentiel
202
+ engine.merge(node1Output, node2Output);
203
+ // → { ..., properties: { accountId: { type: "string", enum: ["a", "b"] } } }
204
+
205
+ // ✅ overlay (deep spread) : le dernier écrivain gagne — CORRECT
206
+ engine.overlay(node1Output, node2Output);
207
+ // → { ..., properties: { accountId: { type: "string" } } }
208
+ ```
209
+
159
210
  👉 Pour la documentation complète de chaque méthode avec tous les exemples, consultez la **[Référence API](./docs/api-reference.md)**.
160
211
 
161
212
  ---
@@ -164,13 +215,13 @@ console.log(result.resolvedSup.branch); // "then"
164
215
 
165
216
  | Page | Description |
166
217
  |---|---|
167
- | **[Référence API](./docs/api-reference.md)** | Documentation détaillée de chaque méthode avec exemples |
218
+ | **[Référence API](./docs/api-reference.md)** | Documentation détaillée de chaque méthode (`JsonSchemaCompatibilityChecker` + `MergeEngine`) avec exemples |
168
219
  | **[Guide des fonctionnalités](./docs/features-guide.md)** | Tour complet des fonctionnalités : types, `required`, contraintes numériques, `enum`/`const`, `anyOf`/`oneOf`, `not`, `format`, `pattern`, conditions `if/then/else`, `allOf`... |
169
220
  | **[Fonctions utilitaires](./docs/utilities.md)** | `isPatternSubset`, `arePatternsEquivalent`, `isTrivialPattern` |
170
- | **[Cas d'usage concrets](./docs/use-cases.md)** | Connexion de nœuds dans un orchestrateur, validation de réponse API, unions discriminées, formulaires conditionnels |
221
+ | **[Cas d'usage concrets](./docs/use-cases.md)** | Connexion de nœuds, pipeline séquentiel (overlay), validation de réponse API, unions discriminées, formulaires conditionnels |
171
222
  | **[Types exportés](./docs/types.md)** | `SubsetResult`, `SchemaError`, `ResolvedConditionResult`, `ResolvedSubsetResult`, `CheckConditionsOptions` |
172
223
  | **[Limitations connues](./docs/limitations.md)** | Cross-keyword constraints, `oneOf` exclusivité, patterns probabilistes, `$ref` non supporté |
173
- | **[Architecture interne](./docs/architecture.md)** | Diagramme des modules, flux de vérification, dépendances |
224
+ | **[Architecture interne](./docs/architecture.md)** | Diagramme des modules, flux de vérification, merge vs overlay, dépendances |
174
225
 
175
226
  ---
176
227
 
@@ -27,4 +27,95 @@ export declare class MergeEngine {
27
27
  * Vérifie l'égalité structurelle entre deux schema definitions.
28
28
  */
29
29
  isEqual(a: JSONSchema7Definition, b: JSONSchema7Definition): boolean;
30
+ /**
31
+ * Computes a **deep** schema overlay: properties from `override`
32
+ * **replace** same-named properties in `base` using last-writer-wins
33
+ * spread semantics. When both the base and override define the same
34
+ * property as object-like schemas, the overlay **recurses** into that
35
+ * property so that nested sub-properties are spread rather than
36
+ * wholesale-replaced.
37
+ *
38
+ * This is the correct operation for sequential pipeline context
39
+ * accumulation where each node overwrites keys it produces:
40
+ *
41
+ * ```ts
42
+ * // Runtime semantics (deep spread):
43
+ * context = deepSpread(context, node.output)
44
+ * ```
45
+ *
46
+ * Unlike `merge` / `mergeOrThrow` (which compute `allOf` — the set
47
+ * **intersection**), `overlay` is **non-commutative**: the order of
48
+ * arguments matters. `base` is what existed before, `override` is
49
+ * what the new node produces.
50
+ *
51
+ * Behavior per keyword:
52
+ * - **`properties`**: deep spread — when both base and override define
53
+ * the same property and both are object-like, `overlay` recurses.
54
+ * Otherwise the override's property replaces the base's.
55
+ * Base-only properties are always kept.
56
+ * - **`required`**: union of both arrays (a property that was required
57
+ * before or is required by the override stays required).
58
+ * - **`additionalProperties`**: override wins if present, else base.
59
+ * - **Other object-level keywords** (`minProperties`, `maxProperties`,
60
+ * `propertyNames`, `patternProperties`, `dependencies`): override
61
+ * wins if present, else base is kept.
62
+ * - **Non-object schemas**: if either schema is not an object schema
63
+ * (no `properties`, no `type: "object"`), the override replaces
64
+ * the base entirely — there are no properties to spread.
65
+ *
66
+ * @param base - The existing accumulated schema (what came before)
67
+ * @param override - The new schema to overlay on top (last writer)
68
+ * @returns A new schema with deep spread semantics applied
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * const base = {
73
+ * type: "object",
74
+ * properties: {
75
+ * accountId: { type: "string", enum: ["a", "b"] },
76
+ * config: {
77
+ * type: "object",
78
+ * properties: {
79
+ * host: { type: "string" },
80
+ * port: { type: "integer" },
81
+ * },
82
+ * required: ["host", "port"],
83
+ * },
84
+ * },
85
+ * required: ["accountId", "config"],
86
+ * };
87
+ *
88
+ * const override = {
89
+ * type: "object",
90
+ * properties: {
91
+ * accountId: { type: "string" }, // widens the type
92
+ * config: {
93
+ * type: "object",
94
+ * properties: {
95
+ * host: { type: "string", format: "hostname" },
96
+ * },
97
+ * },
98
+ * },
99
+ * required: ["accountId"],
100
+ * };
101
+ *
102
+ * engine.overlay(base, override);
103
+ * // → {
104
+ * // type: "object",
105
+ * // properties: {
106
+ * // accountId: { type: "string" }, ← override wins (flat)
107
+ * // config: {
108
+ * // type: "object",
109
+ * // properties: {
110
+ * // host: { type: "string", format: "hostname" }, ← override wins (deep)
111
+ * // port: { type: "integer" }, ← kept from base (deep)
112
+ * // },
113
+ * // required: ["host", "port"],
114
+ * // },
115
+ * // },
116
+ * // required: ["accountId", "config"],
117
+ * // }
118
+ * ```
119
+ */
120
+ overlay(base: JSONSchema7Definition, override: JSONSchema7Definition): JSONSchema7Definition;
30
121
  }
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"MergeEngine",{enumerable:true,get:function(){return MergeEngine}});const _jsonschemamerge=require("@x0k/json-schema-merge");const _array=require("@x0k/json-schema-merge/lib/array");const _formatvalidator=require("./format-validator.js");const _utils=require("./utils.js");function _define_property(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}function hasConstConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;const aHasConst=(0,_utils.hasOwn)(a,"const");const bHasConst=(0,_utils.hasOwn)(b,"const");const aConst=a.const;const bConst=b.const;const aEnum=a.enum;const bEnum=b.enum;if(aHasConst&&bHasConst){return!(0,_utils.deepEqual)(aConst,bConst)}if(aHasConst&&Array.isArray(bEnum)){return!bEnum.some(v=>(0,_utils.deepEqual)(v,aConst))}if(bHasConst&&Array.isArray(aEnum)){return!aEnum.some(v=>(0,_utils.deepEqual)(v,bConst))}return false}const SINGLE_SCHEMA_CONFLICT_KEYS=["items","additionalProperties","contains","propertyNames","not"];const PROPERTIES_MAP_CONFLICT_KEYS=["properties","patternProperties"];function hasDeepConstConflict(a,b){if(hasConstConflict(a,b))return true;if(typeof a==="boolean"||typeof b==="boolean")return false;for(const key of SINGLE_SCHEMA_CONFLICT_KEYS){const aVal=a[key];const bVal=b[key];if((0,_utils.isPlainObj)(aVal)&&(0,_utils.isPlainObj)(bVal)&&hasDeepConstConflict(aVal,bVal)){return true}}for(const key of PROPERTIES_MAP_CONFLICT_KEYS){const aMap=a[key];const bMap=b[key];if(!(0,_utils.isPlainObj)(aMap)||!(0,_utils.isPlainObj)(bMap))continue;const aMapSafe=aMap;const bMapSafe=bMap;for(const propKey of Object.keys(aMapSafe)){const aVal=aMapSafe[propKey];const bVal=bMapSafe[propKey];if(aVal!==undefined&&bVal!==undefined&&(0,_utils.hasOwn)(bMapSafe,propKey)&&hasDeepConstConflict(aVal,bVal)){return true}}}if(Array.isArray(a.items)&&Array.isArray(b.items)){const aItems=a.items;const bItems=b.items;const len=Math.min(aItems.length,bItems.length);for(let i=0;i<len;i++){const aItem=aItems[i];const bItem=bItems[i];if(aItem===undefined||bItem===undefined)continue;if(hasDeepConstConflict(aItem,bItem)){return true}}}return false}function hasAdditionalPropertiesConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;const aProps=(0,_utils.isPlainObj)(a.properties)?a.properties:undefined;const bProps=(0,_utils.isPlainObj)(b.properties)?b.properties:undefined;if(!aProps&&!bProps)return false;const aKeys=aProps?Object.keys(aProps):[];const bKeys=bProps?Object.keys(bProps):[];const aRequired=Array.isArray(a.required)?a.required:[];const bRequired=Array.isArray(b.required)?b.required:[];if(a.additionalProperties===false&&aProps&&bProps){const hasRequiredExtra=bRequired.some(k=>!(0,_utils.hasOwn)(aProps,k)&&(0,_utils.hasOwn)(bProps,k));if(hasRequiredExtra&&aKeys.length>0)return true}if((0,_utils.isPlainObj)(a.additionalProperties)&&typeof a.additionalProperties!=="boolean"&&aProps&&bProps){const addPropsSchema=a.additionalProperties;if((0,_utils.hasOwn)(addPropsSchema,"type")){const addPropsType=addPropsSchema.type;const hasTypeConflict=bRequired.some(k=>{if((0,_utils.hasOwn)(aProps,k))return false;if(!(0,_utils.hasOwn)(bProps,k))return false;const bPropDef=bProps[k];if(typeof bPropDef==="boolean")return false;const bProp=bPropDef;if(!(0,_utils.hasOwn)(bProp,"type"))return false;if(typeof addPropsType==="string"&&typeof bProp.type==="string"){return addPropsType!==bProp.type&&!(addPropsType==="number"&&bProp.type==="integer")&&!(addPropsType==="integer"&&bProp.type==="number")}return false});if(hasTypeConflict)return true}}if(b.additionalProperties===false&&bProps&&aProps){const hasRequiredExtra=aRequired.some(k=>!(0,_utils.hasOwn)(bProps,k)&&(0,_utils.hasOwn)(aProps,k));if(hasRequiredExtra&&bKeys.length>0)return true}if((0,_utils.isPlainObj)(b.additionalProperties)&&typeof b.additionalProperties!=="boolean"&&bProps&&aProps){const addPropsSchema=b.additionalProperties;if((0,_utils.hasOwn)(addPropsSchema,"type")){const addPropsType=addPropsSchema.type;const hasTypeConflict=aRequired.some(k=>{if((0,_utils.hasOwn)(bProps,k))return false;if(!(0,_utils.hasOwn)(aProps,k))return false;const aPropDef=aProps[k];if(typeof aPropDef==="boolean")return false;const aProp=aPropDef;if(!(0,_utils.hasOwn)(aProp,"type"))return false;if(typeof addPropsType==="string"&&typeof aProp.type==="string"){return addPropsType!==aProp.type&&!(addPropsType==="number"&&aProp.type==="integer")&&!(addPropsType==="integer"&&aProp.type==="number")}return false});if(hasTypeConflict)return true}}if(aProps&&bProps){for(const k of aKeys){if(!(0,_utils.hasOwn)(bProps,k))continue;const aPropDef=aProps[k];const bPropDef=bProps[k];if(typeof aPropDef==="boolean"||typeof bPropDef==="boolean")continue;if(hasAdditionalPropertiesConflict(aPropDef,bPropDef)){return true}}}return false}function hasFormatConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;if((0,_utils.hasOwn)(a,"format")&&(0,_utils.hasOwn)(b,"format")){const aFormat=a.format;const bFormat=b.format;if(aFormat!==bFormat){const subsetCheck=(0,_formatvalidator.isFormatSubset)(aFormat,bFormat);if(subsetCheck!==true){const reverseCheck=(0,_formatvalidator.isFormatSubset)(bFormat,aFormat);if(reverseCheck!==true){return true}}}}if((0,_utils.isPlainObj)(a.properties)&&(0,_utils.isPlainObj)(b.properties)){const aMap=a.properties;const bMap=b.properties;for(const k of Object.keys(aMap)){const aVal=aMap[k];const bVal=bMap[k];if(aVal!==undefined&&bVal!==undefined&&(0,_utils.hasOwn)(bMap,k)&&hasFormatConflict(aVal,bVal)){return true}}}if((0,_utils.isPlainObj)(a.items)&&(0,_utils.isPlainObj)(b.items)){if(hasFormatConflict(a.items,b.items))return true}if((0,_utils.isPlainObj)(a.additionalProperties)&&(0,_utils.isPlainObj)(b.additionalProperties)){if(hasFormatConflict(a.additionalProperties,b.additionalProperties))return true}return false}class MergeEngine{merge(a,b){if(hasDeepConstConflict(a,b)){return null}if(hasFormatConflict(a,b)){return null}if(hasAdditionalPropertiesConflict(a,b)){return null}try{return this.shallowAllOfMergeFn({allOf:[a,b]})}catch{return null}}mergeOrThrow(a,b){if(hasDeepConstConflict(a,b)){throw new Error("Incompatible const values: schemas have conflicting const constraints")}if(hasFormatConflict(a,b)){throw new Error("Incompatible format values: schemas have conflicting format constraints")}if(hasAdditionalPropertiesConflict(a,b)){throw new Error("Incompatible additionalProperties: required properties conflict with additionalProperties constraint")}return this.shallowAllOfMergeFn({allOf:[a,b]})}compare(a,b){return this.compareFn(a,b)}isEqual(a,b){return this.compareFn(a,b)===0}constructor(){_define_property(this,"compareFn",void 0);_define_property(this,"shallowAllOfMergeFn",void 0);const{compareSchemaDefinitions,compareSchemaValues}=(0,_jsonschemamerge.createComparator)();const safeCompareSchemaValues=(a,b)=>{if(a===null&&b===null)return 0;return compareSchemaValues(a,b)};const{mergeArrayOfSchemaDefinitions}=(0,_jsonschemamerge.createMerger)({intersectJson:(0,_array.createIntersector)(safeCompareSchemaValues),deduplicateJsonSchemaDef:(0,_array.createDeduplicator)(compareSchemaDefinitions)});this.compareFn=compareSchemaDefinitions;this.shallowAllOfMergeFn=(0,_jsonschemamerge.createShallowAllOfMerge)(mergeArrayOfSchemaDefinitions)}}
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"MergeEngine",{enumerable:true,get:function(){return MergeEngine}});const _jsonschemamerge=require("@x0k/json-schema-merge");const _array=require("@x0k/json-schema-merge/lib/array");const _formatvalidator=require("./format-validator.js");const _utils=require("./utils.js");function _define_property(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}function hasConstConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;const aHasConst=(0,_utils.hasOwn)(a,"const");const bHasConst=(0,_utils.hasOwn)(b,"const");const aConst=a.const;const bConst=b.const;const aEnum=a.enum;const bEnum=b.enum;if(aHasConst&&bHasConst){return!(0,_utils.deepEqual)(aConst,bConst)}if(aHasConst&&Array.isArray(bEnum)){return!bEnum.some(v=>(0,_utils.deepEqual)(v,aConst))}if(bHasConst&&Array.isArray(aEnum)){return!aEnum.some(v=>(0,_utils.deepEqual)(v,bConst))}return false}const SINGLE_SCHEMA_CONFLICT_KEYS=["items","additionalProperties","contains","propertyNames","not"];const PROPERTIES_MAP_CONFLICT_KEYS=["properties","patternProperties"];function hasDeepConstConflict(a,b){if(hasConstConflict(a,b))return true;if(typeof a==="boolean"||typeof b==="boolean")return false;for(const key of SINGLE_SCHEMA_CONFLICT_KEYS){const aVal=a[key];const bVal=b[key];if((0,_utils.isPlainObj)(aVal)&&(0,_utils.isPlainObj)(bVal)&&hasDeepConstConflict(aVal,bVal)){return true}}for(const key of PROPERTIES_MAP_CONFLICT_KEYS){const aMap=a[key];const bMap=b[key];if(!(0,_utils.isPlainObj)(aMap)||!(0,_utils.isPlainObj)(bMap))continue;const aMapSafe=aMap;const bMapSafe=bMap;for(const propKey of Object.keys(aMapSafe)){const aVal=aMapSafe[propKey];const bVal=bMapSafe[propKey];if(aVal!==undefined&&bVal!==undefined&&(0,_utils.hasOwn)(bMapSafe,propKey)&&hasDeepConstConflict(aVal,bVal)){return true}}}if(Array.isArray(a.items)&&Array.isArray(b.items)){const aItems=a.items;const bItems=b.items;const len=Math.min(aItems.length,bItems.length);for(let i=0;i<len;i++){const aItem=aItems[i];const bItem=bItems[i];if(aItem===undefined||bItem===undefined)continue;if(hasDeepConstConflict(aItem,bItem)){return true}}}return false}function hasAdditionalPropertiesConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;const aProps=(0,_utils.isPlainObj)(a.properties)?a.properties:undefined;const bProps=(0,_utils.isPlainObj)(b.properties)?b.properties:undefined;if(!aProps&&!bProps)return false;const aKeys=aProps?Object.keys(aProps):[];const bKeys=bProps?Object.keys(bProps):[];const aRequired=Array.isArray(a.required)?a.required:[];const bRequired=Array.isArray(b.required)?b.required:[];if(a.additionalProperties===false&&aProps&&bProps){const hasRequiredExtra=bRequired.some(k=>!(0,_utils.hasOwn)(aProps,k)&&(0,_utils.hasOwn)(bProps,k));if(hasRequiredExtra&&aKeys.length>0)return true}if((0,_utils.isPlainObj)(a.additionalProperties)&&typeof a.additionalProperties!=="boolean"&&aProps&&bProps){const addPropsSchema=a.additionalProperties;if((0,_utils.hasOwn)(addPropsSchema,"type")){const addPropsType=addPropsSchema.type;const hasTypeConflict=bRequired.some(k=>{if((0,_utils.hasOwn)(aProps,k))return false;if(!(0,_utils.hasOwn)(bProps,k))return false;const bPropDef=bProps[k];if(typeof bPropDef==="boolean")return false;const bProp=bPropDef;if(!(0,_utils.hasOwn)(bProp,"type"))return false;if(typeof addPropsType==="string"&&typeof bProp.type==="string"){return addPropsType!==bProp.type&&!(addPropsType==="number"&&bProp.type==="integer")&&!(addPropsType==="integer"&&bProp.type==="number")}return false});if(hasTypeConflict)return true}}if(b.additionalProperties===false&&bProps&&aProps){const hasRequiredExtra=aRequired.some(k=>!(0,_utils.hasOwn)(bProps,k)&&(0,_utils.hasOwn)(aProps,k));if(hasRequiredExtra&&bKeys.length>0)return true}if((0,_utils.isPlainObj)(b.additionalProperties)&&typeof b.additionalProperties!=="boolean"&&bProps&&aProps){const addPropsSchema=b.additionalProperties;if((0,_utils.hasOwn)(addPropsSchema,"type")){const addPropsType=addPropsSchema.type;const hasTypeConflict=aRequired.some(k=>{if((0,_utils.hasOwn)(bProps,k))return false;if(!(0,_utils.hasOwn)(aProps,k))return false;const aPropDef=aProps[k];if(typeof aPropDef==="boolean")return false;const aProp=aPropDef;if(!(0,_utils.hasOwn)(aProp,"type"))return false;if(typeof addPropsType==="string"&&typeof aProp.type==="string"){return addPropsType!==aProp.type&&!(addPropsType==="number"&&aProp.type==="integer")&&!(addPropsType==="integer"&&aProp.type==="number")}return false});if(hasTypeConflict)return true}}if(aProps&&bProps){for(const k of aKeys){if(!(0,_utils.hasOwn)(bProps,k))continue;const aPropDef=aProps[k];const bPropDef=bProps[k];if(typeof aPropDef==="boolean"||typeof bPropDef==="boolean")continue;if(hasAdditionalPropertiesConflict(aPropDef,bPropDef)){return true}}}return false}function hasFormatConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;if((0,_utils.hasOwn)(a,"format")&&(0,_utils.hasOwn)(b,"format")){const aFormat=a.format;const bFormat=b.format;if(aFormat!==bFormat){const subsetCheck=(0,_formatvalidator.isFormatSubset)(aFormat,bFormat);if(subsetCheck!==true){const reverseCheck=(0,_formatvalidator.isFormatSubset)(bFormat,aFormat);if(reverseCheck!==true){return true}}}}if((0,_utils.isPlainObj)(a.properties)&&(0,_utils.isPlainObj)(b.properties)){const aMap=a.properties;const bMap=b.properties;for(const k of Object.keys(aMap)){const aVal=aMap[k];const bVal=bMap[k];if(aVal!==undefined&&bVal!==undefined&&(0,_utils.hasOwn)(bMap,k)&&hasFormatConflict(aVal,bVal)){return true}}}if((0,_utils.isPlainObj)(a.items)&&(0,_utils.isPlainObj)(b.items)){if(hasFormatConflict(a.items,b.items))return true}if((0,_utils.isPlainObj)(a.additionalProperties)&&(0,_utils.isPlainObj)(b.additionalProperties)){if(hasFormatConflict(a.additionalProperties,b.additionalProperties))return true}return false}class MergeEngine{merge(a,b){if(hasDeepConstConflict(a,b)){return null}if(hasFormatConflict(a,b)){return null}if(hasAdditionalPropertiesConflict(a,b)){return null}try{return this.shallowAllOfMergeFn({allOf:[a,b]})}catch{return null}}mergeOrThrow(a,b){if(hasDeepConstConflict(a,b)){throw new Error("Incompatible const values: schemas have conflicting const constraints")}if(hasFormatConflict(a,b)){throw new Error("Incompatible format values: schemas have conflicting format constraints")}if(hasAdditionalPropertiesConflict(a,b)){throw new Error("Incompatible additionalProperties: required properties conflict with additionalProperties constraint")}return this.shallowAllOfMergeFn({allOf:[a,b]})}compare(a,b){return this.compareFn(a,b)}isEqual(a,b){return this.compareFn(a,b)===0}overlay(base,override){if(override===false)return false;if(override===true)return true;if(typeof base==="boolean")return override;const baseObj=base;const overrideObj=override;if(!isObjectLike(baseObj)&&!isObjectLike(overrideObj)){return override}if(!isObjectLike(baseObj)){return override}if(!isObjectLike(overrideObj)){return override}const baseProps=baseObj.properties??{};const overrideProps=overrideObj.properties??{};const mergedProps={};for(const key of Object.keys(baseProps)){const baseProp=baseProps[key];if(baseProp===undefined)continue;mergedProps[key]=baseProp}for(const key of Object.keys(overrideProps)){const overrideProp=overrideProps[key];if(overrideProp===undefined)continue;const baseProp=baseProps[key];if(baseProp!==undefined&&typeof baseProp!=="boolean"&&typeof overrideProp!=="boolean"&&isObjectLike(baseProp)&&isObjectLike(overrideProp)){mergedProps[key]=this.overlay(baseProp,overrideProp)}else{mergedProps[key]=overrideProp}}const baseRequired=Array.isArray(baseObj.required)?baseObj.required:[];const overrideRequired=Array.isArray(overrideObj.required)?overrideObj.required:[];const mergedRequired=(0,_utils.unionStrings)(baseRequired,overrideRequired);const result={...baseObj};result.properties=mergedProps;if(mergedRequired.length>0){result.required=mergedRequired}else{delete result.required}if((0,_utils.hasOwn)(overrideObj,"additionalProperties")){result.additionalProperties=overrideObj.additionalProperties}if((0,_utils.hasOwn)(overrideObj,"minProperties")){result.minProperties=overrideObj.minProperties}if((0,_utils.hasOwn)(overrideObj,"maxProperties")){result.maxProperties=overrideObj.maxProperties}if((0,_utils.hasOwn)(overrideObj,"propertyNames")){result.propertyNames=overrideObj.propertyNames}if((0,_utils.hasOwn)(overrideObj,"patternProperties")){result.patternProperties=overrideObj.patternProperties}if((0,_utils.hasOwn)(overrideObj,"dependencies")){result.dependencies=overrideObj.dependencies}if((0,_utils.hasOwn)(overrideObj,"type")){result.type=overrideObj.type}return result}constructor(){_define_property(this,"compareFn",void 0);_define_property(this,"shallowAllOfMergeFn",void 0);const{compareSchemaDefinitions,compareSchemaValues}=(0,_jsonschemamerge.createComparator)();const safeCompareSchemaValues=(a,b)=>{if(a===null&&b===null)return 0;return compareSchemaValues(a,b)};const{mergeArrayOfSchemaDefinitions}=(0,_jsonschemamerge.createMerger)({intersectJson:(0,_array.createIntersector)(safeCompareSchemaValues),deduplicateJsonSchemaDef:(0,_array.createDeduplicator)(compareSchemaDefinitions)});this.compareFn=compareSchemaDefinitions;this.shallowAllOfMergeFn=(0,_jsonschemamerge.createShallowAllOfMerge)(mergeArrayOfSchemaDefinitions)}}const OBJECT_SHAPE_KEYWORDS=["properties","patternProperties","additionalProperties","required","dependencies","propertyNames","minProperties","maxProperties"];function isObjectLike(schema){if(schema.type==="object")return true;for(const kw of OBJECT_SHAPE_KEYWORDS){if((0,_utils.hasOwn)(schema,kw))return true}return false}
2
2
  //# sourceMappingURL=merge-engine.js.map
@@ -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 * 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":"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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, unionStrings } 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\t// ── Overlay (sequential spread) ────────────────────────────────────────\n\n\t/**\n\t * Computes a **deep** schema overlay: properties from `override`\n\t * **replace** same-named properties in `base` using last-writer-wins\n\t * spread semantics. When both the base and override define the same\n\t * property as object-like schemas, the overlay **recurses** into that\n\t * property so that nested sub-properties are spread rather than\n\t * wholesale-replaced.\n\t *\n\t * This is the correct operation for sequential pipeline context\n\t * accumulation where each node overwrites keys it produces:\n\t *\n\t * ```ts\n\t * // Runtime semantics (deep spread):\n\t * context = deepSpread(context, node.output)\n\t * ```\n\t *\n\t * Unlike `merge` / `mergeOrThrow` (which compute `allOf` — the set\n\t * **intersection**), `overlay` is **non-commutative**: the order of\n\t * arguments matters. `base` is what existed before, `override` is\n\t * what the new node produces.\n\t *\n\t * Behavior per keyword:\n\t * - **`properties`**: deep spread — when both base and override define\n\t * the same property and both are object-like, `overlay` recurses.\n\t * Otherwise the override's property replaces the base's.\n\t * Base-only properties are always kept.\n\t * - **`required`**: union of both arrays (a property that was required\n\t * before or is required by the override stays required).\n\t * - **`additionalProperties`**: override wins if present, else base.\n\t * - **Other object-level keywords** (`minProperties`, `maxProperties`,\n\t * `propertyNames`, `patternProperties`, `dependencies`): override\n\t * wins if present, else base is kept.\n\t * - **Non-object schemas**: if either schema is not an object schema\n\t * (no `properties`, no `type: \"object\"`), the override replaces\n\t * the base entirely — there are no properties to spread.\n\t *\n\t * @param base - The existing accumulated schema (what came before)\n\t * @param override - The new schema to overlay on top (last writer)\n\t * @returns A new schema with deep spread semantics applied\n\t *\n\t * @example\n\t * ```ts\n\t * const base = {\n\t * type: \"object\",\n\t * properties: {\n\t * accountId: { type: \"string\", enum: [\"a\", \"b\"] },\n\t * config: {\n\t * type: \"object\",\n\t * properties: {\n\t * host: { type: \"string\" },\n\t * port: { type: \"integer\" },\n\t * },\n\t * required: [\"host\", \"port\"],\n\t * },\n\t * },\n\t * required: [\"accountId\", \"config\"],\n\t * };\n\t *\n\t * const override = {\n\t * type: \"object\",\n\t * properties: {\n\t * accountId: { type: \"string\" }, // widens the type\n\t * config: {\n\t * type: \"object\",\n\t * properties: {\n\t * host: { type: \"string\", format: \"hostname\" },\n\t * },\n\t * },\n\t * },\n\t * required: [\"accountId\"],\n\t * };\n\t *\n\t * engine.overlay(base, override);\n\t * // → {\n\t * // type: \"object\",\n\t * // properties: {\n\t * // accountId: { type: \"string\" }, ← override wins (flat)\n\t * // config: {\n\t * // type: \"object\",\n\t * // properties: {\n\t * // host: { type: \"string\", format: \"hostname\" }, ← override wins (deep)\n\t * // port: { type: \"integer\" }, ← kept from base (deep)\n\t * // },\n\t * // required: [\"host\", \"port\"],\n\t * // },\n\t * // },\n\t * // required: [\"accountId\", \"config\"],\n\t * // }\n\t * ```\n\t */\n\toverlay(\n\t\tbase: JSONSchema7Definition,\n\t\toverride: JSONSchema7Definition,\n\t): JSONSchema7Definition {\n\t\t// ── Boolean schema fast paths ──\n\t\t// `false` absorbs everything (no values allowed)\n\t\tif (override === false) return false;\n\t\t// `true` (accept everything) as override means base is completely replaced\n\t\tif (override === true) return true;\n\t\t// `true`/`false` base with a real override → override wins entirely\n\t\tif (typeof base === \"boolean\") return override;\n\n\t\tconst baseObj = base as JSONSchema7;\n\t\tconst overrideObj = override as JSONSchema7;\n\n\t\t// ── Non-object schemas: override replaces entirely ──\n\t\t// If neither schema looks like an object schema, there's no\n\t\t// property-level spreading to do — the override simply wins.\n\t\tif (!isObjectLike(baseObj) && !isObjectLike(overrideObj)) {\n\t\t\treturn override;\n\t\t}\n\n\t\t// ── If only the override is object-like, it replaces entirely ──\n\t\tif (!isObjectLike(baseObj)) {\n\t\t\treturn override;\n\t\t}\n\n\t\t// ── If only the base is object-like, override replaces entirely ──\n\t\t// (the override is a non-object schema — it redefines the shape)\n\t\tif (!isObjectLike(overrideObj)) {\n\t\t\treturn override;\n\t\t}\n\n\t\t// ── Both are object-like: deep spread properties ──\n\t\tconst baseProps = (baseObj.properties ?? {}) as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tconst overrideProps = (overrideObj.properties ?? {}) as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\n\t\t// Deep spread: for each property, recurse if both sides are object-like,\n\t\t// otherwise override wins. Base-only properties are kept as-is.\n\t\tconst mergedProps: Record<string, JSONSchema7Definition> = {};\n\n\t\t// 1. Copy all base properties (may be overridden below)\n\t\tfor (const key of Object.keys(baseProps)) {\n\t\t\tconst baseProp = baseProps[key];\n\t\t\tif (baseProp === undefined) continue;\n\t\t\tmergedProps[key] = baseProp;\n\t\t}\n\n\t\t// 2. Apply override properties — recurse when both are object-like\n\t\tfor (const key of Object.keys(overrideProps)) {\n\t\t\tconst overrideProp = overrideProps[key];\n\t\t\tif (overrideProp === undefined) continue;\n\n\t\t\tconst baseProp = baseProps[key];\n\n\t\t\t// If this property exists in both and both are object-like schemas,\n\t\t\t// recurse to deep-spread their sub-properties.\n\t\t\tif (\n\t\t\t\tbaseProp !== undefined &&\n\t\t\t\ttypeof baseProp !== \"boolean\" &&\n\t\t\t\ttypeof overrideProp !== \"boolean\" &&\n\t\t\t\tisObjectLike(baseProp as JSONSchema7) &&\n\t\t\t\tisObjectLike(overrideProp as JSONSchema7)\n\t\t\t) {\n\t\t\t\tmergedProps[key] = this.overlay(baseProp, overrideProp);\n\t\t\t} else {\n\t\t\t\t// Otherwise: override wins entirely (primitive, array, type change, etc.)\n\t\t\t\tmergedProps[key] = overrideProp;\n\t\t\t}\n\t\t}\n\n\t\t// Union of required arrays\n\t\tconst baseRequired = Array.isArray(baseObj.required)\n\t\t\t? baseObj.required\n\t\t\t: [];\n\t\tconst overrideRequired = Array.isArray(overrideObj.required)\n\t\t\t? overrideObj.required\n\t\t\t: [];\n\t\tconst mergedRequired = unionStrings(baseRequired, overrideRequired);\n\n\t\t// Start from base, apply override's object-level keywords on top\n\t\tconst result: JSONSchema7 = { ...baseObj };\n\n\t\t// Always set the merged properties\n\t\tresult.properties = mergedProps;\n\n\t\t// Set required only if non-empty\n\t\tif (mergedRequired.length > 0) {\n\t\t\tresult.required = mergedRequired;\n\t\t} else {\n\t\t\tdelete result.required;\n\t\t}\n\n\t\t// Override-wins for object-level constraint keywords\n\t\tif (hasOwn(overrideObj, \"additionalProperties\")) {\n\t\t\tresult.additionalProperties = overrideObj.additionalProperties;\n\t\t}\n\t\tif (hasOwn(overrideObj, \"minProperties\")) {\n\t\t\tresult.minProperties = overrideObj.minProperties;\n\t\t}\n\t\tif (hasOwn(overrideObj, \"maxProperties\")) {\n\t\t\tresult.maxProperties = overrideObj.maxProperties;\n\t\t}\n\t\tif (hasOwn(overrideObj, \"propertyNames\")) {\n\t\t\tresult.propertyNames = overrideObj.propertyNames;\n\t\t}\n\t\tif (hasOwn(overrideObj, \"patternProperties\")) {\n\t\t\tresult.patternProperties = overrideObj.patternProperties;\n\t\t}\n\t\tif (hasOwn(overrideObj, \"dependencies\")) {\n\t\t\tresult.dependencies = overrideObj.dependencies;\n\t\t}\n\n\t\t// Override type if explicitly provided\n\t\tif (hasOwn(overrideObj, \"type\")) {\n\t\t\tresult.type = overrideObj.type;\n\t\t}\n\n\t\treturn result;\n\t}\n}\n\n// ─── Overlay helpers ─────────────────────────────────────────────────────────\n\n/** Object-level keywords that indicate a schema describes an object shape. */\nconst OBJECT_SHAPE_KEYWORDS: ReadonlyArray<string> = [\n\t\"properties\",\n\t\"patternProperties\",\n\t\"additionalProperties\",\n\t\"required\",\n\t\"dependencies\",\n\t\"propertyNames\",\n\t\"minProperties\",\n\t\"maxProperties\",\n];\n\n/**\n * Heuristic: does this schema look like it describes an object?\n * True if `type` is `\"object\"` or if any object-shape keyword is present.\n */\nfunction isObjectLike(schema: JSONSchema7): boolean {\n\tif (schema.type === \"object\") return true;\n\tfor (const kw of OBJECT_SHAPE_KEYWORDS) {\n\t\tif (hasOwn(schema, kw)) return true;\n\t}\n\treturn false;\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","overlay","base","override","baseObj","overrideObj","isObjectLike","baseProps","overrideProps","mergedProps","baseProp","overrideProp","baseRequired","overrideRequired","mergedRequired","unionStrings","result","minProperties","maxProperties","propertyNames","patternProperties","dependencies","compareSchemaDefinitions","compareSchemaValues","createComparator","safeCompareSchemaValues","mergeArrayOfSchemaDefinitions","createMerger","intersectJson","createIntersector","deduplicateJsonSchemaDef","createDeduplicator","createShallowAllOfMerge","OBJECT_SHAPE_KEYWORDS","schema","kw"],"mappings":"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"}
@@ -27,4 +27,95 @@ export declare class MergeEngine {
27
27
  * Vérifie l'égalité structurelle entre deux schema definitions.
28
28
  */
29
29
  isEqual(a: JSONSchema7Definition, b: JSONSchema7Definition): boolean;
30
+ /**
31
+ * Computes a **deep** schema overlay: properties from `override`
32
+ * **replace** same-named properties in `base` using last-writer-wins
33
+ * spread semantics. When both the base and override define the same
34
+ * property as object-like schemas, the overlay **recurses** into that
35
+ * property so that nested sub-properties are spread rather than
36
+ * wholesale-replaced.
37
+ *
38
+ * This is the correct operation for sequential pipeline context
39
+ * accumulation where each node overwrites keys it produces:
40
+ *
41
+ * ```ts
42
+ * // Runtime semantics (deep spread):
43
+ * context = deepSpread(context, node.output)
44
+ * ```
45
+ *
46
+ * Unlike `merge` / `mergeOrThrow` (which compute `allOf` — the set
47
+ * **intersection**), `overlay` is **non-commutative**: the order of
48
+ * arguments matters. `base` is what existed before, `override` is
49
+ * what the new node produces.
50
+ *
51
+ * Behavior per keyword:
52
+ * - **`properties`**: deep spread — when both base and override define
53
+ * the same property and both are object-like, `overlay` recurses.
54
+ * Otherwise the override's property replaces the base's.
55
+ * Base-only properties are always kept.
56
+ * - **`required`**: union of both arrays (a property that was required
57
+ * before or is required by the override stays required).
58
+ * - **`additionalProperties`**: override wins if present, else base.
59
+ * - **Other object-level keywords** (`minProperties`, `maxProperties`,
60
+ * `propertyNames`, `patternProperties`, `dependencies`): override
61
+ * wins if present, else base is kept.
62
+ * - **Non-object schemas**: if either schema is not an object schema
63
+ * (no `properties`, no `type: "object"`), the override replaces
64
+ * the base entirely — there are no properties to spread.
65
+ *
66
+ * @param base - The existing accumulated schema (what came before)
67
+ * @param override - The new schema to overlay on top (last writer)
68
+ * @returns A new schema with deep spread semantics applied
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * const base = {
73
+ * type: "object",
74
+ * properties: {
75
+ * accountId: { type: "string", enum: ["a", "b"] },
76
+ * config: {
77
+ * type: "object",
78
+ * properties: {
79
+ * host: { type: "string" },
80
+ * port: { type: "integer" },
81
+ * },
82
+ * required: ["host", "port"],
83
+ * },
84
+ * },
85
+ * required: ["accountId", "config"],
86
+ * };
87
+ *
88
+ * const override = {
89
+ * type: "object",
90
+ * properties: {
91
+ * accountId: { type: "string" }, // widens the type
92
+ * config: {
93
+ * type: "object",
94
+ * properties: {
95
+ * host: { type: "string", format: "hostname" },
96
+ * },
97
+ * },
98
+ * },
99
+ * required: ["accountId"],
100
+ * };
101
+ *
102
+ * engine.overlay(base, override);
103
+ * // → {
104
+ * // type: "object",
105
+ * // properties: {
106
+ * // accountId: { type: "string" }, ← override wins (flat)
107
+ * // config: {
108
+ * // type: "object",
109
+ * // properties: {
110
+ * // host: { type: "string", format: "hostname" }, ← override wins (deep)
111
+ * // port: { type: "integer" }, ← kept from base (deep)
112
+ * // },
113
+ * // required: ["host", "port"],
114
+ * // },
115
+ * // },
116
+ * // required: ["accountId", "config"],
117
+ * // }
118
+ * ```
119
+ */
120
+ overlay(base: JSONSchema7Definition, override: JSONSchema7Definition): JSONSchema7Definition;
30
121
  }
@@ -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{createComparator,createMerger,createShallowAllOfMerge}from"@x0k/json-schema-merge";import{createDeduplicator,createIntersector}from"@x0k/json-schema-merge/lib/array";import{isFormatSubset}from"./format-validator.js";import{deepEqual,hasOwn,isPlainObj}from"./utils.js";function hasConstConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;const aHasConst=hasOwn(a,"const");const bHasConst=hasOwn(b,"const");const aConst=a.const;const bConst=b.const;const aEnum=a.enum;const bEnum=b.enum;if(aHasConst&&bHasConst){return!deepEqual(aConst,bConst)}if(aHasConst&&Array.isArray(bEnum)){return!bEnum.some(v=>deepEqual(v,aConst))}if(bHasConst&&Array.isArray(aEnum)){return!aEnum.some(v=>deepEqual(v,bConst))}return false}const SINGLE_SCHEMA_CONFLICT_KEYS=["items","additionalProperties","contains","propertyNames","not"];const PROPERTIES_MAP_CONFLICT_KEYS=["properties","patternProperties"];function hasDeepConstConflict(a,b){if(hasConstConflict(a,b))return true;if(typeof a==="boolean"||typeof b==="boolean")return false;for(const key of SINGLE_SCHEMA_CONFLICT_KEYS){const aVal=a[key];const bVal=b[key];if(isPlainObj(aVal)&&isPlainObj(bVal)&&hasDeepConstConflict(aVal,bVal)){return true}}for(const key of PROPERTIES_MAP_CONFLICT_KEYS){const aMap=a[key];const bMap=b[key];if(!isPlainObj(aMap)||!isPlainObj(bMap))continue;const aMapSafe=aMap;const bMapSafe=bMap;for(const propKey of Object.keys(aMapSafe)){const aVal=aMapSafe[propKey];const bVal=bMapSafe[propKey];if(aVal!==undefined&&bVal!==undefined&&hasOwn(bMapSafe,propKey)&&hasDeepConstConflict(aVal,bVal)){return true}}}if(Array.isArray(a.items)&&Array.isArray(b.items)){const aItems=a.items;const bItems=b.items;const len=Math.min(aItems.length,bItems.length);for(let i=0;i<len;i++){const aItem=aItems[i];const bItem=bItems[i];if(aItem===undefined||bItem===undefined)continue;if(hasDeepConstConflict(aItem,bItem)){return true}}}return false}function hasAdditionalPropertiesConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;const aProps=isPlainObj(a.properties)?a.properties:undefined;const bProps=isPlainObj(b.properties)?b.properties:undefined;if(!aProps&&!bProps)return false;const aKeys=aProps?Object.keys(aProps):[];const bKeys=bProps?Object.keys(bProps):[];const aRequired=Array.isArray(a.required)?a.required:[];const bRequired=Array.isArray(b.required)?b.required:[];if(a.additionalProperties===false&&aProps&&bProps){const hasRequiredExtra=bRequired.some(k=>!hasOwn(aProps,k)&&hasOwn(bProps,k));if(hasRequiredExtra&&aKeys.length>0)return true}if(isPlainObj(a.additionalProperties)&&typeof a.additionalProperties!=="boolean"&&aProps&&bProps){const addPropsSchema=a.additionalProperties;if(hasOwn(addPropsSchema,"type")){const addPropsType=addPropsSchema.type;const hasTypeConflict=bRequired.some(k=>{if(hasOwn(aProps,k))return false;if(!hasOwn(bProps,k))return false;const bPropDef=bProps[k];if(typeof bPropDef==="boolean")return false;const bProp=bPropDef;if(!hasOwn(bProp,"type"))return false;if(typeof addPropsType==="string"&&typeof bProp.type==="string"){return addPropsType!==bProp.type&&!(addPropsType==="number"&&bProp.type==="integer")&&!(addPropsType==="integer"&&bProp.type==="number")}return false});if(hasTypeConflict)return true}}if(b.additionalProperties===false&&bProps&&aProps){const hasRequiredExtra=aRequired.some(k=>!hasOwn(bProps,k)&&hasOwn(aProps,k));if(hasRequiredExtra&&bKeys.length>0)return true}if(isPlainObj(b.additionalProperties)&&typeof b.additionalProperties!=="boolean"&&bProps&&aProps){const addPropsSchema=b.additionalProperties;if(hasOwn(addPropsSchema,"type")){const addPropsType=addPropsSchema.type;const hasTypeConflict=aRequired.some(k=>{if(hasOwn(bProps,k))return false;if(!hasOwn(aProps,k))return false;const aPropDef=aProps[k];if(typeof aPropDef==="boolean")return false;const aProp=aPropDef;if(!hasOwn(aProp,"type"))return false;if(typeof addPropsType==="string"&&typeof aProp.type==="string"){return addPropsType!==aProp.type&&!(addPropsType==="number"&&aProp.type==="integer")&&!(addPropsType==="integer"&&aProp.type==="number")}return false});if(hasTypeConflict)return true}}if(aProps&&bProps){for(const k of aKeys){if(!hasOwn(bProps,k))continue;const aPropDef=aProps[k];const bPropDef=bProps[k];if(typeof aPropDef==="boolean"||typeof bPropDef==="boolean")continue;if(hasAdditionalPropertiesConflict(aPropDef,bPropDef)){return true}}}return false}function hasFormatConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;if(hasOwn(a,"format")&&hasOwn(b,"format")){const aFormat=a.format;const bFormat=b.format;if(aFormat!==bFormat){const subsetCheck=isFormatSubset(aFormat,bFormat);if(subsetCheck!==true){const reverseCheck=isFormatSubset(bFormat,aFormat);if(reverseCheck!==true){return true}}}}if(isPlainObj(a.properties)&&isPlainObj(b.properties)){const aMap=a.properties;const bMap=b.properties;for(const k of Object.keys(aMap)){const aVal=aMap[k];const bVal=bMap[k];if(aVal!==undefined&&bVal!==undefined&&hasOwn(bMap,k)&&hasFormatConflict(aVal,bVal)){return true}}}if(isPlainObj(a.items)&&isPlainObj(b.items)){if(hasFormatConflict(a.items,b.items))return true}if(isPlainObj(a.additionalProperties)&&isPlainObj(b.additionalProperties)){if(hasFormatConflict(a.additionalProperties,b.additionalProperties))return true}return false}export class MergeEngine{merge(a,b){if(hasDeepConstConflict(a,b)){return null}if(hasFormatConflict(a,b)){return null}if(hasAdditionalPropertiesConflict(a,b)){return null}try{return this.shallowAllOfMergeFn({allOf:[a,b]})}catch{return null}}mergeOrThrow(a,b){if(hasDeepConstConflict(a,b)){throw new Error("Incompatible const values: schemas have conflicting const constraints")}if(hasFormatConflict(a,b)){throw new Error("Incompatible format values: schemas have conflicting format constraints")}if(hasAdditionalPropertiesConflict(a,b)){throw new Error("Incompatible additionalProperties: required properties conflict with additionalProperties constraint")}return this.shallowAllOfMergeFn({allOf:[a,b]})}compare(a,b){return this.compareFn(a,b)}isEqual(a,b){return this.compareFn(a,b)===0}constructor(){_define_property(this,"compareFn",void 0);_define_property(this,"shallowAllOfMergeFn",void 0);const{compareSchemaDefinitions,compareSchemaValues}=createComparator();const safeCompareSchemaValues=(a,b)=>{if(a===null&&b===null)return 0;return compareSchemaValues(a,b)};const{mergeArrayOfSchemaDefinitions}=createMerger({intersectJson:createIntersector(safeCompareSchemaValues),deduplicateJsonSchemaDef:createDeduplicator(compareSchemaDefinitions)});this.compareFn=compareSchemaDefinitions;this.shallowAllOfMergeFn=createShallowAllOfMerge(mergeArrayOfSchemaDefinitions)}}
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{createComparator,createMerger,createShallowAllOfMerge}from"@x0k/json-schema-merge";import{createDeduplicator,createIntersector}from"@x0k/json-schema-merge/lib/array";import{isFormatSubset}from"./format-validator.js";import{deepEqual,hasOwn,isPlainObj,unionStrings}from"./utils.js";function hasConstConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;const aHasConst=hasOwn(a,"const");const bHasConst=hasOwn(b,"const");const aConst=a.const;const bConst=b.const;const aEnum=a.enum;const bEnum=b.enum;if(aHasConst&&bHasConst){return!deepEqual(aConst,bConst)}if(aHasConst&&Array.isArray(bEnum)){return!bEnum.some(v=>deepEqual(v,aConst))}if(bHasConst&&Array.isArray(aEnum)){return!aEnum.some(v=>deepEqual(v,bConst))}return false}const SINGLE_SCHEMA_CONFLICT_KEYS=["items","additionalProperties","contains","propertyNames","not"];const PROPERTIES_MAP_CONFLICT_KEYS=["properties","patternProperties"];function hasDeepConstConflict(a,b){if(hasConstConflict(a,b))return true;if(typeof a==="boolean"||typeof b==="boolean")return false;for(const key of SINGLE_SCHEMA_CONFLICT_KEYS){const aVal=a[key];const bVal=b[key];if(isPlainObj(aVal)&&isPlainObj(bVal)&&hasDeepConstConflict(aVal,bVal)){return true}}for(const key of PROPERTIES_MAP_CONFLICT_KEYS){const aMap=a[key];const bMap=b[key];if(!isPlainObj(aMap)||!isPlainObj(bMap))continue;const aMapSafe=aMap;const bMapSafe=bMap;for(const propKey of Object.keys(aMapSafe)){const aVal=aMapSafe[propKey];const bVal=bMapSafe[propKey];if(aVal!==undefined&&bVal!==undefined&&hasOwn(bMapSafe,propKey)&&hasDeepConstConflict(aVal,bVal)){return true}}}if(Array.isArray(a.items)&&Array.isArray(b.items)){const aItems=a.items;const bItems=b.items;const len=Math.min(aItems.length,bItems.length);for(let i=0;i<len;i++){const aItem=aItems[i];const bItem=bItems[i];if(aItem===undefined||bItem===undefined)continue;if(hasDeepConstConflict(aItem,bItem)){return true}}}return false}function hasAdditionalPropertiesConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;const aProps=isPlainObj(a.properties)?a.properties:undefined;const bProps=isPlainObj(b.properties)?b.properties:undefined;if(!aProps&&!bProps)return false;const aKeys=aProps?Object.keys(aProps):[];const bKeys=bProps?Object.keys(bProps):[];const aRequired=Array.isArray(a.required)?a.required:[];const bRequired=Array.isArray(b.required)?b.required:[];if(a.additionalProperties===false&&aProps&&bProps){const hasRequiredExtra=bRequired.some(k=>!hasOwn(aProps,k)&&hasOwn(bProps,k));if(hasRequiredExtra&&aKeys.length>0)return true}if(isPlainObj(a.additionalProperties)&&typeof a.additionalProperties!=="boolean"&&aProps&&bProps){const addPropsSchema=a.additionalProperties;if(hasOwn(addPropsSchema,"type")){const addPropsType=addPropsSchema.type;const hasTypeConflict=bRequired.some(k=>{if(hasOwn(aProps,k))return false;if(!hasOwn(bProps,k))return false;const bPropDef=bProps[k];if(typeof bPropDef==="boolean")return false;const bProp=bPropDef;if(!hasOwn(bProp,"type"))return false;if(typeof addPropsType==="string"&&typeof bProp.type==="string"){return addPropsType!==bProp.type&&!(addPropsType==="number"&&bProp.type==="integer")&&!(addPropsType==="integer"&&bProp.type==="number")}return false});if(hasTypeConflict)return true}}if(b.additionalProperties===false&&bProps&&aProps){const hasRequiredExtra=aRequired.some(k=>!hasOwn(bProps,k)&&hasOwn(aProps,k));if(hasRequiredExtra&&bKeys.length>0)return true}if(isPlainObj(b.additionalProperties)&&typeof b.additionalProperties!=="boolean"&&bProps&&aProps){const addPropsSchema=b.additionalProperties;if(hasOwn(addPropsSchema,"type")){const addPropsType=addPropsSchema.type;const hasTypeConflict=aRequired.some(k=>{if(hasOwn(bProps,k))return false;if(!hasOwn(aProps,k))return false;const aPropDef=aProps[k];if(typeof aPropDef==="boolean")return false;const aProp=aPropDef;if(!hasOwn(aProp,"type"))return false;if(typeof addPropsType==="string"&&typeof aProp.type==="string"){return addPropsType!==aProp.type&&!(addPropsType==="number"&&aProp.type==="integer")&&!(addPropsType==="integer"&&aProp.type==="number")}return false});if(hasTypeConflict)return true}}if(aProps&&bProps){for(const k of aKeys){if(!hasOwn(bProps,k))continue;const aPropDef=aProps[k];const bPropDef=bProps[k];if(typeof aPropDef==="boolean"||typeof bPropDef==="boolean")continue;if(hasAdditionalPropertiesConflict(aPropDef,bPropDef)){return true}}}return false}function hasFormatConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;if(hasOwn(a,"format")&&hasOwn(b,"format")){const aFormat=a.format;const bFormat=b.format;if(aFormat!==bFormat){const subsetCheck=isFormatSubset(aFormat,bFormat);if(subsetCheck!==true){const reverseCheck=isFormatSubset(bFormat,aFormat);if(reverseCheck!==true){return true}}}}if(isPlainObj(a.properties)&&isPlainObj(b.properties)){const aMap=a.properties;const bMap=b.properties;for(const k of Object.keys(aMap)){const aVal=aMap[k];const bVal=bMap[k];if(aVal!==undefined&&bVal!==undefined&&hasOwn(bMap,k)&&hasFormatConflict(aVal,bVal)){return true}}}if(isPlainObj(a.items)&&isPlainObj(b.items)){if(hasFormatConflict(a.items,b.items))return true}if(isPlainObj(a.additionalProperties)&&isPlainObj(b.additionalProperties)){if(hasFormatConflict(a.additionalProperties,b.additionalProperties))return true}return false}export class MergeEngine{merge(a,b){if(hasDeepConstConflict(a,b)){return null}if(hasFormatConflict(a,b)){return null}if(hasAdditionalPropertiesConflict(a,b)){return null}try{return this.shallowAllOfMergeFn({allOf:[a,b]})}catch{return null}}mergeOrThrow(a,b){if(hasDeepConstConflict(a,b)){throw new Error("Incompatible const values: schemas have conflicting const constraints")}if(hasFormatConflict(a,b)){throw new Error("Incompatible format values: schemas have conflicting format constraints")}if(hasAdditionalPropertiesConflict(a,b)){throw new Error("Incompatible additionalProperties: required properties conflict with additionalProperties constraint")}return this.shallowAllOfMergeFn({allOf:[a,b]})}compare(a,b){return this.compareFn(a,b)}isEqual(a,b){return this.compareFn(a,b)===0}overlay(base,override){if(override===false)return false;if(override===true)return true;if(typeof base==="boolean")return override;const baseObj=base;const overrideObj=override;if(!isObjectLike(baseObj)&&!isObjectLike(overrideObj)){return override}if(!isObjectLike(baseObj)){return override}if(!isObjectLike(overrideObj)){return override}const baseProps=baseObj.properties??{};const overrideProps=overrideObj.properties??{};const mergedProps={};for(const key of Object.keys(baseProps)){const baseProp=baseProps[key];if(baseProp===undefined)continue;mergedProps[key]=baseProp}for(const key of Object.keys(overrideProps)){const overrideProp=overrideProps[key];if(overrideProp===undefined)continue;const baseProp=baseProps[key];if(baseProp!==undefined&&typeof baseProp!=="boolean"&&typeof overrideProp!=="boolean"&&isObjectLike(baseProp)&&isObjectLike(overrideProp)){mergedProps[key]=this.overlay(baseProp,overrideProp)}else{mergedProps[key]=overrideProp}}const baseRequired=Array.isArray(baseObj.required)?baseObj.required:[];const overrideRequired=Array.isArray(overrideObj.required)?overrideObj.required:[];const mergedRequired=unionStrings(baseRequired,overrideRequired);const result={...baseObj};result.properties=mergedProps;if(mergedRequired.length>0){result.required=mergedRequired}else{delete result.required}if(hasOwn(overrideObj,"additionalProperties")){result.additionalProperties=overrideObj.additionalProperties}if(hasOwn(overrideObj,"minProperties")){result.minProperties=overrideObj.minProperties}if(hasOwn(overrideObj,"maxProperties")){result.maxProperties=overrideObj.maxProperties}if(hasOwn(overrideObj,"propertyNames")){result.propertyNames=overrideObj.propertyNames}if(hasOwn(overrideObj,"patternProperties")){result.patternProperties=overrideObj.patternProperties}if(hasOwn(overrideObj,"dependencies")){result.dependencies=overrideObj.dependencies}if(hasOwn(overrideObj,"type")){result.type=overrideObj.type}return result}constructor(){_define_property(this,"compareFn",void 0);_define_property(this,"shallowAllOfMergeFn",void 0);const{compareSchemaDefinitions,compareSchemaValues}=createComparator();const safeCompareSchemaValues=(a,b)=>{if(a===null&&b===null)return 0;return compareSchemaValues(a,b)};const{mergeArrayOfSchemaDefinitions}=createMerger({intersectJson:createIntersector(safeCompareSchemaValues),deduplicateJsonSchemaDef:createDeduplicator(compareSchemaDefinitions)});this.compareFn=compareSchemaDefinitions;this.shallowAllOfMergeFn=createShallowAllOfMerge(mergeArrayOfSchemaDefinitions)}}const OBJECT_SHAPE_KEYWORDS=["properties","patternProperties","additionalProperties","required","dependencies","propertyNames","minProperties","maxProperties"];function isObjectLike(schema){if(schema.type==="object")return true;for(const kw of OBJECT_SHAPE_KEYWORDS){if(hasOwn(schema,kw))return true}return false}
2
2
  //# sourceMappingURL=merge-engine.js.map
@@ -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 * 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":["createComparator","createMerger","createShallowAllOfMerge","createDeduplicator","createIntersector","isFormatSubset","deepEqual","hasOwn","isPlainObj","hasConstConflict","a","b","aHasConst","bHasConst","aConst","const","bConst","aEnum","enum","bEnum","Array","isArray","some","v","SINGLE_SCHEMA_CONFLICT_KEYS","PROPERTIES_MAP_CONFLICT_KEYS","hasDeepConstConflict","key","aVal","bVal","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","reverseCheck","MergeEngine","merge","shallowAllOfMergeFn","allOf","mergeOrThrow","Error","compare","compareFn","isEqual","compareSchemaDefinitions","compareSchemaValues","safeCompareSchemaValues","mergeArrayOfSchemaDefinitions","intersectJson","deduplicateJsonSchemaDef"],"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, unionStrings } 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\t// ── Overlay (sequential spread) ────────────────────────────────────────\n\n\t/**\n\t * Computes a **deep** schema overlay: properties from `override`\n\t * **replace** same-named properties in `base` using last-writer-wins\n\t * spread semantics. When both the base and override define the same\n\t * property as object-like schemas, the overlay **recurses** into that\n\t * property so that nested sub-properties are spread rather than\n\t * wholesale-replaced.\n\t *\n\t * This is the correct operation for sequential pipeline context\n\t * accumulation where each node overwrites keys it produces:\n\t *\n\t * ```ts\n\t * // Runtime semantics (deep spread):\n\t * context = deepSpread(context, node.output)\n\t * ```\n\t *\n\t * Unlike `merge` / `mergeOrThrow` (which compute `allOf` — the set\n\t * **intersection**), `overlay` is **non-commutative**: the order of\n\t * arguments matters. `base` is what existed before, `override` is\n\t * what the new node produces.\n\t *\n\t * Behavior per keyword:\n\t * - **`properties`**: deep spread — when both base and override define\n\t * the same property and both are object-like, `overlay` recurses.\n\t * Otherwise the override's property replaces the base's.\n\t * Base-only properties are always kept.\n\t * - **`required`**: union of both arrays (a property that was required\n\t * before or is required by the override stays required).\n\t * - **`additionalProperties`**: override wins if present, else base.\n\t * - **Other object-level keywords** (`minProperties`, `maxProperties`,\n\t * `propertyNames`, `patternProperties`, `dependencies`): override\n\t * wins if present, else base is kept.\n\t * - **Non-object schemas**: if either schema is not an object schema\n\t * (no `properties`, no `type: \"object\"`), the override replaces\n\t * the base entirely — there are no properties to spread.\n\t *\n\t * @param base - The existing accumulated schema (what came before)\n\t * @param override - The new schema to overlay on top (last writer)\n\t * @returns A new schema with deep spread semantics applied\n\t *\n\t * @example\n\t * ```ts\n\t * const base = {\n\t * type: \"object\",\n\t * properties: {\n\t * accountId: { type: \"string\", enum: [\"a\", \"b\"] },\n\t * config: {\n\t * type: \"object\",\n\t * properties: {\n\t * host: { type: \"string\" },\n\t * port: { type: \"integer\" },\n\t * },\n\t * required: [\"host\", \"port\"],\n\t * },\n\t * },\n\t * required: [\"accountId\", \"config\"],\n\t * };\n\t *\n\t * const override = {\n\t * type: \"object\",\n\t * properties: {\n\t * accountId: { type: \"string\" }, // widens the type\n\t * config: {\n\t * type: \"object\",\n\t * properties: {\n\t * host: { type: \"string\", format: \"hostname\" },\n\t * },\n\t * },\n\t * },\n\t * required: [\"accountId\"],\n\t * };\n\t *\n\t * engine.overlay(base, override);\n\t * // → {\n\t * // type: \"object\",\n\t * // properties: {\n\t * // accountId: { type: \"string\" }, ← override wins (flat)\n\t * // config: {\n\t * // type: \"object\",\n\t * // properties: {\n\t * // host: { type: \"string\", format: \"hostname\" }, ← override wins (deep)\n\t * // port: { type: \"integer\" }, ← kept from base (deep)\n\t * // },\n\t * // required: [\"host\", \"port\"],\n\t * // },\n\t * // },\n\t * // required: [\"accountId\", \"config\"],\n\t * // }\n\t * ```\n\t */\n\toverlay(\n\t\tbase: JSONSchema7Definition,\n\t\toverride: JSONSchema7Definition,\n\t): JSONSchema7Definition {\n\t\t// ── Boolean schema fast paths ──\n\t\t// `false` absorbs everything (no values allowed)\n\t\tif (override === false) return false;\n\t\t// `true` (accept everything) as override means base is completely replaced\n\t\tif (override === true) return true;\n\t\t// `true`/`false` base with a real override → override wins entirely\n\t\tif (typeof base === \"boolean\") return override;\n\n\t\tconst baseObj = base as JSONSchema7;\n\t\tconst overrideObj = override as JSONSchema7;\n\n\t\t// ── Non-object schemas: override replaces entirely ──\n\t\t// If neither schema looks like an object schema, there's no\n\t\t// property-level spreading to do — the override simply wins.\n\t\tif (!isObjectLike(baseObj) && !isObjectLike(overrideObj)) {\n\t\t\treturn override;\n\t\t}\n\n\t\t// ── If only the override is object-like, it replaces entirely ──\n\t\tif (!isObjectLike(baseObj)) {\n\t\t\treturn override;\n\t\t}\n\n\t\t// ── If only the base is object-like, override replaces entirely ──\n\t\t// (the override is a non-object schema — it redefines the shape)\n\t\tif (!isObjectLike(overrideObj)) {\n\t\t\treturn override;\n\t\t}\n\n\t\t// ── Both are object-like: deep spread properties ──\n\t\tconst baseProps = (baseObj.properties ?? {}) as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tconst overrideProps = (overrideObj.properties ?? {}) as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\n\t\t// Deep spread: for each property, recurse if both sides are object-like,\n\t\t// otherwise override wins. Base-only properties are kept as-is.\n\t\tconst mergedProps: Record<string, JSONSchema7Definition> = {};\n\n\t\t// 1. Copy all base properties (may be overridden below)\n\t\tfor (const key of Object.keys(baseProps)) {\n\t\t\tconst baseProp = baseProps[key];\n\t\t\tif (baseProp === undefined) continue;\n\t\t\tmergedProps[key] = baseProp;\n\t\t}\n\n\t\t// 2. Apply override properties — recurse when both are object-like\n\t\tfor (const key of Object.keys(overrideProps)) {\n\t\t\tconst overrideProp = overrideProps[key];\n\t\t\tif (overrideProp === undefined) continue;\n\n\t\t\tconst baseProp = baseProps[key];\n\n\t\t\t// If this property exists in both and both are object-like schemas,\n\t\t\t// recurse to deep-spread their sub-properties.\n\t\t\tif (\n\t\t\t\tbaseProp !== undefined &&\n\t\t\t\ttypeof baseProp !== \"boolean\" &&\n\t\t\t\ttypeof overrideProp !== \"boolean\" &&\n\t\t\t\tisObjectLike(baseProp as JSONSchema7) &&\n\t\t\t\tisObjectLike(overrideProp as JSONSchema7)\n\t\t\t) {\n\t\t\t\tmergedProps[key] = this.overlay(baseProp, overrideProp);\n\t\t\t} else {\n\t\t\t\t// Otherwise: override wins entirely (primitive, array, type change, etc.)\n\t\t\t\tmergedProps[key] = overrideProp;\n\t\t\t}\n\t\t}\n\n\t\t// Union of required arrays\n\t\tconst baseRequired = Array.isArray(baseObj.required)\n\t\t\t? baseObj.required\n\t\t\t: [];\n\t\tconst overrideRequired = Array.isArray(overrideObj.required)\n\t\t\t? overrideObj.required\n\t\t\t: [];\n\t\tconst mergedRequired = unionStrings(baseRequired, overrideRequired);\n\n\t\t// Start from base, apply override's object-level keywords on top\n\t\tconst result: JSONSchema7 = { ...baseObj };\n\n\t\t// Always set the merged properties\n\t\tresult.properties = mergedProps;\n\n\t\t// Set required only if non-empty\n\t\tif (mergedRequired.length > 0) {\n\t\t\tresult.required = mergedRequired;\n\t\t} else {\n\t\t\tdelete result.required;\n\t\t}\n\n\t\t// Override-wins for object-level constraint keywords\n\t\tif (hasOwn(overrideObj, \"additionalProperties\")) {\n\t\t\tresult.additionalProperties = overrideObj.additionalProperties;\n\t\t}\n\t\tif (hasOwn(overrideObj, \"minProperties\")) {\n\t\t\tresult.minProperties = overrideObj.minProperties;\n\t\t}\n\t\tif (hasOwn(overrideObj, \"maxProperties\")) {\n\t\t\tresult.maxProperties = overrideObj.maxProperties;\n\t\t}\n\t\tif (hasOwn(overrideObj, \"propertyNames\")) {\n\t\t\tresult.propertyNames = overrideObj.propertyNames;\n\t\t}\n\t\tif (hasOwn(overrideObj, \"patternProperties\")) {\n\t\t\tresult.patternProperties = overrideObj.patternProperties;\n\t\t}\n\t\tif (hasOwn(overrideObj, \"dependencies\")) {\n\t\t\tresult.dependencies = overrideObj.dependencies;\n\t\t}\n\n\t\t// Override type if explicitly provided\n\t\tif (hasOwn(overrideObj, \"type\")) {\n\t\t\tresult.type = overrideObj.type;\n\t\t}\n\n\t\treturn result;\n\t}\n}\n\n// ─── Overlay helpers ─────────────────────────────────────────────────────────\n\n/** Object-level keywords that indicate a schema describes an object shape. */\nconst OBJECT_SHAPE_KEYWORDS: ReadonlyArray<string> = [\n\t\"properties\",\n\t\"patternProperties\",\n\t\"additionalProperties\",\n\t\"required\",\n\t\"dependencies\",\n\t\"propertyNames\",\n\t\"minProperties\",\n\t\"maxProperties\",\n];\n\n/**\n * Heuristic: does this schema look like it describes an object?\n * True if `type` is `\"object\"` or if any object-shape keyword is present.\n */\nfunction isObjectLike(schema: JSONSchema7): boolean {\n\tif (schema.type === \"object\") return true;\n\tfor (const kw of OBJECT_SHAPE_KEYWORDS) {\n\t\tif (hasOwn(schema, kw)) return true;\n\t}\n\treturn false;\n}\n"],"names":["createComparator","createMerger","createShallowAllOfMerge","createDeduplicator","createIntersector","isFormatSubset","deepEqual","hasOwn","isPlainObj","unionStrings","hasConstConflict","a","b","aHasConst","bHasConst","aConst","const","bConst","aEnum","enum","bEnum","Array","isArray","some","v","SINGLE_SCHEMA_CONFLICT_KEYS","PROPERTIES_MAP_CONFLICT_KEYS","hasDeepConstConflict","key","aVal","bVal","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","reverseCheck","MergeEngine","merge","shallowAllOfMergeFn","allOf","mergeOrThrow","Error","compare","compareFn","isEqual","overlay","base","override","baseObj","overrideObj","isObjectLike","baseProps","overrideProps","mergedProps","baseProp","overrideProp","baseRequired","overrideRequired","mergedRequired","result","minProperties","maxProperties","propertyNames","patternProperties","dependencies","compareSchemaDefinitions","compareSchemaValues","safeCompareSchemaValues","mergeArrayOfSchemaDefinitions","intersectJson","deduplicateJsonSchemaDef","OBJECT_SHAPE_KEYWORDS","schema","kw"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-schema-compatibility-checker",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "license": "MIT",
5
5
  "description": "A tool to check compatibility between two JSON Schemas.",
6
6
  "author": {