json-schema-compatibility-checker 1.1.2 → 1.1.3
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/dist/cjs/condition-resolver.js +1 -1
- package/dist/cjs/condition-resolver.js.map +1 -1
- package/dist/cjs/constraint-validator.d.ts +4 -4
- package/dist/cjs/constraint-validator.js.map +1 -1
- package/dist/cjs/json-schema-compatibility-checker.js +1 -1
- package/dist/cjs/json-schema-compatibility-checker.js.map +1 -1
- package/dist/cjs/merge-engine.js +1 -1
- package/dist/cjs/merge-engine.js.map +1 -1
- package/dist/cjs/normalizer.js +1 -1
- package/dist/cjs/normalizer.js.map +1 -1
- package/dist/cjs/semantic-errors.js +1 -1
- package/dist/cjs/semantic-errors.js.map +1 -1
- package/dist/esm/condition-resolver.js +1 -1
- package/dist/esm/condition-resolver.js.map +1 -1
- package/dist/esm/constraint-validator.d.ts +4 -4
- package/dist/esm/constraint-validator.js.map +1 -1
- package/dist/esm/json-schema-compatibility-checker.js +1 -1
- package/dist/esm/json-schema-compatibility-checker.js.map +1 -1
- package/dist/esm/merge-engine.js +1 -1
- package/dist/esm/merge-engine.js.map +1 -1
- package/dist/esm/normalizer.js +1 -1
- package/dist/esm/normalizer.js.map +1 -1
- package/dist/esm/semantic-errors.js +1 -1
- package/dist/esm/semantic-errors.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/merge-engine.ts"],"sourcesContent":["import {\n\tcreateComparator,\n\tcreateMerger,\n\tcreateShallowAllOfMerge,\n} from \"@x0k/json-schema-merge\";\nimport {\n\tcreateDeduplicator,\n\tcreateIntersector,\n} from \"@x0k/json-schema-merge/lib/array\";\n\nimport type {\n\tJSONSchema7,\n\tJSONSchema7Definition,\n\tJSONSchema7Type,\n} from \"json-schema\";\n\nimport { isFormatSubset } from \"./format-validator.ts\";\nimport {\n\tdeepEqual,\n\thasOwn,\n\tisPlainObj,\n\tmergeConstraints,\n\tunionStrings,\n} from \"./utils.ts\";\n\n// ─── Merge Engine ────────────────────────────────────────────────────────────\n//\n// Wraps the `@x0k/json-schema-merge` library and exposes a simple API\n// for merging and comparing JSON Schemas.\n//\n// Mathematical principle:\n// A ∩ B = allOf([A, B]) resolved via shallow merge\n// A ≡ B ⟺ compare(A, B) === 0\n//\n// Pre-checks before merge:\n// - `hasDeepConstConflict`: detects `const`/`enum` conflicts\n// - `hasAdditionalPropertiesConflict`: detects `additionalProperties` conflicts\n// - `hasFormatConflict`: detects `format` conflicts between two schemas\n\n// ─── Const conflict detection ────────────────────────────────────────────────\n\n/**\n * Detects a `const` conflict between two schemas.\n *\n * Case 1 — const vs const: both schemas have a `const` with different\n * values → empty intersection.\n *\n * Case 2 — const vs enum: one schema has `const`, the other has `enum`.\n * If the `const` value is not in the `enum` → empty intersection.\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// Case 1 — const vs const\n\tif (aHasConst && bHasConst) {\n\t\treturn !deepEqual(aConst, bConst);\n\t}\n\n\t// Case 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/** Keywords containing a single sub-schema to check recursively */\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/** Keywords containing a Record<string, JSONSchema7Definition> */\nconst PROPERTIES_MAP_CONFLICT_KEYS = [\n\t\"properties\",\n\t\"patternProperties\",\n] as const;\n\n/**\n * Recursively detects `const` conflicts in sub-schemas.\n *\n * When the merge library performs a shallow merge, nested sub-schemas\n * can also have hidden `const` conflicts\n * (it uses `identity` for `const`).\n *\n * Recurses into:\n * - `properties`, `patternProperties` (common keys)\n * - `items` (single schema), tuple `items` (by 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 * Detects a conflict between `additionalProperties` and the extra\n * **required** properties of the other schema.\n *\n * ⚠️ This function is **ultra-conservative**: it only detects conflicts\n * where a property is simultaneously:\n * - FORBIDDEN by `additionalProperties: false` on one side\n * - REQUIRED (`required`) by the other side\n * - ABSENT from `properties` on the restrictive side\n * - AND the restrictive side ALSO has a `required` that makes the object non-empty\n * (otherwise the library already handles the case by excluding extra properties)\n *\n * The merge library (`@x0k/json-schema-merge`) ALREADY correctly handles\n * the `additionalProperties: false` case with properties that are merely DEFINED\n * (not required) in the other schema — it excludes them from the result.\n * We therefore only detect `required` contradictions that are impossible to resolve.\n *\n * Cases handled:\n * 1. `a` has `additionalProperties: false` and `b` REQUIRES properties\n * absent from `a.properties`, AND those properties are in `b.properties`\n * → certain conflict (empty intersection because b requires, a forbids)\n * 2. Symmetric for `b.additionalProperties: false`\n * 3. `additionalProperties` as a schema → check type compatibility\n * of extra REQUIRED properties only\n * 4. Recursion into common properties (sub-objects)\n *\n * ⚠️ Only checks keys from `properties`, not `patternProperties`\n * (too complex to resolve statically).\n *\n * Returns `true` if an obvious conflict is detected, `false` otherwise.\n * When in doubt → `false` (conservative, let the merge decide).\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// If neither has properties, we cannot determine anything\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// ── Check additionalProperties: false of a vs extra REQUIRED properties of b ──\n\t// Strict condition: b must DEFINE the property in b.properties AND\n\t// REQUIRE it in b.required, AND this property must be ABSENT from a.properties.\n\t// Additionally, a must itself have properties (otherwise we can't determine anything).\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// Only detect the conflict if a also has a required that makes the object\n\t\t// structurally constrained (not a vague schema)\n\t\tif (hasRequiredExtra && aKeys.length > 0) return true;\n\t}\n\n\t// ── Check for additionalProperties as a schema ──\n\t// If a.additionalProperties is a schema with a type, and b REQUIRES\n\t// an extra property whose type is incompatible → conflict\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// ── Symmetric check: additionalProperties of b vs extra REQUIRED properties of 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// Symmetric for additionalProperties as a 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// ── Recursion into common properties ──\n\t// If both schemas have common properties that are objects,\n\t// recursively check additionalProperties conflicts\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 * Detects a format conflict between two schemas.\n *\n * ⚠️ Only triggers when BOTH schemas have a `format`.\n * If only one schema has a `format`, there is NO conflict — the merge\n * engine handles this case natively (the format is preserved in the intersection,\n * and the `merged ≡ sub` comparison correctly determines the ⊆ relation).\n *\n * Two schemas with different formats and no known inclusion relation\n * have an empty intersection (e.g., \"email\" ∩ \"ipv4\" = ∅).\n *\n * Uses `isFormatSubset` from `format-validator.ts` to check the hierarchy.\n *\n * Recurses into sub-schemas (`properties`, `items`, etc.) to detect\n * nested format conflicts.\n *\n * @returns `true` if a format conflict is detected, `false` otherwise\n */\nfunction hasFormatConflict(\n\ta: JSONSchema7Definition,\n\tb: JSONSchema7Definition,\n): boolean {\n\tif (typeof a === \"boolean\" || typeof b === \"boolean\") return false;\n\n\t// ── Only when BOTH have a format ──\n\t// If only one has a format → no conflict, the merge handles it natively\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// Same format → no conflict\n\t\tif (aFormat !== bFormat) {\n\t\t\t// Check if one is a subset of the other via the hierarchy\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// Different formats with no known relation → conflict\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Recursion into sub-schemas ──\n\t// Check format conflicts in common properties\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// Check 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// Check 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// ─── Constraints merge helpers ───────────────────────────────────────────────\n\n// `toConstraintArray` and `mergeConstraints` are imported from `./utils.ts`.\n// They are shared with `condition-resolver.ts`.\n\n/**\n * Returns `true` if the schema (or any of its nested sub-schemas) contains\n * the custom `constraints` keyword. Used as a cheap guard to skip the\n * expensive `applyConstraintsMerge` post-processor when no constraints\n * exist in either input — which is the overwhelmingly common case.\n *\n * Recurses into: `properties`, `patternProperties`, `items` (single or\n * tuple), `additionalProperties`, `dependencies` (schema form).\n */\nfunction hasConstraintsAnywhere(schema: JSONSchema7Definition): boolean {\n\tif (typeof schema === \"boolean\") return false;\n\n\tif (hasOwn(schema, \"constraints\") && schema.constraints !== undefined) {\n\t\treturn true;\n\t}\n\n\tif (isPlainObj(schema.properties)) {\n\t\tconst props = schema.properties as Record<string, JSONSchema7Definition>;\n\t\tfor (const key of Object.keys(props)) {\n\t\t\tconst prop = props[key];\n\t\t\tif (prop !== undefined && hasConstraintsAnywhere(prop)) return true;\n\t\t}\n\t}\n\n\tif (isPlainObj(schema.patternProperties)) {\n\t\tconst pp = schema.patternProperties as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tfor (const key of Object.keys(pp)) {\n\t\t\tconst val = pp[key];\n\t\t\tif (val !== undefined && hasConstraintsAnywhere(val)) return true;\n\t\t}\n\t}\n\n\tif (Array.isArray(schema.items)) {\n\t\tfor (const item of schema.items as JSONSchema7Definition[]) {\n\t\t\tif (item !== undefined && hasConstraintsAnywhere(item)) return true;\n\t\t}\n\t} else if (isPlainObj(schema.items)) {\n\t\tif (hasConstraintsAnywhere(schema.items as JSONSchema7Definition))\n\t\t\treturn true;\n\t}\n\n\tif (isPlainObj(schema.additionalProperties)) {\n\t\tif (\n\t\t\thasConstraintsAnywhere(\n\t\t\t\tschema.additionalProperties as JSONSchema7Definition,\n\t\t\t)\n\t\t)\n\t\t\treturn true;\n\t}\n\n\tif (isPlainObj(schema.dependencies)) {\n\t\tconst deps = schema.dependencies as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t\tfor (const key of Object.keys(deps)) {\n\t\t\tconst val = deps[key];\n\t\t\tif (\n\t\t\t\tval !== undefined &&\n\t\t\t\t!Array.isArray(val) &&\n\t\t\t\thasConstraintsAnywhere(val as JSONSchema7Definition)\n\t\t\t)\n\t\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n/**\n * Recursively applies constraint merging to a schema that was produced\n * by the `shallowAllOfMerge` engine. The external library does not know\n * about our custom `constraints` keyword, so it applies an arbitrary\n * default (identity / last-wins). This post-processor walks the merged\n * result and replaces `constraints` with the proper union from both\n * original input schemas.\n *\n * **Performance guard:** If neither `a` nor `b` contains `constraints`\n * anywhere in their schema tree, returns `merged` immediately with zero\n * allocation. This is the overwhelmingly common case (schemas without\n * custom constraints), so the guard eliminates the shallow copy + recursion\n * overhead that was causing a ~10-25% regression on every merge call.\n *\n * Recurses into: `properties`, `patternProperties`, `items` (single or\n * tuple), `additionalProperties`, `dependencies` (schema form).\n */\nfunction applyConstraintsMerge(\n\tmerged: JSONSchema7Definition,\n\ta: JSONSchema7Definition,\n\tb: JSONSchema7Definition,\n): JSONSchema7Definition {\n\tif (typeof merged === \"boolean\") return merged;\n\tif (typeof a === \"boolean\" || typeof b === \"boolean\") return merged;\n\n\t// ── Fast path: no constraints anywhere → return merged as-is ──\n\t// The guard checks only the original inputs (a, b). If neither has\n\t// constraints, the merged result cannot have meaningful constraints\n\t// either — skip the shallow copy and recursive traversal entirely.\n\tif (!hasConstraintsAnywhere(a) && !hasConstraintsAnywhere(b)) {\n\t\treturn merged;\n\t}\n\n\tlet changed = false;\n\tconst result = { ...merged };\n\n\t// ── Root-level constraints ──\n\tconst mergedConstraints = mergeConstraints(a.constraints, b.constraints);\n\tconst currentConstraints = result.constraints;\n\n\tif (mergedConstraints !== undefined) {\n\t\tif (!deepEqual(currentConstraints, mergedConstraints)) {\n\t\t\tresult.constraints = mergedConstraints;\n\t\t\tchanged = true;\n\t\t}\n\t} else if (currentConstraints !== undefined) {\n\t\tdelete result.constraints;\n\t\tchanged = true;\n\t}\n\n\t// ── Recurse into properties ──\n\tif (\n\t\tisPlainObj(result.properties) &&\n\t\t(isPlainObj(a.properties) || isPlainObj(b.properties))\n\t) {\n\t\tconst mergedProps = result.properties as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tconst aProps = (a.properties ?? {}) as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tconst bProps = (b.properties ?? {}) as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\n\t\tlet propsChanged = false;\n\t\tconst newProps: Record<string, JSONSchema7Definition> = {};\n\n\t\tfor (const key of Object.keys(mergedProps)) {\n\t\t\tconst mProp = mergedProps[key];\n\t\t\tconst aProp = aProps[key];\n\t\t\tconst bProp = bProps[key];\n\n\t\t\tif (mProp === undefined) continue;\n\n\t\t\t// Only recurse if both originals exist and are object schemas\n\t\t\tif (\n\t\t\t\taProp !== undefined &&\n\t\t\t\tbProp !== undefined &&\n\t\t\t\ttypeof mProp !== \"boolean\" &&\n\t\t\t\ttypeof aProp !== \"boolean\" &&\n\t\t\t\ttypeof bProp !== \"boolean\"\n\t\t\t) {\n\t\t\t\tconst patched = applyConstraintsMerge(mProp, aProp, bProp);\n\t\t\t\tnewProps[key] = patched;\n\t\t\t\tif (patched !== mProp) propsChanged = true;\n\t\t\t} else {\n\t\t\t\tnewProps[key] = mProp;\n\t\t\t}\n\t\t}\n\n\t\tif (propsChanged) {\n\t\t\tresult.properties = newProps;\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\t// ── Recurse into items (single schema) ──\n\tif (isPlainObj(result.items) && isPlainObj(a.items) && isPlainObj(b.items)) {\n\t\tconst patched = applyConstraintsMerge(\n\t\t\tresult.items as JSONSchema7Definition,\n\t\t\ta.items as JSONSchema7Definition,\n\t\t\tb.items as JSONSchema7Definition,\n\t\t);\n\t\tif (patched !== result.items) {\n\t\t\tresult.items = patched;\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\t// ── Recurse into patternProperties ──\n\tif (\n\t\tisPlainObj(result.patternProperties) &&\n\t\t(isPlainObj(a.patternProperties) || isPlainObj(b.patternProperties))\n\t) {\n\t\tconst mergedPP = result.patternProperties as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tconst aPP = (a.patternProperties ?? {}) as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tconst bPP = (b.patternProperties ?? {}) as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\n\t\tlet ppChanged = false;\n\t\tconst newPP: Record<string, JSONSchema7Definition> = {};\n\n\t\tfor (const key of Object.keys(mergedPP)) {\n\t\t\tconst mVal = mergedPP[key];\n\t\t\tconst aVal = aPP[key];\n\t\t\tconst bVal = bPP[key];\n\n\t\t\tif (mVal === undefined) continue;\n\n\t\t\tif (\n\t\t\t\taVal !== undefined &&\n\t\t\t\tbVal !== undefined &&\n\t\t\t\ttypeof mVal !== \"boolean\" &&\n\t\t\t\ttypeof aVal !== \"boolean\" &&\n\t\t\t\ttypeof bVal !== \"boolean\"\n\t\t\t) {\n\t\t\t\tconst patched = applyConstraintsMerge(mVal, aVal, bVal);\n\t\t\t\tnewPP[key] = patched;\n\t\t\t\tif (patched !== mVal) ppChanged = true;\n\t\t\t} else {\n\t\t\t\tnewPP[key] = mVal;\n\t\t\t}\n\t\t}\n\n\t\tif (ppChanged) {\n\t\t\tresult.patternProperties = newPP;\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\t// ── Recurse into tuple items (array of schemas) ──\n\tif (\n\t\tArray.isArray(result.items) &&\n\t\tArray.isArray(a.items) &&\n\t\tArray.isArray(b.items)\n\t) {\n\t\tconst mergedItems = result.items as JSONSchema7Definition[];\n\t\tconst aItems = a.items as JSONSchema7Definition[];\n\t\tconst bItems = b.items as JSONSchema7Definition[];\n\t\tconst len = mergedItems.length;\n\n\t\tlet tupleChanged = false;\n\t\tconst newItems: JSONSchema7Definition[] = new Array(len);\n\n\t\tfor (let i = 0; i < len; i++) {\n\t\t\tconst mItem = mergedItems[i];\n\t\t\tconst aItem = aItems[i];\n\t\t\tconst bItem = bItems[i];\n\n\t\t\tif (\n\t\t\t\tmItem !== undefined &&\n\t\t\t\taItem !== undefined &&\n\t\t\t\tbItem !== undefined &&\n\t\t\t\ttypeof mItem !== \"boolean\" &&\n\t\t\t\ttypeof aItem !== \"boolean\" &&\n\t\t\t\ttypeof bItem !== \"boolean\"\n\t\t\t) {\n\t\t\t\tconst patched = applyConstraintsMerge(mItem, aItem, bItem);\n\t\t\t\tnewItems[i] = patched;\n\t\t\t\tif (patched !== mItem) tupleChanged = true;\n\t\t\t} else {\n\t\t\t\tnewItems[i] = mItem as JSONSchema7Definition;\n\t\t\t}\n\t\t}\n\n\t\tif (tupleChanged) {\n\t\t\tresult.items = newItems;\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\t// ── Recurse into additionalProperties (schema form) ──\n\tif (\n\t\tisPlainObj(result.additionalProperties) &&\n\t\tisPlainObj(a.additionalProperties) &&\n\t\tisPlainObj(b.additionalProperties)\n\t) {\n\t\tconst patched = applyConstraintsMerge(\n\t\t\tresult.additionalProperties as JSONSchema7Definition,\n\t\t\ta.additionalProperties as JSONSchema7Definition,\n\t\t\tb.additionalProperties as JSONSchema7Definition,\n\t\t);\n\t\tif (patched !== result.additionalProperties) {\n\t\t\tresult.additionalProperties = patched;\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\t// ── Recurse into dependencies (schema form) ──\n\tif (\n\t\tisPlainObj(result.dependencies) &&\n\t\t(isPlainObj(a.dependencies) || isPlainObj(b.dependencies))\n\t) {\n\t\tconst mergedDeps = result.dependencies as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t\tconst aDeps = (a.dependencies ?? {}) as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t\tconst bDeps = (b.dependencies ?? {}) as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\n\t\tlet depsChanged = false;\n\t\tconst newDeps: Record<string, JSONSchema7Definition | string[]> = {};\n\n\t\tfor (const key of Object.keys(mergedDeps)) {\n\t\t\tconst mVal = mergedDeps[key];\n\t\t\tconst aVal = aDeps[key];\n\t\t\tconst bVal = bDeps[key];\n\n\t\t\tif (mVal === undefined) continue;\n\n\t\t\t// Only recurse for schema-form dependencies (not string-array form)\n\t\t\tif (\n\t\t\t\taVal !== undefined &&\n\t\t\t\tbVal !== undefined &&\n\t\t\t\t!Array.isArray(mVal) &&\n\t\t\t\t!Array.isArray(aVal) &&\n\t\t\t\t!Array.isArray(bVal) &&\n\t\t\t\ttypeof mVal !== \"boolean\" &&\n\t\t\t\ttypeof aVal !== \"boolean\" &&\n\t\t\t\ttypeof bVal !== \"boolean\"\n\t\t\t) {\n\t\t\t\tconst patched = applyConstraintsMerge(\n\t\t\t\t\tmVal as JSONSchema7Definition,\n\t\t\t\t\taVal as JSONSchema7Definition,\n\t\t\t\t\tbVal as JSONSchema7Definition,\n\t\t\t\t);\n\t\t\t\tnewDeps[key] = patched;\n\t\t\t\tif (patched !== mVal) depsChanged = true;\n\t\t\t} else {\n\t\t\t\tnewDeps[key] = mVal;\n\t\t\t}\n\t\t}\n\n\t\tif (depsChanged) {\n\t\t\tresult.dependencies = newDeps;\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\treturn changed ? result : merged;\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 * Merges two schemas via `allOf([a, b])`.\n\t * Returns `null` if the schemas are incompatible.\n\t *\n\t * Post-merge: detects `const` conflicts that the library\n\t * does not capture (it uses `identity` for `const`).\n\t */\n\tmerge(\n\t\ta: JSONSchema7Definition,\n\t\tb: JSONSchema7Definition,\n\t): JSONSchema7Definition | null {\n\t\t// ── Trivial fast paths ──\n\t\t// Avoid expensive recursive conflict checks and external merge calls\n\t\t// for the most common identity/boolean intersection cases.\n\t\tif (a === b) return a;\n\t\tif (a === false || b === false) return false;\n\t\tif (a === true) return b;\n\t\tif (b === true) return a;\n\n\t\t// Pre-check: const conflict detectable before the merge\n\t\tif (hasDeepConstConflict(a, b)) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Pre-check: format conflict (BOTH have an incompatible format)\n\t\tif (hasFormatConflict(a, b)) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Pre-check: additionalProperties vs extra REQUIRED properties conflict\n\t\t// Only detects cases where a property is simultaneously forbidden\n\t\t// (additionalProperties: false) and required (required) → empty intersection.\n\t\t// Cases where properties are merely defined without being required\n\t\t// are handled correctly by the merge library itself.\n\t\tif (hasAdditionalPropertiesConflict(a, b)) {\n\t\t\treturn null;\n\t\t}\n\n\t\ttry {\n\t\t\tconst result = this.shallowAllOfMergeFn({ allOf: [a, b] });\n\t\t\t// Post-merge: the external library does not handle our custom\n\t\t\t// `constraints` keyword — apply union + deduplication.\n\t\t\treturn applyConstraintsMerge(result, a, b);\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Merges via `shallowAllOfMerge` — throws an exception if incompatible.\n\t * Useful when you want to capture the error for diagnostics.\n\t *\n\t * Post-merge: detects `const` conflicts and throws an exception.\n\t */\n\tmergeOrThrow(\n\t\ta: JSONSchema7Definition,\n\t\tb: JSONSchema7Definition,\n\t): JSONSchema7Definition {\n\t\t// ── Trivial fast paths ──\n\t\t// Keep mergeOrThrow aligned with merge() for the common boolean/identity\n\t\t// intersections that can be resolved without touching the merge library.\n\t\tif (a === b) return a;\n\t\tif (a === false || b === false) return false;\n\t\tif (a === true) return b;\n\t\tif (b === true) return a;\n\n\t\t// Pre-check: const conflict\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// Pre-check: format conflict\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// Pre-check: additionalProperties vs extra REQUIRED properties conflict\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\tconst result = this.shallowAllOfMergeFn({ allOf: [a, b] });\n\t\t// Post-merge: apply constraints union + deduplication.\n\t\treturn applyConstraintsMerge(result, a, b);\n\t}\n\n\t/**\n\t * Structurally compares two schema definitions.\n\t * Returns 0 if they are identical, otherwise a non-zero integer.\n\t */\n\tcompare(a: JSONSchema7Definition, b: JSONSchema7Definition): number {\n\t\treturn this.compareFn(a, b);\n\t}\n\n\t/**\n\t * Checks structural equality between two 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","hasConstraintsAnywhere","schema","constraints","props","prop","patternProperties","pp","val","item","dependencies","deps","applyConstraintsMerge","merged","changed","result","mergedConstraints","mergeConstraints","currentConstraints","mergedProps","propsChanged","newProps","mProp","patched","mergedPP","aPP","bPP","ppChanged","newPP","mVal","mergedItems","tupleChanged","newItems","mItem","mergedDeps","aDeps","bDeps","depsChanged","newDeps","merge","shallowAllOfMergeFn","allOf","mergeOrThrow","Error","compare","compareFn","isEqual","overlay","base","override","baseObj","overrideObj","isObjectLike","baseProps","overrideProps","baseProp","overrideProp","baseRequired","overrideRequired","mergedRequired","unionStrings","minProperties","maxProperties","propertyNames","compareSchemaDefinitions","compareSchemaValues","createComparator","safeCompareSchemaValues","mergeArrayOfSchemaDefinitions","createMerger","intersectJson","createIntersector","deduplicateJsonSchemaDef","createDeduplicator","createShallowAllOfMerge","OBJECT_SHAPE_KEYWORDS","kw"],"mappings":"oGA+xBaA,qDAAAA,8CA3xBN,+CAIA,qEAQwB,gDAOxB,kMA6BP,SAASC,iBACRC,CAAwB,CACxBC,CAAwB,EAExB,GAAI,OAAOD,IAAM,WAAa,OAAOC,IAAM,UAAW,OAAO,MAE7D,MAAMC,UAAYC,GAAAA,eAAM,EAACH,EAAG,SAC5B,MAAMI,UAAYD,GAAAA,eAAM,EAACF,EAAG,SAC5B,MAAMI,OAAS,AAACL,EAA8BM,KAAK,CACnD,MAAMC,OAAS,AAACN,EAA8BK,KAAK,CACnD,MAAME,MAAQR,EAAES,IAAI,CACpB,MAAMC,MAAQT,EAAEQ,IAAI,CAGpB,GAAIP,WAAaE,UAAW,CAC3B,MAAO,CAACO,GAAAA,kBAAS,EAACN,OAAQE,OAC3B,CAGA,GAAIL,WAAaU,MAAMC,OAAO,CAACH,OAAQ,CACtC,MAAO,CAACA,MAAMI,IAAI,CAAC,AAACC,GAAMJ,GAAAA,kBAAS,EAACI,EAAGV,QACxC,CACA,GAAID,WAAaQ,MAAMC,OAAO,CAACL,OAAQ,CACtC,MAAO,CAACA,MAAMM,IAAI,CAAC,AAACC,GAAMJ,GAAAA,kBAAS,EAACI,EAAGR,QACxC,CAEA,OAAO,KACR,CAGA,MAAMS,4BAA8B,CACnC,QACA,uBACA,WACA,gBACA,MACA,CAGD,MAAMC,6BAA+B,CACpC,aACA,oBACA,CAcD,SAASC,qBACRlB,CAAwB,CACxBC,CAAwB,EAExB,GAAIF,iBAAiBC,EAAGC,GAAI,OAAO,KAEnC,GAAI,OAAOD,IAAM,WAAa,OAAOC,IAAM,UAAW,OAAO,MAG7D,IAAK,MAAMkB,OAAOH,4BAA6B,CAC9C,MAAMI,KAAO,AAACpB,CAA6B,CAACmB,IAAI,CAGhD,MAAME,KAAO,AAACpB,CAA6B,CAACkB,IAAI,CAGhD,GACCG,GAAAA,mBAAU,EAACF,OACXE,GAAAA,mBAAU,EAACD,OACXH,qBACCE,KACAC,MAEA,CACD,OAAO,IACR,CACD,CAGA,IAAK,MAAMF,OAAOF,6BAA8B,CAC/C,MAAMM,KAAO,AAACvB,CAA6B,CAACmB,IAAI,CAGhD,MAAMK,KAAO,AAACvB,CAA6B,CAACkB,IAAI,CAGhD,GAAI,CAACG,GAAAA,mBAAU,EAACC,OAAS,CAACD,GAAAA,mBAAU,EAACE,MAAO,SAC5C,MAAMC,SAAWF,KACjB,MAAMG,SAAWF,KACjB,IAAK,MAAMG,WAAWC,OAAOC,IAAI,CAACJ,UAAW,CAC5C,MAAML,KAAOK,QAAQ,CAACE,QAAQ,CAC9B,MAAMN,KAAOK,QAAQ,CAACC,QAAQ,CAC9B,GACCP,OAASU,WACTT,OAASS,WACT3B,GAAAA,eAAM,EAACuB,SAAUC,UACjBT,qBAAqBE,KAAMC,MAC1B,CACD,OAAO,IACR,CACD,CACD,CAGA,GAAIT,MAAMC,OAAO,CAACb,EAAE+B,KAAK,GAAKnB,MAAMC,OAAO,CAACZ,EAAE8B,KAAK,EAAG,CACrD,MAAMC,OAAShC,EAAE+B,KAAK,CACtB,MAAME,OAAShC,EAAE8B,KAAK,CACtB,MAAMG,IAAMC,KAAKC,GAAG,CAACJ,OAAOK,MAAM,CAAEJ,OAAOI,MAAM,EACjD,IAAK,IAAIC,EAAI,EAAGA,EAAIJ,IAAKI,IAAK,CAC7B,MAAMC,MAAQP,MAAM,CAACM,EAAE,CACvB,MAAME,MAAQP,MAAM,CAACK,EAAE,CACvB,GAAIC,QAAUT,WAAaU,QAAUV,UAAW,SAChD,GAAIZ,qBAAqBqB,MAAOC,OAAQ,CACvC,OAAO,IACR,CACD,CACD,CAEA,OAAO,KACR,CAoCA,SAASC,gCACRzC,CAAwB,CACxBC,CAAwB,EAExB,GAAI,OAAOD,IAAM,WAAa,OAAOC,IAAM,UAAW,OAAO,MAE7D,MAAMyC,OAASpB,GAAAA,mBAAU,EAACtB,EAAE2C,UAAU,EAClC3C,EAAE2C,UAAU,CACbb,UACH,MAAMc,OAAStB,GAAAA,mBAAU,EAACrB,EAAE0C,UAAU,EAClC1C,EAAE0C,UAAU,CACbb,UAGH,GAAI,CAACY,QAAU,CAACE,OAAQ,OAAO,MAE/B,MAAMC,MAAQH,OAASd,OAAOC,IAAI,CAACa,QAAU,EAAE,CAC/C,MAAMI,MAAQF,OAAShB,OAAOC,IAAI,CAACe,QAAU,EAAE,CAC/C,MAAMG,UAAYnC,MAAMC,OAAO,CAACb,EAAEgD,QAAQ,EAAKhD,EAAEgD,QAAQ,CAAgB,EAAE,CAC3E,MAAMC,UAAYrC,MAAMC,OAAO,CAACZ,EAAE+C,QAAQ,EAAK/C,EAAE+C,QAAQ,CAAgB,EAAE,CAM3E,GAAIhD,EAAEkD,oBAAoB,GAAK,OAASR,QAAUE,OAAQ,CACzD,MAAMO,iBAAmBF,UAAUnC,IAAI,CACtC,AAACsC,GAAM,CAACjD,GAAAA,eAAM,EAACuC,OAAQU,IAAMjD,GAAAA,eAAM,EAACyC,OAAQQ,IAI7C,GAAID,kBAAoBN,MAAMR,MAAM,CAAG,EAAG,OAAO,IAClD,CAKA,GACCf,GAAAA,mBAAU,EAACtB,EAAEkD,oBAAoB,GACjC,OAAOlD,EAAEkD,oBAAoB,GAAK,WAClCR,QACAE,OACC,CACD,MAAMS,eAAiBrD,EAAEkD,oBAAoB,CAC7C,GAAI/C,GAAAA,eAAM,EAACkD,eAAgB,QAAS,CACnC,MAAMC,aAAeD,eAAeE,IAAI,CACxC,MAAMC,gBAAkBP,UAAUnC,IAAI,CAAC,AAACsC,IACvC,GAAIjD,GAAAA,eAAM,EAACuC,OAAQU,GAAI,OAAO,MAC9B,GAAI,CAACjD,GAAAA,eAAM,EAACyC,OAAQQ,GAAI,OAAO,MAC/B,MAAMK,SAAWb,MAAM,CAACQ,EAAE,CAC1B,GAAI,OAAOK,WAAa,UAAW,OAAO,MAC1C,MAAMC,MAAQD,SACd,GAAI,CAACtD,GAAAA,eAAM,EAACuD,MAAO,QAAS,OAAO,MACnC,GACC,OAAOJ,eAAiB,UACxB,OAAOI,MAAMH,IAAI,GAAK,SACrB,CACD,OACCD,eAAiBI,MAAMH,IAAI,EAC3B,CAAED,CAAAA,eAAiB,UAAYI,MAAMH,IAAI,GAAK,SAAQ,GACtD,CAAED,CAAAA,eAAiB,WAAaI,MAAMH,IAAI,GAAK,QAAO,CAExD,CACA,OAAO,KACR,GACA,GAAIC,gBAAiB,OAAO,IAC7B,CACD,CAGA,GAAIvD,EAAEiD,oBAAoB,GAAK,OAASN,QAAUF,OAAQ,CACzD,MAAMS,iBAAmBJ,UAAUjC,IAAI,CACtC,AAACsC,GAAM,CAACjD,GAAAA,eAAM,EAACyC,OAAQQ,IAAMjD,GAAAA,eAAM,EAACuC,OAAQU,IAE7C,GAAID,kBAAoBL,MAAMT,MAAM,CAAG,EAAG,OAAO,IAClD,CAGA,GACCf,GAAAA,mBAAU,EAACrB,EAAEiD,oBAAoB,GACjC,OAAOjD,EAAEiD,oBAAoB,GAAK,WAClCN,QACAF,OACC,CACD,MAAMW,eAAiBpD,EAAEiD,oBAAoB,CAC7C,GAAI/C,GAAAA,eAAM,EAACkD,eAAgB,QAAS,CACnC,MAAMC,aAAeD,eAAeE,IAAI,CACxC,MAAMC,gBAAkBT,UAAUjC,IAAI,CAAC,AAACsC,IACvC,GAAIjD,GAAAA,eAAM,EAACyC,OAAQQ,GAAI,OAAO,MAC9B,GAAI,CAACjD,GAAAA,eAAM,EAACuC,OAAQU,GAAI,OAAO,MAC/B,MAAMO,SAAWjB,MAAM,CAACU,EAAE,CAC1B,GAAI,OAAOO,WAAa,UAAW,OAAO,MAC1C,MAAMC,MAAQD,SACd,GAAI,CAACxD,GAAAA,eAAM,EAACyD,MAAO,QAAS,OAAO,MACnC,GACC,OAAON,eAAiB,UACxB,OAAOM,MAAML,IAAI,GAAK,SACrB,CACD,OACCD,eAAiBM,MAAML,IAAI,EAC3B,CAAED,CAAAA,eAAiB,UAAYM,MAAML,IAAI,GAAK,SAAQ,GACtD,CAAED,CAAAA,eAAiB,WAAaM,MAAML,IAAI,GAAK,QAAO,CAExD,CACA,OAAO,KACR,GACA,GAAIC,gBAAiB,OAAO,IAC7B,CACD,CAKA,GAAId,QAAUE,OAAQ,CACrB,IAAK,MAAMQ,KAAKP,MAAO,CACtB,GAAI,CAAC1C,GAAAA,eAAM,EAACyC,OAAQQ,GAAI,SACxB,MAAMO,SAAWjB,MAAM,CAACU,EAAE,CAC1B,MAAMK,SAAWb,MAAM,CAACQ,EAAE,CAC1B,GAAI,OAAOO,WAAa,WAAa,OAAOF,WAAa,UACxD,SACD,GACChB,gCACCkB,SACAF,UAEA,CACD,OAAO,IACR,CACD,CACD,CAEA,OAAO,KACR,CAsBA,SAASI,kBACR7D,CAAwB,CACxBC,CAAwB,EAExB,GAAI,OAAOD,IAAM,WAAa,OAAOC,IAAM,UAAW,OAAO,MAI7D,GAAIE,GAAAA,eAAM,EAACH,EAAG,WAAaG,GAAAA,eAAM,EAACF,EAAG,UAAW,CAC/C,MAAM6D,QAAU9D,EAAE+D,MAAM,CACxB,MAAMC,QAAU/D,EAAE8D,MAAM,CAGxB,GAAID,UAAYE,QAAS,CAExB,MAAMC,YAAcC,GAAAA,iCAAc,EAACJ,QAASE,SAC5C,GAAIC,cAAgB,KAAM,CACzB,MAAME,aAAeD,GAAAA,iCAAc,EAACF,QAASF,SAC7C,GAAIK,eAAiB,KAAM,CAE1B,OAAO,IACR,CACD,CACD,CACD,CAIA,GAAI7C,GAAAA,mBAAU,EAACtB,EAAE2C,UAAU,GAAKrB,GAAAA,mBAAU,EAACrB,EAAE0C,UAAU,EAAG,CACzD,MAAMpB,KAAOvB,EAAE2C,UAAU,CACzB,MAAMnB,KAAOvB,EAAE0C,UAAU,CACzB,IAAK,MAAMS,KAAKxB,OAAOC,IAAI,CAACN,MAAO,CAClC,MAAMH,KAAOG,IAAI,CAAC6B,EAAE,CACpB,MAAM/B,KAAOG,IAAI,CAAC4B,EAAE,CACpB,GACChC,OAASU,WACTT,OAASS,WACT3B,GAAAA,eAAM,EAACqB,KAAM4B,IACbS,kBAAkBzC,KAAMC,MACvB,CACD,OAAO,IACR,CACD,CACD,CAGA,GAAIC,GAAAA,mBAAU,EAACtB,EAAE+B,KAAK,GAAKT,GAAAA,mBAAU,EAACrB,EAAE8B,KAAK,EAAG,CAC/C,GACC8B,kBACC7D,EAAE+B,KAAK,CACP9B,EAAE8B,KAAK,EAGR,OAAO,IACT,CAGA,GACCT,GAAAA,mBAAU,EAACtB,EAAEkD,oBAAoB,GACjC5B,GAAAA,mBAAU,EAACrB,EAAEiD,oBAAoB,EAChC,CACD,GACCW,kBACC7D,EAAEkD,oBAAoB,CACtBjD,EAAEiD,oBAAoB,EAGvB,OAAO,IACT,CAEA,OAAO,KACR,CAgBA,SAASkB,uBAAuBC,MAA6B,EAC5D,GAAI,OAAOA,SAAW,UAAW,OAAO,MAExC,GAAIlE,GAAAA,eAAM,EAACkE,OAAQ,gBAAkBA,OAAOC,WAAW,GAAKxC,UAAW,CACtE,OAAO,IACR,CAEA,GAAIR,GAAAA,mBAAU,EAAC+C,OAAO1B,UAAU,EAAG,CAClC,MAAM4B,MAAQF,OAAO1B,UAAU,CAC/B,IAAK,MAAMxB,OAAOS,OAAOC,IAAI,CAAC0C,OAAQ,CACrC,MAAMC,KAAOD,KAAK,CAACpD,IAAI,CACvB,GAAIqD,OAAS1C,WAAasC,uBAAuBI,MAAO,OAAO,IAChE,CACD,CAEA,GAAIlD,GAAAA,mBAAU,EAAC+C,OAAOI,iBAAiB,EAAG,CACzC,MAAMC,GAAKL,OAAOI,iBAAiB,CAInC,IAAK,MAAMtD,OAAOS,OAAOC,IAAI,CAAC6C,IAAK,CAClC,MAAMC,IAAMD,EAAE,CAACvD,IAAI,CACnB,GAAIwD,MAAQ7C,WAAasC,uBAAuBO,KAAM,OAAO,IAC9D,CACD,CAEA,GAAI/D,MAAMC,OAAO,CAACwD,OAAOtC,KAAK,EAAG,CAChC,IAAK,MAAM6C,QAAQP,OAAOtC,KAAK,CAA6B,CAC3D,GAAI6C,OAAS9C,WAAasC,uBAAuBQ,MAAO,OAAO,IAChE,CACD,MAAO,GAAItD,GAAAA,mBAAU,EAAC+C,OAAOtC,KAAK,EAAG,CACpC,GAAIqC,uBAAuBC,OAAOtC,KAAK,EACtC,OAAO,IACT,CAEA,GAAIT,GAAAA,mBAAU,EAAC+C,OAAOnB,oBAAoB,EAAG,CAC5C,GACCkB,uBACCC,OAAOnB,oBAAoB,EAG5B,OAAO,IACT,CAEA,GAAI5B,GAAAA,mBAAU,EAAC+C,OAAOQ,YAAY,EAAG,CACpC,MAAMC,KAAOT,OAAOQ,YAAY,CAIhC,IAAK,MAAM1D,OAAOS,OAAOC,IAAI,CAACiD,MAAO,CACpC,MAAMH,IAAMG,IAAI,CAAC3D,IAAI,CACrB,GACCwD,MAAQ7C,WACR,CAAClB,MAAMC,OAAO,CAAC8D,MACfP,uBAAuBO,KAEvB,OAAO,IACT,CACD,CAEA,OAAO,KACR,CAmBA,SAASI,sBACRC,MAA6B,CAC7BhF,CAAwB,CACxBC,CAAwB,EAExB,GAAI,OAAO+E,SAAW,UAAW,OAAOA,OACxC,GAAI,OAAOhF,IAAM,WAAa,OAAOC,IAAM,UAAW,OAAO+E,OAM7D,GAAI,CAACZ,uBAAuBpE,IAAM,CAACoE,uBAAuBnE,GAAI,CAC7D,OAAO+E,MACR,CAEA,IAAIC,QAAU,MACd,MAAMC,OAAS,CAAE,GAAGF,MAAM,AAAC,EAG3B,MAAMG,kBAAoBC,GAAAA,yBAAgB,EAACpF,EAAEsE,WAAW,CAAErE,EAAEqE,WAAW,EACvE,MAAMe,mBAAqBH,OAAOZ,WAAW,CAE7C,GAAIa,oBAAsBrD,UAAW,CACpC,GAAI,CAACnB,GAAAA,kBAAS,EAAC0E,mBAAoBF,mBAAoB,CACtDD,OAAOZ,WAAW,CAAGa,kBACrBF,QAAU,IACX,CACD,MAAO,GAAII,qBAAuBvD,UAAW,CAC5C,OAAOoD,OAAOZ,WAAW,CACzBW,QAAU,IACX,CAGA,GACC3D,GAAAA,mBAAU,EAAC4D,OAAOvC,UAAU,GAC3BrB,CAAAA,GAAAA,mBAAU,EAACtB,EAAE2C,UAAU,GAAKrB,GAAAA,mBAAU,EAACrB,EAAE0C,UAAU,CAAA,EACnD,CACD,MAAM2C,YAAcJ,OAAOvC,UAAU,CAIrC,MAAMD,OAAU1C,EAAE2C,UAAU,EAAI,CAAC,EAIjC,MAAMC,OAAU3C,EAAE0C,UAAU,EAAI,CAAC,EAKjC,IAAI4C,aAAe,MACnB,MAAMC,SAAkD,CAAC,EAEzD,IAAK,MAAMrE,OAAOS,OAAOC,IAAI,CAACyD,aAAc,CAC3C,MAAMG,MAAQH,WAAW,CAACnE,IAAI,CAC9B,MAAMyC,MAAQlB,MAAM,CAACvB,IAAI,CACzB,MAAMuC,MAAQd,MAAM,CAACzB,IAAI,CAEzB,GAAIsE,QAAU3D,UAAW,SAGzB,GACC8B,QAAU9B,WACV4B,QAAU5B,WACV,OAAO2D,QAAU,WACjB,OAAO7B,QAAU,WACjB,OAAOF,QAAU,UAChB,CACD,MAAMgC,QAAUX,sBAAsBU,MAAO7B,MAAOF,MACpD8B,CAAAA,QAAQ,CAACrE,IAAI,CAAGuE,QAChB,GAAIA,UAAYD,MAAOF,aAAe,IACvC,KAAO,CACNC,QAAQ,CAACrE,IAAI,CAAGsE,KACjB,CACD,CAEA,GAAIF,aAAc,CACjBL,OAAOvC,UAAU,CAAG6C,SACpBP,QAAU,IACX,CACD,CAGA,GAAI3D,GAAAA,mBAAU,EAAC4D,OAAOnD,KAAK,GAAKT,GAAAA,mBAAU,EAACtB,EAAE+B,KAAK,GAAKT,GAAAA,mBAAU,EAACrB,EAAE8B,KAAK,EAAG,CAC3E,MAAM2D,QAAUX,sBACfG,OAAOnD,KAAK,CACZ/B,EAAE+B,KAAK,CACP9B,EAAE8B,KAAK,EAER,GAAI2D,UAAYR,OAAOnD,KAAK,CAAE,CAC7BmD,OAAOnD,KAAK,CAAG2D,QACfT,QAAU,IACX,CACD,CAGA,GACC3D,GAAAA,mBAAU,EAAC4D,OAAOT,iBAAiB,GAClCnD,CAAAA,GAAAA,mBAAU,EAACtB,EAAEyE,iBAAiB,GAAKnD,GAAAA,mBAAU,EAACrB,EAAEwE,iBAAiB,CAAA,EACjE,CACD,MAAMkB,SAAWT,OAAOT,iBAAiB,CAIzC,MAAMmB,IAAO5F,EAAEyE,iBAAiB,EAAI,CAAC,EAIrC,MAAMoB,IAAO5F,EAAEwE,iBAAiB,EAAI,CAAC,EAKrC,IAAIqB,UAAY,MAChB,MAAMC,MAA+C,CAAC,EAEtD,IAAK,MAAM5E,OAAOS,OAAOC,IAAI,CAAC8D,UAAW,CACxC,MAAMK,KAAOL,QAAQ,CAACxE,IAAI,CAC1B,MAAMC,KAAOwE,GAAG,CAACzE,IAAI,CACrB,MAAME,KAAOwE,GAAG,CAAC1E,IAAI,CAErB,GAAI6E,OAASlE,UAAW,SAExB,GACCV,OAASU,WACTT,OAASS,WACT,OAAOkE,OAAS,WAChB,OAAO5E,OAAS,WAChB,OAAOC,OAAS,UACf,CACD,MAAMqE,QAAUX,sBAAsBiB,KAAM5E,KAAMC,KAClD0E,CAAAA,KAAK,CAAC5E,IAAI,CAAGuE,QACb,GAAIA,UAAYM,KAAMF,UAAY,IACnC,KAAO,CACNC,KAAK,CAAC5E,IAAI,CAAG6E,IACd,CACD,CAEA,GAAIF,UAAW,CACdZ,OAAOT,iBAAiB,CAAGsB,MAC3Bd,QAAU,IACX,CACD,CAGA,GACCrE,MAAMC,OAAO,CAACqE,OAAOnD,KAAK,GAC1BnB,MAAMC,OAAO,CAACb,EAAE+B,KAAK,GACrBnB,MAAMC,OAAO,CAACZ,EAAE8B,KAAK,EACpB,CACD,MAAMkE,YAAcf,OAAOnD,KAAK,CAChC,MAAMC,OAAShC,EAAE+B,KAAK,CACtB,MAAME,OAAShC,EAAE8B,KAAK,CACtB,MAAMG,IAAM+D,YAAY5D,MAAM,CAE9B,IAAI6D,aAAe,MACnB,MAAMC,SAAoC,IAAIvF,MAAMsB,KAEpD,IAAK,IAAII,EAAI,EAAGA,EAAIJ,IAAKI,IAAK,CAC7B,MAAM8D,MAAQH,WAAW,CAAC3D,EAAE,CAC5B,MAAMC,MAAQP,MAAM,CAACM,EAAE,CACvB,MAAME,MAAQP,MAAM,CAACK,EAAE,CAEvB,GACC8D,QAAUtE,WACVS,QAAUT,WACVU,QAAUV,WACV,OAAOsE,QAAU,WACjB,OAAO7D,QAAU,WACjB,OAAOC,QAAU,UAChB,CACD,MAAMkD,QAAUX,sBAAsBqB,MAAO7D,MAAOC,MACpD2D,CAAAA,QAAQ,CAAC7D,EAAE,CAAGoD,QACd,GAAIA,UAAYU,MAAOF,aAAe,IACvC,KAAO,CACNC,QAAQ,CAAC7D,EAAE,CAAG8D,KACf,CACD,CAEA,GAAIF,aAAc,CACjBhB,OAAOnD,KAAK,CAAGoE,SACflB,QAAU,IACX,CACD,CAGA,GACC3D,GAAAA,mBAAU,EAAC4D,OAAOhC,oBAAoB,GACtC5B,GAAAA,mBAAU,EAACtB,EAAEkD,oBAAoB,GACjC5B,GAAAA,mBAAU,EAACrB,EAAEiD,oBAAoB,EAChC,CACD,MAAMwC,QAAUX,sBACfG,OAAOhC,oBAAoB,CAC3BlD,EAAEkD,oBAAoB,CACtBjD,EAAEiD,oBAAoB,EAEvB,GAAIwC,UAAYR,OAAOhC,oBAAoB,CAAE,CAC5CgC,OAAOhC,oBAAoB,CAAGwC,QAC9BT,QAAU,IACX,CACD,CAGA,GACC3D,GAAAA,mBAAU,EAAC4D,OAAOL,YAAY,GAC7BvD,CAAAA,GAAAA,mBAAU,EAACtB,EAAE6E,YAAY,GAAKvD,GAAAA,mBAAU,EAACrB,EAAE4E,YAAY,CAAA,EACvD,CACD,MAAMwB,WAAanB,OAAOL,YAAY,CAItC,MAAMyB,MAAStG,EAAE6E,YAAY,EAAI,CAAC,EAIlC,MAAM0B,MAAStG,EAAE4E,YAAY,EAAI,CAAC,EAKlC,IAAI2B,YAAc,MAClB,MAAMC,QAA4D,CAAC,EAEnE,IAAK,MAAMtF,OAAOS,OAAOC,IAAI,CAACwE,YAAa,CAC1C,MAAML,KAAOK,UAAU,CAAClF,IAAI,CAC5B,MAAMC,KAAOkF,KAAK,CAACnF,IAAI,CACvB,MAAME,KAAOkF,KAAK,CAACpF,IAAI,CAEvB,GAAI6E,OAASlE,UAAW,SAGxB,GACCV,OAASU,WACTT,OAASS,WACT,CAAClB,MAAMC,OAAO,CAACmF,OACf,CAACpF,MAAMC,OAAO,CAACO,OACf,CAACR,MAAMC,OAAO,CAACQ,OACf,OAAO2E,OAAS,WAChB,OAAO5E,OAAS,WAChB,OAAOC,OAAS,UACf,CACD,MAAMqE,QAAUX,sBACfiB,KACA5E,KACAC,KAEDoF,CAAAA,OAAO,CAACtF,IAAI,CAAGuE,QACf,GAAIA,UAAYM,KAAMQ,YAAc,IACrC,KAAO,CACNC,OAAO,CAACtF,IAAI,CAAG6E,IAChB,CACD,CAEA,GAAIQ,YAAa,CAChBtB,OAAOL,YAAY,CAAG4B,QACtBxB,QAAU,IACX,CACD,CAEA,OAAOA,QAAUC,OAASF,MAC3B,CAIO,MAAMlF,YA6CZ4G,MACC1G,CAAwB,CACxBC,CAAwB,CACO,CAI/B,GAAID,IAAMC,EAAG,OAAOD,EACpB,GAAIA,IAAM,OAASC,IAAM,MAAO,OAAO,MACvC,GAAID,IAAM,KAAM,OAAOC,EACvB,GAAIA,IAAM,KAAM,OAAOD,EAGvB,GAAIkB,qBAAqBlB,EAAGC,GAAI,CAC/B,OAAO,IACR,CAGA,GAAI4D,kBAAkB7D,EAAGC,GAAI,CAC5B,OAAO,IACR,CAOA,GAAIwC,gCAAgCzC,EAAGC,GAAI,CAC1C,OAAO,IACR,CAEA,GAAI,CACH,MAAMiF,OAAS,IAAI,CAACyB,mBAAmB,CAAC,CAAEC,MAAO,CAAC5G,EAAGC,EAAE,AAAC,GAGxD,OAAO8E,sBAAsBG,OAAQlF,EAAGC,EACzC,CAAE,KAAM,CACP,OAAO,IACR,CACD,CAQA4G,aACC7G,CAAwB,CACxBC,CAAwB,CACA,CAIxB,GAAID,IAAMC,EAAG,OAAOD,EACpB,GAAIA,IAAM,OAASC,IAAM,MAAO,OAAO,MACvC,GAAID,IAAM,KAAM,OAAOC,EACvB,GAAIA,IAAM,KAAM,OAAOD,EAGvB,GAAIkB,qBAAqBlB,EAAGC,GAAI,CAC/B,MAAM,IAAI6G,MACT,wEAEF,CAGA,GAAIjD,kBAAkB7D,EAAGC,GAAI,CAC5B,MAAM,IAAI6G,MACT,0EAEF,CAGA,GAAIrE,gCAAgCzC,EAAGC,GAAI,CAC1C,MAAM,IAAI6G,MACT,uGAEF,CAEA,MAAM5B,OAAS,IAAI,CAACyB,mBAAmB,CAAC,CAAEC,MAAO,CAAC5G,EAAGC,EAAE,AAAC,GAExD,OAAO8E,sBAAsBG,OAAQlF,EAAGC,EACzC,CAMA8G,QAAQ/G,CAAwB,CAAEC,CAAwB,CAAU,CACnE,OAAO,IAAI,CAAC+G,SAAS,CAAChH,EAAGC,EAC1B,CAKAgH,QAAQjH,CAAwB,CAAEC,CAAwB,CAAW,CACpE,OAAO,IAAI,CAAC+G,SAAS,CAAChH,EAAGC,KAAO,CACjC,CA8FAiH,QACCC,IAA2B,CAC3BC,QAA+B,CACP,CAGxB,GAAIA,WAAa,MAAO,OAAO,MAE/B,GAAIA,WAAa,KAAM,OAAO,KAE9B,GAAI,OAAOD,OAAS,UAAW,OAAOC,SAEtC,MAAMC,QAAUF,KAChB,MAAMG,YAAcF,SAKpB,GAAI,CAACG,aAAaF,UAAY,CAACE,aAAaD,aAAc,CACzD,OAAOF,QACR,CAGA,GAAI,CAACG,aAAaF,SAAU,CAC3B,OAAOD,QACR,CAIA,GAAI,CAACG,aAAaD,aAAc,CAC/B,OAAOF,QACR,CAGA,MAAMI,UAAaH,QAAQ1E,UAAU,EAAI,CAAC,EAI1C,MAAM8E,cAAiBH,YAAY3E,UAAU,EAAI,CAAC,EAOlD,MAAM2C,YAAqD,CAAC,EAG5D,IAAK,MAAMnE,OAAOS,OAAOC,IAAI,CAAC2F,WAAY,CACzC,MAAME,SAAWF,SAAS,CAACrG,IAAI,CAC/B,GAAIuG,WAAa5F,UAAW,QAC5BwD,CAAAA,WAAW,CAACnE,IAAI,CAAGuG,QACpB,CAGA,IAAK,MAAMvG,OAAOS,OAAOC,IAAI,CAAC4F,eAAgB,CAC7C,MAAME,aAAeF,aAAa,CAACtG,IAAI,CACvC,GAAIwG,eAAiB7F,UAAW,SAEhC,MAAM4F,SAAWF,SAAS,CAACrG,IAAI,CAI/B,GACCuG,WAAa5F,WACb,OAAO4F,WAAa,WACpB,OAAOC,eAAiB,WACxBJ,aAAaG,WACbH,aAAaI,cACZ,CACDrC,WAAW,CAACnE,IAAI,CAAG,IAAI,CAAC+F,OAAO,CAACQ,SAAUC,aAC3C,KAAO,CAENrC,WAAW,CAACnE,IAAI,CAAGwG,YACpB,CACD,CAGA,MAAMC,aAAehH,MAAMC,OAAO,CAACwG,QAAQrE,QAAQ,EAChDqE,QAAQrE,QAAQ,CAChB,EAAE,CACL,MAAM6E,iBAAmBjH,MAAMC,OAAO,CAACyG,YAAYtE,QAAQ,EACxDsE,YAAYtE,QAAQ,CACpB,EAAE,CACL,MAAM8E,eAAiBC,GAAAA,qBAAY,EAACH,aAAcC,kBAGlD,MAAM3C,OAAsB,CAAE,GAAGmC,OAAO,AAAC,CAGzCnC,CAAAA,OAAOvC,UAAU,CAAG2C,YAGpB,GAAIwC,eAAezF,MAAM,CAAG,EAAG,CAC9B6C,OAAOlC,QAAQ,CAAG8E,cACnB,KAAO,CACN,OAAO5C,OAAOlC,QAAQ,AACvB,CAGA,GAAI7C,GAAAA,eAAM,EAACmH,YAAa,wBAAyB,CAChDpC,OAAOhC,oBAAoB,CAAGoE,YAAYpE,oBAAoB,AAC/D,CACA,GAAI/C,GAAAA,eAAM,EAACmH,YAAa,iBAAkB,CACzCpC,OAAO8C,aAAa,CAAGV,YAAYU,aAAa,AACjD,CACA,GAAI7H,GAAAA,eAAM,EAACmH,YAAa,iBAAkB,CACzCpC,OAAO+C,aAAa,CAAGX,YAAYW,aAAa,AACjD,CACA,GAAI9H,GAAAA,eAAM,EAACmH,YAAa,iBAAkB,CACzCpC,OAAOgD,aAAa,CAAGZ,YAAYY,aAAa,AACjD,CACA,GAAI/H,GAAAA,eAAM,EAACmH,YAAa,qBAAsB,CAC7CpC,OAAOT,iBAAiB,CAAG6C,YAAY7C,iBAAiB,AACzD,CACA,GAAItE,GAAAA,eAAM,EAACmH,YAAa,gBAAiB,CACxCpC,OAAOL,YAAY,CAAGyC,YAAYzC,YAAY,AAC/C,CAGA,GAAI1E,GAAAA,eAAM,EAACmH,YAAa,QAAS,CAChCpC,OAAO3B,IAAI,CAAG+D,YAAY/D,IAAI,AAC/B,CAEA,OAAO2B,MACR,CAhWA,aAAc,CATd,sBAAiB8B,YAAjB,KAAA,GAKA,sBAAiBL,sBAAjB,KAAA,GAKC,KAAM,CAAEwB,wBAAwB,CAAEC,mBAAmB,CAAE,CACtDC,GAAAA,iCAAgB,IAOjB,MAAMC,wBAA0B,CAC/BtI,EACAC,KAEA,GAAID,IAAM,MAAQC,IAAM,KAAM,OAAO,EACrC,OAAOmI,oBAAoBpI,EAAGC,EAC/B,EAEA,KAAM,CAAEsI,6BAA6B,CAAE,CAAGC,GAAAA,6BAAY,EAAC,CACtDC,cAAeC,GAAAA,wBAAiB,EAACJ,yBACjCK,yBAA0BC,GAAAA,yBAAkB,EAACT,yBAC9C,EAEA,CAAA,IAAI,CAACnB,SAAS,CAAGmB,wBACjB,CAAA,IAAI,CAACxB,mBAAmB,CAAGkC,GAAAA,wCAAuB,EACjDN,8BAEF,CAuUD,CAKA,MAAMO,sBAA+C,CACpD,aACA,oBACA,uBACA,WACA,eACA,gBACA,gBACA,gBACA,CAMD,SAASvB,aAAalD,MAAmB,EACxC,GAAIA,OAAOd,IAAI,GAAK,SAAU,OAAO,KACrC,IAAK,MAAMwF,MAAMD,sBAAuB,CACvC,GAAI3I,GAAAA,eAAM,EAACkE,OAAQ0E,IAAK,OAAO,IAChC,CACA,OAAO,KACR"}
|
|
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.ts\";\nimport { deepEqual, hasOwn, isPlainObj, unionStrings } from \"./utils.ts\";\n\n// ─── Merge Engine ────────────────────────────────────────────────────────────\n//\n// Wraps the `@x0k/json-schema-merge` library and exposes a simple API\n// for merging and comparing JSON Schemas.\n//\n// Mathematical principle:\n// A ∩ B = allOf([A, B]) resolved via shallow merge\n// A ≡ B ⟺ compare(A, B) === 0\n//\n// Pre-checks before merge:\n// - `hasDeepConstConflict`: detects `const`/`enum` conflicts\n// - `hasAdditionalPropertiesConflict`: detects `additionalProperties` conflicts\n// - `hasFormatConflict`: detects `format` conflicts between two schemas\n\n// ─── Const conflict detection ────────────────────────────────────────────────\n\n/**\n * Detects a `const` conflict between two schemas.\n *\n * Case 1 — const vs const: both schemas have a `const` with different\n * values → empty intersection.\n *\n * Case 2 — const vs enum: one schema has `const`, the other has `enum`.\n * If the `const` value is not in the `enum` → empty intersection.\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// Case 1 — const vs const\n\tif (aHasConst && bHasConst) {\n\t\treturn !deepEqual(aConst, bConst);\n\t}\n\n\t// Case 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/** Keywords containing a single sub-schema to check recursively */\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/** Keywords containing a Record<string, JSONSchema7Definition> */\nconst PROPERTIES_MAP_CONFLICT_KEYS = [\n\t\"properties\",\n\t\"patternProperties\",\n] as const;\n\n/**\n * Recursively detects `const` conflicts in sub-schemas.\n *\n * When the merge library performs a shallow merge, nested sub-schemas\n * can also have hidden `const` conflicts\n * (it uses `identity` for `const`).\n *\n * Recurses into:\n * - `properties`, `patternProperties` (common keys)\n * - `items` (single schema), tuple `items` (by 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 * Detects a conflict between `additionalProperties` and the extra\n * **required** properties of the other schema.\n *\n * ⚠️ This function is **ultra-conservative**: it only detects conflicts\n * where a property is simultaneously:\n * - FORBIDDEN by `additionalProperties: false` on one side\n * - REQUIRED (`required`) by the other side\n * - ABSENT from `properties` on the restrictive side\n * - AND the restrictive side ALSO has a `required` that makes the object non-empty\n * (otherwise the library already handles the case by excluding extra properties)\n *\n * The merge library (`@x0k/json-schema-merge`) ALREADY correctly handles\n * the `additionalProperties: false` case with properties that are merely DEFINED\n * (not required) in the other schema — it excludes them from the result.\n * We therefore only detect `required` contradictions that are impossible to resolve.\n *\n * Cases handled:\n * 1. `a` has `additionalProperties: false` and `b` REQUIRES properties\n * absent from `a.properties`, AND those properties are in `b.properties`\n * → certain conflict (empty intersection because b requires, a forbids)\n * 2. Symmetric for `b.additionalProperties: false`\n * 3. `additionalProperties` as a schema → check type compatibility\n * of extra REQUIRED properties only\n * 4. Recursion into common properties (sub-objects)\n *\n * ⚠️ Only checks keys from `properties`, not `patternProperties`\n * (too complex to resolve statically).\n *\n * Returns `true` if an obvious conflict is detected, `false` otherwise.\n * When in doubt → `false` (conservative, let the merge decide).\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// If neither has properties, we cannot determine anything\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// ── Check additionalProperties: false of a vs extra REQUIRED properties of b ──\n\t// Strict condition: b must DEFINE the property in b.properties AND\n\t// REQUIRE it in b.required, AND this property must be ABSENT from a.properties.\n\t// Additionally, a must itself have properties (otherwise we can't determine anything).\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// Only detect the conflict if a also has a required that makes the object\n\t\t// structurally constrained (not a vague schema)\n\t\tif (hasRequiredExtra && aKeys.length > 0) return true;\n\t}\n\n\t// ── Check for additionalProperties as a schema ──\n\t// If a.additionalProperties is a schema with a type, and b REQUIRES\n\t// an extra property whose type is incompatible → conflict\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// ── Symmetric check: additionalProperties of b vs extra REQUIRED properties of 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// Symmetric for additionalProperties as a 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// ── Recursion into common properties ──\n\t// If both schemas have common properties that are objects,\n\t// recursively check additionalProperties conflicts\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 * Detects a format conflict between two schemas.\n *\n * ⚠️ Only triggers when BOTH schemas have a `format`.\n * If only one schema has a `format`, there is NO conflict — the merge\n * engine handles this case natively (the format is preserved in the intersection,\n * and the `merged ≡ sub` comparison correctly determines the ⊆ relation).\n *\n * Two schemas with different formats and no known inclusion relation\n * have an empty intersection (e.g., \"email\" ∩ \"ipv4\" = ∅).\n *\n * Uses `isFormatSubset` from `format-validator.ts` to check the hierarchy.\n *\n * Recurses into sub-schemas (`properties`, `items`, etc.) to detect\n * nested format conflicts.\n *\n * @returns `true` if a format conflict is detected, `false` otherwise\n */\nfunction hasFormatConflict(\n\ta: JSONSchema7Definition,\n\tb: JSONSchema7Definition,\n): boolean {\n\tif (typeof a === \"boolean\" || typeof b === \"boolean\") return false;\n\n\t// ── Only when BOTH have a format ──\n\t// If only one has a format → no conflict, the merge handles it natively\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// Same format → no conflict\n\t\tif (aFormat !== bFormat) {\n\t\t\t// Check if one is a subset of the other via the hierarchy\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// Different formats with no known relation → conflict\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Recursion into sub-schemas ──\n\t// Check format conflicts in common properties\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// Check 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// Check 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 * Merges two schemas via `allOf([a, b])`.\n\t * Returns `null` if the schemas are incompatible.\n\t *\n\t * Post-merge: detects `const` conflicts that the library\n\t * does not capture (it uses `identity` for `const`).\n\t */\n\tmerge(\n\t\ta: JSONSchema7Definition,\n\t\tb: JSONSchema7Definition,\n\t): JSONSchema7Definition | null {\n\t\t// ── Trivial fast paths ──\n\t\t// Avoid expensive recursive conflict checks and external merge calls\n\t\t// for the most common identity/boolean intersection cases.\n\t\tif (a === b) return a;\n\t\tif (a === false || b === false) return false;\n\t\tif (a === true) return b;\n\t\tif (b === true) return a;\n\n\t\t// Pre-check: const conflict detectable before the merge\n\t\tif (hasDeepConstConflict(a, b)) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Pre-check: format conflict (BOTH have an incompatible format)\n\t\tif (hasFormatConflict(a, b)) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Pre-check: additionalProperties vs extra REQUIRED properties conflict\n\t\t// Only detects cases where a property is simultaneously forbidden\n\t\t// (additionalProperties: false) and required (required) → empty intersection.\n\t\t// Cases where properties are merely defined without being required\n\t\t// are handled correctly by the merge library itself.\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 * Merges via `shallowAllOfMerge` — throws an exception if incompatible.\n\t * Useful when you want to capture the error for diagnostics.\n\t *\n\t * Post-merge: detects `const` conflicts and throws an exception.\n\t */\n\tmergeOrThrow(\n\t\ta: JSONSchema7Definition,\n\t\tb: JSONSchema7Definition,\n\t): JSONSchema7Definition {\n\t\t// ── Trivial fast paths ──\n\t\t// Keep mergeOrThrow aligned with merge() for the common boolean/identity\n\t\t// intersections that can be resolved without touching the merge library.\n\t\tif (a === b) return a;\n\t\tif (a === false || b === false) return false;\n\t\tif (a === true) return b;\n\t\tif (b === true) return a;\n\n\t\t// Pre-check: const conflict\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// Pre-check: format conflict\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// Pre-check: additionalProperties vs extra REQUIRED properties conflict\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 * Structurally compares two schema definitions.\n\t * Returns 0 if they are identical, otherwise a non-zero integer.\n\t */\n\tcompare(a: JSONSchema7Definition, b: JSONSchema7Definition): number {\n\t\treturn this.compareFn(a, b);\n\t}\n\n\t/**\n\t * Checks structural equality between two 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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"}
|
package/dist/cjs/normalizer.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get inferType(){return inferType},get normalize(){return normalize}});const _utilsts=require("./utils.js");const normalizeCache=new WeakMap;function inferType(value){if(value===null)return"null";switch(typeof value){case"string":return"string";case"number":return Number.isInteger(value)?"integer":"number";case"boolean":return"boolean";case"object":return Array.isArray(value)?"array":"object";default:return undefined}}const SINGLE_SCHEMA_KEYWORDS=["additionalProperties","additionalItems","contains","propertyNames","not","if","then","else"];const METADATA_KEYWORDS=new Set(["$id","$schema","$comment","title","description","default","examples","definitions","$defs"]);function isPureNotSchema(schema){const schemaKeys=Object.keys(schema);return schemaKeys.every(k=>k==="not"||METADATA_KEYWORDS.has(k))}const ARRAY_SCHEMA_KEYWORDS=["anyOf","oneOf","allOf"];const PROPERTIES_LIKE_KEYWORDS=["properties","patternProperties"];function normalizePropertiesMap(props){const keys=Object.keys(props);let changed=false;for(let i=0;i<keys.length;i++){const key=keys[i];if(key===undefined)continue;const original=props[key];const normalized=normalize(original);if(normalized!==original){changed=true;break}}if(!changed)return props;const result={};for(let i=0;i<keys.length;i++){const key=keys[i];if(key===undefined)continue;result[key]=normalize(props[key])}return result}function inferTypeFromConst(schema){if(!(0,_utilsts.hasOwn)(schema,"const")||schema.type!==undefined)return undefined;const t=inferType(schema.const);return t?t:undefined}function inferTypeFromEnum(schema){if(!Array.isArray(schema.enum)||schema.type!==undefined)return undefined;const typesSet=new Set;for(const v of schema.enum){const t=inferType(v);if(t)typesSet.add(t)}const count=typesSet.size;if(count===0)return undefined;const types=Array.from(typesSet);if(count===1)return types[0];return types}function normalize(def){if(typeof def==="boolean")return def;const cached=normalizeCache.get(def);if(cached!==undefined)return cached;let schema=def;let copied=false;function ensureCopy(){if(!copied){schema={...def};copied=true}return schema}const typeFromConst=inferTypeFromConst(schema);if(typeFromConst){ensureCopy().type=typeFromConst}const typeFromEnum=inferTypeFromEnum(schema);if(typeFromEnum){ensureCopy().type=typeFromEnum}if(Array.isArray(schema.enum)&&schema.enum.length===1&&!(0,_utilsts.hasOwn)(schema,"const")){const s=ensureCopy();s.const=schema.enum[0];delete s.enum}if((0,_utilsts.hasOwn)(schema,"const")&&Array.isArray(schema.enum)){if(schema.enum.some(v=>(0,_utilsts.deepEqual)(v,schema.const))){delete ensureCopy().enum}}if((0,_utilsts.hasOwn)(schema,"constraints")&&schema.constraints!==undefined
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get inferType(){return inferType},get normalize(){return normalize}});const _utilsts=require("./utils.js");const normalizeCache=new WeakMap;function inferType(value){if(value===null)return"null";switch(typeof value){case"string":return"string";case"number":return Number.isInteger(value)?"integer":"number";case"boolean":return"boolean";case"object":return Array.isArray(value)?"array":"object";default:return undefined}}const SINGLE_SCHEMA_KEYWORDS=["additionalProperties","additionalItems","contains","propertyNames","not","if","then","else"];const METADATA_KEYWORDS=new Set(["$id","$schema","$comment","title","description","default","examples","definitions","$defs"]);function isPureNotSchema(schema){const schemaKeys=Object.keys(schema);return schemaKeys.every(k=>k==="not"||METADATA_KEYWORDS.has(k))}const ARRAY_SCHEMA_KEYWORDS=["anyOf","oneOf","allOf"];const PROPERTIES_LIKE_KEYWORDS=["properties","patternProperties"];function normalizePropertiesMap(props){const keys=Object.keys(props);let changed=false;for(let i=0;i<keys.length;i++){const key=keys[i];if(key===undefined)continue;const original=props[key];const normalized=normalize(original);if(normalized!==original){changed=true;break}}if(!changed)return props;const result={};for(let i=0;i<keys.length;i++){const key=keys[i];if(key===undefined)continue;result[key]=normalize(props[key])}return result}function inferTypeFromConst(schema){if(!(0,_utilsts.hasOwn)(schema,"const")||schema.type!==undefined)return undefined;const t=inferType(schema.const);return t?t:undefined}function inferTypeFromEnum(schema){if(!Array.isArray(schema.enum)||schema.type!==undefined)return undefined;const typesSet=new Set;for(const v of schema.enum){const t=inferType(v);if(t)typesSet.add(t)}const count=typesSet.size;if(count===0)return undefined;const types=Array.from(typesSet);if(count===1)return types[0];return types}function normalize(def){if(typeof def==="boolean")return def;const cached=normalizeCache.get(def);if(cached!==undefined)return cached;let schema=def;let copied=false;function ensureCopy(){if(!copied){schema={...def};copied=true}return schema}const typeFromConst=inferTypeFromConst(schema);if(typeFromConst){ensureCopy().type=typeFromConst}const typeFromEnum=inferTypeFromEnum(schema);if(typeFromEnum){ensureCopy().type=typeFromEnum}if(Array.isArray(schema.enum)&&schema.enum.length===1&&!(0,_utilsts.hasOwn)(schema,"const")){const s=ensureCopy();s.const=schema.enum[0];delete s.enum}if((0,_utilsts.hasOwn)(schema,"const")&&Array.isArray(schema.enum)){if(schema.enum.some(v=>(0,_utilsts.deepEqual)(v,schema.const))){delete ensureCopy().enum}}if((0,_utilsts.hasOwn)(schema,"constraints")&&schema.constraints!==undefined){const s=ensureCopy();delete s.constraints}for(const keyword of PROPERTIES_LIKE_KEYWORDS){const val=schema[keyword];if((0,_utilsts.isPlainObj)(val)){const normalized=normalizePropertiesMap(val);if(normalized!==val){ensureCopy()[keyword]=normalized}}}if((0,_utilsts.isPlainObj)(schema.dependencies)){const deps=schema.dependencies;const depsKeys=Object.keys(deps);let depsChanged=false;const newDeps={};for(let i=0;i<depsKeys.length;i++){const key=depsKeys[i];if(key===undefined)continue;const val=deps[key];if(val===undefined)continue;if(Array.isArray(val)){newDeps[key]=val}else if((0,_utilsts.isPlainObj)(val)){const normalized=normalize(val);newDeps[key]=normalized;if(normalized!==val)depsChanged=true}else{newDeps[key]=val}}if(depsChanged){ensureCopy().dependencies=newDeps}}if(schema.items){if(Array.isArray(schema.items)){const items=schema.items;let itemsChanged=false;const newItems=new Array(items.length);for(let i=0;i<items.length;i++){const original=items[i];if(original===undefined)continue;const normalized=normalize(original);newItems[i]=normalized;if(normalized!==original)itemsChanged=true}if(itemsChanged){ensureCopy().items=newItems}}else if((0,_utilsts.isPlainObj)(schema.items)){const normalized=normalize(schema.items);if(normalized!==schema.items){ensureCopy().items=normalized}}}for(const key of SINGLE_SCHEMA_KEYWORDS){const val=schema[key];if(val!==undefined&&typeof val!=="boolean"){const normalized=normalize(val);if(normalized!==val){ensureCopy()[key]=normalized}}}if((0,_utilsts.hasOwn)(schema,"not")&&(0,_utilsts.isPlainObj)(schema.not)&&typeof schema.not!=="boolean"){const notSchema=schema.not;if((0,_utilsts.hasOwn)(notSchema,"not")&&isPureNotSchema(notSchema)&&(0,_utilsts.isPlainObj)(notSchema.not)&&typeof notSchema.not!=="boolean"){const innerSchema=notSchema.not;const s=ensureCopy();delete s.not;const innerKeys=Object.keys(innerSchema);for(let i=0;i<innerKeys.length;i++){const ik=innerKeys[i];if(ik===undefined)continue;s[ik]=innerSchema[ik]}}}for(const key of ARRAY_SCHEMA_KEYWORDS){const val=schema[key];if(Array.isArray(val)){const arr=val;let arrChanged=false;const newArr=new Array(arr.length);for(let i=0;i<arr.length;i++){const original=arr[i];if(original===undefined)continue;const normalized=normalize(original);newArr[i]=normalized;if(normalized!==original)arrChanged=true}if(arrChanged){ensureCopy()[key]=newArr}}}const result=copied?schema:def;normalizeCache.set(def,result);return result}
|
|
2
2
|
//# sourceMappingURL=normalizer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/normalizer.ts"],"sourcesContent":["import type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\nimport { deepEqual, hasOwn, isPlainObj } from \"./utils.ts\";\n\n// ─── Schema Normalizer ───────────────────────────────────────────────────────\n//\n// Pure functions to normalize a JSON Schema:\n// - Infer `type` from `const` or `enum`\n// - Recurse into all sub-structures (properties, items, anyOf, etc.)\n// - Resolve double negation `not.not` → flatten to direct content\n// - Recurse into `patternProperties` (Point 2)\n// - Recurse into `dependencies` schema form (Point 3)\n//\n// Optimizations:\n// - WeakMap cache to avoid re-normalizing the same object\n// - Lazy copy-on-write: only creates a copy when mutations are needed\n// - Returns the original if nothing changed (avoids allocations)\n\n// ─── Normalization Cache ─────────────────────────────────────────────────────\n\n/**\n * WeakMap cache for normalization results.\n * Avoids re-normalizing the same schema object multiple times.\n * WeakMap allows the GC to collect schemas that are no longer referenced.\n */\nconst normalizeCache = new WeakMap<object, JSONSchema7Definition>();\n\n// ─── Type inference ──────────────────────────────────────────────────────────\n\n/**\n * Infers the JSON Schema type from a JavaScript value.\n */\nexport function inferType(value: unknown): string | undefined {\n\tif (value === null) return \"null\";\n\tswitch (typeof value) {\n\t\tcase \"string\":\n\t\t\treturn \"string\";\n\t\tcase \"number\":\n\t\t\treturn Number.isInteger(value) ? \"integer\" : \"number\";\n\t\tcase \"boolean\":\n\t\t\treturn \"boolean\";\n\t\tcase \"object\":\n\t\t\treturn Array.isArray(value) ? \"array\" : \"object\";\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\n// ─── Sub-schema keywords ─────────────────────────────────────────────────────\n\n/** Keywords containing a single sub-schema */\nconst SINGLE_SCHEMA_KEYWORDS = [\n\t\"additionalProperties\",\n\t\"additionalItems\",\n\t\"contains\",\n\t\"propertyNames\",\n\t\"not\",\n\t\"if\",\n\t\"then\",\n\t\"else\",\n] as const;\n\n/**\n * Checks whether a schema contains only the `not` keyword (and no other\n * significant keyword). Used for double negation resolution.\n *\n * A \"pure not\" schema has the form `{ not: X }` without any other constraint.\n * In that case, `{ not: { not: Y } }` ≡ `Y`.\n *\n * Metadata keywords (`$id`, `$schema`, `$comment`, `title`, `description`,\n * `default`, `examples`, `definitions`, `$defs`) are NOT considered\n * significant for this detection.\n */\nconst METADATA_KEYWORDS = new Set([\n\t\"$id\",\n\t\"$schema\",\n\t\"$comment\",\n\t\"title\",\n\t\"description\",\n\t\"default\",\n\t\"examples\",\n\t\"definitions\",\n\t\"$defs\",\n]);\n\n/**\n * Checks whether a schema object contains only the `not` keyword\n * (plus optionally non-significant metadata).\n */\nfunction isPureNotSchema(schema: JSONSchema7): boolean {\n\tconst schemaKeys = Object.keys(schema);\n\treturn schemaKeys.every((k) => k === \"not\" || METADATA_KEYWORDS.has(k));\n}\n\n/** Keywords containing an array of sub-schemas */\nconst ARRAY_SCHEMA_KEYWORDS = [\"anyOf\", \"oneOf\", \"allOf\"] as const;\n\n/**\n * Keywords containing a Record<string, JSONSchema7Definition>\n * (each value is a sub-schema to normalize recursively).\n */\nconst PROPERTIES_LIKE_KEYWORDS = [\"properties\", \"patternProperties\"] as const;\n\n// ─── Internal helpers ────────────────────────────────────────────────────────\n\n/**\n * Normalizes a `Record<string, JSONSchema7Definition>` by applying\n * `normalize` to each value.\n * Returns the original object if nothing changed (avoids allocations).\n */\nfunction normalizePropertiesMap(\n\tprops: Record<string, JSONSchema7Definition>,\n): Record<string, JSONSchema7Definition> {\n\tconst keys = Object.keys(props);\n\tlet changed = false;\n\n\t// First pass: detect if anything changes (sub-schemas get cached)\n\tfor (let i = 0; i < keys.length; i++) {\n\t\tconst key = keys[i];\n\t\tif (key === undefined) continue;\n\t\tconst original = props[key];\n\t\tconst normalized = normalize(original as JSONSchema7Definition);\n\t\tif (normalized !== original) {\n\t\t\tchanged = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!changed) return props;\n\n\t// Build result only when something changed (sub normalize calls hit cache)\n\tconst result: Record<string, JSONSchema7Definition> = {};\n\tfor (let i = 0; i < keys.length; i++) {\n\t\tconst key = keys[i];\n\t\tif (key === undefined) continue;\n\t\tresult[key] = normalize(props[key] as JSONSchema7Definition);\n\t}\n\n\treturn result;\n}\n\n/**\n * Infers `type` from `const` if absent.\n * Returns the inferred type or undefined if not applicable.\n */\nfunction inferTypeFromConst(\n\tschema: JSONSchema7,\n): JSONSchema7[\"type\"] | undefined {\n\tif (!hasOwn(schema, \"const\") || schema.type !== undefined) return undefined;\n\tconst t = inferType(schema.const);\n\treturn t ? (t as JSONSchema7[\"type\"]) : undefined;\n}\n\n/**\n * Infers `type` from `enum` if absent.\n * Returns the inferred type (single or array) or undefined if not applicable.\n */\nfunction inferTypeFromEnum(\n\tschema: JSONSchema7,\n): JSONSchema7[\"type\"] | undefined {\n\tif (!Array.isArray(schema.enum) || schema.type !== undefined)\n\t\treturn undefined;\n\n\tconst typesSet = new Set<string>();\n\tfor (const v of schema.enum) {\n\t\tconst t = inferType(v);\n\t\tif (t) typesSet.add(t);\n\t}\n\n\tconst count = typesSet.size;\n\tif (count === 0) return undefined;\n\n\tconst types = Array.from(typesSet);\n\tif (count === 1) return types[0] as JSONSchema7[\"type\"];\n\treturn types as JSONSchema7[\"type\"];\n}\n\n// ─── Normalization ───────────────────────────────────────────────────────────\n\n/**\n * Normalizes a schema: infers `type` from `const`/`enum`,\n * and recursively normalizes all sub-schemas.\n *\n * Recurses into:\n * - `properties` and `patternProperties` (Point 2)\n * - `dependencies` schema form (Point 3) — array values (form 1)\n * are left unchanged\n * - `items` (single or tuple)\n * - Single-schema keywords (`additionalProperties`, `not`, `if`, etc.)\n * - Array-of-schema keywords (`anyOf`, `oneOf`, `allOf`)\n *\n * Optimizations:\n * - WeakMap cache: returns the cached result in O(1)\n * - Lazy copy-on-write: only creates a shallow copy when the first\n * mutation is needed, via `ensureCopy()`\n * - Sub-structures are only replaced if actually changed\n */\nexport function normalize(def: JSONSchema7Definition): JSONSchema7Definition {\n\tif (typeof def === \"boolean\") return def;\n\n\t// ── Cache lookup (O(1) fast path) ──\n\tconst cached = normalizeCache.get(def);\n\tif (cached !== undefined) return cached;\n\n\t// ── Lazy copy-on-write ──\n\t// We delay creating a shallow copy until the first actual mutation.\n\t// `schema` starts as `def` and only becomes a copy when `ensureCopy()` is called.\n\tlet schema = def as JSONSchema7 & Record<string, unknown>;\n\tlet copied = false;\n\n\tfunction ensureCopy(): JSONSchema7 & Record<string, unknown> {\n\t\tif (!copied) {\n\t\t\tschema = { ...(def as JSONSchema7) } as JSONSchema7 &\n\t\t\t\tRecord<string, unknown>;\n\t\t\tcopied = true;\n\t\t}\n\t\treturn schema;\n\t}\n\n\t// ── Infer type from const ──\n\tconst typeFromConst = inferTypeFromConst(schema);\n\tif (typeFromConst) {\n\t\tensureCopy().type = typeFromConst;\n\t}\n\n\t// ── Infer type from enum ──\n\tconst typeFromEnum = inferTypeFromEnum(schema);\n\tif (typeFromEnum) {\n\t\tensureCopy().type = typeFromEnum;\n\t}\n\n\t// ── Convert single-element enum to const ──\n\t// Semantically, { enum: [X] } ≡ { const: X }.\n\t// This normalization ensures that structural comparison (isEqual) does not\n\t// produce false negatives when one schema uses enum and the other uses\n\t// const for the same value.\n\tif (\n\t\tArray.isArray(schema.enum) &&\n\t\tschema.enum.length === 1 &&\n\t\t!hasOwn(schema, \"const\")\n\t) {\n\t\tconst s = ensureCopy();\n\t\ts.const = schema.enum[0];\n\t\tdelete s.enum;\n\t}\n\n\t// ── Strip redundant enum when const is present ──\n\t// If `const: X` and `enum: [... X ...]` coexist, `const` is more\n\t// restrictive → `enum` is redundant. The merge engine can produce\n\t// this combination during the const ∩ enum intersection.\n\tif (hasOwn(schema, \"const\") && Array.isArray(schema.enum)) {\n\t\tif (schema.enum.some((v) => deepEqual(v, schema.const))) {\n\t\t\tdelete ensureCopy().enum;\n\t\t}\n\t}\n\n\t// ── Normalize constraints to array form ──\n\t// The `constraints` custom keyword accepts `Constraint | Constraint[]`.\n\t// Canonicalize to always be an array so that deepEqual comparisons\n\t// in the subset checker work correctly.\n\tif (\n\t\thasOwn(schema, \"constraints\") &&\n\t\tschema.constraints !== undefined &&\n\t\t!Array.isArray(schema.constraints)\n\t) {\n\t\tensureCopy().constraints = [schema.constraints];\n\t}\n\n\t// ── Recurse into properties & patternProperties (Point 2) ──\n\tfor (const keyword of PROPERTIES_LIKE_KEYWORDS) {\n\t\tconst val = schema[keyword];\n\t\tif (isPlainObj(val)) {\n\t\t\tconst normalized = normalizePropertiesMap(\n\t\t\t\tval as Record<string, JSONSchema7Definition>,\n\t\t\t);\n\t\t\tif (normalized !== val) {\n\t\t\t\tensureCopy()[keyword] = normalized as JSONSchema7[\"properties\"];\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Recurse into dependencies (Point 3) ──\n\t// `dependencies` can contain:\n\t// - Form 1 (property deps): { foo: [\"bar\", \"baz\"] } → string array, skip\n\t// - Form 2 (schema deps): { foo: { required: [...] } } → schema object, normalize\n\tif (isPlainObj(schema.dependencies)) {\n\t\tconst deps = schema.dependencies as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t\tconst depsKeys = Object.keys(deps);\n\t\tlet depsChanged = false;\n\t\tconst newDeps: Record<string, JSONSchema7Definition | string[]> = {};\n\n\t\tfor (let i = 0; i < depsKeys.length; i++) {\n\t\t\tconst key = depsKeys[i];\n\t\t\tif (key === undefined) continue;\n\t\t\tconst val = deps[key];\n\t\t\tif (val === undefined) continue;\n\t\t\tif (Array.isArray(val)) {\n\t\t\t\t// Form 1: string array → leave as-is\n\t\t\t\tnewDeps[key] = val;\n\t\t\t} else if (isPlainObj(val)) {\n\t\t\t\t// Form 2: sub-schema → normalize recursively\n\t\t\t\tconst normalized = normalize(val as JSONSchema7Definition);\n\t\t\t\tnewDeps[key] = normalized;\n\t\t\t\tif (normalized !== val) depsChanged = true;\n\t\t\t} else {\n\t\t\t\tnewDeps[key] = val as JSONSchema7Definition;\n\t\t\t}\n\t\t}\n\n\t\tif (depsChanged) {\n\t\t\tensureCopy().dependencies = newDeps;\n\t\t}\n\t}\n\n\t// ── Recurse into items (tuple or single) ──\n\tif (schema.items) {\n\t\tif (Array.isArray(schema.items)) {\n\t\t\t// Tuple: normalize each element\n\t\t\tconst items = schema.items as JSONSchema7Definition[];\n\t\t\tlet itemsChanged = false;\n\t\t\tconst newItems: JSONSchema7Definition[] = new Array(items.length);\n\n\t\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\t\tconst original = items[i];\n\t\t\t\tif (original === undefined) continue;\n\t\t\t\tconst normalized = normalize(original);\n\t\t\t\tnewItems[i] = normalized;\n\t\t\t\tif (normalized !== original) itemsChanged = true;\n\t\t\t}\n\n\t\t\tif (itemsChanged) {\n\t\t\t\tensureCopy().items = newItems;\n\t\t\t}\n\t\t} else if (isPlainObj(schema.items)) {\n\t\t\t// Single items schema\n\t\t\tconst normalized = normalize(schema.items as JSONSchema7Definition);\n\t\t\tif (normalized !== schema.items) {\n\t\t\t\tensureCopy().items = normalized;\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Recurse into single-schema keywords ──\n\tfor (const key of SINGLE_SCHEMA_KEYWORDS) {\n\t\tconst val = schema[key];\n\t\tif (val !== undefined && typeof val !== \"boolean\") {\n\t\t\tconst normalized = normalize(val as JSONSchema7Definition);\n\t\t\tif (normalized !== val) {\n\t\t\t\t(ensureCopy() as Record<string, JSONSchema7Definition>)[key] =\n\t\t\t\t\tnormalized;\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Resolve double negation not(not(X)) → X ──\n\t// After recursing into sub-schemas, `schema.not` is normalized.\n\t// If `schema.not` is an object that only contains `not` (a \"pure not\"),\n\t// then `{ ...rest, not: { not: X } }` ≡ `{ ...rest, ...X }`.\n\t//\n\t// Propositional logic: ¬¬P ≡ P\n\t//\n\t// We only resolve the \"pure\" case (schema.not has only `not` as a\n\t// significant key) to avoid false positives in complex cases.\n\tif (\n\t\thasOwn(schema, \"not\") &&\n\t\tisPlainObj(schema.not) &&\n\t\ttypeof schema.not !== \"boolean\"\n\t) {\n\t\tconst notSchema = schema.not as JSONSchema7;\n\t\tif (\n\t\t\thasOwn(notSchema, \"not\") &&\n\t\t\tisPureNotSchema(notSchema) &&\n\t\t\tisPlainObj(notSchema.not) &&\n\t\t\ttypeof notSchema.not !== \"boolean\"\n\t\t) {\n\t\t\t// Extract the content of not.not and merge it into the rest of the schema\n\t\t\tconst innerSchema = notSchema.not as JSONSchema7;\n\t\t\tconst s = ensureCopy();\n\t\t\t// Remove `not` from the current schema\n\t\t\tdelete s.not;\n\t\t\t// Merge the inner content into the current schema\n\t\t\tconst innerKeys = Object.keys(innerSchema);\n\t\t\tfor (let i = 0; i < innerKeys.length; i++) {\n\t\t\t\tconst ik = innerKeys[i];\n\t\t\t\tif (ik === undefined) continue;\n\t\t\t\t(s as Record<string, unknown>)[ik] = (\n\t\t\t\t\tinnerSchema as Record<string, unknown>\n\t\t\t\t)[ik];\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Recurse into array-of-schema keywords ──\n\tfor (const key of ARRAY_SCHEMA_KEYWORDS) {\n\t\tconst val = schema[key];\n\t\tif (Array.isArray(val)) {\n\t\t\tconst arr = val as JSONSchema7Definition[];\n\t\t\tlet arrChanged = false;\n\t\t\tconst newArr: JSONSchema7Definition[] = new Array(arr.length);\n\n\t\t\tfor (let i = 0; i < arr.length; i++) {\n\t\t\t\tconst original = arr[i];\n\t\t\t\tif (original === undefined) continue;\n\t\t\t\tconst normalized = normalize(original);\n\t\t\t\tnewArr[i] = normalized;\n\t\t\t\tif (normalized !== original) arrChanged = true;\n\t\t\t}\n\n\t\t\tif (arrChanged) {\n\t\t\t\tensureCopy()[key] = newArr;\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Determine result ──\n\t// If nothing changed (copied === false), return the original def.\n\t// Otherwise, return the mutated copy.\n\tconst result = (copied ? schema : def) as JSONSchema7Definition;\n\n\t// ── Cache the result ──\n\tnormalizeCache.set(def, result);\n\n\treturn result;\n}\n"],"names":["inferType","normalize","normalizeCache","WeakMap","value","Number","isInteger","Array","isArray","undefined","SINGLE_SCHEMA_KEYWORDS","METADATA_KEYWORDS","Set","isPureNotSchema","schema","schemaKeys","Object","keys","every","k","has","ARRAY_SCHEMA_KEYWORDS","PROPERTIES_LIKE_KEYWORDS","normalizePropertiesMap","props","changed","i","length","key","original","normalized","result","inferTypeFromConst","hasOwn","type","t","const","inferTypeFromEnum","enum","typesSet","v","add","count","size","types","from","def","cached","get","copied","ensureCopy","typeFromConst","typeFromEnum","s","some","deepEqual","constraints","keyword","val","isPlainObj","dependencies","deps","depsKeys","depsChanged","newDeps","items","itemsChanged","newItems","not","notSchema","innerSchema","innerKeys","ik","arr","arrChanged","newArr","set"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/normalizer.ts"],"sourcesContent":["import type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\nimport { deepEqual, hasOwn, isPlainObj } from \"./utils.ts\";\n\n// ─── Schema Normalizer ───────────────────────────────────────────────────────\n//\n// Pure functions to normalize a JSON Schema:\n// - Infer `type` from `const` or `enum`\n// - Recurse into all sub-structures (properties, items, anyOf, etc.)\n// - Resolve double negation `not.not` → flatten to direct content\n// - Recurse into `patternProperties` (Point 2)\n// - Recurse into `dependencies` schema form (Point 3)\n//\n// Optimizations:\n// - WeakMap cache to avoid re-normalizing the same object\n// - Lazy copy-on-write: only creates a copy when mutations are needed\n// - Returns the original if nothing changed (avoids allocations)\n\n// ─── Normalization Cache ─────────────────────────────────────────────────────\n\n/**\n * WeakMap cache for normalization results.\n * Avoids re-normalizing the same schema object multiple times.\n * WeakMap allows the GC to collect schemas that are no longer referenced.\n */\nconst normalizeCache = new WeakMap<object, JSONSchema7Definition>();\n\n// ─── Type inference ──────────────────────────────────────────────────────────\n\n/**\n * Infers the JSON Schema type from a JavaScript value.\n */\nexport function inferType(value: unknown): string | undefined {\n\tif (value === null) return \"null\";\n\tswitch (typeof value) {\n\t\tcase \"string\":\n\t\t\treturn \"string\";\n\t\tcase \"number\":\n\t\t\treturn Number.isInteger(value) ? \"integer\" : \"number\";\n\t\tcase \"boolean\":\n\t\t\treturn \"boolean\";\n\t\tcase \"object\":\n\t\t\treturn Array.isArray(value) ? \"array\" : \"object\";\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\n// ─── Sub-schema keywords ─────────────────────────────────────────────────────\n\n/** Keywords containing a single sub-schema */\nconst SINGLE_SCHEMA_KEYWORDS = [\n\t\"additionalProperties\",\n\t\"additionalItems\",\n\t\"contains\",\n\t\"propertyNames\",\n\t\"not\",\n\t\"if\",\n\t\"then\",\n\t\"else\",\n] as const;\n\n/**\n * Checks whether a schema contains only the `not` keyword (and no other\n * significant keyword). Used for double negation resolution.\n *\n * A \"pure not\" schema has the form `{ not: X }` without any other constraint.\n * In that case, `{ not: { not: Y } }` ≡ `Y`.\n *\n * Metadata keywords (`$id`, `$schema`, `$comment`, `title`, `description`,\n * `default`, `examples`, `definitions`, `$defs`) are NOT considered\n * significant for this detection.\n */\nconst METADATA_KEYWORDS = new Set([\n\t\"$id\",\n\t\"$schema\",\n\t\"$comment\",\n\t\"title\",\n\t\"description\",\n\t\"default\",\n\t\"examples\",\n\t\"definitions\",\n\t\"$defs\",\n]);\n\n/**\n * Checks whether a schema object contains only the `not` keyword\n * (plus optionally non-significant metadata).\n */\nfunction isPureNotSchema(schema: JSONSchema7): boolean {\n\tconst schemaKeys = Object.keys(schema);\n\treturn schemaKeys.every((k) => k === \"not\" || METADATA_KEYWORDS.has(k));\n}\n\n/** Keywords containing an array of sub-schemas */\nconst ARRAY_SCHEMA_KEYWORDS = [\"anyOf\", \"oneOf\", \"allOf\"] as const;\n\n/**\n * Keywords containing a Record<string, JSONSchema7Definition>\n * (each value is a sub-schema to normalize recursively).\n */\nconst PROPERTIES_LIKE_KEYWORDS = [\"properties\", \"patternProperties\"] as const;\n\n// ─── Internal helpers ────────────────────────────────────────────────────────\n\n/**\n * Normalizes a `Record<string, JSONSchema7Definition>` by applying\n * `normalize` to each value.\n * Returns the original object if nothing changed (avoids allocations).\n */\nfunction normalizePropertiesMap(\n\tprops: Record<string, JSONSchema7Definition>,\n): Record<string, JSONSchema7Definition> {\n\tconst keys = Object.keys(props);\n\tlet changed = false;\n\n\t// First pass: detect if anything changes (sub-schemas get cached)\n\tfor (let i = 0; i < keys.length; i++) {\n\t\tconst key = keys[i];\n\t\tif (key === undefined) continue;\n\t\tconst original = props[key];\n\t\tconst normalized = normalize(original as JSONSchema7Definition);\n\t\tif (normalized !== original) {\n\t\t\tchanged = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!changed) return props;\n\n\t// Build result only when something changed (sub normalize calls hit cache)\n\tconst result: Record<string, JSONSchema7Definition> = {};\n\tfor (let i = 0; i < keys.length; i++) {\n\t\tconst key = keys[i];\n\t\tif (key === undefined) continue;\n\t\tresult[key] = normalize(props[key] as JSONSchema7Definition);\n\t}\n\n\treturn result;\n}\n\n/**\n * Infers `type` from `const` if absent.\n * Returns the inferred type or undefined if not applicable.\n */\nfunction inferTypeFromConst(\n\tschema: JSONSchema7,\n): JSONSchema7[\"type\"] | undefined {\n\tif (!hasOwn(schema, \"const\") || schema.type !== undefined) return undefined;\n\tconst t = inferType(schema.const);\n\treturn t ? (t as JSONSchema7[\"type\"]) : undefined;\n}\n\n/**\n * Infers `type` from `enum` if absent.\n * Returns the inferred type (single or array) or undefined if not applicable.\n */\nfunction inferTypeFromEnum(\n\tschema: JSONSchema7,\n): JSONSchema7[\"type\"] | undefined {\n\tif (!Array.isArray(schema.enum) || schema.type !== undefined)\n\t\treturn undefined;\n\n\tconst typesSet = new Set<string>();\n\tfor (const v of schema.enum) {\n\t\tconst t = inferType(v);\n\t\tif (t) typesSet.add(t);\n\t}\n\n\tconst count = typesSet.size;\n\tif (count === 0) return undefined;\n\n\tconst types = Array.from(typesSet);\n\tif (count === 1) return types[0] as JSONSchema7[\"type\"];\n\treturn types as JSONSchema7[\"type\"];\n}\n\n// ─── Normalization ───────────────────────────────────────────────────────────\n\n/**\n * Normalizes a schema: infers `type` from `const`/`enum`,\n * and recursively normalizes all sub-schemas.\n *\n * Recurses into:\n * - `properties` and `patternProperties` (Point 2)\n * - `dependencies` schema form (Point 3) — array values (form 1)\n * are left unchanged\n * - `items` (single or tuple)\n * - Single-schema keywords (`additionalProperties`, `not`, `if`, etc.)\n * - Array-of-schema keywords (`anyOf`, `oneOf`, `allOf`)\n *\n * Optimizations:\n * - WeakMap cache: returns the cached result in O(1)\n * - Lazy copy-on-write: only creates a shallow copy when the first\n * mutation is needed, via `ensureCopy()`\n * - Sub-structures are only replaced if actually changed\n */\nexport function normalize(def: JSONSchema7Definition): JSONSchema7Definition {\n\tif (typeof def === \"boolean\") return def;\n\n\t// ── Cache lookup (O(1) fast path) ──\n\tconst cached = normalizeCache.get(def);\n\tif (cached !== undefined) return cached;\n\n\t// ── Lazy copy-on-write ──\n\t// We delay creating a shallow copy until the first actual mutation.\n\t// `schema` starts as `def` and only becomes a copy when `ensureCopy()` is called.\n\tlet schema = def as JSONSchema7 & Record<string, unknown>;\n\tlet copied = false;\n\n\tfunction ensureCopy(): JSONSchema7 & Record<string, unknown> {\n\t\tif (!copied) {\n\t\t\tschema = { ...(def as JSONSchema7) } as JSONSchema7 &\n\t\t\t\tRecord<string, unknown>;\n\t\t\tcopied = true;\n\t\t}\n\t\treturn schema;\n\t}\n\n\t// ── Infer type from const ──\n\tconst typeFromConst = inferTypeFromConst(schema);\n\tif (typeFromConst) {\n\t\tensureCopy().type = typeFromConst;\n\t}\n\n\t// ── Infer type from enum ──\n\tconst typeFromEnum = inferTypeFromEnum(schema);\n\tif (typeFromEnum) {\n\t\tensureCopy().type = typeFromEnum;\n\t}\n\n\t// ── Convert single-element enum to const ──\n\t// Semantically, { enum: [X] } ≡ { const: X }.\n\t// This normalization ensures that structural comparison (isEqual) does not\n\t// produce false negatives when one schema uses enum and the other uses\n\t// const for the same value.\n\tif (\n\t\tArray.isArray(schema.enum) &&\n\t\tschema.enum.length === 1 &&\n\t\t!hasOwn(schema, \"const\")\n\t) {\n\t\tconst s = ensureCopy();\n\t\ts.const = schema.enum[0];\n\t\tdelete s.enum;\n\t}\n\n\t// ── Strip redundant enum when const is present ──\n\t// If `const: X` and `enum: [... X ...]` coexist, `const` is more\n\t// restrictive → `enum` is redundant. The merge engine can produce\n\t// this combination during the const ∩ enum intersection.\n\tif (hasOwn(schema, \"const\") && Array.isArray(schema.enum)) {\n\t\tif (schema.enum.some((v) => deepEqual(v, schema.const))) {\n\t\t\tdelete ensureCopy().enum;\n\t\t}\n\t}\n\n\t// ── Strip constraints from the static path ──\n\t// The `constraints` keyword is a runtime-only concept: it represents\n\t// custom validators (e.g. \"IsUuid\", \"NotFoundConstraint\") that can only\n\t// be evaluated against concrete data. Including them in the normalized\n\t// schema would cause false negatives in the structural subset check\n\t// (e.g. `{ type: \"string\" }` would fail to be recognized as a subset of\n\t// `{ type: \"string\", constraints: [\"X\"] }` because the merge adds the\n\t// constraint to the result, making merged ≠ sub).\n\t//\n\t// Stripping here is safe: the runtime validation path\n\t// (`validateSchemaConstraints`) receives the original resolved/narrowed\n\t// schemas that have NOT been through `normalize()`, so constraints are\n\t// still available for runtime evaluation.\n\tif (hasOwn(schema, \"constraints\") && schema.constraints !== undefined) {\n\t\tconst s = ensureCopy();\n\t\tdelete s.constraints;\n\t}\n\n\t// ── Recurse into properties & patternProperties (Point 2) ──\n\tfor (const keyword of PROPERTIES_LIKE_KEYWORDS) {\n\t\tconst val = schema[keyword];\n\t\tif (isPlainObj(val)) {\n\t\t\tconst normalized = normalizePropertiesMap(\n\t\t\t\tval as Record<string, JSONSchema7Definition>,\n\t\t\t);\n\t\t\tif (normalized !== val) {\n\t\t\t\tensureCopy()[keyword] = normalized as JSONSchema7[\"properties\"];\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Recurse into dependencies (Point 3) ──\n\t// `dependencies` can contain:\n\t// - Form 1 (property deps): { foo: [\"bar\", \"baz\"] } → string array, skip\n\t// - Form 2 (schema deps): { foo: { required: [...] } } → schema object, normalize\n\tif (isPlainObj(schema.dependencies)) {\n\t\tconst deps = schema.dependencies as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t\tconst depsKeys = Object.keys(deps);\n\t\tlet depsChanged = false;\n\t\tconst newDeps: Record<string, JSONSchema7Definition | string[]> = {};\n\n\t\tfor (let i = 0; i < depsKeys.length; i++) {\n\t\t\tconst key = depsKeys[i];\n\t\t\tif (key === undefined) continue;\n\t\t\tconst val = deps[key];\n\t\t\tif (val === undefined) continue;\n\t\t\tif (Array.isArray(val)) {\n\t\t\t\t// Form 1: string array → leave as-is\n\t\t\t\tnewDeps[key] = val;\n\t\t\t} else if (isPlainObj(val)) {\n\t\t\t\t// Form 2: sub-schema → normalize recursively\n\t\t\t\tconst normalized = normalize(val as JSONSchema7Definition);\n\t\t\t\tnewDeps[key] = normalized;\n\t\t\t\tif (normalized !== val) depsChanged = true;\n\t\t\t} else {\n\t\t\t\tnewDeps[key] = val as JSONSchema7Definition;\n\t\t\t}\n\t\t}\n\n\t\tif (depsChanged) {\n\t\t\tensureCopy().dependencies = newDeps;\n\t\t}\n\t}\n\n\t// ── Recurse into items (tuple or single) ──\n\tif (schema.items) {\n\t\tif (Array.isArray(schema.items)) {\n\t\t\t// Tuple: normalize each element\n\t\t\tconst items = schema.items as JSONSchema7Definition[];\n\t\t\tlet itemsChanged = false;\n\t\t\tconst newItems: JSONSchema7Definition[] = new Array(items.length);\n\n\t\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\t\tconst original = items[i];\n\t\t\t\tif (original === undefined) continue;\n\t\t\t\tconst normalized = normalize(original);\n\t\t\t\tnewItems[i] = normalized;\n\t\t\t\tif (normalized !== original) itemsChanged = true;\n\t\t\t}\n\n\t\t\tif (itemsChanged) {\n\t\t\t\tensureCopy().items = newItems;\n\t\t\t}\n\t\t} else if (isPlainObj(schema.items)) {\n\t\t\t// Single items schema\n\t\t\tconst normalized = normalize(schema.items as JSONSchema7Definition);\n\t\t\tif (normalized !== schema.items) {\n\t\t\t\tensureCopy().items = normalized;\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Recurse into single-schema keywords ──\n\tfor (const key of SINGLE_SCHEMA_KEYWORDS) {\n\t\tconst val = schema[key];\n\t\tif (val !== undefined && typeof val !== \"boolean\") {\n\t\t\tconst normalized = normalize(val as JSONSchema7Definition);\n\t\t\tif (normalized !== val) {\n\t\t\t\t(ensureCopy() as Record<string, JSONSchema7Definition>)[key] =\n\t\t\t\t\tnormalized;\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Resolve double negation not(not(X)) → X ──\n\t// After recursing into sub-schemas, `schema.not` is normalized.\n\t// If `schema.not` is an object that only contains `not` (a \"pure not\"),\n\t// then `{ ...rest, not: { not: X } }` ≡ `{ ...rest, ...X }`.\n\t//\n\t// Propositional logic: ¬¬P ≡ P\n\t//\n\t// We only resolve the \"pure\" case (schema.not has only `not` as a\n\t// significant key) to avoid false positives in complex cases.\n\tif (\n\t\thasOwn(schema, \"not\") &&\n\t\tisPlainObj(schema.not) &&\n\t\ttypeof schema.not !== \"boolean\"\n\t) {\n\t\tconst notSchema = schema.not as JSONSchema7;\n\t\tif (\n\t\t\thasOwn(notSchema, \"not\") &&\n\t\t\tisPureNotSchema(notSchema) &&\n\t\t\tisPlainObj(notSchema.not) &&\n\t\t\ttypeof notSchema.not !== \"boolean\"\n\t\t) {\n\t\t\t// Extract the content of not.not and merge it into the rest of the schema\n\t\t\tconst innerSchema = notSchema.not as JSONSchema7;\n\t\t\tconst s = ensureCopy();\n\t\t\t// Remove `not` from the current schema\n\t\t\tdelete s.not;\n\t\t\t// Merge the inner content into the current schema\n\t\t\tconst innerKeys = Object.keys(innerSchema);\n\t\t\tfor (let i = 0; i < innerKeys.length; i++) {\n\t\t\t\tconst ik = innerKeys[i];\n\t\t\t\tif (ik === undefined) continue;\n\t\t\t\t(s as Record<string, unknown>)[ik] = (\n\t\t\t\t\tinnerSchema as Record<string, unknown>\n\t\t\t\t)[ik];\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Recurse into array-of-schema keywords ──\n\tfor (const key of ARRAY_SCHEMA_KEYWORDS) {\n\t\tconst val = schema[key];\n\t\tif (Array.isArray(val)) {\n\t\t\tconst arr = val as JSONSchema7Definition[];\n\t\t\tlet arrChanged = false;\n\t\t\tconst newArr: JSONSchema7Definition[] = new Array(arr.length);\n\n\t\t\tfor (let i = 0; i < arr.length; i++) {\n\t\t\t\tconst original = arr[i];\n\t\t\t\tif (original === undefined) continue;\n\t\t\t\tconst normalized = normalize(original);\n\t\t\t\tnewArr[i] = normalized;\n\t\t\t\tif (normalized !== original) arrChanged = true;\n\t\t\t}\n\n\t\t\tif (arrChanged) {\n\t\t\t\tensureCopy()[key] = newArr;\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Determine result ──\n\t// If nothing changed (copied === false), return the original def.\n\t// Otherwise, return the mutated copy.\n\tconst result = (copied ? schema : def) as JSONSchema7Definition;\n\n\t// ── Cache the result ──\n\tnormalizeCache.set(def, result);\n\n\treturn result;\n}\n"],"names":["inferType","normalize","normalizeCache","WeakMap","value","Number","isInteger","Array","isArray","undefined","SINGLE_SCHEMA_KEYWORDS","METADATA_KEYWORDS","Set","isPureNotSchema","schema","schemaKeys","Object","keys","every","k","has","ARRAY_SCHEMA_KEYWORDS","PROPERTIES_LIKE_KEYWORDS","normalizePropertiesMap","props","changed","i","length","key","original","normalized","result","inferTypeFromConst","hasOwn","type","t","const","inferTypeFromEnum","enum","typesSet","v","add","count","size","types","from","def","cached","get","copied","ensureCopy","typeFromConst","typeFromEnum","s","some","deepEqual","constraints","keyword","val","isPlainObj","dependencies","deps","depsKeys","depsChanged","newDeps","items","itemsChanged","newItems","not","notSchema","innerSchema","innerKeys","ik","arr","arrChanged","newArr","set"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get computeSemanticErrors(){return computeSemanticErrors},get formatSchemaType(){return formatSchemaType}});const _utilsts=require("./utils.js");function formatEnumValues(values){const parts=values.map(v=>typeof v==="string"?v:JSON.stringify(v));if(parts.length===0)return"never";if(parts.length===1)return parts[0];if(parts.length===2)return`${parts[0]} or ${parts[1]}`;const last=parts.pop();return`${parts.join(", ")}, or ${last}`}function formatSchemaType(def){const base=formatSchemaTypeInternal(def);if(def===undefined||typeof def==="boolean")return base;return base+formatConstraintsSuffix(def)}function formatConstraintsSuffix(schema){const constraints=schema.constraints;if(constraints===undefined)return"";const arr=Array.isArray(constraints)?constraints:[constraints];if(arr.length===0)return"";return` [${arr.map(formatCustomConstraint).join(", ")}]`}function formatSchemaTypeInternal(def){if(def===undefined)return"undefined";if(typeof def==="boolean")return def?"any":"never";const schema=def;if((0,_utilsts.hasOwn)(schema,"const")){const v=schema.const;return typeof v==="string"?v:JSON.stringify(v)}if(Array.isArray(schema.enum)){return formatEnumValues(schema.enum)}const branches=schema.anyOf??schema.oneOf;if(Array.isArray(branches)&&branches.length>0){const parts=branches.map(b=>formatSchemaType(b));return parts.join(" | ")}if(schema.type==="array"){if(schema.items!==undefined&&typeof schema.items!=="boolean"){const itemSchema=schema.items;const itemBranches=itemSchema.anyOf??itemSchema.oneOf;if(Array.isArray(itemBranches)&&itemBranches.length>0){const parts=itemBranches.map(b=>`${formatSchemaType(b)}[]`);return parts.join(" | ")}if(Array.isArray(itemSchema.type)){const parts=itemSchema.type.map(t=>`${t}[]`);return parts.join(" | ")}const itemType=formatSchemaType(itemSchema);return`${itemType}[]`}return"array"}if(typeof schema.type==="string"){return schema.type}if(Array.isArray(schema.type)){return schema.type.join(" | ")}if((0,_utilsts.hasOwn)(schema,"not")&&!schema.type&&!(0,_utilsts.isPlainObj)(schema.properties)&&schema.items===undefined&&!Array.isArray(schema.enum)&&!(0,_utilsts.hasOwn)(schema,"const")){return`not ${formatSchemaType(schema.not)}`}if((0,_utilsts.isPlainObj)(schema.properties))return"object";if(schema.items!==undefined)return"array";return"unknown"}function joinPath(parent,key){if(!parent)return key;return`${parent}.${key}`}function arrayPath(parent){if(!parent)return"[]";return`${parent}[]`}function getProperties(schema){if((0,_utilsts.isPlainObj)(schema.properties)){return schema.properties}return null}function getRequired(schema){if(Array.isArray(schema.required)){return schema.required}return[]}function getEffectiveType(schema){if(schema.type!==undefined)return schema.type;if((0,_utilsts.hasOwn)(schema,"const")){const v=schema.const;if(v===null)return"null";if(Array.isArray(v))return"array";return typeof v}if((0,_utilsts.isPlainObj)(schema.properties))return"object";if(schema.items!==undefined)return"array";return undefined}function typeIncludes(schemaType,target){if(schemaType===undefined)return false;if(typeof schemaType==="string"){if(target==="number"&&schemaType==="integer")return true;if(target==="integer"&&schemaType==="number")return true;return schemaType===target}return schemaType.includes(target)}function typesAreCompatible(subType,supType){if(supType===undefined)return true;if(subType===undefined)return true;if(typeof subType==="string"&&typeof supType==="string"){if(subType===supType)return true;if(subType==="integer"&&supType==="number")return true;return false}if(typeof subType==="string"&&Array.isArray(supType)){return supType.some(t=>t===subType||subType==="integer"&&t==="number")}if(Array.isArray(subType)&&typeof supType==="string"){return subType.every(t=>t===supType||t==="integer"&&supType==="number")}if(Array.isArray(subType)&&Array.isArray(supType)){return subType.every(st=>supType.some(supt=>supt===st||st==="integer"&&supt==="number"))}return true}function formatCustomConstraint(c){if(typeof c==="string")return c;if(c.params&&Object.keys(c.params).length>0){return`${c.name}(${JSON.stringify(c.params)})`}return c.name}function formatCustomConstraintList(cs){return cs.map(formatCustomConstraint).join(", ")}function checkCustomConstraints(sub,sup,path,errors){const supConstraints=sup.constraints;const subConstraints=sub.constraints;if(supConstraints===undefined)return;const supArr=Array.isArray(supConstraints)?supConstraints:[supConstraints];const subArr=subConstraints===undefined?[]:Array.isArray(subConstraints)?subConstraints:[subConstraints];for(const supC of supArr){const found=subArr.some(subC=>(0,_utilsts.deepEqual)(subC,supC));if(!found){errors.push({key:path||"$root",expected:`constraint: ${formatCustomConstraint(supC)}`,received:subArr.length>0?`constraints: ${formatCustomConstraintList(subArr)}`:"no constraints"})}}}function fmtConstraint(name,value){if(value===undefined)return`${name}: not set`;if(typeof value==="boolean")return`${name}: ${value}`;if(typeof value==="number"||typeof value==="string")return`${name}: ${value}`;return`${name}: ${JSON.stringify(value)}`}function checkMinConstraint(subVal,supVal,name,path,errors){if(supVal!==undefined){if(subVal===undefined||subVal<supVal){errors.push({key:path||"$root",expected:fmtConstraint(name,supVal),received:fmtConstraint(name,subVal)})}}}function checkMaxConstraint(subVal,supVal,name,path,errors){if(supVal!==undefined){if(subVal===undefined||subVal>supVal){errors.push({key:path||"$root",expected:fmtConstraint(name,supVal),received:fmtConstraint(name,subVal)})}}}function checkNumericConstraints(sub,sup,path,errors){checkMinConstraint(sub.minimum,sup.minimum,"minimum",path,errors);checkMaxConstraint(sub.maximum,sup.maximum,"maximum",path,errors);checkMinConstraint(sub.exclusiveMinimum,sup.exclusiveMinimum,"exclusiveMinimum",path,errors);checkMaxConstraint(sub.exclusiveMaximum,sup.exclusiveMaximum,"exclusiveMaximum",path,errors);if(sup.multipleOf!==undefined){if(sub.multipleOf===undefined){errors.push({key:path||"$root",expected:fmtConstraint("multipleOf",sup.multipleOf),received:fmtConstraint("multipleOf",sub.multipleOf)})}else if(sub.multipleOf!==sup.multipleOf){if(sub.multipleOf%sup.multipleOf!==0){errors.push({key:path||"$root",expected:fmtConstraint("multipleOf",sup.multipleOf),received:fmtConstraint("multipleOf",sub.multipleOf)})}}}}function checkStringConstraints(sub,sup,path,errors){checkMinConstraint(sub.minLength,sup.minLength,"minLength",path,errors);checkMaxConstraint(sub.maxLength,sup.maxLength,"maxLength",path,errors);if(sup.pattern!==undefined){if(sub.pattern===undefined){errors.push({key:path||"$root",expected:fmtConstraint("pattern",sup.pattern),received:"no pattern constraint"})}else if(sub.pattern!==sup.pattern){errors.push({key:path||"$root",expected:fmtConstraint("pattern",sup.pattern),received:fmtConstraint("pattern",sub.pattern)})}}if(sup.format!==undefined&&sub.format!==sup.format){if(sub.format===undefined){errors.push({key:path||"$root",expected:fmtConstraint("format",sup.format),received:"no format constraint"})}else{errors.push({key:path||"$root",expected:fmtConstraint("format",sup.format),received:fmtConstraint("format",sub.format)})}}}function checkObjectConstraints(sub,sup,path,errors){if(sup.additionalProperties!==undefined){if(sup.additionalProperties===false){if(sub.additionalProperties===undefined||sub.additionalProperties===true){errors.push({key:path||"$root",expected:"additionalProperties: false",received:"additional properties allowed"})}else if(typeof sub.additionalProperties==="object"&&sub.additionalProperties!==null){errors.push({key:path||"$root",expected:"additionalProperties: false",received:"additionalProperties: schema"})}}else if(typeof sup.additionalProperties==="object"&&sup.additionalProperties!==null){if(sub.additionalProperties===undefined||sub.additionalProperties===true){errors.push({key:path||"$root",expected:`additionalProperties: ${formatSchemaType(sup.additionalProperties)}`,received:"additional properties allowed"})}else if(typeof sub.additionalProperties==="object"&&sub.additionalProperties!==null){const apPath=path?`${path}.<additionalProperties>`:"<additionalProperties>";const apErrors=computeSemanticErrors(sub.additionalProperties,sup.additionalProperties,apPath);errors.push(...apErrors)}}}checkMinConstraint(sub.minProperties,sup.minProperties,"minProperties",path,errors);checkMaxConstraint(sub.maxProperties,sup.maxProperties,"maxProperties",path,errors);if(sup.propertyNames!==undefined){if(sub.propertyNames===undefined){errors.push({key:path||"$root",expected:`propertyNames: ${formatSchemaType(sup.propertyNames)}`,received:"no propertyNames constraint"})}else{const pnErrors=computeSemanticErrors(sub.propertyNames,sup.propertyNames,path?`${path}.<propertyNames>`:"<propertyNames>");errors.push(...pnErrors)}}if((0,_utilsts.isPlainObj)(sup.dependencies)){const supDeps=sup.dependencies;const subDeps=(0,_utilsts.isPlainObj)(sub.dependencies)?sub.dependencies:null;for(const key of Object.keys(supDeps)){const supDep=supDeps[key];const subDep=subDeps?.[key];if(subDep===undefined){if(Array.isArray(supDep)){errors.push({key:path||"$root",expected:`dependency: ${key} requires ${supDep.join(", ")}`,received:`no dependency for ${key}`})}else{errors.push({key:path||"$root",expected:`dependency: ${key} requires schema`,received:`no dependency for ${key}`})}}else if(Array.isArray(supDep)&&Array.isArray(subDep)){const missing=supDep.filter(d=>!subDep.includes(d));if(missing.length>0){errors.push({key:path||"$root",expected:`dependency: ${key} requires ${supDep.join(", ")}`,received:`dependency: ${key} requires ${subDep.join(", ")}`})}}else if(!Array.isArray(supDep)&&!Array.isArray(subDep)){const depPath=path?`${path}.<dependency:${key}>`:`<dependency:${key}>`;const depErrors=computeSemanticErrors(subDep,supDep,depPath);errors.push(...depErrors)}else{errors.push({key:path||"$root",expected:Array.isArray(supDep)?`dependency: ${key} requires ${supDep.join(", ")}`:`dependency: ${key} requires schema`,received:Array.isArray(subDep)?`dependency: ${key} requires ${subDep.join(", ")}`:`dependency: ${key} requires schema`})}}}if((0,_utilsts.isPlainObj)(sup.patternProperties)){const supPP=sup.patternProperties;const subPP=(0,_utilsts.isPlainObj)(sub.patternProperties)?sub.patternProperties:null;for(const pattern of Object.keys(supPP)){const supPropDef=supPP[pattern];if(supPropDef===undefined)continue;const subPropDef=subPP?.[pattern];const ppPath=path?`${path}.<patternProperties:${pattern}>`:`<patternProperties:${pattern}>`;if(subPropDef===undefined){errors.push({key:ppPath,expected:formatSchemaType(supPropDef),received:"no constraint for this pattern"})}else{const ppErrors=computeSemanticErrors(subPropDef,supPropDef,ppPath);errors.push(...ppErrors)}}}}function checkArrayConstraints(sub,sup,path,errors){checkMinConstraint(sub.minItems,sup.minItems,"minItems",path,errors);checkMaxConstraint(sub.maxItems,sup.maxItems,"maxItems",path,errors);if(sup.uniqueItems===true&&sub.uniqueItems!==true){errors.push({key:path||"$root",expected:"uniqueItems: true",received:fmtConstraint("uniqueItems",sub.uniqueItems??false)})}if(sup.contains!==undefined){if(sub.contains===undefined){errors.push({key:path||"$root",expected:`contains: ${formatSchemaType(sup.contains)}`,received:"no contains constraint"})}else{const containsPath=path?`${path}.<contains>`:"<contains>";const containsErrors=computeSemanticErrors(sub.contains,sup.contains,containsPath);errors.push(...containsErrors)}}}function isNumericType(t){if(t===undefined)return false;if(typeof t==="string")return t==="number"||t==="integer";return t.some(v=>v==="number"||v==="integer")}function isStringType(t){if(t===undefined)return false;if(typeof t==="string")return t==="string";return t.includes("string")}function isObjectType(t){if(t===undefined)return false;if(typeof t==="string")return t==="object";return t.includes("object")}function isArrayType(t){if(t===undefined)return false;if(typeof t==="string")return t==="array";return t.includes("array")}function hasNumericKeywords(s){return s.minimum!==undefined||s.maximum!==undefined||s.exclusiveMinimum!==undefined||s.exclusiveMaximum!==undefined||s.multipleOf!==undefined}function hasStringKeywords(s){return s.minLength!==undefined||s.maxLength!==undefined||s.pattern!==undefined||s.format!==undefined}function hasObjectKeywords(s){return s.minProperties!==undefined||s.maxProperties!==undefined||s.propertyNames!==undefined||s.additionalProperties!==undefined||(0,_utilsts.isPlainObj)(s.patternProperties)||(0,_utilsts.isPlainObj)(s.dependencies)}function hasArrayKeywords(s){return s.minItems!==undefined||s.maxItems!==undefined||s.uniqueItems!==undefined||s.contains!==undefined}function computeSemanticErrors(sub,sup,path=""){if(typeof sup==="boolean"){if(sup===false){return[{key:path||"$root",expected:"never",received:formatSchemaType(sub)}]}return[]}if(typeof sub==="boolean"){if(sub===true){return[{key:path||"$root",expected:formatSchemaType(sup),received:"any"}]}return[]}const subSchema=sub;const supSchema=sup;const errors=[];if((0,_utilsts.hasOwn)(supSchema,"not")&&(0,_utilsts.isPlainObj)(supSchema.not)&&typeof supSchema.not!=="boolean"){const notSchema=supSchema.not;const notFormatted=formatSchemaType(notSchema);if(!(0,_utilsts.hasOwn)(subSchema,"not")){errors.push({key:path||"$root",expected:`not ${notFormatted}`,received:formatSchemaType(subSchema)})}else if((0,_utilsts.isPlainObj)(subSchema.not)&&typeof subSchema.not!=="boolean"){const subNotSchema=subSchema.not;if(!(0,_utilsts.deepEqual)(subNotSchema,notSchema)){errors.push({key:path||"$root",expected:`not ${notFormatted}`,received:`not ${formatSchemaType(subNotSchema)}`})}}}const subType=getEffectiveType(subSchema);const supType=getEffectiveType(supSchema);const supBranches=supSchema.anyOf??supSchema.oneOf;if(Array.isArray(supBranches)&&supBranches.length>0&&!supSchema.type){return computeErrorsAgainstBranches(subSchema,supBranches,path)}const subBranches=subSchema.anyOf??subSchema.oneOf;if(Array.isArray(subBranches)&&subBranches.length>0&&!subSchema.type){const branchErrors=[];for(const branch of subBranches){const errs=computeSemanticErrors(branch,sup,path);branchErrors.push(...errs)}return branchErrors}const supProps=getProperties(supSchema);const subProps=getProperties(subSchema);if(supProps!==null||isObjectType(supType)){if(subType!==undefined&&!typeIncludes(subType,"object")){errors.push({key:path||"$root",expected:formatSchemaType(supSchema),received:formatSchemaType(subSchema)});return errors}if(supProps!==null){const supRequired=getRequired(supSchema);const subRequired=getRequired(subSchema);for(const key of Object.keys(supProps)){const propPath=joinPath(path,key);const supPropDef=supProps[key];const subPropDef=subProps?.[key];if(supPropDef===undefined)continue;const isRequiredInSup=supRequired.includes(key);if(subPropDef===undefined){if(isRequiredInSup){errors.push({key:propPath,expected:formatSchemaType(supPropDef),received:"undefined"})}continue}if(isRequiredInSup&&!subRequired.includes(key)){errors.push({key:propPath,expected:"not optional",received:"optional"});continue}const propErrors=comparePropertySchemas(subPropDef,supPropDef,propPath);errors.push(...propErrors)}}checkCustomConstraints(subSchema,supSchema,path,errors);checkObjectConstraints(subSchema,supSchema,path,errors);return errors}if((supType==="array"||supSchema.items!==undefined)&&(subType==="array"||subSchema.items!==undefined)){if(supSchema.items!==undefined&&typeof supSchema.items!=="boolean"){if(subSchema.items!==undefined&&typeof subSchema.items!=="boolean"){if(Array.isArray(supSchema.items)&&Array.isArray(subSchema.items)){const maxLen=Math.max(supSchema.items.length,subSchema.items.length);for(let i=0;i<maxLen;i++){const supItem=supSchema.items[i];const subItem=subSchema.items[i];const itemPath=joinPath(path,`[${i}]`);if(supItem!==undefined&&subItem===undefined){errors.push({key:itemPath,expected:formatSchemaType(supItem),received:"undefined"})}else if(supItem!==undefined&&subItem!==undefined){errors.push(...computeSemanticErrors(subItem,supItem,itemPath))}}}else if(!Array.isArray(supSchema.items)&&!Array.isArray(subSchema.items)){const itemPath=arrayPath(path);const itemErrors=computeSemanticErrors(subSchema.items,supSchema.items,itemPath);errors.push(...itemErrors)}}else{errors.push({key:path||"$root",expected:formatSchemaType(supSchema),received:formatSchemaType(subSchema)})}}checkCustomConstraints(subSchema,supSchema,path,errors);checkArrayConstraints(subSchema,supSchema,path,errors);return errors}if(subType!==undefined&&supType!==undefined){if(!typesAreCompatible(subType,supType)){errors.push({key:path||"$root",expected:formatSchemaType(supSchema),received:formatSchemaType(subSchema)});return errors}}if(Array.isArray(supSchema.enum)){if(Array.isArray(subSchema.enum)){const subExtra=subSchema.enum.filter(v=>!supSchema.enum?.some(sv=>(0,_utilsts.deepEqual)(v,sv)));if(subExtra.length>0){errors.push({key:path||"$root",expected:formatEnumValues(supSchema.enum),received:formatEnumValues(subSchema.enum)})}}else if((0,_utilsts.hasOwn)(subSchema,"const")){const constInEnum=supSchema.enum.some(v=>(0,_utilsts.deepEqual)(v,subSchema.const));if(!constInEnum){errors.push({key:path||"$root",expected:formatEnumValues(supSchema.enum),received:formatSchemaType(subSchema)})}}else{errors.push({key:path||"$root",expected:formatEnumValues(supSchema.enum),received:formatSchemaType(subSchema)})}return errors}if((0,_utilsts.hasOwn)(supSchema,"const")&&(0,_utilsts.hasOwn)(subSchema,"const")){if(!(0,_utilsts.deepEqual)(supSchema.const,subSchema.const)){errors.push({key:path||"$root",expected:formatSchemaType(supSchema),received:formatSchemaType(subSchema)})}return errors}checkCustomConstraints(subSchema,supSchema,path,errors);if(isNumericType(subType)||isNumericType(supType)||hasNumericKeywords(supSchema)||hasNumericKeywords(subSchema)){checkNumericConstraints(subSchema,supSchema,path,errors)}if(isStringType(subType)||isStringType(supType)||hasStringKeywords(supSchema)||hasStringKeywords(subSchema)){checkStringConstraints(subSchema,supSchema,path,errors)}if(isObjectType(subType)||isObjectType(supType)||hasObjectKeywords(supSchema)||hasObjectKeywords(subSchema)){checkObjectConstraints(subSchema,supSchema,path,errors)}if(isArrayType(subType)||isArrayType(supType)||hasArrayKeywords(supSchema)||hasArrayKeywords(subSchema)){checkArrayConstraints(subSchema,supSchema,path,errors)}if(errors.length>0){return errors}const expectedStr=formatSchemaType(supSchema);const receivedStr=formatSchemaType(subSchema);if(expectedStr!==receivedStr){errors.push({key:path||"$root",expected:expectedStr,received:receivedStr})}return errors}function comparePropertySchemas(subDef,supDef,path){if(typeof subDef==="boolean"||typeof supDef==="boolean"){if(subDef!==supDef){return[{key:path,expected:formatSchemaType(supDef),received:formatSchemaType(subDef)}]}return[]}const subSchema=subDef;const supSchema=supDef;const subType=getEffectiveType(subSchema);const supType=getEffectiveType(supSchema);if(Array.isArray(supSchema.enum)){if(Array.isArray(subSchema.enum)){const subExtra=subSchema.enum.filter(v=>!supSchema.enum?.some(sv=>(0,_utilsts.deepEqual)(v,sv)));if(subExtra.length>0){return[{key:path,expected:formatEnumValues(supSchema.enum),received:formatEnumValues(subSchema.enum)}]}return[]}if((0,_utilsts.hasOwn)(subSchema,"const")){const constInEnum=supSchema.enum.some(v=>(0,_utilsts.deepEqual)(v,subSchema.const));if(!constInEnum){return[{key:path,expected:formatEnumValues(supSchema.enum),received:formatSchemaType(subSchema)}]}return[]}return[{key:path,expected:formatEnumValues(supSchema.enum),received:formatSchemaType(subSchema)}]}if((0,_utilsts.hasOwn)(supSchema,"const")&&(0,_utilsts.hasOwn)(subSchema,"const")){if(!(0,_utilsts.deepEqual)(supSchema.const,subSchema.const)){return[{key:path,expected:formatSchemaType(supSchema),received:formatSchemaType(subSchema)}]}return[]}if(subType!==undefined&&supType!==undefined){if(!typesAreCompatible(subType,supType)){return[{key:path,expected:formatSchemaType(supSchema),received:formatSchemaType(subSchema)}]}}return computeSemanticErrors(subDef,supDef,path)}function computeErrorsAgainstBranches(sub,branches,path){let bestErrors=null;for(const branch of branches){const errors=computeSemanticErrors(sub,branch,path);if(errors.length===0)return[];if(bestErrors===null||errors.length<bestErrors.length){bestErrors=errors}}return bestErrors??[{key:path||"$root",expected:formatSchemaType({anyOf:branches}),received:formatSchemaType(sub)}]}
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:true});function _export(target,all){for(var name in all)Object.defineProperty(target,name,{enumerable:true,get:Object.getOwnPropertyDescriptor(all,name).get})}_export(exports,{get computeSemanticErrors(){return computeSemanticErrors},get formatSchemaType(){return formatSchemaType}});const _utilsts=require("./utils.js");function formatEnumValues(values){const parts=values.map(v=>typeof v==="string"?v:JSON.stringify(v));if(parts.length===0)return"never";if(parts.length===1)return parts[0];if(parts.length===2)return`${parts[0]} or ${parts[1]}`;const last=parts.pop();return`${parts.join(", ")}, or ${last}`}function formatSchemaType(def){return formatSchemaTypeInternal(def)}function formatSchemaTypeInternal(def){if(def===undefined)return"undefined";if(typeof def==="boolean")return def?"any":"never";const schema=def;if((0,_utilsts.hasOwn)(schema,"const")){const v=schema.const;return typeof v==="string"?v:JSON.stringify(v)}if(Array.isArray(schema.enum)){return formatEnumValues(schema.enum)}const branches=schema.anyOf??schema.oneOf;if(Array.isArray(branches)&&branches.length>0){const parts=branches.map(b=>formatSchemaType(b));return parts.join(" | ")}if(schema.type==="array"){if(schema.items!==undefined&&typeof schema.items!=="boolean"){const itemSchema=schema.items;const itemBranches=itemSchema.anyOf??itemSchema.oneOf;if(Array.isArray(itemBranches)&&itemBranches.length>0){const parts=itemBranches.map(b=>`${formatSchemaType(b)}[]`);return parts.join(" | ")}if(Array.isArray(itemSchema.type)){const parts=itemSchema.type.map(t=>`${t}[]`);return parts.join(" | ")}const itemType=formatSchemaType(itemSchema);return`${itemType}[]`}return"array"}if(typeof schema.type==="string"){return schema.type}if(Array.isArray(schema.type)){return schema.type.join(" | ")}if((0,_utilsts.hasOwn)(schema,"not")&&!schema.type&&!(0,_utilsts.isPlainObj)(schema.properties)&&schema.items===undefined&&!Array.isArray(schema.enum)&&!(0,_utilsts.hasOwn)(schema,"const")){return`not ${formatSchemaType(schema.not)}`}if((0,_utilsts.isPlainObj)(schema.properties))return"object";if(schema.items!==undefined)return"array";return"unknown"}function joinPath(parent,key){if(!parent)return key;return`${parent}.${key}`}function arrayPath(parent){if(!parent)return"[]";return`${parent}[]`}function getProperties(schema){if((0,_utilsts.isPlainObj)(schema.properties)){return schema.properties}return null}function getRequired(schema){if(Array.isArray(schema.required)){return schema.required}return[]}function getEffectiveType(schema){if(schema.type!==undefined)return schema.type;if((0,_utilsts.hasOwn)(schema,"const")){const v=schema.const;if(v===null)return"null";if(Array.isArray(v))return"array";return typeof v}if((0,_utilsts.isPlainObj)(schema.properties))return"object";if(schema.items!==undefined)return"array";return undefined}function typeIncludes(schemaType,target){if(schemaType===undefined)return false;if(typeof schemaType==="string"){if(target==="number"&&schemaType==="integer")return true;if(target==="integer"&&schemaType==="number")return true;return schemaType===target}return schemaType.includes(target)}function typesAreCompatible(subType,supType){if(supType===undefined)return true;if(subType===undefined)return true;if(typeof subType==="string"&&typeof supType==="string"){if(subType===supType)return true;if(subType==="integer"&&supType==="number")return true;return false}if(typeof subType==="string"&&Array.isArray(supType)){return supType.some(t=>t===subType||subType==="integer"&&t==="number")}if(Array.isArray(subType)&&typeof supType==="string"){return subType.every(t=>t===supType||t==="integer"&&supType==="number")}if(Array.isArray(subType)&&Array.isArray(supType)){return subType.every(st=>supType.some(supt=>supt===st||st==="integer"&&supt==="number"))}return true}function fmtConstraint(name,value){if(value===undefined)return`${name}: not set`;if(typeof value==="boolean")return`${name}: ${value}`;if(typeof value==="number"||typeof value==="string")return`${name}: ${value}`;return`${name}: ${JSON.stringify(value)}`}function checkMinConstraint(subVal,supVal,name,path,errors){if(supVal!==undefined){if(subVal===undefined||subVal<supVal){errors.push({key:path||"$root",expected:fmtConstraint(name,supVal),received:fmtConstraint(name,subVal)})}}}function checkMaxConstraint(subVal,supVal,name,path,errors){if(supVal!==undefined){if(subVal===undefined||subVal>supVal){errors.push({key:path||"$root",expected:fmtConstraint(name,supVal),received:fmtConstraint(name,subVal)})}}}function checkNumericConstraints(sub,sup,path,errors){checkMinConstraint(sub.minimum,sup.minimum,"minimum",path,errors);checkMaxConstraint(sub.maximum,sup.maximum,"maximum",path,errors);checkMinConstraint(sub.exclusiveMinimum,sup.exclusiveMinimum,"exclusiveMinimum",path,errors);checkMaxConstraint(sub.exclusiveMaximum,sup.exclusiveMaximum,"exclusiveMaximum",path,errors);if(sup.multipleOf!==undefined){if(sub.multipleOf===undefined){errors.push({key:path||"$root",expected:fmtConstraint("multipleOf",sup.multipleOf),received:fmtConstraint("multipleOf",sub.multipleOf)})}else if(sub.multipleOf!==sup.multipleOf){if(sub.multipleOf%sup.multipleOf!==0){errors.push({key:path||"$root",expected:fmtConstraint("multipleOf",sup.multipleOf),received:fmtConstraint("multipleOf",sub.multipleOf)})}}}}function checkStringConstraints(sub,sup,path,errors){checkMinConstraint(sub.minLength,sup.minLength,"minLength",path,errors);checkMaxConstraint(sub.maxLength,sup.maxLength,"maxLength",path,errors);if(sup.pattern!==undefined){if(sub.pattern===undefined){errors.push({key:path||"$root",expected:fmtConstraint("pattern",sup.pattern),received:"no pattern constraint"})}else if(sub.pattern!==sup.pattern){errors.push({key:path||"$root",expected:fmtConstraint("pattern",sup.pattern),received:fmtConstraint("pattern",sub.pattern)})}}if(sup.format!==undefined&&sub.format!==sup.format){if(sub.format===undefined){errors.push({key:path||"$root",expected:fmtConstraint("format",sup.format),received:"no format constraint"})}else{errors.push({key:path||"$root",expected:fmtConstraint("format",sup.format),received:fmtConstraint("format",sub.format)})}}}function checkObjectConstraints(sub,sup,path,errors){if(sup.additionalProperties!==undefined){if(sup.additionalProperties===false){if(sub.additionalProperties===undefined||sub.additionalProperties===true){errors.push({key:path||"$root",expected:"additionalProperties: false",received:"additional properties allowed"})}else if(typeof sub.additionalProperties==="object"&&sub.additionalProperties!==null){errors.push({key:path||"$root",expected:"additionalProperties: false",received:"additionalProperties: schema"})}}else if(typeof sup.additionalProperties==="object"&&sup.additionalProperties!==null){if(sub.additionalProperties===undefined||sub.additionalProperties===true){errors.push({key:path||"$root",expected:`additionalProperties: ${formatSchemaType(sup.additionalProperties)}`,received:"additional properties allowed"})}else if(typeof sub.additionalProperties==="object"&&sub.additionalProperties!==null){const apPath=path?`${path}.<additionalProperties>`:"<additionalProperties>";const apErrors=computeSemanticErrors(sub.additionalProperties,sup.additionalProperties,apPath);errors.push(...apErrors)}}}checkMinConstraint(sub.minProperties,sup.minProperties,"minProperties",path,errors);checkMaxConstraint(sub.maxProperties,sup.maxProperties,"maxProperties",path,errors);if(sup.propertyNames!==undefined){if(sub.propertyNames===undefined){errors.push({key:path||"$root",expected:`propertyNames: ${formatSchemaType(sup.propertyNames)}`,received:"no propertyNames constraint"})}else{const pnErrors=computeSemanticErrors(sub.propertyNames,sup.propertyNames,path?`${path}.<propertyNames>`:"<propertyNames>");errors.push(...pnErrors)}}if((0,_utilsts.isPlainObj)(sup.dependencies)){const supDeps=sup.dependencies;const subDeps=(0,_utilsts.isPlainObj)(sub.dependencies)?sub.dependencies:null;for(const key of Object.keys(supDeps)){const supDep=supDeps[key];const subDep=subDeps?.[key];if(subDep===undefined){if(Array.isArray(supDep)){errors.push({key:path||"$root",expected:`dependency: ${key} requires ${supDep.join(", ")}`,received:`no dependency for ${key}`})}else{errors.push({key:path||"$root",expected:`dependency: ${key} requires schema`,received:`no dependency for ${key}`})}}else if(Array.isArray(supDep)&&Array.isArray(subDep)){const missing=supDep.filter(d=>!subDep.includes(d));if(missing.length>0){errors.push({key:path||"$root",expected:`dependency: ${key} requires ${supDep.join(", ")}`,received:`dependency: ${key} requires ${subDep.join(", ")}`})}}else if(!Array.isArray(supDep)&&!Array.isArray(subDep)){const depPath=path?`${path}.<dependency:${key}>`:`<dependency:${key}>`;const depErrors=computeSemanticErrors(subDep,supDep,depPath);errors.push(...depErrors)}else{errors.push({key:path||"$root",expected:Array.isArray(supDep)?`dependency: ${key} requires ${supDep.join(", ")}`:`dependency: ${key} requires schema`,received:Array.isArray(subDep)?`dependency: ${key} requires ${subDep.join(", ")}`:`dependency: ${key} requires schema`})}}}if((0,_utilsts.isPlainObj)(sup.patternProperties)){const supPP=sup.patternProperties;const subPP=(0,_utilsts.isPlainObj)(sub.patternProperties)?sub.patternProperties:null;for(const pattern of Object.keys(supPP)){const supPropDef=supPP[pattern];if(supPropDef===undefined)continue;const subPropDef=subPP?.[pattern];const ppPath=path?`${path}.<patternProperties:${pattern}>`:`<patternProperties:${pattern}>`;if(subPropDef===undefined){errors.push({key:ppPath,expected:formatSchemaType(supPropDef),received:"no constraint for this pattern"})}else{const ppErrors=computeSemanticErrors(subPropDef,supPropDef,ppPath);errors.push(...ppErrors)}}}}function checkArrayConstraints(sub,sup,path,errors){checkMinConstraint(sub.minItems,sup.minItems,"minItems",path,errors);checkMaxConstraint(sub.maxItems,sup.maxItems,"maxItems",path,errors);if(sup.uniqueItems===true&&sub.uniqueItems!==true){errors.push({key:path||"$root",expected:"uniqueItems: true",received:fmtConstraint("uniqueItems",sub.uniqueItems??false)})}if(sup.contains!==undefined){if(sub.contains===undefined){errors.push({key:path||"$root",expected:`contains: ${formatSchemaType(sup.contains)}`,received:"no contains constraint"})}else{const containsPath=path?`${path}.<contains>`:"<contains>";const containsErrors=computeSemanticErrors(sub.contains,sup.contains,containsPath);errors.push(...containsErrors)}}}function isNumericType(t){if(t===undefined)return false;if(typeof t==="string")return t==="number"||t==="integer";return t.some(v=>v==="number"||v==="integer")}function isStringType(t){if(t===undefined)return false;if(typeof t==="string")return t==="string";return t.includes("string")}function isObjectType(t){if(t===undefined)return false;if(typeof t==="string")return t==="object";return t.includes("object")}function isArrayType(t){if(t===undefined)return false;if(typeof t==="string")return t==="array";return t.includes("array")}function hasNumericKeywords(s){return s.minimum!==undefined||s.maximum!==undefined||s.exclusiveMinimum!==undefined||s.exclusiveMaximum!==undefined||s.multipleOf!==undefined}function hasStringKeywords(s){return s.minLength!==undefined||s.maxLength!==undefined||s.pattern!==undefined||s.format!==undefined}function hasObjectKeywords(s){return s.minProperties!==undefined||s.maxProperties!==undefined||s.propertyNames!==undefined||s.additionalProperties!==undefined||(0,_utilsts.isPlainObj)(s.patternProperties)||(0,_utilsts.isPlainObj)(s.dependencies)}function hasArrayKeywords(s){return s.minItems!==undefined||s.maxItems!==undefined||s.uniqueItems!==undefined||s.contains!==undefined}function computeSemanticErrors(sub,sup,path=""){if(typeof sup==="boolean"){if(sup===false){return[{key:path||"$root",expected:"never",received:formatSchemaType(sub)}]}return[]}if(typeof sub==="boolean"){if(sub===true){return[{key:path||"$root",expected:formatSchemaType(sup),received:"any"}]}return[]}const subSchema=sub;const supSchema=sup;const errors=[];if((0,_utilsts.hasOwn)(supSchema,"not")&&(0,_utilsts.isPlainObj)(supSchema.not)&&typeof supSchema.not!=="boolean"){const notSchema=supSchema.not;const notFormatted=formatSchemaType(notSchema);if(!(0,_utilsts.hasOwn)(subSchema,"not")){errors.push({key:path||"$root",expected:`not ${notFormatted}`,received:formatSchemaType(subSchema)})}else if((0,_utilsts.isPlainObj)(subSchema.not)&&typeof subSchema.not!=="boolean"){const subNotSchema=subSchema.not;if(!(0,_utilsts.deepEqual)(subNotSchema,notSchema)){errors.push({key:path||"$root",expected:`not ${notFormatted}`,received:`not ${formatSchemaType(subNotSchema)}`})}}}const subType=getEffectiveType(subSchema);const supType=getEffectiveType(supSchema);const supBranches=supSchema.anyOf??supSchema.oneOf;if(Array.isArray(supBranches)&&supBranches.length>0&&!supSchema.type){return computeErrorsAgainstBranches(subSchema,supBranches,path)}const subBranches=subSchema.anyOf??subSchema.oneOf;if(Array.isArray(subBranches)&&subBranches.length>0&&!subSchema.type){const branchErrors=[];for(const branch of subBranches){const errs=computeSemanticErrors(branch,sup,path);branchErrors.push(...errs)}return branchErrors}const supProps=getProperties(supSchema);const subProps=getProperties(subSchema);if(supProps!==null||isObjectType(supType)){if(subType!==undefined&&!typeIncludes(subType,"object")){errors.push({key:path||"$root",expected:formatSchemaType(supSchema),received:formatSchemaType(subSchema)});return errors}if(supProps!==null){const supRequired=getRequired(supSchema);const subRequired=getRequired(subSchema);for(const key of Object.keys(supProps)){const propPath=joinPath(path,key);const supPropDef=supProps[key];const subPropDef=subProps?.[key];if(supPropDef===undefined)continue;const isRequiredInSup=supRequired.includes(key);if(subPropDef===undefined){if(isRequiredInSup){errors.push({key:propPath,expected:formatSchemaType(supPropDef),received:"undefined"})}continue}if(isRequiredInSup&&!subRequired.includes(key)){errors.push({key:propPath,expected:"not optional",received:"optional"});continue}const propErrors=comparePropertySchemas(subPropDef,supPropDef,propPath);errors.push(...propErrors)}}checkObjectConstraints(subSchema,supSchema,path,errors);return errors}if((supType==="array"||supSchema.items!==undefined)&&(subType==="array"||subSchema.items!==undefined)){if(supSchema.items!==undefined&&typeof supSchema.items!=="boolean"){if(subSchema.items!==undefined&&typeof subSchema.items!=="boolean"){if(Array.isArray(supSchema.items)&&Array.isArray(subSchema.items)){const maxLen=Math.max(supSchema.items.length,subSchema.items.length);for(let i=0;i<maxLen;i++){const supItem=supSchema.items[i];const subItem=subSchema.items[i];const itemPath=joinPath(path,`[${i}]`);if(supItem!==undefined&&subItem===undefined){errors.push({key:itemPath,expected:formatSchemaType(supItem),received:"undefined"})}else if(supItem!==undefined&&subItem!==undefined){errors.push(...computeSemanticErrors(subItem,supItem,itemPath))}}}else if(!Array.isArray(supSchema.items)&&!Array.isArray(subSchema.items)){const itemPath=arrayPath(path);const itemErrors=computeSemanticErrors(subSchema.items,supSchema.items,itemPath);errors.push(...itemErrors)}}else{errors.push({key:path||"$root",expected:formatSchemaType(supSchema),received:formatSchemaType(subSchema)})}}checkArrayConstraints(subSchema,supSchema,path,errors);return errors}if(subType!==undefined&&supType!==undefined){if(!typesAreCompatible(subType,supType)){errors.push({key:path||"$root",expected:formatSchemaType(supSchema),received:formatSchemaType(subSchema)});return errors}}if(Array.isArray(supSchema.enum)){if(Array.isArray(subSchema.enum)){const subExtra=subSchema.enum.filter(v=>!supSchema.enum?.some(sv=>(0,_utilsts.deepEqual)(v,sv)));if(subExtra.length>0){errors.push({key:path||"$root",expected:formatEnumValues(supSchema.enum),received:formatEnumValues(subSchema.enum)})}}else if((0,_utilsts.hasOwn)(subSchema,"const")){const constInEnum=supSchema.enum.some(v=>(0,_utilsts.deepEqual)(v,subSchema.const));if(!constInEnum){errors.push({key:path||"$root",expected:formatEnumValues(supSchema.enum),received:formatSchemaType(subSchema)})}}else{errors.push({key:path||"$root",expected:formatEnumValues(supSchema.enum),received:formatSchemaType(subSchema)})}return errors}if((0,_utilsts.hasOwn)(supSchema,"const")&&(0,_utilsts.hasOwn)(subSchema,"const")){if(!(0,_utilsts.deepEqual)(supSchema.const,subSchema.const)){errors.push({key:path||"$root",expected:formatSchemaType(supSchema),received:formatSchemaType(subSchema)})}return errors}if(isNumericType(subType)||isNumericType(supType)||hasNumericKeywords(supSchema)||hasNumericKeywords(subSchema)){checkNumericConstraints(subSchema,supSchema,path,errors)}if(isStringType(subType)||isStringType(supType)||hasStringKeywords(supSchema)||hasStringKeywords(subSchema)){checkStringConstraints(subSchema,supSchema,path,errors)}if(isObjectType(subType)||isObjectType(supType)||hasObjectKeywords(supSchema)||hasObjectKeywords(subSchema)){checkObjectConstraints(subSchema,supSchema,path,errors)}if(isArrayType(subType)||isArrayType(supType)||hasArrayKeywords(supSchema)||hasArrayKeywords(subSchema)){checkArrayConstraints(subSchema,supSchema,path,errors)}if(errors.length>0){return errors}const expectedStr=formatSchemaType(supSchema);const receivedStr=formatSchemaType(subSchema);if(expectedStr!==receivedStr){errors.push({key:path||"$root",expected:expectedStr,received:receivedStr})}return errors}function comparePropertySchemas(subDef,supDef,path){if(typeof subDef==="boolean"||typeof supDef==="boolean"){if(subDef!==supDef){return[{key:path,expected:formatSchemaType(supDef),received:formatSchemaType(subDef)}]}return[]}const subSchema=subDef;const supSchema=supDef;const subType=getEffectiveType(subSchema);const supType=getEffectiveType(supSchema);if(Array.isArray(supSchema.enum)){if(Array.isArray(subSchema.enum)){const subExtra=subSchema.enum.filter(v=>!supSchema.enum?.some(sv=>(0,_utilsts.deepEqual)(v,sv)));if(subExtra.length>0){return[{key:path,expected:formatEnumValues(supSchema.enum),received:formatEnumValues(subSchema.enum)}]}return[]}if((0,_utilsts.hasOwn)(subSchema,"const")){const constInEnum=supSchema.enum.some(v=>(0,_utilsts.deepEqual)(v,subSchema.const));if(!constInEnum){return[{key:path,expected:formatEnumValues(supSchema.enum),received:formatSchemaType(subSchema)}]}return[]}return[{key:path,expected:formatEnumValues(supSchema.enum),received:formatSchemaType(subSchema)}]}if((0,_utilsts.hasOwn)(supSchema,"const")&&(0,_utilsts.hasOwn)(subSchema,"const")){if(!(0,_utilsts.deepEqual)(supSchema.const,subSchema.const)){return[{key:path,expected:formatSchemaType(supSchema),received:formatSchemaType(subSchema)}]}return[]}if(subType!==undefined&&supType!==undefined){if(!typesAreCompatible(subType,supType)){return[{key:path,expected:formatSchemaType(supSchema),received:formatSchemaType(subSchema)}]}}return computeSemanticErrors(subDef,supDef,path)}function computeErrorsAgainstBranches(sub,branches,path){let bestErrors=null;for(const branch of branches){const errors=computeSemanticErrors(sub,branch,path);if(errors.length===0)return[];if(bestErrors===null||errors.length<bestErrors.length){bestErrors=errors}}return bestErrors??[{key:path||"$root",expected:formatSchemaType({anyOf:branches}),received:formatSchemaType(sub)}]}
|
|
2
2
|
//# sourceMappingURL=semantic-errors.js.map
|