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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/constraint-validator.ts"],"sourcesContent":["import type { JSONSchema7Definition } from \"json-schema\";\nimport type {\n\tConstraint,\n\tConstraintValidatorRegistry,\n\tSchemaError,\n} from \"./types.ts\";\nimport { hasOwn, isPlainObj, toConstraintArray } from \"./utils.ts\";\n\n// ─── Constraint Validator ────────────────────────────────────────────────────\n//\n// Validates runtime data against custom `constraints` found in a schema,\n// using the provided validator registry.\n//\n// This module is separate from `runtime-validator.ts` (which wraps AJV)\n// and from `format-validator.ts` (which handles the `format` keyword).\n\n/**\n * Validates a single value against a list of constraints using the registry.\n *\n * @param constraints - The constraints to validate against\n * @param value - The runtime value\n * @param registry - The constraint validator registry\n * @param path - The property path for error reporting\n * @returns Array of errors (empty if all constraints pass)\n */\nfunction validateValue(\n\tconstraints: Constraint[],\n\tvalue: unknown,\n\tregistry: ConstraintValidatorRegistry,\n\tpath: string,\n): SchemaError[] {\n\tconst errors: SchemaError[] = [];\n\n\tfor (const constraint of constraints) {\n\t\tconst name = typeof constraint === \"string\" ? constraint : constraint.name;\n\t\tconst params =\n\t\t\ttypeof constraint === \"string\" ? undefined : constraint.params;\n\n\t\tconst validator = registry[name];\n\n\t\tif (!validator) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: `constraint: ${name}`,\n\t\t\t\treceived: \"unknown constraint (not registered)\",\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst result = validator(value, params);\n\t\t\tif (!result.valid) {\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: `constraint: ${name}`,\n\t\t\t\t\treceived: result.message ?? \"constraint validation failed\",\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: `constraint: ${name}`,\n\t\t\t\treceived:\n\t\t\t\t\terr instanceof Error ? err.message : \"constraint validation error\",\n\t\t\t});\n\t\t}\n\t}\n\n\treturn errors;\n}\n\n/**\n * Recursively validates runtime data against all `constraints` found\n * in a schema, using the provided validator registry.\n *\n * Walks into: root-level constraints, `properties`, `patternProperties`,\n * `items` (single schema and tuple form), `additionalProperties` (schema form),\n * `dependencies` (schema form).\n *\n * @precondition `registry` must be non-empty. Callers should check\n * `Object.keys(registry).length > 0` before calling this function\n * to avoid unnecessary recursion into schemas that have no validators.\n *\n * @param schema - The resolved/narrowed schema containing constraints\n * @param data - The runtime data to validate\n * @param registry - The constraint validator registry (must be non-empty)\n * @param path - The current property path (for error reporting)\n * @returns Array of schema errors (empty if all constraints pass)\n */\nexport function validateSchemaConstraints(\n\tschema: JSONSchema7Definition,\n\tdata: unknown,\n\tregistry: ConstraintValidatorRegistry,\n\tpath = \"\",\n): SchemaError[] {\n\t// Boolean schemas → nothing to validate\n\tif (typeof schema === \"boolean\") return [];\n\n\tconst errors: SchemaError[] = [];\n\n\t// ── Root-level constraints ──\n\tconst constraints = toConstraintArray(schema.constraints);\n\tif (constraints.length > 0) {\n\t\terrors.push(...validateValue(constraints, data, registry, path));\n\t}\n\n\t// ── Recurse into properties ──\n\tif (isPlainObj(schema.properties) && isPlainObj(data)) {\n\t\tconst props = schema.properties as Record<string, JSONSchema7Definition>;\n\t\tconst dataObj = data as Record<string, unknown>;\n\n\t\tfor (const key of Object.keys(props)) {\n\t\t\tconst propSchema = props[key];\n\t\t\tif (propSchema === undefined) continue;\n\n\t\t\tconst propValue = dataObj[key];\n\t\t\t// Only validate if the property exists in the data\n\t\t\tif (propValue === undefined && !hasOwn(dataObj, key)) continue;\n\n\t\t\tconst propPath = path ? `${path}.${key}` : key;\n\t\t\terrors.push(\n\t\t\t\t...validateSchemaConstraints(propSchema, propValue, registry, propPath),\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── Recurse into items (single schema) ──\n\tif (isPlainObj(schema.items) && Array.isArray(data)) {\n\t\tconst itemSchema = schema.items as JSONSchema7Definition;\n\t\tconst itemPath = path ? `${path}[]` : \"[]\";\n\n\t\tfor (let i = 0; i < data.length; i++) {\n\t\t\terrors.push(\n\t\t\t\t...validateSchemaConstraints(itemSchema, data[i], registry, itemPath),\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── Recurse into tuple items ──\n\tif (Array.isArray(schema.items) && Array.isArray(data)) {\n\t\tconst tupleSchemas = schema.items as JSONSchema7Definition[];\n\t\tfor (let i = 0; i < tupleSchemas.length && i < data.length; i++) {\n\t\t\tconst itemSchema = tupleSchemas[i];\n\t\t\tif (itemSchema === undefined) continue;\n\t\t\tconst itemPath = path ? `${path}[${i}]` : `[${i}]`;\n\t\t\terrors.push(\n\t\t\t\t...validateSchemaConstraints(itemSchema, data[i], registry, itemPath),\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── Recurse into patternProperties ──\n\tif (isPlainObj(schema.patternProperties) && isPlainObj(data)) {\n\t\tconst pp = schema.patternProperties as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tconst dataObj = data as Record<string, unknown>;\n\n\t\tfor (const pattern of Object.keys(pp)) {\n\t\t\tconst patternSchema = pp[pattern];\n\t\t\tif (patternSchema === undefined || typeof patternSchema === \"boolean\")\n\t\t\t\tcontinue;\n\n\t\t\tlet regex: RegExp;\n\t\t\ttry {\n\t\t\t\tregex = new RegExp(pattern);\n\t\t\t} catch {\n\t\t\t\t// Invalid regex pattern — skip silently (same approach as AJV)\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const dataKey of Object.keys(dataObj)) {\n\t\t\t\tif (!regex.test(dataKey)) continue;\n\n\t\t\t\tconst dataValue = dataObj[dataKey];\n\t\t\t\tconst ppPath = path ? `${path}.${dataKey}` : dataKey;\n\t\t\t\terrors.push(\n\t\t\t\t\t...validateSchemaConstraints(\n\t\t\t\t\t\tpatternSchema,\n\t\t\t\t\t\tdataValue,\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t\tppPath,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Recurse into additionalProperties (schema form) ──\n\tif (\n\t\tisPlainObj(schema.additionalProperties) &&\n\t\ttypeof schema.additionalProperties !== \"boolean\" &&\n\t\tisPlainObj(data)\n\t) {\n\t\tconst apSchema = schema.additionalProperties as JSONSchema7Definition;\n\t\tconst dataObj = data as Record<string, unknown>;\n\t\tconst definedProps = isPlainObj(schema.properties)\n\t\t\t? new Set(Object.keys(schema.properties as Record<string, unknown>))\n\t\t\t: new Set<string>();\n\n\t\t// Collect patternProperties regexes to exclude matching keys\n\t\tconst ppPatterns: RegExp[] = [];\n\t\tif (isPlainObj(schema.patternProperties)) {\n\t\t\tfor (const pattern of Object.keys(\n\t\t\t\tschema.patternProperties as Record<string, unknown>,\n\t\t\t)) {\n\t\t\t\ttry {\n\t\t\t\t\tppPatterns.push(new RegExp(pattern));\n\t\t\t\t} catch {\n\t\t\t\t\t// Invalid pattern — skip\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const dataKey of Object.keys(dataObj)) {\n\t\t\t// Skip keys defined in properties\n\t\t\tif (definedProps.has(dataKey)) continue;\n\n\t\t\t// Skip keys matching any patternProperties pattern\n\t\t\tif (ppPatterns.some((re) => re.test(dataKey))) continue;\n\n\t\t\tconst dataValue = dataObj[dataKey];\n\t\t\tconst apPath = path ? `${path}.${dataKey}` : dataKey;\n\t\t\terrors.push(\n\t\t\t\t...validateSchemaConstraints(apSchema, dataValue, registry, apPath),\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── Recurse into dependencies (schema form) ──\n\tif (isPlainObj(schema.dependencies) && isPlainObj(data)) {\n\t\tconst deps = schema.dependencies as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t\tconst dataObj = data as Record<string, unknown>;\n\n\t\tfor (const depKey of Object.keys(deps)) {\n\t\t\t// Dependency only applies if the trigger key is present in data\n\t\t\tif (!hasOwn(dataObj, depKey)) continue;\n\n\t\t\tconst depValue = deps[depKey];\n\t\t\tif (depValue === undefined) continue;\n\n\t\t\t// Skip array-form dependencies (property deps, not schema deps)\n\t\t\tif (Array.isArray(depValue)) continue;\n\n\t\t\t// Skip boolean schemas\n\t\t\tif (typeof depValue === \"boolean\") continue;\n\n\t\t\t// Schema-form dependency: validate the entire data object against it\n\t\t\t// The dependency schema applies to the whole object, not just the dep key\n\t\t\terrors.push(...validateSchemaConstraints(depValue, data, registry, path));\n\t\t}\n\t}\n\n\treturn errors;\n}\n"],"names":["hasOwn","isPlainObj","toConstraintArray","validateValue","constraints","value","registry","path","errors","constraint","name","params","undefined","validator","push","key","expected","received","result","valid","message","err","Error","validateSchemaConstraints","schema","data","length","properties","props","dataObj","Object","keys","propSchema","propValue","propPath","items","Array","isArray","itemSchema","itemPath","i","tupleSchemas","patternProperties","pp","pattern","patternSchema","regex","RegExp","dataKey","test","dataValue","ppPath","additionalProperties","apSchema","definedProps","Set","ppPatterns","has","some","re","apPath","dependencies","deps","depKey","depValue"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/constraint-validator.ts"],"sourcesContent":["import type { JSONSchema7Definition } from \"json-schema\";\nimport type {\n\tConstraint,\n\tConstraintValidatorRegistry,\n\tSchemaError,\n} from \"./types.ts\";\nimport { hasOwn, isPlainObj, toConstraintArray } from \"./utils.ts\";\n\n// ─── Constraint Validator ────────────────────────────────────────────────────\n//\n// Validates runtime data against custom `constraints` found in a schema,\n// using the provided validator registry.\n//\n// This module is separate from `runtime-validator.ts` (which wraps AJV)\n// and from `format-validator.ts` (which handles the `format` keyword).\n\n/**\n * Validates a single value against a list of constraints using the registry.\n *\n * @param constraints - The constraints to validate against\n * @param value - The runtime value\n * @param registry - The constraint validator registry\n * @param path - The property path for error reporting\n * @returns Array of errors (empty if all constraints pass)\n */\nfunction validateValue(\n\tconstraints: Constraint[],\n\tvalue: unknown,\n\tregistry: ConstraintValidatorRegistry,\n\tpath: string,\n): SchemaError[] {\n\tconst errors: SchemaError[] = [];\n\n\tfor (const constraint of constraints) {\n\t\tconst name = typeof constraint === \"string\" ? constraint : constraint.name;\n\t\tconst params =\n\t\t\ttypeof constraint === \"string\" ? undefined : constraint.params;\n\n\t\tconst validator = registry[name];\n\n\t\tif (!validator) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: `constraint: ${name}`,\n\t\t\t\treceived: \"unknown constraint (not registered)\",\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst result = validator(value, params);\n\t\t\tif (!result.valid) {\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: `constraint: ${name}`,\n\t\t\t\t\treceived: result.message ?? \"constraint validation failed\",\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: `constraint: ${name}`,\n\t\t\t\treceived:\n\t\t\t\t\terr instanceof Error ? err.message : \"constraint validation error\",\n\t\t\t});\n\t\t}\n\t}\n\n\treturn errors;\n}\n\n/**\n * Recursively validates runtime data against all `constraints` found\n * in a schema, using the provided validator registry.\n *\n * Walks into: root-level constraints, `properties`, `patternProperties`,\n * `items` (single schema and tuple form), `additionalProperties` (schema form),\n * `dependencies` (schema form).\n *\n * When a schema declares a constraint that is not present in the registry,\n * an \"unknown constraint (not registered)\" error is produced. This ensures\n * that unregistered constraints are never silently ignored at runtime.\n *\n * @param schema - The resolved/narrowed schema containing constraints\n * @param data - The runtime data to validate\n * @param registry - The constraint validator registry (may be empty)\n * @param path - The current property path (for error reporting)\n * @returns Array of schema errors (empty if all constraints pass)\n */\nexport function validateSchemaConstraints(\n\tschema: JSONSchema7Definition,\n\tdata: unknown,\n\tregistry: ConstraintValidatorRegistry,\n\tpath = \"\",\n): SchemaError[] {\n\t// Boolean schemas → nothing to validate\n\tif (typeof schema === \"boolean\") return [];\n\n\tconst errors: SchemaError[] = [];\n\n\t// ── Root-level constraints ──\n\tconst constraints = toConstraintArray(schema.constraints);\n\tif (constraints.length > 0) {\n\t\terrors.push(...validateValue(constraints, data, registry, path));\n\t}\n\n\t// ── Recurse into properties ──\n\tif (isPlainObj(schema.properties) && isPlainObj(data)) {\n\t\tconst props = schema.properties as Record<string, JSONSchema7Definition>;\n\t\tconst dataObj = data as Record<string, unknown>;\n\n\t\tfor (const key of Object.keys(props)) {\n\t\t\tconst propSchema = props[key];\n\t\t\tif (propSchema === undefined) continue;\n\n\t\t\tconst propValue = dataObj[key];\n\t\t\t// Only validate if the property exists in the data\n\t\t\tif (propValue === undefined && !hasOwn(dataObj, key)) continue;\n\n\t\t\tconst propPath = path ? `${path}.${key}` : key;\n\t\t\terrors.push(\n\t\t\t\t...validateSchemaConstraints(propSchema, propValue, registry, propPath),\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── Recurse into items (single schema) ──\n\tif (isPlainObj(schema.items) && Array.isArray(data)) {\n\t\tconst itemSchema = schema.items as JSONSchema7Definition;\n\t\tconst itemPath = path ? `${path}[]` : \"[]\";\n\n\t\tfor (let i = 0; i < data.length; i++) {\n\t\t\terrors.push(\n\t\t\t\t...validateSchemaConstraints(itemSchema, data[i], registry, itemPath),\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── Recurse into tuple items ──\n\tif (Array.isArray(schema.items) && Array.isArray(data)) {\n\t\tconst tupleSchemas = schema.items as JSONSchema7Definition[];\n\t\tfor (let i = 0; i < tupleSchemas.length && i < data.length; i++) {\n\t\t\tconst itemSchema = tupleSchemas[i];\n\t\t\tif (itemSchema === undefined) continue;\n\t\t\tconst itemPath = path ? `${path}[${i}]` : `[${i}]`;\n\t\t\terrors.push(\n\t\t\t\t...validateSchemaConstraints(itemSchema, data[i], registry, itemPath),\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── Recurse into patternProperties ──\n\tif (isPlainObj(schema.patternProperties) && isPlainObj(data)) {\n\t\tconst pp = schema.patternProperties as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tconst dataObj = data as Record<string, unknown>;\n\n\t\tfor (const pattern of Object.keys(pp)) {\n\t\t\tconst patternSchema = pp[pattern];\n\t\t\tif (patternSchema === undefined || typeof patternSchema === \"boolean\")\n\t\t\t\tcontinue;\n\n\t\t\tlet regex: RegExp;\n\t\t\ttry {\n\t\t\t\tregex = new RegExp(pattern);\n\t\t\t} catch {\n\t\t\t\t// Invalid regex pattern — skip silently (same approach as AJV)\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const dataKey of Object.keys(dataObj)) {\n\t\t\t\tif (!regex.test(dataKey)) continue;\n\n\t\t\t\tconst dataValue = dataObj[dataKey];\n\t\t\t\tconst ppPath = path ? `${path}.${dataKey}` : dataKey;\n\t\t\t\terrors.push(\n\t\t\t\t\t...validateSchemaConstraints(\n\t\t\t\t\t\tpatternSchema,\n\t\t\t\t\t\tdataValue,\n\t\t\t\t\t\tregistry,\n\t\t\t\t\t\tppPath,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Recurse into additionalProperties (schema form) ──\n\tif (\n\t\tisPlainObj(schema.additionalProperties) &&\n\t\ttypeof schema.additionalProperties !== \"boolean\" &&\n\t\tisPlainObj(data)\n\t) {\n\t\tconst apSchema = schema.additionalProperties as JSONSchema7Definition;\n\t\tconst dataObj = data as Record<string, unknown>;\n\t\tconst definedProps = isPlainObj(schema.properties)\n\t\t\t? new Set(Object.keys(schema.properties as Record<string, unknown>))\n\t\t\t: new Set<string>();\n\n\t\t// Collect patternProperties regexes to exclude matching keys\n\t\tconst ppPatterns: RegExp[] = [];\n\t\tif (isPlainObj(schema.patternProperties)) {\n\t\t\tfor (const pattern of Object.keys(\n\t\t\t\tschema.patternProperties as Record<string, unknown>,\n\t\t\t)) {\n\t\t\t\ttry {\n\t\t\t\t\tppPatterns.push(new RegExp(pattern));\n\t\t\t\t} catch {\n\t\t\t\t\t// Invalid pattern — skip\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const dataKey of Object.keys(dataObj)) {\n\t\t\t// Skip keys defined in properties\n\t\t\tif (definedProps.has(dataKey)) continue;\n\n\t\t\t// Skip keys matching any patternProperties pattern\n\t\t\tif (ppPatterns.some((re) => re.test(dataKey))) continue;\n\n\t\t\tconst dataValue = dataObj[dataKey];\n\t\t\tconst apPath = path ? `${path}.${dataKey}` : dataKey;\n\t\t\terrors.push(\n\t\t\t\t...validateSchemaConstraints(apSchema, dataValue, registry, apPath),\n\t\t\t);\n\t\t}\n\t}\n\n\t// ── Recurse into dependencies (schema form) ──\n\tif (isPlainObj(schema.dependencies) && isPlainObj(data)) {\n\t\tconst deps = schema.dependencies as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t\tconst dataObj = data as Record<string, unknown>;\n\n\t\tfor (const depKey of Object.keys(deps)) {\n\t\t\t// Dependency only applies if the trigger key is present in data\n\t\t\tif (!hasOwn(dataObj, depKey)) continue;\n\n\t\t\tconst depValue = deps[depKey];\n\t\t\tif (depValue === undefined) continue;\n\n\t\t\t// Skip array-form dependencies (property deps, not schema deps)\n\t\t\tif (Array.isArray(depValue)) continue;\n\n\t\t\t// Skip boolean schemas\n\t\t\tif (typeof depValue === \"boolean\") continue;\n\n\t\t\t// Schema-form dependency: validate the entire data object against it\n\t\t\t// The dependency schema applies to the whole object, not just the dep key\n\t\t\terrors.push(...validateSchemaConstraints(depValue, data, registry, path));\n\t\t}\n\t}\n\n\treturn errors;\n}\n"],"names":["hasOwn","isPlainObj","toConstraintArray","validateValue","constraints","value","registry","path","errors","constraint","name","params","undefined","validator","push","key","expected","received","result","valid","message","err","Error","validateSchemaConstraints","schema","data","length","properties","props","dataObj","Object","keys","propSchema","propValue","propPath","items","Array","isArray","itemSchema","itemPath","i","tupleSchemas","patternProperties","pp","pattern","patternSchema","regex","RegExp","dataKey","test","dataValue","ppPath","additionalProperties","apSchema","definedProps","Set","ppPatterns","has","some","re","apPath","dependencies","deps","depKey","depValue"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- function _define_property(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}import{resolveConditions}from"./condition-resolver.js";import{validateSchemaConstraints}from"./constraint-validator.js";import{narrowSchemaWithData}from"./data-narrowing.js";import{formatResult}from"./formatter.js";import{MergeEngine}from"./merge-engine.js";import{normalize}from"./normalizer.js";import{arePatternsEquivalent,isPatternSubset,isTrivialPattern}from"./pattern-subset.js";import{clearAllValidatorCaches,getRuntimeValidationErrors}from"./runtime-validator.js";import{checkAtomic,checkBranchedSub,checkBranchedSup,getBranchesTyped,isAtomicSubsetOf}from"./subset-checker.js";import{deepEqual,isPlainObj}from"./utils.js";export{normalize,resolveConditions,formatResult,MergeEngine,isPatternSubset,arePatternsEquivalent,isTrivialPattern};export class JsonSchemaCompatibilityChecker{isSubset(sub,sup){if(sub===sup)return true;if(deepEqual(sub,sup))return true;const nSub=normalize(sub);const nSup=normalize(sup);if(nSub!==sub&&nSup!==sup&&deepEqual(nSub,nSup))return true;if(nSub!==nSup&&deepEqual(nSub,nSup))return true;const{branches:subBranches}=getBranchesTyped(nSub);if(subBranches.length>1||subBranches[0]!==nSub){return subBranches.every(branch=>isAtomicSubsetOf(branch,nSup,this.engine))}return isAtomicSubsetOf(nSub,nSup,this.engine)}check(sub,sup,options){if(options){const data=options.data;const shouldValidate=options.validate===true;const dataForConditions=isPlainObj(data)?data:{};const resolvedSub=resolveConditions(sub,dataForConditions,this.engine);const resolvedSup=resolveConditions(sup,dataForConditions,this.engine);const canNarrow=data!==undefined;const canNarrowSub=canNarrow&&isPlainObj(resolvedSub.resolved);const canNarrowSup=canNarrow&&isPlainObj(resolvedSup.resolved);const narrowedSubResolved=canNarrowSub?narrowSchemaWithData(resolvedSub.resolved,data,resolvedSup.resolved):resolvedSub.resolved;const narrowedSupResolved=canNarrowSup?narrowSchemaWithData(resolvedSup.resolved,data,resolvedSub.resolved):resolvedSup.resolved;const staticResult=this.checkInternal(narrowedSubResolved,narrowedSupResolved);if(!staticResult.isSubset){return{...staticResult,resolvedSub:{...resolvedSub,resolved:narrowedSubResolved},resolvedSup:{...resolvedSup,resolved:narrowedSupResolved}}}if(shouldValidate&&data!==undefined){const runtimeErrors=[];runtimeErrors.push(...this.prefixRuntimeErrors(getRuntimeValidationErrors(narrowedSubResolved,data),"$sub"));runtimeErrors.push(...this.prefixRuntimeErrors(getRuntimeValidationErrors(narrowedSupResolved,data),"$sup"));if(Object.keys(this.constraintValidators).length>0){runtimeErrors.push(...this.prefixRuntimeErrors(validateSchemaConstraints(narrowedSubResolved,data,this.constraintValidators),"$sub"));runtimeErrors.push(...this.prefixRuntimeErrors(validateSchemaConstraints(narrowedSupResolved,data,this.constraintValidators),"$sup"))}if(runtimeErrors.length>0){return{isSubset:false,merged:null,errors:runtimeErrors,resolvedSub:{...resolvedSub,resolved:narrowedSubResolved},resolvedSup:{...resolvedSup,resolved:narrowedSupResolved}}}}return{...staticResult,resolvedSub:{...resolvedSub,resolved:narrowedSubResolved},resolvedSup:{...resolvedSup,resolved:narrowedSupResolved}}}return this.checkInternal(sub,sup)}isEqual(a,b){return this.engine.isEqual(normalize(a),normalize(b))}intersect(a,b){if(a===b||deepEqual(a,b))return normalize(a);const nA=normalize(a);const nB=normalize(b);if(deepEqual(nA,nB))return nA;const merged=this.engine.merge(nA,nB);if(merged===null)return null;if(deepEqual(merged,nA)||deepEqual(merged,nB))return merged;return normalize(merged)}normalize(def){return normalize(def)}formatResult(label,result){return formatResult(label,result)}resolveConditions(schema,data){return resolveConditions(schema,data,this.engine)}prefixRuntimeErrors(errors,rootKey){return errors.map(error=>({...error,key:error.key==="$root"?rootKey:`${rootKey}.${error.key}`}))}checkInternal(sub,sup){if(sub===sup){return{isSubset:true,merged:sub,errors:[]}}if(deepEqual(sub,sup)){return{isSubset:true,merged:sub,errors:[]}}const nSub=normalize(sub);const nSup=normalize(sup);if(deepEqual(nSub,nSup)){return{isSubset:true,merged:nSub,errors:[]}}const{branches:subBranches,type:subBranchType}=getBranchesTyped(nSub);const{branches:supBranches,type:supBranchType}=getBranchesTyped(nSup);if(subBranches.length>1||subBranches[0]!==nSub){return checkBranchedSub(subBranches,nSup,this.engine,subBranchType)}if(supBranches.length>1||supBranches[0]!==nSup){return checkBranchedSup(nSub,supBranches,this.engine,supBranchType)}return checkAtomic(nSub,nSup,this.engine)}static clearCache(){clearAllValidatorCaches()}constructor(options){_define_property(this,"constraintValidators",void 0);_define_property(this,"engine",void 0);this.engine=new MergeEngine;this.constraintValidators=options?.constraints??{}}}
1
+ function _define_property(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}import{resolveConditions}from"./condition-resolver.js";import{validateSchemaConstraints}from"./constraint-validator.js";import{narrowSchemaWithData}from"./data-narrowing.js";import{formatResult}from"./formatter.js";import{MergeEngine}from"./merge-engine.js";import{normalize}from"./normalizer.js";import{arePatternsEquivalent,isPatternSubset,isTrivialPattern}from"./pattern-subset.js";import{clearAllValidatorCaches,getRuntimeValidationErrors}from"./runtime-validator.js";import{checkAtomic,checkBranchedSub,checkBranchedSup,getBranchesTyped,isAtomicSubsetOf}from"./subset-checker.js";import{deepEqual,isPlainObj}from"./utils.js";export{normalize,resolveConditions,formatResult,MergeEngine,isPatternSubset,arePatternsEquivalent,isTrivialPattern};export class JsonSchemaCompatibilityChecker{isSubset(sub,sup){if(sub===sup)return true;if(deepEqual(sub,sup))return true;const nSub=normalize(sub);const nSup=normalize(sup);if(nSub!==sub&&nSup!==sup&&deepEqual(nSub,nSup))return true;if(nSub!==nSup&&deepEqual(nSub,nSup))return true;const{branches:subBranches}=getBranchesTyped(nSub);if(subBranches.length>1||subBranches[0]!==nSub){return subBranches.every(branch=>isAtomicSubsetOf(branch,nSup,this.engine))}return isAtomicSubsetOf(nSub,nSup,this.engine)}check(sub,sup,options){if(options){const data=options.data;const shouldValidate=options.validate===true;const dataForConditions=isPlainObj(data)?data:{};const resolvedSub=resolveConditions(sub,dataForConditions,this.engine);const resolvedSup=resolveConditions(sup,dataForConditions,this.engine);const canNarrow=data!==undefined;const canNarrowSub=canNarrow&&isPlainObj(resolvedSub.resolved);const canNarrowSup=canNarrow&&isPlainObj(resolvedSup.resolved);const narrowedSubResolved=canNarrowSub?narrowSchemaWithData(resolvedSub.resolved,data,resolvedSup.resolved):resolvedSub.resolved;const narrowedSupResolved=canNarrowSup?narrowSchemaWithData(resolvedSup.resolved,data,resolvedSub.resolved):resolvedSup.resolved;const staticResult=this.checkInternal(narrowedSubResolved,narrowedSupResolved);if(!staticResult.isSubset){return{...staticResult,resolvedSub:{...resolvedSub,resolved:narrowedSubResolved},resolvedSup:{...resolvedSup,resolved:narrowedSupResolved}}}if(shouldValidate&&data!==undefined){const runtimeErrors=[];runtimeErrors.push(...this.prefixRuntimeErrors(getRuntimeValidationErrors(narrowedSubResolved,data),"$sub"));runtimeErrors.push(...this.prefixRuntimeErrors(getRuntimeValidationErrors(narrowedSupResolved,data),"$sup"));runtimeErrors.push(...this.prefixRuntimeErrors(validateSchemaConstraints(narrowedSubResolved,data,this.constraintValidators),"$sub"));runtimeErrors.push(...this.prefixRuntimeErrors(validateSchemaConstraints(narrowedSupResolved,data,this.constraintValidators),"$sup"));if(runtimeErrors.length>0){return{isSubset:false,merged:null,errors:runtimeErrors,resolvedSub:{...resolvedSub,resolved:narrowedSubResolved},resolvedSup:{...resolvedSup,resolved:narrowedSupResolved}}}}return{...staticResult,resolvedSub:{...resolvedSub,resolved:narrowedSubResolved},resolvedSup:{...resolvedSup,resolved:narrowedSupResolved}}}return this.checkInternal(sub,sup)}isEqual(a,b){return this.engine.isEqual(normalize(a),normalize(b))}intersect(a,b){if(a===b||deepEqual(a,b))return normalize(a);const nA=normalize(a);const nB=normalize(b);if(deepEqual(nA,nB))return nA;const merged=this.engine.merge(nA,nB);if(merged===null)return null;if(deepEqual(merged,nA)||deepEqual(merged,nB))return merged;return normalize(merged)}normalize(def){return normalize(def)}formatResult(label,result){return formatResult(label,result)}resolveConditions(schema,data){return resolveConditions(schema,data,this.engine)}prefixRuntimeErrors(errors,rootKey){return errors.map(error=>({...error,key:error.key==="$root"?rootKey:`${rootKey}.${error.key}`}))}checkInternal(sub,sup){if(sub===sup){return{isSubset:true,merged:sub,errors:[]}}if(deepEqual(sub,sup)){return{isSubset:true,merged:sub,errors:[]}}const nSub=normalize(sub);const nSup=normalize(sup);if(deepEqual(nSub,nSup)){return{isSubset:true,merged:nSub,errors:[]}}const{branches:subBranches,type:subBranchType}=getBranchesTyped(nSub);const{branches:supBranches,type:supBranchType}=getBranchesTyped(nSup);if(subBranches.length>1||subBranches[0]!==nSub){return checkBranchedSub(subBranches,nSup,this.engine,subBranchType)}if(supBranches.length>1||supBranches[0]!==nSup){return checkBranchedSup(nSub,supBranches,this.engine,supBranchType)}return checkAtomic(nSub,nSup,this.engine)}static clearCache(){clearAllValidatorCaches()}constructor(options){_define_property(this,"constraintValidators",void 0);_define_property(this,"engine",void 0);this.engine=new MergeEngine;this.constraintValidators=options?.constraints??{}}}
2
2
  //# sourceMappingURL=json-schema-compatibility-checker.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/json-schema-compatibility-checker.ts"],"sourcesContent":["import type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\nimport { resolveConditions } from \"./condition-resolver.ts\";\nimport { validateSchemaConstraints } from \"./constraint-validator.ts\";\nimport { narrowSchemaWithData } from \"./data-narrowing.ts\";\nimport { formatResult } from \"./formatter.ts\";\nimport { MergeEngine } from \"./merge-engine.ts\";\nimport { normalize } from \"./normalizer.ts\";\nimport {\n\tarePatternsEquivalent,\n\tisPatternSubset,\n\tisTrivialPattern,\n} from \"./pattern-subset.ts\";\nimport {\n\tclearAllValidatorCaches,\n\tgetRuntimeValidationErrors,\n} from \"./runtime-validator.ts\";\nimport type { BranchResult, BranchType } from \"./subset-checker.ts\";\nimport {\n\tcheckAtomic,\n\tcheckBranchedSub,\n\tcheckBranchedSup,\n\tgetBranchesTyped,\n\tisAtomicSubsetOf,\n} from \"./subset-checker.ts\";\nimport type {\n\tCheckerOptions,\n\tCheckRuntimeOptions,\n\tConstraintValidatorRegistry,\n\tResolvedConditionResult,\n\tResolvedSubsetResult,\n\tSchemaError,\n\tSubsetResult,\n} from \"./types.ts\";\nimport { deepEqual, isPlainObj } from \"./utils.ts\";\n\n// ─── Re-exports ──────────────────────────────────────────────────────────────\n\nexport type {\n\tSchemaError,\n\tSubsetResult,\n\tResolvedConditionResult,\n\tResolvedSubsetResult,\n\tCheckRuntimeOptions,\n\tBranchType,\n\tBranchResult,\n};\n\nexport {\n\tnormalize,\n\tresolveConditions,\n\tformatResult,\n\tMergeEngine,\n\tisPatternSubset,\n\tarePatternsEquivalent,\n\tisTrivialPattern,\n};\n\n// ─── Main Class ──────────────────────────────────────────────────────────────\n//\n// Lightweight facade that orchestrates sub-modules to verify compatibility\n// between JSON Schemas (Draft-07).\n//\n// Mathematical principle:\n// A ⊆ B ⟺ A ∩ B ≡ A\n//\n// In JSON Schema terms:\n// - A ∩ B = allOf([A, B]) resolved via merge\n// - ≡ = structural comparison\n//\n// @example\n// ```ts\n// const checker = new JsonSchemaCompatibilityChecker();\n//\n// checker.isSubset(strict, loose); // true\n// checker.check(loose, strict); // { isSubset: false, diffs: [...] }\n// checker.check(sub, sup, { data: {...} }); // resolves conditions then checks\n// ```\n\nexport class JsonSchemaCompatibilityChecker {\n\tprivate readonly constraintValidators: ConstraintValidatorRegistry;\n\tprivate readonly engine: MergeEngine;\n\n\tconstructor(options?: CheckerOptions) {\n\t\tthis.engine = new MergeEngine();\n\t\tthis.constraintValidators = options?.constraints ?? {};\n\t}\n\n\t// ── Subset check (boolean) ─────────────────────────────────────────────\n\n\t/**\n\t * Checks whether `sub ⊆ sup`.\n\t * Is every value valid for sub also valid for sup?\n\t *\n\t * Uses `getBranchesTyped` to distinguish `anyOf` from `oneOf`\n\t * internally, although the boolean result does not reflect the distinction.\n\t */\n\tisSubset(sub: JSONSchema7Definition, sup: JSONSchema7Definition): boolean {\n\t\t// ── Identity short-circuit ──\n\t\t// If sub and sup are the same reference, sub ⊆ sup is trivially true.\n\t\t// This avoids the entire normalize + merge + compare pipeline.\n\t\tif (sub === sup) return true;\n\n\t\t// ── Pre-normalize structural equality ──\n\t\t// If sub and sup are structurally identical before normalization,\n\t\t// they represent the same schema → sub ⊆ sup trivially.\n\t\t// This avoids the WeakMap overhead of normalize() for common cases\n\t\t// like {} ⊆ {} or identical schema objects with different references.\n\t\tif (deepEqual(sub, sup)) return true;\n\n\t\tconst nSub = normalize(sub);\n\t\tconst nSup = normalize(sup);\n\n\t\t// ── Post-normalize structural identity ──\n\t\t// After normalization, schemas that were syntactically different\n\t\t// but semantically equivalent become structurally equal\n\t\t// (e.g. {const:1} vs {const:1, type:\"integer\"}).\n\t\tif (nSub !== sub && nSup !== sup && deepEqual(nSub, nSup)) return true;\n\t\tif (nSub !== nSup && deepEqual(nSub, nSup)) return true;\n\n\t\tconst { branches: subBranches } = getBranchesTyped(nSub);\n\n\t\tif (subBranches.length > 1 || subBranches[0] !== nSub) {\n\t\t\treturn subBranches.every((branch) =>\n\t\t\t\tisAtomicSubsetOf(branch, nSup, this.engine),\n\t\t\t);\n\t\t}\n\n\t\treturn isAtomicSubsetOf(nSub, nSup, this.engine);\n\t}\n\n\t// ── Subset check (detailed) ────────────────────────────────────────────\n\n\t/**\n\t * Checks `sub ⊆ sup` and returns a detailed diagnostic\n\t * with human-readable semantic errors.\n\t *\n\t * When `options` is provided, both schemas go through runtime-aware\n\t * processing before the static check:\n\t * 1. Conditions (`if/then/else`) are resolved using `data`\n\t * (if `data` is `undefined`, conditions are resolved with `{}`)\n\t * 2. Schemas are narrowed using runtime values (enum materialization)\n\t * 3. The static subset check runs on the resolved/narrowed schemas\n\t *\n\t * When `validate: true` is set in options, two additional runtime steps\n\t * run **after** the static check passes:\n\t * 4. `data` is validated against both resolved schemas via AJV\n\t * 5. Custom constraints are validated against `data`\n\t *\n\t * @param sub - The source schema (subset candidate)\n\t * @param sup - The target schema (expected superset)\n\t * @param options - Runtime options with `data` and optional `validate` flag\n\t * @returns SubsetResult if no options, ResolvedSubsetResult if options provided\n\t *\n\t * @example\n\t * ```ts\n\t * // Static check (no runtime data)\n\t * checker.check(sub, sup);\n\t *\n\t * // Resolve conditions + narrowing + static check (no runtime validation)\n\t * checker.check(sub, sup, { data: { kind: \"text\", value: \"hello\" } });\n\t *\n\t * // Full pipeline including AJV + constraint runtime validation\n\t * checker.check(sub, sup, { data: { kind: \"text\", value: \"hello\" }, validate: true });\n\t * ```\n\t */\n\tcheck(\n\t\tsub: JSONSchema7Definition,\n\t\tsup: JSONSchema7Definition,\n\t\toptions: CheckRuntimeOptions,\n\t): ResolvedSubsetResult;\n\tcheck(sub: JSONSchema7Definition, sup: JSONSchema7Definition): SubsetResult;\n\tcheck(\n\t\tsub: JSONSchema7Definition,\n\t\tsup: JSONSchema7Definition,\n\t\toptions?: CheckRuntimeOptions,\n\t): SubsetResult | ResolvedSubsetResult {\n\t\t// ── Runtime-aware path ──\n\t\tif (options) {\n\t\t\tconst data = options.data;\n\t\t\tconst shouldValidate = options.validate === true;\n\n\t\t\t// resolveConditions expects Record<string, unknown> for property access;\n\t\t\t// coerce non-object / undefined data to empty object so conditions\n\t\t\t// are always resolved (v1.0.11 compat: subData: undefined → {})\n\t\t\tconst dataForConditions: Record<string, unknown> = isPlainObj(data)\n\t\t\t\t? data\n\t\t\t\t: {};\n\n\t\t\tconst resolvedSub = resolveConditions(\n\t\t\t\tsub as JSONSchema7,\n\t\t\t\tdataForConditions,\n\t\t\t\tthis.engine,\n\t\t\t);\n\t\t\tconst resolvedSup = resolveConditions(\n\t\t\t\tsup as JSONSchema7,\n\t\t\t\tdataForConditions,\n\t\t\t\tthis.engine,\n\t\t\t);\n\n\t\t\t// ── Runtime-aware data narrowing ──\n\t\t\t// Apply narrowing only when concrete data is available.\n\t\t\t// When data is undefined there is nothing to narrow with.\n\t\t\t// Boolean schemas (true/false) cannot be narrowed — skip narrowing\n\t\t\t// to avoid passing a non-object to narrowSchemaWithData.\n\t\t\tconst canNarrow = data !== undefined;\n\t\t\tconst canNarrowSub = canNarrow && isPlainObj(resolvedSub.resolved);\n\t\t\tconst canNarrowSup = canNarrow && isPlainObj(resolvedSup.resolved);\n\n\t\t\tconst narrowedSubResolved = canNarrowSub\n\t\t\t\t? narrowSchemaWithData(resolvedSub.resolved, data, resolvedSup.resolved)\n\t\t\t\t: resolvedSub.resolved;\n\n\t\t\tconst narrowedSupResolved = canNarrowSup\n\t\t\t\t? narrowSchemaWithData(resolvedSup.resolved, data, resolvedSub.resolved)\n\t\t\t\t: resolvedSup.resolved;\n\n\t\t\t// ── Static subset check ──\n\t\t\t// Structural incompatibilities are schema-level problems — they are\n\t\t\t// permanent regardless of the concrete data. Run this before runtime\n\t\t\t// validation so that static errors always surface with higher priority.\n\t\t\tconst staticResult = this.checkInternal(\n\t\t\t\tnarrowedSubResolved,\n\t\t\t\tnarrowedSupResolved,\n\t\t\t);\n\n\t\t\tif (!staticResult.isSubset) {\n\t\t\t\treturn {\n\t\t\t\t\t...staticResult,\n\t\t\t\t\tresolvedSub: { ...resolvedSub, resolved: narrowedSubResolved },\n\t\t\t\t\tresolvedSup: { ...resolvedSup, resolved: narrowedSupResolved },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// ── Runtime validation (opt-in) ──\n\t\t\t// Only runs when `validate: true` is explicitly set.\n\t\t\t// Validates the concrete data against both resolved/narrowed schemas\n\t\t\t// via AJV, then runs custom constraint validators if registered.\n\t\t\tif (shouldValidate && data !== undefined) {\n\t\t\t\tconst runtimeErrors: SchemaError[] = [];\n\n\t\t\t\truntimeErrors.push(\n\t\t\t\t\t...this.prefixRuntimeErrors(\n\t\t\t\t\t\tgetRuntimeValidationErrors(narrowedSubResolved, data),\n\t\t\t\t\t\t\"$sub\",\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\truntimeErrors.push(\n\t\t\t\t\t...this.prefixRuntimeErrors(\n\t\t\t\t\t\tgetRuntimeValidationErrors(narrowedSupResolved, data),\n\t\t\t\t\t\t\"$sup\",\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\t// ── Constraint validation ──\n\t\t\t\t// Validate runtime data against custom constraints in both schemas.\n\t\t\t\t// Only runs if constraint validators were registered in the constructor.\n\t\t\t\tif (Object.keys(this.constraintValidators).length > 0) {\n\t\t\t\t\truntimeErrors.push(\n\t\t\t\t\t\t...this.prefixRuntimeErrors(\n\t\t\t\t\t\t\tvalidateSchemaConstraints(\n\t\t\t\t\t\t\t\tnarrowedSubResolved,\n\t\t\t\t\t\t\t\tdata,\n\t\t\t\t\t\t\t\tthis.constraintValidators,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\"$sub\",\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\n\t\t\t\t\truntimeErrors.push(\n\t\t\t\t\t\t...this.prefixRuntimeErrors(\n\t\t\t\t\t\t\tvalidateSchemaConstraints(\n\t\t\t\t\t\t\t\tnarrowedSupResolved,\n\t\t\t\t\t\t\t\tdata,\n\t\t\t\t\t\t\t\tthis.constraintValidators,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\"$sup\",\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (runtimeErrors.length > 0) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tisSubset: false,\n\t\t\t\t\t\tmerged: null,\n\t\t\t\t\t\terrors: runtimeErrors,\n\t\t\t\t\t\tresolvedSub: { ...resolvedSub, resolved: narrowedSubResolved },\n\t\t\t\t\t\tresolvedSup: { ...resolvedSup, resolved: narrowedSupResolved },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...staticResult,\n\t\t\t\tresolvedSub: { ...resolvedSub, resolved: narrowedSubResolved },\n\t\t\t\tresolvedSup: { ...resolvedSup, resolved: narrowedSupResolved },\n\t\t\t};\n\t\t}\n\n\t\t// ── Standard path (no condition resolution) ──\n\t\treturn this.checkInternal(sub, sup);\n\t}\n\n\t// ── Equality ───────────────────────────────────────────────────────────\n\n\t/**\n\t * Checks structural equality between two schemas.\n\t */\n\tisEqual(a: JSONSchema7Definition, b: JSONSchema7Definition): boolean {\n\t\treturn this.engine.isEqual(normalize(a), normalize(b));\n\t}\n\n\t// ── Intersection ───────────────────────────────────────────────────────\n\n\t/**\n\t * Computes the intersection of two schemas (allOf merge).\n\t * Returns null if the schemas are incompatible.\n\t *\n\t * The result is normalized to eliminate structural artifacts\n\t * from the merge (e.g. redundant `enum` when `const` is present).\n\t */\n\tintersect(\n\t\ta: JSONSchema7Definition,\n\t\tb: JSONSchema7Definition,\n\t): JSONSchema7Definition | null {\n\t\t// ── Identity short-circuit ──\n\t\t// If a and b are the same reference or structurally equal,\n\t\t// intersection is just normalize(a) — skip the merge entirely.\n\t\tif (a === b || deepEqual(a, b)) return normalize(a);\n\n\t\tconst nA = normalize(a);\n\t\tconst nB = normalize(b);\n\n\t\t// ── Post-normalize identity ──\n\t\tif (deepEqual(nA, nB)) return nA;\n\n\t\tconst merged = this.engine.merge(nA, nB);\n\t\tif (merged === null) return null;\n\t\t// Fast path: if merge result equals one of the normalized inputs,\n\t\t// it's already normalized — skip redundant normalize call.\n\t\tif (deepEqual(merged, nA) || deepEqual(merged, nB)) return merged;\n\t\treturn normalize(merged);\n\t}\n\n\t// ── Normalization ──────────────────────────────────────────────────────\n\n\t/**\n\t * Normalizes a schema: infers `type` from `const`/`enum`,\n\t * and recursively normalizes all sub-schemas.\n\t */\n\tnormalize(def: JSONSchema7Definition): JSONSchema7Definition {\n\t\treturn normalize(def);\n\t}\n\n\t// ── Formatting ─────────────────────────────────────────────────────────\n\n\t/**\n\t * Formats a SubsetResult into a readable string (useful for logs/debug).\n\t */\n\tformatResult(label: string, result: SubsetResult): string {\n\t\treturn formatResult(label, result);\n\t}\n\n\t// ── Condition Resolution ────────────────────────────────────────────────\n\n\t/**\n\t * Resolves `if/then/else` conditions in a schema by evaluating the `if`\n\t * against runtime data.\n\t *\n\t * @param schema - The schema containing conditions to resolve\n\t * @param data - The runtime data used to evaluate conditions\n\t * @returns The resolved schema with branch info and discriminants\n\t */\n\tresolveConditions(\n\t\tschema: JSONSchema7,\n\t\tdata: Record<string, unknown>,\n\t): ResolvedConditionResult {\n\t\treturn resolveConditions(schema, data, this.engine);\n\t}\n\n\t// ── Private ────────────────────────────────────────────────────────────\n\n\tprivate prefixRuntimeErrors(\n\t\terrors: SchemaError[],\n\t\trootKey: \"$sub\" | \"$sup\",\n\t): SchemaError[] {\n\t\treturn errors.map((error) => ({\n\t\t\t...error,\n\t\t\tkey: error.key === \"$root\" ? rootKey : `${rootKey}.${error.key}`,\n\t\t}));\n\t}\n\n\t/**\n\t * Internal check logic without condition resolution.\n\t * Factorizes the normalize → branch → atomic pipeline to avoid\n\t * duplication between the two paths of `check()`.\n\t */\n\tprivate checkInternal(\n\t\tsub: JSONSchema7Definition,\n\t\tsup: JSONSchema7Definition,\n\t): SubsetResult {\n\t\t// ── Identity short-circuit ──\n\t\t// Same reference → no errors, no merge needed.\n\t\tif (sub === sup) {\n\t\t\treturn { isSubset: true, merged: sub, errors: [] };\n\t\t}\n\n\t\t// ── Pre-normalize structural equality ──\n\t\t// Avoids WeakMap overhead for identical schemas ({} ⊆ {}, etc.).\n\t\tif (deepEqual(sub, sup)) {\n\t\t\treturn { isSubset: true, merged: sub, errors: [] };\n\t\t}\n\n\t\tconst nSub = normalize(sub);\n\t\tconst nSup = normalize(sup);\n\n\t\t// ── Post-normalize structural identity ──\n\t\t// Catches semantically equivalent schemas after normalization.\n\t\tif (deepEqual(nSub, nSup)) {\n\t\t\treturn { isSubset: true, merged: nSub, errors: [] };\n\t\t}\n\n\t\tconst { branches: subBranches, type: subBranchType } =\n\t\t\tgetBranchesTyped(nSub);\n\t\tconst { branches: supBranches, type: supBranchType } =\n\t\t\tgetBranchesTyped(nSup);\n\n\t\t// anyOf/oneOf in sub\n\t\tif (subBranches.length > 1 || subBranches[0] !== nSub) {\n\t\t\treturn checkBranchedSub(subBranches, nSup, this.engine, subBranchType);\n\t\t}\n\n\t\t// anyOf/oneOf in sup only\n\t\tif (supBranches.length > 1 || supBranches[0] !== nSup) {\n\t\t\treturn checkBranchedSup(nSub, supBranches, this.engine, supBranchType);\n\t\t}\n\n\t\t// Standard case\n\t\treturn checkAtomic(nSub, nSup, this.engine);\n\t}\n\n\t// ── Cache management ───────────────────────────────────────────────────\n\n\t/**\n\t * Clears all compiled AJV validator caches (WeakMap, LRU, and AJV internal).\n\t *\n\t * Useful for:\n\t * - Long-running processes where schemas evolve over time\n\t * - Test isolation (ensuring no cross-test cache pollution)\n\t * - Memory pressure situations where cached validators are no longer needed\n\t *\n\t * After calling this, the next validation call will recompile validators\n\t * from scratch — there is a one-time performance cost per unique schema.\n\t *\n\t * This is a static method because the AJV instance is a module-level\n\t * singleton shared across all `JsonSchemaCompatibilityChecker` instances.\n\t *\n\t * @example\n\t * ```ts\n\t * JsonSchemaCompatibilityChecker.clearCache();\n\t * ```\n\t */\n\tstatic clearCache(): void {\n\t\tclearAllValidatorCaches();\n\t}\n}\n"],"names":["resolveConditions","validateSchemaConstraints","narrowSchemaWithData","formatResult","MergeEngine","normalize","arePatternsEquivalent","isPatternSubset","isTrivialPattern","clearAllValidatorCaches","getRuntimeValidationErrors","checkAtomic","checkBranchedSub","checkBranchedSup","getBranchesTyped","isAtomicSubsetOf","deepEqual","isPlainObj","JsonSchemaCompatibilityChecker","isSubset","sub","sup","nSub","nSup","branches","subBranches","length","every","branch","engine","check","options","data","shouldValidate","validate","dataForConditions","resolvedSub","resolvedSup","canNarrow","undefined","canNarrowSub","resolved","canNarrowSup","narrowedSubResolved","narrowedSupResolved","staticResult","checkInternal","runtimeErrors","push","prefixRuntimeErrors","Object","keys","constraintValidators","merged","errors","isEqual","a","b","intersect","nA","nB","merge","def","label","result","schema","rootKey","map","error","key","type","subBranchType","supBranches","supBranchType","clearCache","constraints"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/json-schema-compatibility-checker.ts"],"sourcesContent":["import type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\nimport { resolveConditions } from \"./condition-resolver.ts\";\nimport { validateSchemaConstraints } from \"./constraint-validator.ts\";\nimport { narrowSchemaWithData } from \"./data-narrowing.ts\";\nimport { formatResult } from \"./formatter.ts\";\nimport { MergeEngine } from \"./merge-engine.ts\";\nimport { normalize } from \"./normalizer.ts\";\nimport {\n\tarePatternsEquivalent,\n\tisPatternSubset,\n\tisTrivialPattern,\n} from \"./pattern-subset.ts\";\nimport {\n\tclearAllValidatorCaches,\n\tgetRuntimeValidationErrors,\n} from \"./runtime-validator.ts\";\nimport type { BranchResult, BranchType } from \"./subset-checker.ts\";\nimport {\n\tcheckAtomic,\n\tcheckBranchedSub,\n\tcheckBranchedSup,\n\tgetBranchesTyped,\n\tisAtomicSubsetOf,\n} from \"./subset-checker.ts\";\nimport type {\n\tCheckerOptions,\n\tCheckRuntimeOptions,\n\tConstraintValidatorRegistry,\n\tResolvedConditionResult,\n\tResolvedSubsetResult,\n\tSchemaError,\n\tSubsetResult,\n} from \"./types.ts\";\nimport { deepEqual, isPlainObj } from \"./utils.ts\";\n\n// ─── Re-exports ──────────────────────────────────────────────────────────────\n\nexport type {\n\tSchemaError,\n\tSubsetResult,\n\tResolvedConditionResult,\n\tResolvedSubsetResult,\n\tCheckRuntimeOptions,\n\tBranchType,\n\tBranchResult,\n};\n\nexport {\n\tnormalize,\n\tresolveConditions,\n\tformatResult,\n\tMergeEngine,\n\tisPatternSubset,\n\tarePatternsEquivalent,\n\tisTrivialPattern,\n};\n\n// ─── Main Class ──────────────────────────────────────────────────────────────\n//\n// Lightweight facade that orchestrates sub-modules to verify compatibility\n// between JSON Schemas (Draft-07).\n//\n// Mathematical principle:\n// A ⊆ B ⟺ A ∩ B ≡ A\n//\n// In JSON Schema terms:\n// - A ∩ B = allOf([A, B]) resolved via merge\n// - ≡ = structural comparison\n//\n// @example\n// ```ts\n// const checker = new JsonSchemaCompatibilityChecker();\n//\n// checker.isSubset(strict, loose); // true\n// checker.check(loose, strict); // { isSubset: false, diffs: [...] }\n// checker.check(sub, sup, { data: {...} }); // resolves conditions then checks\n// ```\n\nexport class JsonSchemaCompatibilityChecker {\n\tprivate readonly constraintValidators: ConstraintValidatorRegistry;\n\tprivate readonly engine: MergeEngine;\n\n\tconstructor(options?: CheckerOptions) {\n\t\tthis.engine = new MergeEngine();\n\t\tthis.constraintValidators = options?.constraints ?? {};\n\t}\n\n\t// ── Subset check (boolean) ─────────────────────────────────────────────\n\n\t/**\n\t * Checks whether `sub ⊆ sup`.\n\t * Is every value valid for sub also valid for sup?\n\t *\n\t * Uses `getBranchesTyped` to distinguish `anyOf` from `oneOf`\n\t * internally, although the boolean result does not reflect the distinction.\n\t */\n\tisSubset(sub: JSONSchema7Definition, sup: JSONSchema7Definition): boolean {\n\t\t// ── Identity short-circuit ──\n\t\t// If sub and sup are the same reference, sub ⊆ sup is trivially true.\n\t\t// This avoids the entire normalize + merge + compare pipeline.\n\t\tif (sub === sup) return true;\n\n\t\t// ── Pre-normalize structural equality ──\n\t\t// If sub and sup are structurally identical before normalization,\n\t\t// they represent the same schema → sub ⊆ sup trivially.\n\t\t// This avoids the WeakMap overhead of normalize() for common cases\n\t\t// like {} ⊆ {} or identical schema objects with different references.\n\t\tif (deepEqual(sub, sup)) return true;\n\n\t\tconst nSub = normalize(sub);\n\t\tconst nSup = normalize(sup);\n\n\t\t// ── Post-normalize structural identity ──\n\t\t// After normalization, schemas that were syntactically different\n\t\t// but semantically equivalent become structurally equal\n\t\t// (e.g. {const:1} vs {const:1, type:\"integer\"}).\n\t\tif (nSub !== sub && nSup !== sup && deepEqual(nSub, nSup)) return true;\n\t\tif (nSub !== nSup && deepEqual(nSub, nSup)) return true;\n\n\t\tconst { branches: subBranches } = getBranchesTyped(nSub);\n\n\t\tif (subBranches.length > 1 || subBranches[0] !== nSub) {\n\t\t\treturn subBranches.every((branch) =>\n\t\t\t\tisAtomicSubsetOf(branch, nSup, this.engine),\n\t\t\t);\n\t\t}\n\n\t\treturn isAtomicSubsetOf(nSub, nSup, this.engine);\n\t}\n\n\t// ── Subset check (detailed) ────────────────────────────────────────────\n\n\t/**\n\t * Checks `sub ⊆ sup` and returns a detailed diagnostic\n\t * with human-readable semantic errors.\n\t *\n\t * When `options` is provided, both schemas go through runtime-aware\n\t * processing before the static check:\n\t * 1. Conditions (`if/then/else`) are resolved using `data`\n\t * (if `data` is `undefined`, conditions are resolved with `{}`)\n\t * 2. Schemas are narrowed using runtime values (enum materialization)\n\t * 3. The static subset check runs on the resolved/narrowed schemas\n\t *\n\t * When `validate: true` is set in options, two additional runtime steps\n\t * run **after** the static check passes:\n\t * 4. `data` is validated against both resolved schemas via AJV\n\t * 5. Custom constraints are validated against `data`\n\t *\n\t * @param sub - The source schema (subset candidate)\n\t * @param sup - The target schema (expected superset)\n\t * @param options - Runtime options with `data` and optional `validate` flag\n\t * @returns SubsetResult if no options, ResolvedSubsetResult if options provided\n\t *\n\t * @example\n\t * ```ts\n\t * // Static check (no runtime data)\n\t * checker.check(sub, sup);\n\t *\n\t * // Resolve conditions + narrowing + static check (no runtime validation)\n\t * checker.check(sub, sup, { data: { kind: \"text\", value: \"hello\" } });\n\t *\n\t * // Full pipeline including AJV + constraint runtime validation\n\t * checker.check(sub, sup, { data: { kind: \"text\", value: \"hello\" }, validate: true });\n\t * ```\n\t */\n\tcheck(\n\t\tsub: JSONSchema7Definition,\n\t\tsup: JSONSchema7Definition,\n\t\toptions: CheckRuntimeOptions,\n\t): ResolvedSubsetResult;\n\tcheck(sub: JSONSchema7Definition, sup: JSONSchema7Definition): SubsetResult;\n\tcheck(\n\t\tsub: JSONSchema7Definition,\n\t\tsup: JSONSchema7Definition,\n\t\toptions?: CheckRuntimeOptions,\n\t): SubsetResult | ResolvedSubsetResult {\n\t\t// ── Runtime-aware path ──\n\t\tif (options) {\n\t\t\tconst data = options.data;\n\t\t\tconst shouldValidate = options.validate === true;\n\n\t\t\t// resolveConditions expects Record<string, unknown> for property access;\n\t\t\t// coerce non-object / undefined data to empty object so conditions\n\t\t\t// are always resolved (v1.0.11 compat: subData: undefined → {})\n\t\t\tconst dataForConditions: Record<string, unknown> = isPlainObj(data)\n\t\t\t\t? data\n\t\t\t\t: {};\n\n\t\t\tconst resolvedSub = resolveConditions(\n\t\t\t\tsub as JSONSchema7,\n\t\t\t\tdataForConditions,\n\t\t\t\tthis.engine,\n\t\t\t);\n\t\t\tconst resolvedSup = resolveConditions(\n\t\t\t\tsup as JSONSchema7,\n\t\t\t\tdataForConditions,\n\t\t\t\tthis.engine,\n\t\t\t);\n\n\t\t\t// ── Runtime-aware data narrowing ──\n\t\t\t// Apply narrowing only when concrete data is available.\n\t\t\t// When data is undefined there is nothing to narrow with.\n\t\t\t// Boolean schemas (true/false) cannot be narrowed — skip narrowing\n\t\t\t// to avoid passing a non-object to narrowSchemaWithData.\n\t\t\tconst canNarrow = data !== undefined;\n\t\t\tconst canNarrowSub = canNarrow && isPlainObj(resolvedSub.resolved);\n\t\t\tconst canNarrowSup = canNarrow && isPlainObj(resolvedSup.resolved);\n\n\t\t\tconst narrowedSubResolved = canNarrowSub\n\t\t\t\t? narrowSchemaWithData(resolvedSub.resolved, data, resolvedSup.resolved)\n\t\t\t\t: resolvedSub.resolved;\n\n\t\t\tconst narrowedSupResolved = canNarrowSup\n\t\t\t\t? narrowSchemaWithData(resolvedSup.resolved, data, resolvedSub.resolved)\n\t\t\t\t: resolvedSup.resolved;\n\n\t\t\t// ── Static subset check ──\n\t\t\t// Structural incompatibilities are schema-level problems — they are\n\t\t\t// permanent regardless of the concrete data. Run this before runtime\n\t\t\t// validation so that static errors always surface with higher priority.\n\t\t\tconst staticResult = this.checkInternal(\n\t\t\t\tnarrowedSubResolved,\n\t\t\t\tnarrowedSupResolved,\n\t\t\t);\n\n\t\t\tif (!staticResult.isSubset) {\n\t\t\t\treturn {\n\t\t\t\t\t...staticResult,\n\t\t\t\t\tresolvedSub: { ...resolvedSub, resolved: narrowedSubResolved },\n\t\t\t\t\tresolvedSup: { ...resolvedSup, resolved: narrowedSupResolved },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// ── Runtime validation (opt-in) ──\n\t\t\t// Only runs when `validate: true` is explicitly set.\n\t\t\t// Validates the concrete data against both resolved/narrowed schemas\n\t\t\t// via AJV, then runs custom constraint validators if registered.\n\t\t\tif (shouldValidate && data !== undefined) {\n\t\t\t\tconst runtimeErrors: SchemaError[] = [];\n\n\t\t\t\truntimeErrors.push(\n\t\t\t\t\t...this.prefixRuntimeErrors(\n\t\t\t\t\t\tgetRuntimeValidationErrors(narrowedSubResolved, data),\n\t\t\t\t\t\t\"$sub\",\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\truntimeErrors.push(\n\t\t\t\t\t...this.prefixRuntimeErrors(\n\t\t\t\t\t\tgetRuntimeValidationErrors(narrowedSupResolved, data),\n\t\t\t\t\t\t\"$sup\",\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\t// ── Constraint validation ──\n\t\t\t\t// Validate runtime data against custom constraints in both schemas.\n\t\t\t\t// Always runs when validate: true — if a schema declares constraints\n\t\t\t\t// that are not registered in the registry, validateSchemaConstraints\n\t\t\t\t// will report them as \"unknown constraint (not registered)\" errors.\n\t\t\t\truntimeErrors.push(\n\t\t\t\t\t...this.prefixRuntimeErrors(\n\t\t\t\t\t\tvalidateSchemaConstraints(\n\t\t\t\t\t\t\tnarrowedSubResolved,\n\t\t\t\t\t\t\tdata,\n\t\t\t\t\t\t\tthis.constraintValidators,\n\t\t\t\t\t\t),\n\t\t\t\t\t\t\"$sub\",\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\truntimeErrors.push(\n\t\t\t\t\t...this.prefixRuntimeErrors(\n\t\t\t\t\t\tvalidateSchemaConstraints(\n\t\t\t\t\t\t\tnarrowedSupResolved,\n\t\t\t\t\t\t\tdata,\n\t\t\t\t\t\t\tthis.constraintValidators,\n\t\t\t\t\t\t),\n\t\t\t\t\t\t\"$sup\",\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\tif (runtimeErrors.length > 0) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tisSubset: false,\n\t\t\t\t\t\tmerged: null,\n\t\t\t\t\t\terrors: runtimeErrors,\n\t\t\t\t\t\tresolvedSub: { ...resolvedSub, resolved: narrowedSubResolved },\n\t\t\t\t\t\tresolvedSup: { ...resolvedSup, resolved: narrowedSupResolved },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...staticResult,\n\t\t\t\tresolvedSub: { ...resolvedSub, resolved: narrowedSubResolved },\n\t\t\t\tresolvedSup: { ...resolvedSup, resolved: narrowedSupResolved },\n\t\t\t};\n\t\t}\n\n\t\t// ── Standard path (no condition resolution) ──\n\t\treturn this.checkInternal(sub, sup);\n\t}\n\n\t// ── Equality ───────────────────────────────────────────────────────────\n\n\t/**\n\t * Checks structural equality between two schemas.\n\t */\n\tisEqual(a: JSONSchema7Definition, b: JSONSchema7Definition): boolean {\n\t\treturn this.engine.isEqual(normalize(a), normalize(b));\n\t}\n\n\t// ── Intersection ───────────────────────────────────────────────────────\n\n\t/**\n\t * Computes the intersection of two schemas (allOf merge).\n\t * Returns null if the schemas are incompatible.\n\t *\n\t * The result is normalized to eliminate structural artifacts\n\t * from the merge (e.g. redundant `enum` when `const` is present).\n\t */\n\tintersect(\n\t\ta: JSONSchema7Definition,\n\t\tb: JSONSchema7Definition,\n\t): JSONSchema7Definition | null {\n\t\t// ── Identity short-circuit ──\n\t\t// If a and b are the same reference or structurally equal,\n\t\t// intersection is just normalize(a) — skip the merge entirely.\n\t\tif (a === b || deepEqual(a, b)) return normalize(a);\n\n\t\tconst nA = normalize(a);\n\t\tconst nB = normalize(b);\n\n\t\t// ── Post-normalize identity ──\n\t\tif (deepEqual(nA, nB)) return nA;\n\n\t\tconst merged = this.engine.merge(nA, nB);\n\t\tif (merged === null) return null;\n\t\t// Fast path: if merge result equals one of the normalized inputs,\n\t\t// it's already normalized — skip redundant normalize call.\n\t\tif (deepEqual(merged, nA) || deepEqual(merged, nB)) return merged;\n\t\treturn normalize(merged);\n\t}\n\n\t// ── Normalization ──────────────────────────────────────────────────────\n\n\t/**\n\t * Normalizes a schema: infers `type` from `const`/`enum`,\n\t * and recursively normalizes all sub-schemas.\n\t */\n\tnormalize(def: JSONSchema7Definition): JSONSchema7Definition {\n\t\treturn normalize(def);\n\t}\n\n\t// ── Formatting ─────────────────────────────────────────────────────────\n\n\t/**\n\t * Formats a SubsetResult into a readable string (useful for logs/debug).\n\t */\n\tformatResult(label: string, result: SubsetResult): string {\n\t\treturn formatResult(label, result);\n\t}\n\n\t// ── Condition Resolution ────────────────────────────────────────────────\n\n\t/**\n\t * Resolves `if/then/else` conditions in a schema by evaluating the `if`\n\t * against runtime data.\n\t *\n\t * @param schema - The schema containing conditions to resolve\n\t * @param data - The runtime data used to evaluate conditions\n\t * @returns The resolved schema with branch info and discriminants\n\t */\n\tresolveConditions(\n\t\tschema: JSONSchema7,\n\t\tdata: Record<string, unknown>,\n\t): ResolvedConditionResult {\n\t\treturn resolveConditions(schema, data, this.engine);\n\t}\n\n\t// ── Private ────────────────────────────────────────────────────────────\n\n\tprivate prefixRuntimeErrors(\n\t\terrors: SchemaError[],\n\t\trootKey: \"$sub\" | \"$sup\",\n\t): SchemaError[] {\n\t\treturn errors.map((error) => ({\n\t\t\t...error,\n\t\t\tkey: error.key === \"$root\" ? rootKey : `${rootKey}.${error.key}`,\n\t\t}));\n\t}\n\n\t/**\n\t * Internal check logic without condition resolution.\n\t * Factorizes the normalize → branch → atomic pipeline to avoid\n\t * duplication between the two paths of `check()`.\n\t */\n\tprivate checkInternal(\n\t\tsub: JSONSchema7Definition,\n\t\tsup: JSONSchema7Definition,\n\t): SubsetResult {\n\t\t// ── Identity short-circuit ──\n\t\t// Same reference → no errors, no merge needed.\n\t\tif (sub === sup) {\n\t\t\treturn { isSubset: true, merged: sub, errors: [] };\n\t\t}\n\n\t\t// ── Pre-normalize structural equality ──\n\t\t// Avoids WeakMap overhead for identical schemas ({} ⊆ {}, etc.).\n\t\tif (deepEqual(sub, sup)) {\n\t\t\treturn { isSubset: true, merged: sub, errors: [] };\n\t\t}\n\n\t\tconst nSub = normalize(sub);\n\t\tconst nSup = normalize(sup);\n\n\t\t// ── Post-normalize structural identity ──\n\t\t// Catches semantically equivalent schemas after normalization.\n\t\tif (deepEqual(nSub, nSup)) {\n\t\t\treturn { isSubset: true, merged: nSub, errors: [] };\n\t\t}\n\n\t\tconst { branches: subBranches, type: subBranchType } =\n\t\t\tgetBranchesTyped(nSub);\n\t\tconst { branches: supBranches, type: supBranchType } =\n\t\t\tgetBranchesTyped(nSup);\n\n\t\t// anyOf/oneOf in sub\n\t\tif (subBranches.length > 1 || subBranches[0] !== nSub) {\n\t\t\treturn checkBranchedSub(subBranches, nSup, this.engine, subBranchType);\n\t\t}\n\n\t\t// anyOf/oneOf in sup only\n\t\tif (supBranches.length > 1 || supBranches[0] !== nSup) {\n\t\t\treturn checkBranchedSup(nSub, supBranches, this.engine, supBranchType);\n\t\t}\n\n\t\t// Standard case\n\t\treturn checkAtomic(nSub, nSup, this.engine);\n\t}\n\n\t// ── Cache management ───────────────────────────────────────────────────\n\n\t/**\n\t * Clears all compiled AJV validator caches (WeakMap, LRU, and AJV internal).\n\t *\n\t * Useful for:\n\t * - Long-running processes where schemas evolve over time\n\t * - Test isolation (ensuring no cross-test cache pollution)\n\t * - Memory pressure situations where cached validators are no longer needed\n\t *\n\t * After calling this, the next validation call will recompile validators\n\t * from scratch — there is a one-time performance cost per unique schema.\n\t *\n\t * This is a static method because the AJV instance is a module-level\n\t * singleton shared across all `JsonSchemaCompatibilityChecker` instances.\n\t *\n\t * @example\n\t * ```ts\n\t * JsonSchemaCompatibilityChecker.clearCache();\n\t * ```\n\t */\n\tstatic clearCache(): void {\n\t\tclearAllValidatorCaches();\n\t}\n}\n"],"names":["resolveConditions","validateSchemaConstraints","narrowSchemaWithData","formatResult","MergeEngine","normalize","arePatternsEquivalent","isPatternSubset","isTrivialPattern","clearAllValidatorCaches","getRuntimeValidationErrors","checkAtomic","checkBranchedSub","checkBranchedSup","getBranchesTyped","isAtomicSubsetOf","deepEqual","isPlainObj","JsonSchemaCompatibilityChecker","isSubset","sub","sup","nSub","nSup","branches","subBranches","length","every","branch","engine","check","options","data","shouldValidate","validate","dataForConditions","resolvedSub","resolvedSup","canNarrow","undefined","canNarrowSub","resolved","canNarrowSup","narrowedSubResolved","narrowedSupResolved","staticResult","checkInternal","runtimeErrors","push","prefixRuntimeErrors","constraintValidators","merged","errors","isEqual","a","b","intersect","nA","nB","merge","def","label","result","schema","rootKey","map","error","key","type","subBranchType","supBranches","supBranchType","clearCache","constraints"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- function _define_property(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}import{createComparator,createMerger,createShallowAllOfMerge}from"@x0k/json-schema-merge";import{createDeduplicator,createIntersector}from"@x0k/json-schema-merge/lib/array";import{isFormatSubset}from"./format-validator.js";import{deepEqual,hasOwn,isPlainObj,mergeConstraints,unionStrings}from"./utils.js";function hasConstConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;const aHasConst=hasOwn(a,"const");const bHasConst=hasOwn(b,"const");const aConst=a.const;const bConst=b.const;const aEnum=a.enum;const bEnum=b.enum;if(aHasConst&&bHasConst){return!deepEqual(aConst,bConst)}if(aHasConst&&Array.isArray(bEnum)){return!bEnum.some(v=>deepEqual(v,aConst))}if(bHasConst&&Array.isArray(aEnum)){return!aEnum.some(v=>deepEqual(v,bConst))}return false}const SINGLE_SCHEMA_CONFLICT_KEYS=["items","additionalProperties","contains","propertyNames","not"];const PROPERTIES_MAP_CONFLICT_KEYS=["properties","patternProperties"];function hasDeepConstConflict(a,b){if(hasConstConflict(a,b))return true;if(typeof a==="boolean"||typeof b==="boolean")return false;for(const key of SINGLE_SCHEMA_CONFLICT_KEYS){const aVal=a[key];const bVal=b[key];if(isPlainObj(aVal)&&isPlainObj(bVal)&&hasDeepConstConflict(aVal,bVal)){return true}}for(const key of PROPERTIES_MAP_CONFLICT_KEYS){const aMap=a[key];const bMap=b[key];if(!isPlainObj(aMap)||!isPlainObj(bMap))continue;const aMapSafe=aMap;const bMapSafe=bMap;for(const propKey of Object.keys(aMapSafe)){const aVal=aMapSafe[propKey];const bVal=bMapSafe[propKey];if(aVal!==undefined&&bVal!==undefined&&hasOwn(bMapSafe,propKey)&&hasDeepConstConflict(aVal,bVal)){return true}}}if(Array.isArray(a.items)&&Array.isArray(b.items)){const aItems=a.items;const bItems=b.items;const len=Math.min(aItems.length,bItems.length);for(let i=0;i<len;i++){const aItem=aItems[i];const bItem=bItems[i];if(aItem===undefined||bItem===undefined)continue;if(hasDeepConstConflict(aItem,bItem)){return true}}}return false}function hasAdditionalPropertiesConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;const aProps=isPlainObj(a.properties)?a.properties:undefined;const bProps=isPlainObj(b.properties)?b.properties:undefined;if(!aProps&&!bProps)return false;const aKeys=aProps?Object.keys(aProps):[];const bKeys=bProps?Object.keys(bProps):[];const aRequired=Array.isArray(a.required)?a.required:[];const bRequired=Array.isArray(b.required)?b.required:[];if(a.additionalProperties===false&&aProps&&bProps){const hasRequiredExtra=bRequired.some(k=>!hasOwn(aProps,k)&&hasOwn(bProps,k));if(hasRequiredExtra&&aKeys.length>0)return true}if(isPlainObj(a.additionalProperties)&&typeof a.additionalProperties!=="boolean"&&aProps&&bProps){const addPropsSchema=a.additionalProperties;if(hasOwn(addPropsSchema,"type")){const addPropsType=addPropsSchema.type;const hasTypeConflict=bRequired.some(k=>{if(hasOwn(aProps,k))return false;if(!hasOwn(bProps,k))return false;const bPropDef=bProps[k];if(typeof bPropDef==="boolean")return false;const bProp=bPropDef;if(!hasOwn(bProp,"type"))return false;if(typeof addPropsType==="string"&&typeof bProp.type==="string"){return addPropsType!==bProp.type&&!(addPropsType==="number"&&bProp.type==="integer")&&!(addPropsType==="integer"&&bProp.type==="number")}return false});if(hasTypeConflict)return true}}if(b.additionalProperties===false&&bProps&&aProps){const hasRequiredExtra=aRequired.some(k=>!hasOwn(bProps,k)&&hasOwn(aProps,k));if(hasRequiredExtra&&bKeys.length>0)return true}if(isPlainObj(b.additionalProperties)&&typeof b.additionalProperties!=="boolean"&&bProps&&aProps){const addPropsSchema=b.additionalProperties;if(hasOwn(addPropsSchema,"type")){const addPropsType=addPropsSchema.type;const hasTypeConflict=aRequired.some(k=>{if(hasOwn(bProps,k))return false;if(!hasOwn(aProps,k))return false;const aPropDef=aProps[k];if(typeof aPropDef==="boolean")return false;const aProp=aPropDef;if(!hasOwn(aProp,"type"))return false;if(typeof addPropsType==="string"&&typeof aProp.type==="string"){return addPropsType!==aProp.type&&!(addPropsType==="number"&&aProp.type==="integer")&&!(addPropsType==="integer"&&aProp.type==="number")}return false});if(hasTypeConflict)return true}}if(aProps&&bProps){for(const k of aKeys){if(!hasOwn(bProps,k))continue;const aPropDef=aProps[k];const bPropDef=bProps[k];if(typeof aPropDef==="boolean"||typeof bPropDef==="boolean")continue;if(hasAdditionalPropertiesConflict(aPropDef,bPropDef)){return true}}}return false}function hasFormatConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;if(hasOwn(a,"format")&&hasOwn(b,"format")){const aFormat=a.format;const bFormat=b.format;if(aFormat!==bFormat){const subsetCheck=isFormatSubset(aFormat,bFormat);if(subsetCheck!==true){const reverseCheck=isFormatSubset(bFormat,aFormat);if(reverseCheck!==true){return true}}}}if(isPlainObj(a.properties)&&isPlainObj(b.properties)){const aMap=a.properties;const bMap=b.properties;for(const k of Object.keys(aMap)){const aVal=aMap[k];const bVal=bMap[k];if(aVal!==undefined&&bVal!==undefined&&hasOwn(bMap,k)&&hasFormatConflict(aVal,bVal)){return true}}}if(isPlainObj(a.items)&&isPlainObj(b.items)){if(hasFormatConflict(a.items,b.items))return true}if(isPlainObj(a.additionalProperties)&&isPlainObj(b.additionalProperties)){if(hasFormatConflict(a.additionalProperties,b.additionalProperties))return true}return false}function hasConstraintsAnywhere(schema){if(typeof schema==="boolean")return false;if(hasOwn(schema,"constraints")&&schema.constraints!==undefined){return true}if(isPlainObj(schema.properties)){const props=schema.properties;for(const key of Object.keys(props)){const prop=props[key];if(prop!==undefined&&hasConstraintsAnywhere(prop))return true}}if(isPlainObj(schema.patternProperties)){const pp=schema.patternProperties;for(const key of Object.keys(pp)){const val=pp[key];if(val!==undefined&&hasConstraintsAnywhere(val))return true}}if(Array.isArray(schema.items)){for(const item of schema.items){if(item!==undefined&&hasConstraintsAnywhere(item))return true}}else if(isPlainObj(schema.items)){if(hasConstraintsAnywhere(schema.items))return true}if(isPlainObj(schema.additionalProperties)){if(hasConstraintsAnywhere(schema.additionalProperties))return true}if(isPlainObj(schema.dependencies)){const deps=schema.dependencies;for(const key of Object.keys(deps)){const val=deps[key];if(val!==undefined&&!Array.isArray(val)&&hasConstraintsAnywhere(val))return true}}return false}function applyConstraintsMerge(merged,a,b){if(typeof merged==="boolean")return merged;if(typeof a==="boolean"||typeof b==="boolean")return merged;if(!hasConstraintsAnywhere(a)&&!hasConstraintsAnywhere(b)){return merged}let changed=false;const result={...merged};const mergedConstraints=mergeConstraints(a.constraints,b.constraints);const currentConstraints=result.constraints;if(mergedConstraints!==undefined){if(!deepEqual(currentConstraints,mergedConstraints)){result.constraints=mergedConstraints;changed=true}}else if(currentConstraints!==undefined){delete result.constraints;changed=true}if(isPlainObj(result.properties)&&(isPlainObj(a.properties)||isPlainObj(b.properties))){const mergedProps=result.properties;const aProps=a.properties??{};const bProps=b.properties??{};let propsChanged=false;const newProps={};for(const key of Object.keys(mergedProps)){const mProp=mergedProps[key];const aProp=aProps[key];const bProp=bProps[key];if(mProp===undefined)continue;if(aProp!==undefined&&bProp!==undefined&&typeof mProp!=="boolean"&&typeof aProp!=="boolean"&&typeof bProp!=="boolean"){const patched=applyConstraintsMerge(mProp,aProp,bProp);newProps[key]=patched;if(patched!==mProp)propsChanged=true}else{newProps[key]=mProp}}if(propsChanged){result.properties=newProps;changed=true}}if(isPlainObj(result.items)&&isPlainObj(a.items)&&isPlainObj(b.items)){const patched=applyConstraintsMerge(result.items,a.items,b.items);if(patched!==result.items){result.items=patched;changed=true}}if(isPlainObj(result.patternProperties)&&(isPlainObj(a.patternProperties)||isPlainObj(b.patternProperties))){const mergedPP=result.patternProperties;const aPP=a.patternProperties??{};const bPP=b.patternProperties??{};let ppChanged=false;const newPP={};for(const key of Object.keys(mergedPP)){const mVal=mergedPP[key];const aVal=aPP[key];const bVal=bPP[key];if(mVal===undefined)continue;if(aVal!==undefined&&bVal!==undefined&&typeof mVal!=="boolean"&&typeof aVal!=="boolean"&&typeof bVal!=="boolean"){const patched=applyConstraintsMerge(mVal,aVal,bVal);newPP[key]=patched;if(patched!==mVal)ppChanged=true}else{newPP[key]=mVal}}if(ppChanged){result.patternProperties=newPP;changed=true}}if(Array.isArray(result.items)&&Array.isArray(a.items)&&Array.isArray(b.items)){const mergedItems=result.items;const aItems=a.items;const bItems=b.items;const len=mergedItems.length;let tupleChanged=false;const newItems=new Array(len);for(let i=0;i<len;i++){const mItem=mergedItems[i];const aItem=aItems[i];const bItem=bItems[i];if(mItem!==undefined&&aItem!==undefined&&bItem!==undefined&&typeof mItem!=="boolean"&&typeof aItem!=="boolean"&&typeof bItem!=="boolean"){const patched=applyConstraintsMerge(mItem,aItem,bItem);newItems[i]=patched;if(patched!==mItem)tupleChanged=true}else{newItems[i]=mItem}}if(tupleChanged){result.items=newItems;changed=true}}if(isPlainObj(result.additionalProperties)&&isPlainObj(a.additionalProperties)&&isPlainObj(b.additionalProperties)){const patched=applyConstraintsMerge(result.additionalProperties,a.additionalProperties,b.additionalProperties);if(patched!==result.additionalProperties){result.additionalProperties=patched;changed=true}}if(isPlainObj(result.dependencies)&&(isPlainObj(a.dependencies)||isPlainObj(b.dependencies))){const mergedDeps=result.dependencies;const aDeps=a.dependencies??{};const bDeps=b.dependencies??{};let depsChanged=false;const newDeps={};for(const key of Object.keys(mergedDeps)){const mVal=mergedDeps[key];const aVal=aDeps[key];const bVal=bDeps[key];if(mVal===undefined)continue;if(aVal!==undefined&&bVal!==undefined&&!Array.isArray(mVal)&&!Array.isArray(aVal)&&!Array.isArray(bVal)&&typeof mVal!=="boolean"&&typeof aVal!=="boolean"&&typeof bVal!=="boolean"){const patched=applyConstraintsMerge(mVal,aVal,bVal);newDeps[key]=patched;if(patched!==mVal)depsChanged=true}else{newDeps[key]=mVal}}if(depsChanged){result.dependencies=newDeps;changed=true}}return changed?result:merged}export class MergeEngine{merge(a,b){if(a===b)return a;if(a===false||b===false)return false;if(a===true)return b;if(b===true)return a;if(hasDeepConstConflict(a,b)){return null}if(hasFormatConflict(a,b)){return null}if(hasAdditionalPropertiesConflict(a,b)){return null}try{const result=this.shallowAllOfMergeFn({allOf:[a,b]});return applyConstraintsMerge(result,a,b)}catch{return null}}mergeOrThrow(a,b){if(a===b)return a;if(a===false||b===false)return false;if(a===true)return b;if(b===true)return a;if(hasDeepConstConflict(a,b)){throw new Error("Incompatible const values: schemas have conflicting const constraints")}if(hasFormatConflict(a,b)){throw new Error("Incompatible format values: schemas have conflicting format constraints")}if(hasAdditionalPropertiesConflict(a,b)){throw new Error("Incompatible additionalProperties: required properties conflict with additionalProperties constraint")}const result=this.shallowAllOfMergeFn({allOf:[a,b]});return applyConstraintsMerge(result,a,b)}compare(a,b){return this.compareFn(a,b)}isEqual(a,b){return this.compareFn(a,b)===0}overlay(base,override){if(override===false)return false;if(override===true)return true;if(typeof base==="boolean")return override;const baseObj=base;const overrideObj=override;if(!isObjectLike(baseObj)&&!isObjectLike(overrideObj)){return override}if(!isObjectLike(baseObj)){return override}if(!isObjectLike(overrideObj)){return override}const baseProps=baseObj.properties??{};const overrideProps=overrideObj.properties??{};const mergedProps={};for(const key of Object.keys(baseProps)){const baseProp=baseProps[key];if(baseProp===undefined)continue;mergedProps[key]=baseProp}for(const key of Object.keys(overrideProps)){const overrideProp=overrideProps[key];if(overrideProp===undefined)continue;const baseProp=baseProps[key];if(baseProp!==undefined&&typeof baseProp!=="boolean"&&typeof overrideProp!=="boolean"&&isObjectLike(baseProp)&&isObjectLike(overrideProp)){mergedProps[key]=this.overlay(baseProp,overrideProp)}else{mergedProps[key]=overrideProp}}const baseRequired=Array.isArray(baseObj.required)?baseObj.required:[];const overrideRequired=Array.isArray(overrideObj.required)?overrideObj.required:[];const mergedRequired=unionStrings(baseRequired,overrideRequired);const result={...baseObj};result.properties=mergedProps;if(mergedRequired.length>0){result.required=mergedRequired}else{delete result.required}if(hasOwn(overrideObj,"additionalProperties")){result.additionalProperties=overrideObj.additionalProperties}if(hasOwn(overrideObj,"minProperties")){result.minProperties=overrideObj.minProperties}if(hasOwn(overrideObj,"maxProperties")){result.maxProperties=overrideObj.maxProperties}if(hasOwn(overrideObj,"propertyNames")){result.propertyNames=overrideObj.propertyNames}if(hasOwn(overrideObj,"patternProperties")){result.patternProperties=overrideObj.patternProperties}if(hasOwn(overrideObj,"dependencies")){result.dependencies=overrideObj.dependencies}if(hasOwn(overrideObj,"type")){result.type=overrideObj.type}return result}constructor(){_define_property(this,"compareFn",void 0);_define_property(this,"shallowAllOfMergeFn",void 0);const{compareSchemaDefinitions,compareSchemaValues}=createComparator();const safeCompareSchemaValues=(a,b)=>{if(a===null&&b===null)return 0;return compareSchemaValues(a,b)};const{mergeArrayOfSchemaDefinitions}=createMerger({intersectJson:createIntersector(safeCompareSchemaValues),deduplicateJsonSchemaDef:createDeduplicator(compareSchemaDefinitions)});this.compareFn=compareSchemaDefinitions;this.shallowAllOfMergeFn=createShallowAllOfMerge(mergeArrayOfSchemaDefinitions)}}const OBJECT_SHAPE_KEYWORDS=["properties","patternProperties","additionalProperties","required","dependencies","propertyNames","minProperties","maxProperties"];function isObjectLike(schema){if(schema.type==="object")return true;for(const kw of OBJECT_SHAPE_KEYWORDS){if(hasOwn(schema,kw))return true}return false}
1
+ function _define_property(obj,key,value){if(key in obj){Object.defineProperty(obj,key,{value:value,enumerable:true,configurable:true,writable:true})}else{obj[key]=value}return obj}import{createComparator,createMerger,createShallowAllOfMerge}from"@x0k/json-schema-merge";import{createDeduplicator,createIntersector}from"@x0k/json-schema-merge/lib/array";import{isFormatSubset}from"./format-validator.js";import{deepEqual,hasOwn,isPlainObj,unionStrings}from"./utils.js";function hasConstConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;const aHasConst=hasOwn(a,"const");const bHasConst=hasOwn(b,"const");const aConst=a.const;const bConst=b.const;const aEnum=a.enum;const bEnum=b.enum;if(aHasConst&&bHasConst){return!deepEqual(aConst,bConst)}if(aHasConst&&Array.isArray(bEnum)){return!bEnum.some(v=>deepEqual(v,aConst))}if(bHasConst&&Array.isArray(aEnum)){return!aEnum.some(v=>deepEqual(v,bConst))}return false}const SINGLE_SCHEMA_CONFLICT_KEYS=["items","additionalProperties","contains","propertyNames","not"];const PROPERTIES_MAP_CONFLICT_KEYS=["properties","patternProperties"];function hasDeepConstConflict(a,b){if(hasConstConflict(a,b))return true;if(typeof a==="boolean"||typeof b==="boolean")return false;for(const key of SINGLE_SCHEMA_CONFLICT_KEYS){const aVal=a[key];const bVal=b[key];if(isPlainObj(aVal)&&isPlainObj(bVal)&&hasDeepConstConflict(aVal,bVal)){return true}}for(const key of PROPERTIES_MAP_CONFLICT_KEYS){const aMap=a[key];const bMap=b[key];if(!isPlainObj(aMap)||!isPlainObj(bMap))continue;const aMapSafe=aMap;const bMapSafe=bMap;for(const propKey of Object.keys(aMapSafe)){const aVal=aMapSafe[propKey];const bVal=bMapSafe[propKey];if(aVal!==undefined&&bVal!==undefined&&hasOwn(bMapSafe,propKey)&&hasDeepConstConflict(aVal,bVal)){return true}}}if(Array.isArray(a.items)&&Array.isArray(b.items)){const aItems=a.items;const bItems=b.items;const len=Math.min(aItems.length,bItems.length);for(let i=0;i<len;i++){const aItem=aItems[i];const bItem=bItems[i];if(aItem===undefined||bItem===undefined)continue;if(hasDeepConstConflict(aItem,bItem)){return true}}}return false}function hasAdditionalPropertiesConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;const aProps=isPlainObj(a.properties)?a.properties:undefined;const bProps=isPlainObj(b.properties)?b.properties:undefined;if(!aProps&&!bProps)return false;const aKeys=aProps?Object.keys(aProps):[];const bKeys=bProps?Object.keys(bProps):[];const aRequired=Array.isArray(a.required)?a.required:[];const bRequired=Array.isArray(b.required)?b.required:[];if(a.additionalProperties===false&&aProps&&bProps){const hasRequiredExtra=bRequired.some(k=>!hasOwn(aProps,k)&&hasOwn(bProps,k));if(hasRequiredExtra&&aKeys.length>0)return true}if(isPlainObj(a.additionalProperties)&&typeof a.additionalProperties!=="boolean"&&aProps&&bProps){const addPropsSchema=a.additionalProperties;if(hasOwn(addPropsSchema,"type")){const addPropsType=addPropsSchema.type;const hasTypeConflict=bRequired.some(k=>{if(hasOwn(aProps,k))return false;if(!hasOwn(bProps,k))return false;const bPropDef=bProps[k];if(typeof bPropDef==="boolean")return false;const bProp=bPropDef;if(!hasOwn(bProp,"type"))return false;if(typeof addPropsType==="string"&&typeof bProp.type==="string"){return addPropsType!==bProp.type&&!(addPropsType==="number"&&bProp.type==="integer")&&!(addPropsType==="integer"&&bProp.type==="number")}return false});if(hasTypeConflict)return true}}if(b.additionalProperties===false&&bProps&&aProps){const hasRequiredExtra=aRequired.some(k=>!hasOwn(bProps,k)&&hasOwn(aProps,k));if(hasRequiredExtra&&bKeys.length>0)return true}if(isPlainObj(b.additionalProperties)&&typeof b.additionalProperties!=="boolean"&&bProps&&aProps){const addPropsSchema=b.additionalProperties;if(hasOwn(addPropsSchema,"type")){const addPropsType=addPropsSchema.type;const hasTypeConflict=aRequired.some(k=>{if(hasOwn(bProps,k))return false;if(!hasOwn(aProps,k))return false;const aPropDef=aProps[k];if(typeof aPropDef==="boolean")return false;const aProp=aPropDef;if(!hasOwn(aProp,"type"))return false;if(typeof addPropsType==="string"&&typeof aProp.type==="string"){return addPropsType!==aProp.type&&!(addPropsType==="number"&&aProp.type==="integer")&&!(addPropsType==="integer"&&aProp.type==="number")}return false});if(hasTypeConflict)return true}}if(aProps&&bProps){for(const k of aKeys){if(!hasOwn(bProps,k))continue;const aPropDef=aProps[k];const bPropDef=bProps[k];if(typeof aPropDef==="boolean"||typeof bPropDef==="boolean")continue;if(hasAdditionalPropertiesConflict(aPropDef,bPropDef)){return true}}}return false}function hasFormatConflict(a,b){if(typeof a==="boolean"||typeof b==="boolean")return false;if(hasOwn(a,"format")&&hasOwn(b,"format")){const aFormat=a.format;const bFormat=b.format;if(aFormat!==bFormat){const subsetCheck=isFormatSubset(aFormat,bFormat);if(subsetCheck!==true){const reverseCheck=isFormatSubset(bFormat,aFormat);if(reverseCheck!==true){return true}}}}if(isPlainObj(a.properties)&&isPlainObj(b.properties)){const aMap=a.properties;const bMap=b.properties;for(const k of Object.keys(aMap)){const aVal=aMap[k];const bVal=bMap[k];if(aVal!==undefined&&bVal!==undefined&&hasOwn(bMap,k)&&hasFormatConflict(aVal,bVal)){return true}}}if(isPlainObj(a.items)&&isPlainObj(b.items)){if(hasFormatConflict(a.items,b.items))return true}if(isPlainObj(a.additionalProperties)&&isPlainObj(b.additionalProperties)){if(hasFormatConflict(a.additionalProperties,b.additionalProperties))return true}return false}export class MergeEngine{merge(a,b){if(a===b)return a;if(a===false||b===false)return false;if(a===true)return b;if(b===true)return a;if(hasDeepConstConflict(a,b)){return null}if(hasFormatConflict(a,b)){return null}if(hasAdditionalPropertiesConflict(a,b)){return null}try{return this.shallowAllOfMergeFn({allOf:[a,b]})}catch{return null}}mergeOrThrow(a,b){if(a===b)return a;if(a===false||b===false)return false;if(a===true)return b;if(b===true)return a;if(hasDeepConstConflict(a,b)){throw new Error("Incompatible const values: schemas have conflicting const constraints")}if(hasFormatConflict(a,b)){throw new Error("Incompatible format values: schemas have conflicting format constraints")}if(hasAdditionalPropertiesConflict(a,b)){throw new Error("Incompatible additionalProperties: required properties conflict with additionalProperties constraint")}return this.shallowAllOfMergeFn({allOf:[a,b]})}compare(a,b){return this.compareFn(a,b)}isEqual(a,b){return this.compareFn(a,b)===0}overlay(base,override){if(override===false)return false;if(override===true)return true;if(typeof base==="boolean")return override;const baseObj=base;const overrideObj=override;if(!isObjectLike(baseObj)&&!isObjectLike(overrideObj)){return override}if(!isObjectLike(baseObj)){return override}if(!isObjectLike(overrideObj)){return override}const baseProps=baseObj.properties??{};const overrideProps=overrideObj.properties??{};const mergedProps={};for(const key of Object.keys(baseProps)){const baseProp=baseProps[key];if(baseProp===undefined)continue;mergedProps[key]=baseProp}for(const key of Object.keys(overrideProps)){const overrideProp=overrideProps[key];if(overrideProp===undefined)continue;const baseProp=baseProps[key];if(baseProp!==undefined&&typeof baseProp!=="boolean"&&typeof overrideProp!=="boolean"&&isObjectLike(baseProp)&&isObjectLike(overrideProp)){mergedProps[key]=this.overlay(baseProp,overrideProp)}else{mergedProps[key]=overrideProp}}const baseRequired=Array.isArray(baseObj.required)?baseObj.required:[];const overrideRequired=Array.isArray(overrideObj.required)?overrideObj.required:[];const mergedRequired=unionStrings(baseRequired,overrideRequired);const result={...baseObj};result.properties=mergedProps;if(mergedRequired.length>0){result.required=mergedRequired}else{delete result.required}if(hasOwn(overrideObj,"additionalProperties")){result.additionalProperties=overrideObj.additionalProperties}if(hasOwn(overrideObj,"minProperties")){result.minProperties=overrideObj.minProperties}if(hasOwn(overrideObj,"maxProperties")){result.maxProperties=overrideObj.maxProperties}if(hasOwn(overrideObj,"propertyNames")){result.propertyNames=overrideObj.propertyNames}if(hasOwn(overrideObj,"patternProperties")){result.patternProperties=overrideObj.patternProperties}if(hasOwn(overrideObj,"dependencies")){result.dependencies=overrideObj.dependencies}if(hasOwn(overrideObj,"type")){result.type=overrideObj.type}return result}constructor(){_define_property(this,"compareFn",void 0);_define_property(this,"shallowAllOfMergeFn",void 0);const{compareSchemaDefinitions,compareSchemaValues}=createComparator();const safeCompareSchemaValues=(a,b)=>{if(a===null&&b===null)return 0;return compareSchemaValues(a,b)};const{mergeArrayOfSchemaDefinitions}=createMerger({intersectJson:createIntersector(safeCompareSchemaValues),deduplicateJsonSchemaDef:createDeduplicator(compareSchemaDefinitions)});this.compareFn=compareSchemaDefinitions;this.shallowAllOfMergeFn=createShallowAllOfMerge(mergeArrayOfSchemaDefinitions)}}const OBJECT_SHAPE_KEYWORDS=["properties","patternProperties","additionalProperties","required","dependencies","propertyNames","minProperties","maxProperties"];function isObjectLike(schema){if(schema.type==="object")return true;for(const kw of OBJECT_SHAPE_KEYWORDS){if(hasOwn(schema,kw))return true}return false}
2
2
  //# sourceMappingURL=merge-engine.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/merge-engine.ts"],"sourcesContent":["import {\n\tcreateComparator,\n\tcreateMerger,\n\tcreateShallowAllOfMerge,\n} from \"@x0k/json-schema-merge\";\nimport {\n\tcreateDeduplicator,\n\tcreateIntersector,\n} from \"@x0k/json-schema-merge/lib/array\";\n\nimport type {\n\tJSONSchema7,\n\tJSONSchema7Definition,\n\tJSONSchema7Type,\n} from \"json-schema\";\n\nimport { isFormatSubset } from \"./format-validator.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":["createComparator","createMerger","createShallowAllOfMerge","createDeduplicator","createIntersector","isFormatSubset","deepEqual","hasOwn","isPlainObj","mergeConstraints","unionStrings","hasConstConflict","a","b","aHasConst","bHasConst","aConst","const","bConst","aEnum","enum","bEnum","Array","isArray","some","v","SINGLE_SCHEMA_CONFLICT_KEYS","PROPERTIES_MAP_CONFLICT_KEYS","hasDeepConstConflict","key","aVal","bVal","aMap","bMap","aMapSafe","bMapSafe","propKey","Object","keys","undefined","items","aItems","bItems","len","Math","min","length","i","aItem","bItem","hasAdditionalPropertiesConflict","aProps","properties","bProps","aKeys","bKeys","aRequired","required","bRequired","additionalProperties","hasRequiredExtra","k","addPropsSchema","addPropsType","type","hasTypeConflict","bPropDef","bProp","aPropDef","aProp","hasFormatConflict","aFormat","format","bFormat","subsetCheck","reverseCheck","hasConstraintsAnywhere","schema","constraints","props","prop","patternProperties","pp","val","item","dependencies","deps","applyConstraintsMerge","merged","changed","result","mergedConstraints","currentConstraints","mergedProps","propsChanged","newProps","mProp","patched","mergedPP","aPP","bPP","ppChanged","newPP","mVal","mergedItems","tupleChanged","newItems","mItem","mergedDeps","aDeps","bDeps","depsChanged","newDeps","MergeEngine","merge","shallowAllOfMergeFn","allOf","mergeOrThrow","Error","compare","compareFn","isEqual","overlay","base","override","baseObj","overrideObj","isObjectLike","baseProps","overrideProps","baseProp","overrideProp","baseRequired","overrideRequired","mergedRequired","minProperties","maxProperties","propertyNames","compareSchemaDefinitions","compareSchemaValues","safeCompareSchemaValues","mergeArrayOfSchemaDefinitions","intersectJson","deduplicateJsonSchemaDef","OBJECT_SHAPE_KEYWORDS","kw"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/merge-engine.ts"],"sourcesContent":["import {\n\tcreateComparator,\n\tcreateMerger,\n\tcreateShallowAllOfMerge,\n} from \"@x0k/json-schema-merge\";\nimport {\n\tcreateDeduplicator,\n\tcreateIntersector,\n} from \"@x0k/json-schema-merge/lib/array\";\n\nimport type {\n\tJSONSchema7,\n\tJSONSchema7Definition,\n\tJSONSchema7Type,\n} from \"json-schema\";\n\nimport { isFormatSubset } from \"./format-validator.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":["createComparator","createMerger","createShallowAllOfMerge","createDeduplicator","createIntersector","isFormatSubset","deepEqual","hasOwn","isPlainObj","unionStrings","hasConstConflict","a","b","aHasConst","bHasConst","aConst","const","bConst","aEnum","enum","bEnum","Array","isArray","some","v","SINGLE_SCHEMA_CONFLICT_KEYS","PROPERTIES_MAP_CONFLICT_KEYS","hasDeepConstConflict","key","aVal","bVal","aMap","bMap","aMapSafe","bMapSafe","propKey","Object","keys","undefined","items","aItems","bItems","len","Math","min","length","i","aItem","bItem","hasAdditionalPropertiesConflict","aProps","properties","bProps","aKeys","bKeys","aRequired","required","bRequired","additionalProperties","hasRequiredExtra","k","addPropsSchema","addPropsType","type","hasTypeConflict","bPropDef","bProp","aPropDef","aProp","hasFormatConflict","aFormat","format","bFormat","subsetCheck","reverseCheck","MergeEngine","merge","shallowAllOfMergeFn","allOf","mergeOrThrow","Error","compare","compareFn","isEqual","overlay","base","override","baseObj","overrideObj","isObjectLike","baseProps","overrideProps","mergedProps","baseProp","overrideProp","baseRequired","overrideRequired","mergedRequired","result","minProperties","maxProperties","propertyNames","patternProperties","dependencies","compareSchemaDefinitions","compareSchemaValues","safeCompareSchemaValues","mergeArrayOfSchemaDefinitions","intersectJson","deduplicateJsonSchemaDef","OBJECT_SHAPE_KEYWORDS","schema","kw"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{deepEqual,hasOwn,isPlainObj}from"./utils.js";const normalizeCache=new WeakMap;export 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(!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}export 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&&!hasOwn(schema,"const")){const s=ensureCopy();s.const=schema.enum[0];delete s.enum}if(hasOwn(schema,"const")&&Array.isArray(schema.enum)){if(schema.enum.some(v=>deepEqual(v,schema.const))){delete ensureCopy().enum}}if(hasOwn(schema,"constraints")&&schema.constraints!==undefined&&!Array.isArray(schema.constraints)){ensureCopy().constraints=[schema.constraints]}for(const keyword of PROPERTIES_LIKE_KEYWORDS){const val=schema[keyword];if(isPlainObj(val)){const normalized=normalizePropertiesMap(val);if(normalized!==val){ensureCopy()[keyword]=normalized}}}if(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(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(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(hasOwn(schema,"not")&&isPlainObj(schema.not)&&typeof schema.not!=="boolean"){const notSchema=schema.not;if(hasOwn(notSchema,"not")&&isPureNotSchema(notSchema)&&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}
1
+ import{deepEqual,hasOwn,isPlainObj}from"./utils.js";const normalizeCache=new WeakMap;export 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(!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}export 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&&!hasOwn(schema,"const")){const s=ensureCopy();s.const=schema.enum[0];delete s.enum}if(hasOwn(schema,"const")&&Array.isArray(schema.enum)){if(schema.enum.some(v=>deepEqual(v,schema.const))){delete ensureCopy().enum}}if(hasOwn(schema,"constraints")&&schema.constraints!==undefined){const s=ensureCopy();delete s.constraints}for(const keyword of PROPERTIES_LIKE_KEYWORDS){const val=schema[keyword];if(isPlainObj(val)){const normalized=normalizePropertiesMap(val);if(normalized!==val){ensureCopy()[keyword]=normalized}}}if(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(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(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(hasOwn(schema,"not")&&isPlainObj(schema.not)&&typeof schema.not!=="boolean"){const notSchema=schema.not;if(hasOwn(notSchema,"not")&&isPureNotSchema(notSchema)&&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