json-schema-compatibility-checker 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/condition-resolver.js +1 -1
- package/dist/cjs/condition-resolver.js.map +1 -1
- package/dist/cjs/constraint-validator.d.ts +4 -4
- package/dist/cjs/constraint-validator.js.map +1 -1
- package/dist/cjs/json-schema-compatibility-checker.js +1 -1
- package/dist/cjs/json-schema-compatibility-checker.js.map +1 -1
- package/dist/cjs/merge-engine.js +1 -1
- package/dist/cjs/merge-engine.js.map +1 -1
- package/dist/cjs/normalizer.js +1 -1
- package/dist/cjs/normalizer.js.map +1 -1
- package/dist/cjs/semantic-errors.js +1 -1
- package/dist/cjs/semantic-errors.js.map +1 -1
- package/dist/esm/condition-resolver.js +1 -1
- package/dist/esm/condition-resolver.js.map +1 -1
- package/dist/esm/constraint-validator.d.ts +4 -4
- package/dist/esm/constraint-validator.js.map +1 -1
- package/dist/esm/json-schema-compatibility-checker.js +1 -1
- package/dist/esm/json-schema-compatibility-checker.js.map +1 -1
- package/dist/esm/merge-engine.js +1 -1
- package/dist/esm/merge-engine.js.map +1 -1
- package/dist/esm/normalizer.js +1 -1
- package/dist/esm/normalizer.js.map +1 -1
- package/dist/esm/semantic-errors.js +1 -1
- package/dist/esm/semantic-errors.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/semantic-errors.ts"],"sourcesContent":["import type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\nimport type { Constraint, SchemaError } from \"./types.ts\";\nimport { deepEqual, hasOwn, isPlainObj } from \"./utils.ts\";\n\n// ─── Semantic Error Generator ────────────────────────────────────────────────\n//\n// Generates human-readable semantic errors by directly comparing two schemas.\n//\n// Unlike a structural differ (which would compare sub vs merged), this module\n// directly compares sub (source/received) and sup (target/expected) to produce\n// business-oriented error messages.\n//\n// Property paths are normalized:\n// - `accountId` (top-level property)\n// - `user.name` (nested property)\n// - `users[].name` (property inside array items)\n//\n// Convention:\n// - `expected` = what the target schema (sup) expects\n// - `received` = what the source schema (sub) provides\n\n// ─── Type Formatting ─────────────────────────────────────────────────────────\n\n/**\n * Formats enum values into a readable string.\n *\n * Examples:\n * - 1 value : `\"123\"`\n * - 2 values : `\"123 or hello\"`\n * - 3 values : `\"10, 20, or 30\"`\n */\nfunction formatEnumValues(values: unknown[]): string {\n\tconst parts = values.map((v) =>\n\t\ttypeof v === \"string\" ? v : JSON.stringify(v),\n\t);\n\tif (parts.length === 0) return \"never\";\n\tif (parts.length === 1) return parts[0] as string;\n\tif (parts.length === 2) return `${parts[0]} or ${parts[1]}`;\n\tconst last = parts.pop();\n\treturn `${parts.join(\", \")}, or ${last}`;\n}\n\n/**\n * Formats a schema into a readable type representation.\n *\n * Examples:\n * - `{ type: \"string\" }` → `\"string\"`\n * - `{ type: \"array\", items: { type: \"string\" } }` → `\"string[]\"`\n * - `{ type: \"array\", items: { type: [\"string\",\"number\"] }` → `\"string[] | number[]\"`\n * - `{ enum: [1, 2, 3] }` → `\"1, 2, or 3\"`\n * - `{ const: \"hello\" }` → `\"hello\"`\n * - `{ anyOf: [{type:\"string\"},{type:\"number\"}] }` → `\"string | number\"`\n * - `undefined` → `\"undefined\"`\n */\nexport function formatSchemaType(\n\tdef: JSONSchema7Definition | undefined,\n): string {\n\tconst base = formatSchemaTypeInternal(def);\n\tif (def === undefined || typeof def === \"boolean\") return base;\n\treturn base + formatConstraintsSuffix(def as JSONSchema7);\n}\n\n/**\n * Formats the constraints suffix for a schema type description.\n * Returns an empty string if there are no constraints.\n *\n * @example\n * formatConstraintsSuffix({ type: \"string\", constraints: [\"IsUuid\", \"BelongsToScope\"] })\n * // → \" [IsUuid, BelongsToScope]\"\n *\n * formatConstraintsSuffix({ type: \"string\" })\n * // → \"\"\n */\nfunction formatConstraintsSuffix(schema: JSONSchema7): string {\n\tconst constraints = schema.constraints;\n\tif (constraints === undefined) return \"\";\n\n\tconst arr = Array.isArray(constraints) ? constraints : [constraints];\n\tif (arr.length === 0) return \"\";\n\n\treturn ` [${arr.map(formatCustomConstraint).join(\", \")}]`;\n}\n\nfunction formatSchemaTypeInternal(\n\tdef: JSONSchema7Definition | undefined,\n): string {\n\tif (def === undefined) return \"undefined\";\n\tif (typeof def === \"boolean\") return def ? \"any\" : \"never\";\n\n\tconst schema = def as JSONSchema7;\n\n\t// ── Const ──\n\tif (hasOwn(schema, \"const\")) {\n\t\tconst v = schema.const;\n\t\treturn typeof v === \"string\" ? v : JSON.stringify(v);\n\t}\n\n\t// ── Enum ──\n\tif (Array.isArray(schema.enum)) {\n\t\treturn formatEnumValues(schema.enum);\n\t}\n\n\t// ── anyOf / oneOf (union types) ──\n\tconst branches = schema.anyOf ?? schema.oneOf;\n\tif (Array.isArray(branches) && branches.length > 0) {\n\t\tconst parts = branches.map((b) => formatSchemaType(b));\n\t\treturn parts.join(\" | \");\n\t}\n\n\t// ── Array type ──\n\tif (schema.type === \"array\") {\n\t\tif (schema.items !== undefined && typeof schema.items !== \"boolean\") {\n\t\t\tconst itemSchema = schema.items as JSONSchema7;\n\n\t\t\t// Items with anyOf/oneOf → \"string[] | number[]\"\n\t\t\tconst itemBranches = itemSchema.anyOf ?? itemSchema.oneOf;\n\t\t\tif (Array.isArray(itemBranches) && itemBranches.length > 0) {\n\t\t\t\tconst parts = itemBranches.map((b) => `${formatSchemaType(b)}[]`);\n\t\t\t\treturn parts.join(\" | \");\n\t\t\t}\n\n\t\t\t// Items with multiple types → \"string[] | number[]\"\n\t\t\tif (Array.isArray(itemSchema.type)) {\n\t\t\t\tconst parts = itemSchema.type.map((t) => `${t}[]`);\n\t\t\t\treturn parts.join(\" | \");\n\t\t\t}\n\n\t\t\tconst itemType = formatSchemaType(itemSchema);\n\t\t\treturn `${itemType}[]`;\n\t\t}\n\t\t// items is boolean true or missing\n\t\treturn \"array\";\n\t}\n\n\t// ── Simple type ──\n\tif (typeof schema.type === \"string\") {\n\t\treturn schema.type;\n\t}\n\n\t// ── Multiple types (type: [\"string\", \"number\"]) ──\n\tif (Array.isArray(schema.type)) {\n\t\treturn schema.type.join(\" | \");\n\t}\n\n\t// ── not (pure-not schema, no other significant keywords) ──\n\tif (\n\t\thasOwn(schema, \"not\") &&\n\t\t!schema.type &&\n\t\t!isPlainObj(schema.properties) &&\n\t\tschema.items === undefined &&\n\t\t!Array.isArray(schema.enum) &&\n\t\t!hasOwn(schema, \"const\")\n\t) {\n\t\treturn `not ${formatSchemaType(schema.not as JSONSchema7Definition)}`;\n\t}\n\n\t// ── Fallback ──\n\t// Schema without explicit type — try to infer from structure\n\tif (isPlainObj(schema.properties)) return \"object\";\n\tif (schema.items !== undefined) return \"array\";\n\n\treturn \"unknown\";\n}\n\n// ─── Path Helpers ────────────────────────────────────────────────────────────\n\n/**\n * Builds a normalized property path.\n * - Root + key → `\"accountId\"`\n * - Parent + key → `\"user.name\"`\n * - Parent[] + key → `\"users[].name\"`\n */\nfunction joinPath(parent: string, key: string): string {\n\tif (!parent) return key;\n\treturn `${parent}.${key}`;\n}\n\n/**\n * Appends the `[]` suffix to indicate entering array items.\n */\nfunction arrayPath(parent: string): string {\n\tif (!parent) return \"[]\";\n\treturn `${parent}[]`;\n}\n\n// ─── Schema Accessors ────────────────────────────────────────────────────────\n\n/**\n * Safely extracts the properties from a schema.\n */\nfunction getProperties(\n\tschema: JSONSchema7,\n): Record<string, JSONSchema7Definition> | null {\n\tif (isPlainObj(schema.properties)) {\n\t\treturn schema.properties as Record<string, JSONSchema7Definition>;\n\t}\n\treturn null;\n}\n\n/**\n * Safely extracts the required fields from a schema.\n */\nfunction getRequired(schema: JSONSchema7): string[] {\n\tif (Array.isArray(schema.required)) {\n\t\treturn schema.required as string[];\n\t}\n\treturn [];\n}\n\n/**\n * Determines the effective type of a schema (string or array of types).\n */\nfunction getEffectiveType(schema: JSONSchema7): string | string[] | undefined {\n\tif (schema.type !== undefined) return schema.type as string | string[];\n\n\t// Infer from const\n\tif (hasOwn(schema, \"const\")) {\n\t\tconst v = schema.const;\n\t\tif (v === null) return \"null\";\n\t\tif (Array.isArray(v)) return \"array\";\n\t\treturn typeof v;\n\t}\n\n\t// Infer from properties\n\tif (isPlainObj(schema.properties)) return \"object\";\n\n\t// Infer from items\n\tif (schema.items !== undefined) return \"array\";\n\n\treturn undefined;\n}\n\n/**\n * Checks whether a type (string) is included in a type or array of types.\n */\nfunction typeIncludes(\n\tschemaType: string | string[] | undefined,\n\ttarget: string,\n): boolean {\n\tif (schemaType === undefined) return false;\n\tif (typeof schemaType === \"string\") {\n\t\t// integer is a subset of number\n\t\tif (target === \"number\" && schemaType === \"integer\") return true;\n\t\tif (target === \"integer\" && schemaType === \"number\") return true;\n\t\treturn schemaType === target;\n\t}\n\treturn schemaType.includes(target);\n}\n\n/**\n * Checks whether two types are compatible.\n * A type is compatible if the sub type is included in the sup type.\n */\nfunction typesAreCompatible(\n\tsubType: string | string[] | undefined,\n\tsupType: string | string[] | undefined,\n): boolean {\n\tif (supType === undefined) return true; // sup accepts anything\n\tif (subType === undefined) return true; // sub is undetermined, cannot conclude\n\n\tif (typeof subType === \"string\" && typeof supType === \"string\") {\n\t\tif (subType === supType) return true;\n\t\t// integer ⊆ number\n\t\tif (subType === \"integer\" && supType === \"number\") return true;\n\t\treturn false;\n\t}\n\n\tif (typeof subType === \"string\" && Array.isArray(supType)) {\n\t\treturn supType.some(\n\t\t\t(t) => t === subType || (subType === \"integer\" && t === \"number\"),\n\t\t);\n\t}\n\n\tif (Array.isArray(subType) && typeof supType === \"string\") {\n\t\treturn subType.every(\n\t\t\t(t) => t === supType || (t === \"integer\" && supType === \"number\"),\n\t\t);\n\t}\n\n\tif (Array.isArray(subType) && Array.isArray(supType)) {\n\t\treturn subType.every((st) =>\n\t\t\tsupType.some(\n\t\t\t\t(supt) => supt === st || (st === \"integer\" && supt === \"number\"),\n\t\t\t),\n\t\t);\n\t}\n\n\treturn true;\n}\n\n// ─── Custom Constraint Helpers ───────────────────────────────────────────────\n\n/**\n * Formats a custom constraint into a readable string.\n * @example formatCustomConstraint(\"IsUuid\") → \"IsUuid\"\n * @example formatCustomConstraint({ name: \"MinAge\", params: { min: 21 } }) → 'MinAge({\"min\":21})'\n * @example formatCustomConstraint({ name: \"IsCustom\" }) → \"IsCustom\"\n */\nfunction formatCustomConstraint(c: Constraint): string {\n\tif (typeof c === \"string\") return c;\n\tif (c.params && Object.keys(c.params).length > 0) {\n\t\treturn `${c.name}(${JSON.stringify(c.params)})`;\n\t}\n\treturn c.name;\n}\n\n/**\n * Formats a list of custom constraints into a readable string.\n */\nfunction formatCustomConstraintList(cs: Constraint[]): string {\n\treturn cs.map(formatCustomConstraint).join(\", \");\n}\n\n/**\n * Compares custom constraints between sub and sup.\n *\n * For sub ⊆ sup, every constraint in sup must have an exact match\n * (by deep equality) in sub. Missing constraints are reported as errors.\n */\nfunction checkCustomConstraints(\n\tsub: JSONSchema7,\n\tsup: JSONSchema7,\n\tpath: string,\n\terrors: SchemaError[],\n): void {\n\tconst supConstraints = sup.constraints;\n\tconst subConstraints = sub.constraints;\n\n\t// If sup has no constraints, nothing to check\n\tif (supConstraints === undefined) return;\n\n\tconst supArr = Array.isArray(supConstraints)\n\t\t? supConstraints\n\t\t: [supConstraints];\n\tconst subArr =\n\t\tsubConstraints === undefined\n\t\t\t? []\n\t\t\t: Array.isArray(subConstraints)\n\t\t\t\t? subConstraints\n\t\t\t\t: [subConstraints];\n\n\t// Find constraints in sup that are missing from sub\n\tfor (const supC of supArr) {\n\t\tconst found = subArr.some((subC) => deepEqual(subC, supC));\n\t\tif (!found) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: `constraint: ${formatCustomConstraint(supC)}`,\n\t\t\t\treceived:\n\t\t\t\t\tsubArr.length > 0\n\t\t\t\t\t\t? `constraints: ${formatCustomConstraintList(subArr)}`\n\t\t\t\t\t\t: \"no constraints\",\n\t\t\t});\n\t\t}\n\t}\n}\n\n// ─── Constraint Helpers ──────────────────────────────────────────────────────\n\n/**\n * Formats a constraint value into a readable string.\n */\nfunction fmtConstraint(name: string, value: unknown): string {\n\tif (value === undefined) return `${name}: not set`;\n\tif (typeof value === \"boolean\") return `${name}: ${value}`;\n\tif (typeof value === \"number\" || typeof value === \"string\")\n\t\treturn `${name}: ${value}`;\n\treturn `${name}: ${JSON.stringify(value)}`;\n}\n\n/**\n * Compares a \"minimum-like\" numeric constraint (sub.X must be >= sup.X for sub ⊆ sup).\n * Examples: minimum, exclusiveMinimum, minLength, minItems, minProperties\n */\nfunction checkMinConstraint(\n\tsubVal: number | undefined,\n\tsupVal: number | undefined,\n\tname: string,\n\tpath: string,\n\terrors: SchemaError[],\n): void {\n\tif (supVal !== undefined) {\n\t\tif (subVal === undefined || subVal < supVal) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: fmtConstraint(name, supVal),\n\t\t\t\treceived: fmtConstraint(name, subVal),\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * Compares a \"maximum-like\" numeric constraint (sub.X must be <= sup.X for sub ⊆ sup).\n * Examples: maximum, exclusiveMaximum, maxLength, maxItems, maxProperties\n */\nfunction checkMaxConstraint(\n\tsubVal: number | undefined,\n\tsupVal: number | undefined,\n\tname: string,\n\tpath: string,\n\terrors: SchemaError[],\n): void {\n\tif (supVal !== undefined) {\n\t\tif (subVal === undefined || subVal > supVal) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: fmtConstraint(name, supVal),\n\t\t\t\treceived: fmtConstraint(name, subVal),\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * Compares numeric constraints between sub and sup.\n */\nfunction checkNumericConstraints(\n\tsub: JSONSchema7,\n\tsup: JSONSchema7,\n\tpath: string,\n\terrors: SchemaError[],\n): void {\n\tcheckMinConstraint(sub.minimum, sup.minimum, \"minimum\", path, errors);\n\tcheckMaxConstraint(sub.maximum, sup.maximum, \"maximum\", path, errors);\n\tcheckMinConstraint(\n\t\tsub.exclusiveMinimum as number | undefined,\n\t\tsup.exclusiveMinimum as number | undefined,\n\t\t\"exclusiveMinimum\",\n\t\tpath,\n\t\terrors,\n\t);\n\tcheckMaxConstraint(\n\t\tsub.exclusiveMaximum as number | undefined,\n\t\tsup.exclusiveMaximum as number | undefined,\n\t\t\"exclusiveMaximum\",\n\t\tpath,\n\t\terrors,\n\t);\n\n\tif (sup.multipleOf !== undefined) {\n\t\tif (sub.multipleOf === undefined) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: fmtConstraint(\"multipleOf\", sup.multipleOf),\n\t\t\t\treceived: fmtConstraint(\"multipleOf\", sub.multipleOf),\n\t\t\t});\n\t\t} else if (sub.multipleOf !== sup.multipleOf) {\n\t\t\t// sub.multipleOf must be a multiple of sup.multipleOf for sub ⊆ sup\n\t\t\tif (sub.multipleOf % sup.multipleOf !== 0) {\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: fmtConstraint(\"multipleOf\", sup.multipleOf),\n\t\t\t\t\treceived: fmtConstraint(\"multipleOf\", sub.multipleOf),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Compares string constraints between sub and sup.\n */\nfunction checkStringConstraints(\n\tsub: JSONSchema7,\n\tsup: JSONSchema7,\n\tpath: string,\n\terrors: SchemaError[],\n): void {\n\tcheckMinConstraint(sub.minLength, sup.minLength, \"minLength\", path, errors);\n\tcheckMaxConstraint(sub.maxLength, sup.maxLength, \"maxLength\", path, errors);\n\n\t// ── Pattern ──\n\tif (sup.pattern !== undefined) {\n\t\tif (sub.pattern === undefined) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: fmtConstraint(\"pattern\", sup.pattern),\n\t\t\t\treceived: \"no pattern constraint\",\n\t\t\t});\n\t\t} else if (sub.pattern !== sup.pattern) {\n\t\t\t// Different patterns — we can't statically determine subset relationship\n\t\t\t// without sampling, so report it as a potential mismatch.\n\t\t\t// The subset checker may have already stripped equivalent patterns,\n\t\t\t// so if we get here, they're genuinely different.\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: fmtConstraint(\"pattern\", sup.pattern),\n\t\t\t\treceived: fmtConstraint(\"pattern\", sub.pattern),\n\t\t\t});\n\t\t}\n\t}\n\n\t// ── Format ──\n\tif (sup.format !== undefined && sub.format !== sup.format) {\n\t\tif (sub.format === undefined) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: fmtConstraint(\"format\", sup.format),\n\t\t\t\treceived: \"no format constraint\",\n\t\t\t});\n\t\t} else {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: fmtConstraint(\"format\", sup.format),\n\t\t\t\treceived: fmtConstraint(\"format\", sub.format),\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * Compares object constraints (excluding properties/required) between sub and sup.\n */\nfunction checkObjectConstraints(\n\tsub: JSONSchema7,\n\tsup: JSONSchema7,\n\tpath: string,\n\terrors: SchemaError[],\n): void {\n\t// ── additionalProperties ──\n\tif (sup.additionalProperties !== undefined) {\n\t\tif (sup.additionalProperties === false) {\n\t\t\t// sup forbids additional properties\n\t\t\tif (\n\t\t\t\tsub.additionalProperties === undefined ||\n\t\t\t\tsub.additionalProperties === true\n\t\t\t) {\n\t\t\t\t// sub allows them → incompatible\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: \"additionalProperties: false\",\n\t\t\t\t\treceived: \"additional properties allowed\",\n\t\t\t\t});\n\t\t\t} else if (\n\t\t\t\ttypeof sub.additionalProperties === \"object\" &&\n\t\t\t\tsub.additionalProperties !== null\n\t\t\t) {\n\t\t\t\t// sub has a schema for additional properties → still allows them\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: \"additionalProperties: false\",\n\t\t\t\t\treceived: \"additionalProperties: schema\",\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (\n\t\t\ttypeof sup.additionalProperties === \"object\" &&\n\t\t\tsup.additionalProperties !== null\n\t\t) {\n\t\t\t// sup has a schema for additionalProperties\n\t\t\tif (\n\t\t\t\tsub.additionalProperties === undefined ||\n\t\t\t\tsub.additionalProperties === true\n\t\t\t) {\n\t\t\t\t// sub allows anything → more permissive\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: `additionalProperties: ${formatSchemaType(sup.additionalProperties as JSONSchema7Definition)}`,\n\t\t\t\t\treceived: \"additional properties allowed\",\n\t\t\t\t});\n\t\t\t} else if (\n\t\t\t\ttypeof sub.additionalProperties === \"object\" &&\n\t\t\t\tsub.additionalProperties !== null\n\t\t\t) {\n\t\t\t\t// Both have schema-form additionalProperties — recurse\n\t\t\t\tconst apPath = path\n\t\t\t\t\t? `${path}.<additionalProperties>`\n\t\t\t\t\t: \"<additionalProperties>\";\n\t\t\t\tconst apErrors = computeSemanticErrors(\n\t\t\t\t\tsub.additionalProperties as JSONSchema7Definition,\n\t\t\t\t\tsup.additionalProperties as JSONSchema7Definition,\n\t\t\t\t\tapPath,\n\t\t\t\t);\n\t\t\t\terrors.push(...apErrors);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── minProperties / maxProperties ──\n\tcheckMinConstraint(\n\t\tsub.minProperties,\n\t\tsup.minProperties,\n\t\t\"minProperties\",\n\t\tpath,\n\t\terrors,\n\t);\n\tcheckMaxConstraint(\n\t\tsub.maxProperties,\n\t\tsup.maxProperties,\n\t\t\"maxProperties\",\n\t\tpath,\n\t\terrors,\n\t);\n\n\t// ── propertyNames ──\n\tif (sup.propertyNames !== undefined) {\n\t\tif (sub.propertyNames === undefined) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: `propertyNames: ${formatSchemaType(sup.propertyNames)}`,\n\t\t\t\treceived: \"no propertyNames constraint\",\n\t\t\t});\n\t\t} else {\n\t\t\t// Both have propertyNames — recurse\n\t\t\tconst pnErrors = computeSemanticErrors(\n\t\t\t\tsub.propertyNames as JSONSchema7Definition,\n\t\t\t\tsup.propertyNames as JSONSchema7Definition,\n\t\t\t\tpath ? `${path}.<propertyNames>` : \"<propertyNames>\",\n\t\t\t);\n\t\t\terrors.push(...pnErrors);\n\t\t}\n\t}\n\n\t// ── dependencies ──\n\tif (isPlainObj(sup.dependencies)) {\n\t\tconst supDeps = sup.dependencies as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t\tconst subDeps = isPlainObj(sub.dependencies)\n\t\t\t? (sub.dependencies as Record<string, JSONSchema7Definition | string[]>)\n\t\t\t: null;\n\n\t\tfor (const key of Object.keys(supDeps)) {\n\t\t\tconst supDep = supDeps[key];\n\t\t\tconst subDep = subDeps?.[key];\n\n\t\t\tif (subDep === undefined) {\n\t\t\t\t// sup requires a dependency that sub doesn't have\n\t\t\t\tif (Array.isArray(supDep)) {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\t\texpected: `dependency: ${key} requires ${supDep.join(\", \")}`,\n\t\t\t\t\t\treceived: `no dependency for ${key}`,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\t\texpected: `dependency: ${key} requires schema`,\n\t\t\t\t\t\treceived: `no dependency for ${key}`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (Array.isArray(supDep) && Array.isArray(subDep)) {\n\t\t\t\t// Both are array form — check if sub includes all required props from sup\n\t\t\t\tconst missing = supDep.filter((d) => !subDep.includes(d));\n\t\t\t\tif (missing.length > 0) {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\t\texpected: `dependency: ${key} requires ${supDep.join(\", \")}`,\n\t\t\t\t\t\treceived: `dependency: ${key} requires ${subDep.join(\", \")}`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (!Array.isArray(supDep) && !Array.isArray(subDep)) {\n\t\t\t\t// Both are schema form — recurse\n\t\t\t\tconst depPath = path\n\t\t\t\t\t? `${path}.<dependency:${key}>`\n\t\t\t\t\t: `<dependency:${key}>`;\n\t\t\t\tconst depErrors = computeSemanticErrors(\n\t\t\t\t\tsubDep as JSONSchema7Definition,\n\t\t\t\t\tsupDep as JSONSchema7Definition,\n\t\t\t\t\tdepPath,\n\t\t\t\t);\n\t\t\t\terrors.push(...depErrors);\n\t\t\t} else {\n\t\t\t\t// Mixed forms (one array, one schema) — report mismatch\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: Array.isArray(supDep)\n\t\t\t\t\t\t? `dependency: ${key} requires ${supDep.join(\", \")}`\n\t\t\t\t\t\t: `dependency: ${key} requires schema`,\n\t\t\t\t\treceived: Array.isArray(subDep)\n\t\t\t\t\t\t? `dependency: ${key} requires ${subDep.join(\", \")}`\n\t\t\t\t\t\t: `dependency: ${key} requires schema`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── patternProperties ──\n\tif (isPlainObj(sup.patternProperties)) {\n\t\tconst supPP = sup.patternProperties as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tconst subPP = isPlainObj(sub.patternProperties)\n\t\t\t? (sub.patternProperties as Record<string, JSONSchema7Definition>)\n\t\t\t: null;\n\n\t\tfor (const pattern of Object.keys(supPP)) {\n\t\t\tconst supPropDef = supPP[pattern];\n\t\t\tif (supPropDef === undefined) continue;\n\n\t\t\tconst subPropDef = subPP?.[pattern];\n\t\t\tconst ppPath = path\n\t\t\t\t? `${path}.<patternProperties:${pattern}>`\n\t\t\t\t: `<patternProperties:${pattern}>`;\n\n\t\t\tif (subPropDef === undefined) {\n\t\t\t\t// sub doesn't constrain this pattern at all — more permissive\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: ppPath,\n\t\t\t\t\texpected: formatSchemaType(supPropDef),\n\t\t\t\t\treceived: \"no constraint for this pattern\",\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Both define the same pattern — recurse\n\t\t\t\tconst ppErrors = computeSemanticErrors(subPropDef, supPropDef, ppPath);\n\t\t\t\terrors.push(...ppErrors);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Compares array constraints (excluding items) between sub and sup.\n */\nfunction checkArrayConstraints(\n\tsub: JSONSchema7,\n\tsup: JSONSchema7,\n\tpath: string,\n\terrors: SchemaError[],\n): void {\n\tcheckMinConstraint(sub.minItems, sup.minItems, \"minItems\", path, errors);\n\tcheckMaxConstraint(sub.maxItems, sup.maxItems, \"maxItems\", path, errors);\n\n\t// ── uniqueItems ──\n\tif (sup.uniqueItems === true && sub.uniqueItems !== true) {\n\t\terrors.push({\n\t\t\tkey: path || \"$root\",\n\t\t\texpected: \"uniqueItems: true\",\n\t\t\treceived: fmtConstraint(\"uniqueItems\", sub.uniqueItems ?? false),\n\t\t});\n\t}\n\n\t// ── contains ──\n\tif (sup.contains !== undefined) {\n\t\tif (sub.contains === undefined) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: `contains: ${formatSchemaType(sup.contains as JSONSchema7Definition)}`,\n\t\t\t\treceived: \"no contains constraint\",\n\t\t\t});\n\t\t} else {\n\t\t\t// Both have contains — recurse to compare the contained schemas\n\t\t\tconst containsPath = path ? `${path}.<contains>` : \"<contains>\";\n\t\t\tconst containsErrors = computeSemanticErrors(\n\t\t\t\tsub.contains as JSONSchema7Definition,\n\t\t\t\tsup.contains as JSONSchema7Definition,\n\t\t\t\tcontainsPath,\n\t\t\t);\n\t\t\terrors.push(...containsErrors);\n\t\t}\n\t}\n}\n\n/**\n * Detects whether a schema has a numeric type.\n */\nfunction isNumericType(t: string | string[] | undefined): boolean {\n\tif (t === undefined) return false;\n\tif (typeof t === \"string\") return t === \"number\" || t === \"integer\";\n\treturn t.some((v) => v === \"number\" || v === \"integer\");\n}\n\n/**\n * Detects whether a schema has a string type.\n */\nfunction isStringType(t: string | string[] | undefined): boolean {\n\tif (t === undefined) return false;\n\tif (typeof t === \"string\") return t === \"string\";\n\treturn t.includes(\"string\");\n}\n\n/**\n * Detects whether a schema has an object type.\n */\nfunction isObjectType(t: string | string[] | undefined): boolean {\n\tif (t === undefined) return false;\n\tif (typeof t === \"string\") return t === \"object\";\n\treturn t.includes(\"object\");\n}\n\n/**\n * Detects whether a schema has an array type.\n */\nfunction isArrayType(t: string | string[] | undefined): boolean {\n\tif (t === undefined) return false;\n\tif (typeof t === \"string\") return t === \"array\";\n\treturn t.includes(\"array\");\n}\n\n// ─── Keyword-based implicit type detection ───────────────────────────────────\n//\n// propertyNames schemas (e.g. { minLength: 1 }) don't always carry an explicit\n// `type`, yet their keywords unambiguously imply a type family. These helpers\n// let us trigger the right constraint checks even when `getEffectiveType`\n// returns `undefined`.\n\nfunction hasNumericKeywords(s: JSONSchema7): boolean {\n\treturn (\n\t\ts.minimum !== undefined ||\n\t\ts.maximum !== undefined ||\n\t\ts.exclusiveMinimum !== undefined ||\n\t\ts.exclusiveMaximum !== undefined ||\n\t\ts.multipleOf !== undefined\n\t);\n}\n\nfunction hasStringKeywords(s: JSONSchema7): boolean {\n\treturn (\n\t\ts.minLength !== undefined ||\n\t\ts.maxLength !== undefined ||\n\t\ts.pattern !== undefined ||\n\t\ts.format !== undefined\n\t);\n}\n\nfunction hasObjectKeywords(s: JSONSchema7): boolean {\n\treturn (\n\t\ts.minProperties !== undefined ||\n\t\ts.maxProperties !== undefined ||\n\t\ts.propertyNames !== undefined ||\n\t\ts.additionalProperties !== undefined ||\n\t\tisPlainObj(s.patternProperties) ||\n\t\tisPlainObj(s.dependencies)\n\t);\n}\n\nfunction hasArrayKeywords(s: JSONSchema7): boolean {\n\treturn (\n\t\ts.minItems !== undefined ||\n\t\ts.maxItems !== undefined ||\n\t\ts.uniqueItems !== undefined ||\n\t\ts.contains !== undefined\n\t);\n}\n\n// ─── Core Comparison ─────────────────────────────────────────────────────────\n\n/**\n * Compares two schemas and produces semantic errors.\n *\n * @param sub The source schema (what is produced / received)\n * @param sup The target schema (what is expected)\n * @param path The current normalized path\n * @returns List of semantic errors\n */\nexport function computeSemanticErrors(\n\tsub: JSONSchema7Definition,\n\tsup: JSONSchema7Definition,\n\tpath = \"\",\n): SchemaError[] {\n\t// ── Boolean schemas ──\n\tif (typeof sup === \"boolean\") {\n\t\tif (sup === false) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: \"never\",\n\t\t\t\t\treceived: formatSchemaType(sub),\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t\treturn []; // sup = true accepts everything\n\t}\n\tif (typeof sub === \"boolean\") {\n\t\tif (sub === true) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: formatSchemaType(sup),\n\t\t\t\t\treceived: \"any\",\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t\treturn []; // sub = false produces nothing, trivially subset\n\t}\n\n\tconst subSchema = sub as JSONSchema7;\n\tconst supSchema = sup as JSONSchema7;\n\n\tconst errors: SchemaError[] = [];\n\n\t// ── Handle `not` keyword ──\n\t// Check sup.not: sub must not satisfy the not-schema for sub ⊆ sup.\n\t// Check sub.not: if sub has a not that sup doesn't, sub is more constrained (OK).\n\t// if sup has a not that sub doesn't, sub may be too permissive.\n\tif (\n\t\thasOwn(supSchema, \"not\") &&\n\t\tisPlainObj(supSchema.not) &&\n\t\ttypeof supSchema.not !== \"boolean\"\n\t) {\n\t\tconst notSchema = supSchema.not as JSONSchema7;\n\t\tconst notFormatted = formatSchemaType(notSchema);\n\n\t\tif (!hasOwn(subSchema, \"not\")) {\n\t\t\t// sup excludes something, sub doesn't → sub is more permissive\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: `not ${notFormatted}`,\n\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t});\n\t\t} else if (\n\t\t\tisPlainObj(subSchema.not) &&\n\t\t\ttypeof subSchema.not !== \"boolean\"\n\t\t) {\n\t\t\t// Both have not — compare the not schemas\n\t\t\t// For sub ⊆ sup, sub.not must be at least as broad as sup.not\n\t\t\t// (i.e. sub excludes at least as much). We report if they differ.\n\t\t\tconst subNotSchema = subSchema.not as JSONSchema7;\n\t\t\tif (!deepEqual(subNotSchema, notSchema)) {\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: `not ${notFormatted}`,\n\t\t\t\t\treceived: `not ${formatSchemaType(subNotSchema)}`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Get effective types ──\n\tconst subType = getEffectiveType(subSchema);\n\tconst supType = getEffectiveType(supSchema);\n\n\t// ── Handle anyOf/oneOf in sup ──\n\t// If sup has branches, try to find the best matching one for error reporting\n\tconst supBranches = supSchema.anyOf ?? supSchema.oneOf;\n\tif (Array.isArray(supBranches) && supBranches.length > 0 && !supSchema.type) {\n\t\treturn computeErrorsAgainstBranches(subSchema, supBranches, path);\n\t}\n\n\t// ── Handle anyOf/oneOf in sub ──\n\tconst subBranches = subSchema.anyOf ?? subSchema.oneOf;\n\tif (Array.isArray(subBranches) && subBranches.length > 0 && !subSchema.type) {\n\t\tconst branchErrors: SchemaError[] = [];\n\t\tfor (const branch of subBranches) {\n\t\t\tconst errs = computeSemanticErrors(branch, sup, path);\n\t\t\tbranchErrors.push(...errs);\n\t\t}\n\t\treturn branchErrors;\n\t}\n\n\t// ── Both are object types → compare properties + object constraints ──\n\tconst supProps = getProperties(supSchema);\n\tconst subProps = getProperties(subSchema);\n\n\tif (supProps !== null || isObjectType(supType)) {\n\t\t// sup is an object schema\n\t\tif (subType !== undefined && !typeIncludes(subType, \"object\")) {\n\t\t\t// sub is not an object at all\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: formatSchemaType(supSchema),\n\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t});\n\t\t\treturn errors;\n\t\t}\n\n\t\tif (supProps !== null) {\n\t\t\tconst supRequired = getRequired(supSchema);\n\t\t\tconst subRequired = getRequired(subSchema);\n\n\t\t\tfor (const key of Object.keys(supProps)) {\n\t\t\t\tconst propPath = joinPath(path, key);\n\t\t\t\tconst supPropDef = supProps[key];\n\t\t\t\tconst subPropDef = subProps?.[key];\n\n\t\t\t\tif (supPropDef === undefined) continue;\n\n\t\t\t\tconst isRequiredInSup = supRequired.includes(key);\n\n\t\t\t\t// ── Missing property (required in sup, absent in sub) ──\n\t\t\t\tif (subPropDef === undefined) {\n\t\t\t\t\tif (isRequiredInSup) {\n\t\t\t\t\t\terrors.push({\n\t\t\t\t\t\t\tkey: propPath,\n\t\t\t\t\t\t\texpected: formatSchemaType(supPropDef),\n\t\t\t\t\t\t\treceived: \"undefined\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// ── Optionality mismatch (required in sup, optional in sub) ──\n\t\t\t\tif (isRequiredInSup && !subRequired.includes(key)) {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tkey: propPath,\n\t\t\t\t\t\texpected: \"not optional\",\n\t\t\t\t\t\treceived: \"optional\",\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// ── Recurse into the property schemas ──\n\t\t\t\tconst propErrors = comparePropertySchemas(\n\t\t\t\t\tsubPropDef,\n\t\t\t\t\tsupPropDef,\n\t\t\t\t\tpropPath,\n\t\t\t\t);\n\t\t\t\terrors.push(...propErrors);\n\t\t\t}\n\t\t}\n\n\t\t// ── Custom constraints ──\n\t\tcheckCustomConstraints(subSchema, supSchema, path, errors);\n\n\t\t// ── Object-level constraints ──\n\t\tcheckObjectConstraints(subSchema, supSchema, path, errors);\n\n\t\treturn errors;\n\t}\n\n\t// ── Both are array types → compare items + array constraints ──\n\tif (\n\t\t(supType === \"array\" || supSchema.items !== undefined) &&\n\t\t(subType === \"array\" || subSchema.items !== undefined)\n\t) {\n\t\t// Check items compatibility\n\t\tif (supSchema.items !== undefined && typeof supSchema.items !== \"boolean\") {\n\t\t\tif (\n\t\t\t\tsubSchema.items !== undefined &&\n\t\t\t\ttypeof subSchema.items !== \"boolean\"\n\t\t\t) {\n\t\t\t\t// Both have items schemas — recurse\n\t\t\t\tif (Array.isArray(supSchema.items) && Array.isArray(subSchema.items)) {\n\t\t\t\t\t// Tuple comparison\n\t\t\t\t\tconst maxLen = Math.max(\n\t\t\t\t\t\tsupSchema.items.length,\n\t\t\t\t\t\tsubSchema.items.length,\n\t\t\t\t\t);\n\t\t\t\t\tfor (let i = 0; i < maxLen; i++) {\n\t\t\t\t\t\tconst supItem = supSchema.items[i];\n\t\t\t\t\t\tconst subItem = subSchema.items[i];\n\t\t\t\t\t\tconst itemPath = joinPath(path, `[${i}]`);\n\t\t\t\t\t\tif (supItem !== undefined && subItem === undefined) {\n\t\t\t\t\t\t\terrors.push({\n\t\t\t\t\t\t\t\tkey: itemPath,\n\t\t\t\t\t\t\t\texpected: formatSchemaType(supItem),\n\t\t\t\t\t\t\t\treceived: \"undefined\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else if (supItem !== undefined && subItem !== undefined) {\n\t\t\t\t\t\t\terrors.push(...computeSemanticErrors(subItem, supItem, itemPath));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (\n\t\t\t\t\t!Array.isArray(supSchema.items) &&\n\t\t\t\t\t!Array.isArray(subSchema.items)\n\t\t\t\t) {\n\t\t\t\t\t// Single items schema — recurse with [] path\n\t\t\t\t\tconst itemPath = arrayPath(path);\n\t\t\t\t\tconst itemErrors = computeSemanticErrors(\n\t\t\t\t\t\tsubSchema.items as JSONSchema7Definition,\n\t\t\t\t\t\tsupSchema.items as JSONSchema7Definition,\n\t\t\t\t\t\titemPath,\n\t\t\t\t\t);\n\t\t\t\t\terrors.push(...itemErrors);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// sup has items schema but sub doesn't\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: formatSchemaType(supSchema),\n\t\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// ── Custom constraints ──\n\t\tcheckCustomConstraints(subSchema, supSchema, path, errors);\n\n\t\t// ── Array-level constraints ──\n\t\tcheckArrayConstraints(subSchema, supSchema, path, errors);\n\n\t\treturn errors;\n\t}\n\n\t// ── Type mismatch at current level ──\n\tif (subType !== undefined && supType !== undefined) {\n\t\tif (!typesAreCompatible(subType, supType)) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: formatSchemaType(supSchema),\n\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t});\n\t\t\treturn errors;\n\t\t}\n\t}\n\n\t// ── Enum comparison ──\n\tif (Array.isArray(supSchema.enum)) {\n\t\tif (Array.isArray(subSchema.enum)) {\n\t\t\t// Both have enums — check if sub.enum ⊆ sup.enum\n\t\t\tconst subExtra = subSchema.enum.filter(\n\t\t\t\t(v) => !supSchema.enum?.some((sv) => deepEqual(v, sv)),\n\t\t\t);\n\t\t\tif (subExtra.length > 0) {\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: formatEnumValues(supSchema.enum),\n\t\t\t\t\treceived: formatEnumValues(subSchema.enum),\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (hasOwn(subSchema, \"const\")) {\n\t\t\t// sub has const, sup has enum — check inclusion\n\t\t\tconst constInEnum = supSchema.enum.some((v) =>\n\t\t\t\tdeepEqual(v, subSchema.const),\n\t\t\t);\n\t\t\tif (!constInEnum) {\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: formatEnumValues(supSchema.enum),\n\t\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\t// sup has enum but sub is a plain type (no enum restriction)\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: formatEnumValues(supSchema.enum),\n\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t});\n\t\t}\n\t\treturn errors;\n\t}\n\n\t// ── Const comparison ──\n\tif (hasOwn(supSchema, \"const\") && hasOwn(subSchema, \"const\")) {\n\t\tif (!deepEqual(supSchema.const, subSchema.const)) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: formatSchemaType(supSchema),\n\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t});\n\t\t}\n\t\treturn errors;\n\t}\n\n\t// ── Same-type constraint comparison ──\n\t// Types are compatible (or unspecified), now check individual keywords.\n\n\t// ── Custom constraints (applies to all types) ──\n\tcheckCustomConstraints(subSchema, supSchema, path, errors);\n\n\tif (\n\t\tisNumericType(subType) ||\n\t\tisNumericType(supType) ||\n\t\thasNumericKeywords(supSchema) ||\n\t\thasNumericKeywords(subSchema)\n\t) {\n\t\tcheckNumericConstraints(subSchema, supSchema, path, errors);\n\t}\n\n\tif (\n\t\tisStringType(subType) ||\n\t\tisStringType(supType) ||\n\t\thasStringKeywords(supSchema) ||\n\t\thasStringKeywords(subSchema)\n\t) {\n\t\tcheckStringConstraints(subSchema, supSchema, path, errors);\n\t}\n\n\t// Object-level constraints when sup doesn't have explicit properties\n\t// but still has object constraints (e.g., just { type: \"object\", minProperties: 3 })\n\tif (\n\t\tisObjectType(subType) ||\n\t\tisObjectType(supType) ||\n\t\thasObjectKeywords(supSchema) ||\n\t\thasObjectKeywords(subSchema)\n\t) {\n\t\tcheckObjectConstraints(subSchema, supSchema, path, errors);\n\t}\n\n\t// Array-level constraints when sup doesn't have explicit items\n\t// but still has array constraints (e.g., just { type: \"array\", minItems: 2 })\n\tif (\n\t\tisArrayType(subType) ||\n\t\tisArrayType(supType) ||\n\t\thasArrayKeywords(supSchema) ||\n\t\thasArrayKeywords(subSchema)\n\t) {\n\t\tcheckArrayConstraints(subSchema, supSchema, path, errors);\n\t}\n\n\tif (errors.length > 0) {\n\t\treturn errors;\n\t}\n\n\t// ── Fallback: generic incompatibility ──\n\t// If we get here, there's an incompatibility we couldn't pinpoint precisely.\n\t// Produce a root-level error with the formatted types.\n\tconst expectedStr = formatSchemaType(supSchema);\n\tconst receivedStr = formatSchemaType(subSchema);\n\tif (expectedStr !== receivedStr) {\n\t\terrors.push({\n\t\t\tkey: path || \"$root\",\n\t\t\texpected: expectedStr,\n\t\t\treceived: receivedStr,\n\t\t});\n\t}\n\n\treturn errors;\n}\n\n// ─── Property Schema Comparison ──────────────────────────────────────────────\n\n/**\n * Compares two property schemas and produces errors.\n * Handles recursion into nested objects and arrays.\n */\nfunction comparePropertySchemas(\n\tsubDef: JSONSchema7Definition,\n\tsupDef: JSONSchema7Definition,\n\tpath: string,\n): SchemaError[] {\n\tif (typeof subDef === \"boolean\" || typeof supDef === \"boolean\") {\n\t\tif (subDef !== supDef) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkey: path,\n\t\t\t\t\texpected: formatSchemaType(supDef),\n\t\t\t\t\treceived: formatSchemaType(subDef),\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t\treturn [];\n\t}\n\n\tconst subSchema = subDef as JSONSchema7;\n\tconst supSchema = supDef as JSONSchema7;\n\n\tconst subType = getEffectiveType(subSchema);\n\tconst supType = getEffectiveType(supSchema);\n\n\t// ── Enum comparison (before type check, as enums can cross types) ──\n\tif (Array.isArray(supSchema.enum)) {\n\t\tif (Array.isArray(subSchema.enum)) {\n\t\t\tconst subExtra = subSchema.enum.filter(\n\t\t\t\t(v) => !supSchema.enum?.some((sv) => deepEqual(v, sv)),\n\t\t\t);\n\t\t\tif (subExtra.length > 0) {\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: path,\n\t\t\t\t\t\texpected: formatEnumValues(supSchema.enum),\n\t\t\t\t\t\treceived: formatEnumValues(subSchema.enum),\n\t\t\t\t\t},\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn [];\n\t\t}\n\t\tif (hasOwn(subSchema, \"const\")) {\n\t\t\tconst constInEnum = supSchema.enum.some((v) =>\n\t\t\t\tdeepEqual(v, subSchema.const),\n\t\t\t);\n\t\t\tif (!constInEnum) {\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: path,\n\t\t\t\t\t\texpected: formatEnumValues(supSchema.enum),\n\t\t\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t\t\t},\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn [];\n\t\t}\n\t\t// sup has enum, sub is a plain type\n\t\treturn [\n\t\t\t{\n\t\t\t\tkey: path,\n\t\t\t\texpected: formatEnumValues(supSchema.enum),\n\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t},\n\t\t];\n\t}\n\n\t// ── Const comparison ──\n\tif (hasOwn(supSchema, \"const\") && hasOwn(subSchema, \"const\")) {\n\t\tif (!deepEqual(supSchema.const, subSchema.const)) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkey: path,\n\t\t\t\t\texpected: formatSchemaType(supSchema),\n\t\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t\treturn [];\n\t}\n\n\t// ── Type mismatch ──\n\tif (subType !== undefined && supType !== undefined) {\n\t\tif (!typesAreCompatible(subType, supType)) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkey: path,\n\t\t\t\t\texpected: formatSchemaType(supSchema),\n\t\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t}\n\n\t// ── If same types, recurse deeper ──\n\treturn computeSemanticErrors(subDef, supDef, path);\n}\n\n// ─── Branch Error Computation ────────────────────────────────────────────────\n\n/**\n * When sup has branches (anyOf/oneOf), attempts to find the closest\n * matching branch and generates errors against it.\n *\n * Strategy: compute errors for each branch and return those from the\n * branch with the fewest errors (best match).\n */\nfunction computeErrorsAgainstBranches(\n\tsub: JSONSchema7,\n\tbranches: JSONSchema7Definition[],\n\tpath: string,\n): SchemaError[] {\n\tlet bestErrors: SchemaError[] | null = null;\n\n\tfor (const branch of branches) {\n\t\tconst errors = computeSemanticErrors(sub, branch, path);\n\t\tif (errors.length === 0) return [];\n\t\tif (bestErrors === null || errors.length < bestErrors.length) {\n\t\t\tbestErrors = errors;\n\t\t}\n\t}\n\n\treturn (\n\t\tbestErrors ?? [\n\t\t\t{\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: formatSchemaType({ anyOf: branches } as JSONSchema7),\n\t\t\t\treceived: formatSchemaType(sub),\n\t\t\t},\n\t\t]\n\t);\n}\n"],"names":["computeSemanticErrors","formatSchemaType","formatEnumValues","values","parts","map","v","JSON","stringify","length","last","pop","join","def","base","formatSchemaTypeInternal","undefined","formatConstraintsSuffix","schema","constraints","arr","Array","isArray","formatCustomConstraint","hasOwn","const","enum","branches","anyOf","oneOf","b","type","items","itemSchema","itemBranches","t","itemType","isPlainObj","properties","not","joinPath","parent","key","arrayPath","getProperties","getRequired","required","getEffectiveType","typeIncludes","schemaType","target","includes","typesAreCompatible","subType","supType","some","every","st","supt","c","params","Object","keys","name","formatCustomConstraintList","cs","checkCustomConstraints","sub","sup","path","errors","supConstraints","subConstraints","supArr","subArr","supC","found","subC","deepEqual","push","expected","received","fmtConstraint","value","checkMinConstraint","subVal","supVal","checkMaxConstraint","checkNumericConstraints","minimum","maximum","exclusiveMinimum","exclusiveMaximum","multipleOf","checkStringConstraints","minLength","maxLength","pattern","format","checkObjectConstraints","additionalProperties","apPath","apErrors","minProperties","maxProperties","propertyNames","pnErrors","dependencies","supDeps","subDeps","supDep","subDep","missing","filter","d","depPath","depErrors","patternProperties","supPP","subPP","supPropDef","subPropDef","ppPath","ppErrors","checkArrayConstraints","minItems","maxItems","uniqueItems","contains","containsPath","containsErrors","isNumericType","isStringType","isObjectType","isArrayType","hasNumericKeywords","s","hasStringKeywords","hasObjectKeywords","hasArrayKeywords","subSchema","supSchema","notSchema","notFormatted","subNotSchema","supBranches","computeErrorsAgainstBranches","subBranches","branchErrors","branch","errs","supProps","subProps","supRequired","subRequired","propPath","isRequiredInSup","propErrors","comparePropertySchemas","maxLen","Math","max","i","supItem","subItem","itemPath","itemErrors","subExtra","sv","constInEnum","expectedStr","receivedStr","subDef","supDef","bestErrors"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/semantic-errors.ts"],"sourcesContent":["import type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\nimport type { SchemaError } from \"./types.ts\";\nimport { deepEqual, hasOwn, isPlainObj } from \"./utils.ts\";\n\n// ─── Semantic Error Generator ────────────────────────────────────────────────\n//\n// Generates human-readable semantic errors by directly comparing two schemas.\n//\n// Unlike a structural differ (which would compare sub vs merged), this module\n// directly compares sub (source/received) and sup (target/expected) to produce\n// business-oriented error messages.\n//\n// Property paths are normalized:\n// - `accountId` (top-level property)\n// - `user.name` (nested property)\n// - `users[].name` (property inside array items)\n//\n// Convention:\n// - `expected` = what the target schema (sup) expects\n// - `received` = what the source schema (sub) provides\n\n// ─── Type Formatting ─────────────────────────────────────────────────────────\n\n/**\n * Formats enum values into a readable string.\n *\n * Examples:\n * - 1 value : `\"123\"`\n * - 2 values : `\"123 or hello\"`\n * - 3 values : `\"10, 20, or 30\"`\n */\nfunction formatEnumValues(values: unknown[]): string {\n\tconst parts = values.map((v) =>\n\t\ttypeof v === \"string\" ? v : JSON.stringify(v),\n\t);\n\tif (parts.length === 0) return \"never\";\n\tif (parts.length === 1) return parts[0] as string;\n\tif (parts.length === 2) return `${parts[0]} or ${parts[1]}`;\n\tconst last = parts.pop();\n\treturn `${parts.join(\", \")}, or ${last}`;\n}\n\n/**\n * Formats a schema into a readable type representation.\n *\n * Examples:\n * - `{ type: \"string\" }` → `\"string\"`\n * - `{ type: \"array\", items: { type: \"string\" } }` → `\"string[]\"`\n * - `{ type: \"array\", items: { type: [\"string\",\"number\"] }` → `\"string[] | number[]\"`\n * - `{ enum: [1, 2, 3] }` → `\"1, 2, or 3\"`\n * - `{ const: \"hello\" }` → `\"hello\"`\n * - `{ anyOf: [{type:\"string\"},{type:\"number\"}] }` → `\"string | number\"`\n * - `undefined` → `\"undefined\"`\n */\nexport function formatSchemaType(\n\tdef: JSONSchema7Definition | undefined,\n): string {\n\treturn formatSchemaTypeInternal(def);\n}\n\nfunction formatSchemaTypeInternal(\n\tdef: JSONSchema7Definition | undefined,\n): string {\n\tif (def === undefined) return \"undefined\";\n\tif (typeof def === \"boolean\") return def ? \"any\" : \"never\";\n\n\tconst schema = def as JSONSchema7;\n\n\t// ── Const ──\n\tif (hasOwn(schema, \"const\")) {\n\t\tconst v = schema.const;\n\t\treturn typeof v === \"string\" ? v : JSON.stringify(v);\n\t}\n\n\t// ── Enum ──\n\tif (Array.isArray(schema.enum)) {\n\t\treturn formatEnumValues(schema.enum);\n\t}\n\n\t// ── anyOf / oneOf (union types) ──\n\tconst branches = schema.anyOf ?? schema.oneOf;\n\tif (Array.isArray(branches) && branches.length > 0) {\n\t\tconst parts = branches.map((b) => formatSchemaType(b));\n\t\treturn parts.join(\" | \");\n\t}\n\n\t// ── Array type ──\n\tif (schema.type === \"array\") {\n\t\tif (schema.items !== undefined && typeof schema.items !== \"boolean\") {\n\t\t\tconst itemSchema = schema.items as JSONSchema7;\n\n\t\t\t// Items with anyOf/oneOf → \"string[] | number[]\"\n\t\t\tconst itemBranches = itemSchema.anyOf ?? itemSchema.oneOf;\n\t\t\tif (Array.isArray(itemBranches) && itemBranches.length > 0) {\n\t\t\t\tconst parts = itemBranches.map((b) => `${formatSchemaType(b)}[]`);\n\t\t\t\treturn parts.join(\" | \");\n\t\t\t}\n\n\t\t\t// Items with multiple types → \"string[] | number[]\"\n\t\t\tif (Array.isArray(itemSchema.type)) {\n\t\t\t\tconst parts = itemSchema.type.map((t) => `${t}[]`);\n\t\t\t\treturn parts.join(\" | \");\n\t\t\t}\n\n\t\t\tconst itemType = formatSchemaType(itemSchema);\n\t\t\treturn `${itemType}[]`;\n\t\t}\n\t\t// items is boolean true or missing\n\t\treturn \"array\";\n\t}\n\n\t// ── Simple type ──\n\tif (typeof schema.type === \"string\") {\n\t\treturn schema.type;\n\t}\n\n\t// ── Multiple types (type: [\"string\", \"number\"]) ──\n\tif (Array.isArray(schema.type)) {\n\t\treturn schema.type.join(\" | \");\n\t}\n\n\t// ── not (pure-not schema, no other significant keywords) ──\n\tif (\n\t\thasOwn(schema, \"not\") &&\n\t\t!schema.type &&\n\t\t!isPlainObj(schema.properties) &&\n\t\tschema.items === undefined &&\n\t\t!Array.isArray(schema.enum) &&\n\t\t!hasOwn(schema, \"const\")\n\t) {\n\t\treturn `not ${formatSchemaType(schema.not as JSONSchema7Definition)}`;\n\t}\n\n\t// ── Fallback ──\n\t// Schema without explicit type — try to infer from structure\n\tif (isPlainObj(schema.properties)) return \"object\";\n\tif (schema.items !== undefined) return \"array\";\n\n\treturn \"unknown\";\n}\n\n// ─── Path Helpers ────────────────────────────────────────────────────────────\n\n/**\n * Builds a normalized property path.\n * - Root + key → `\"accountId\"`\n * - Parent + key → `\"user.name\"`\n * - Parent[] + key → `\"users[].name\"`\n */\nfunction joinPath(parent: string, key: string): string {\n\tif (!parent) return key;\n\treturn `${parent}.${key}`;\n}\n\n/**\n * Appends the `[]` suffix to indicate entering array items.\n */\nfunction arrayPath(parent: string): string {\n\tif (!parent) return \"[]\";\n\treturn `${parent}[]`;\n}\n\n// ─── Schema Accessors ────────────────────────────────────────────────────────\n\n/**\n * Safely extracts the properties from a schema.\n */\nfunction getProperties(\n\tschema: JSONSchema7,\n): Record<string, JSONSchema7Definition> | null {\n\tif (isPlainObj(schema.properties)) {\n\t\treturn schema.properties as Record<string, JSONSchema7Definition>;\n\t}\n\treturn null;\n}\n\n/**\n * Safely extracts the required fields from a schema.\n */\nfunction getRequired(schema: JSONSchema7): string[] {\n\tif (Array.isArray(schema.required)) {\n\t\treturn schema.required as string[];\n\t}\n\treturn [];\n}\n\n/**\n * Determines the effective type of a schema (string or array of types).\n */\nfunction getEffectiveType(schema: JSONSchema7): string | string[] | undefined {\n\tif (schema.type !== undefined) return schema.type as string | string[];\n\n\t// Infer from const\n\tif (hasOwn(schema, \"const\")) {\n\t\tconst v = schema.const;\n\t\tif (v === null) return \"null\";\n\t\tif (Array.isArray(v)) return \"array\";\n\t\treturn typeof v;\n\t}\n\n\t// Infer from properties\n\tif (isPlainObj(schema.properties)) return \"object\";\n\n\t// Infer from items\n\tif (schema.items !== undefined) return \"array\";\n\n\treturn undefined;\n}\n\n/**\n * Checks whether a type (string) is included in a type or array of types.\n */\nfunction typeIncludes(\n\tschemaType: string | string[] | undefined,\n\ttarget: string,\n): boolean {\n\tif (schemaType === undefined) return false;\n\tif (typeof schemaType === \"string\") {\n\t\t// integer is a subset of number\n\t\tif (target === \"number\" && schemaType === \"integer\") return true;\n\t\tif (target === \"integer\" && schemaType === \"number\") return true;\n\t\treturn schemaType === target;\n\t}\n\treturn schemaType.includes(target);\n}\n\n/**\n * Checks whether two types are compatible.\n * A type is compatible if the sub type is included in the sup type.\n */\nfunction typesAreCompatible(\n\tsubType: string | string[] | undefined,\n\tsupType: string | string[] | undefined,\n): boolean {\n\tif (supType === undefined) return true; // sup accepts anything\n\tif (subType === undefined) return true; // sub is undetermined, cannot conclude\n\n\tif (typeof subType === \"string\" && typeof supType === \"string\") {\n\t\tif (subType === supType) return true;\n\t\t// integer ⊆ number\n\t\tif (subType === \"integer\" && supType === \"number\") return true;\n\t\treturn false;\n\t}\n\n\tif (typeof subType === \"string\" && Array.isArray(supType)) {\n\t\treturn supType.some(\n\t\t\t(t) => t === subType || (subType === \"integer\" && t === \"number\"),\n\t\t);\n\t}\n\n\tif (Array.isArray(subType) && typeof supType === \"string\") {\n\t\treturn subType.every(\n\t\t\t(t) => t === supType || (t === \"integer\" && supType === \"number\"),\n\t\t);\n\t}\n\n\tif (Array.isArray(subType) && Array.isArray(supType)) {\n\t\treturn subType.every((st) =>\n\t\t\tsupType.some(\n\t\t\t\t(supt) => supt === st || (st === \"integer\" && supt === \"number\"),\n\t\t\t),\n\t\t);\n\t}\n\n\treturn true;\n}\n\n// ─── Constraint Helpers ──────────────────────────────────────────────────────\n\n/**\n * Formats a constraint value into a readable string.\n */\nfunction fmtConstraint(name: string, value: unknown): string {\n\tif (value === undefined) return `${name}: not set`;\n\tif (typeof value === \"boolean\") return `${name}: ${value}`;\n\tif (typeof value === \"number\" || typeof value === \"string\")\n\t\treturn `${name}: ${value}`;\n\treturn `${name}: ${JSON.stringify(value)}`;\n}\n\n/**\n * Compares a \"minimum-like\" numeric constraint (sub.X must be >= sup.X for sub ⊆ sup).\n * Examples: minimum, exclusiveMinimum, minLength, minItems, minProperties\n */\nfunction checkMinConstraint(\n\tsubVal: number | undefined,\n\tsupVal: number | undefined,\n\tname: string,\n\tpath: string,\n\terrors: SchemaError[],\n): void {\n\tif (supVal !== undefined) {\n\t\tif (subVal === undefined || subVal < supVal) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: fmtConstraint(name, supVal),\n\t\t\t\treceived: fmtConstraint(name, subVal),\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * Compares a \"maximum-like\" numeric constraint (sub.X must be <= sup.X for sub ⊆ sup).\n * Examples: maximum, exclusiveMaximum, maxLength, maxItems, maxProperties\n */\nfunction checkMaxConstraint(\n\tsubVal: number | undefined,\n\tsupVal: number | undefined,\n\tname: string,\n\tpath: string,\n\terrors: SchemaError[],\n): void {\n\tif (supVal !== undefined) {\n\t\tif (subVal === undefined || subVal > supVal) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: fmtConstraint(name, supVal),\n\t\t\t\treceived: fmtConstraint(name, subVal),\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * Compares numeric constraints between sub and sup.\n */\nfunction checkNumericConstraints(\n\tsub: JSONSchema7,\n\tsup: JSONSchema7,\n\tpath: string,\n\terrors: SchemaError[],\n): void {\n\tcheckMinConstraint(sub.minimum, sup.minimum, \"minimum\", path, errors);\n\tcheckMaxConstraint(sub.maximum, sup.maximum, \"maximum\", path, errors);\n\tcheckMinConstraint(\n\t\tsub.exclusiveMinimum as number | undefined,\n\t\tsup.exclusiveMinimum as number | undefined,\n\t\t\"exclusiveMinimum\",\n\t\tpath,\n\t\terrors,\n\t);\n\tcheckMaxConstraint(\n\t\tsub.exclusiveMaximum as number | undefined,\n\t\tsup.exclusiveMaximum as number | undefined,\n\t\t\"exclusiveMaximum\",\n\t\tpath,\n\t\terrors,\n\t);\n\n\tif (sup.multipleOf !== undefined) {\n\t\tif (sub.multipleOf === undefined) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: fmtConstraint(\"multipleOf\", sup.multipleOf),\n\t\t\t\treceived: fmtConstraint(\"multipleOf\", sub.multipleOf),\n\t\t\t});\n\t\t} else if (sub.multipleOf !== sup.multipleOf) {\n\t\t\t// sub.multipleOf must be a multiple of sup.multipleOf for sub ⊆ sup\n\t\t\tif (sub.multipleOf % sup.multipleOf !== 0) {\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: fmtConstraint(\"multipleOf\", sup.multipleOf),\n\t\t\t\t\treceived: fmtConstraint(\"multipleOf\", sub.multipleOf),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Compares string constraints between sub and sup.\n */\nfunction checkStringConstraints(\n\tsub: JSONSchema7,\n\tsup: JSONSchema7,\n\tpath: string,\n\terrors: SchemaError[],\n): void {\n\tcheckMinConstraint(sub.minLength, sup.minLength, \"minLength\", path, errors);\n\tcheckMaxConstraint(sub.maxLength, sup.maxLength, \"maxLength\", path, errors);\n\n\t// ── Pattern ──\n\tif (sup.pattern !== undefined) {\n\t\tif (sub.pattern === undefined) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: fmtConstraint(\"pattern\", sup.pattern),\n\t\t\t\treceived: \"no pattern constraint\",\n\t\t\t});\n\t\t} else if (sub.pattern !== sup.pattern) {\n\t\t\t// Different patterns — we can't statically determine subset relationship\n\t\t\t// without sampling, so report it as a potential mismatch.\n\t\t\t// The subset checker may have already stripped equivalent patterns,\n\t\t\t// so if we get here, they're genuinely different.\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: fmtConstraint(\"pattern\", sup.pattern),\n\t\t\t\treceived: fmtConstraint(\"pattern\", sub.pattern),\n\t\t\t});\n\t\t}\n\t}\n\n\t// ── Format ──\n\tif (sup.format !== undefined && sub.format !== sup.format) {\n\t\tif (sub.format === undefined) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: fmtConstraint(\"format\", sup.format),\n\t\t\t\treceived: \"no format constraint\",\n\t\t\t});\n\t\t} else {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: fmtConstraint(\"format\", sup.format),\n\t\t\t\treceived: fmtConstraint(\"format\", sub.format),\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * Compares object constraints (excluding properties/required) between sub and sup.\n */\nfunction checkObjectConstraints(\n\tsub: JSONSchema7,\n\tsup: JSONSchema7,\n\tpath: string,\n\terrors: SchemaError[],\n): void {\n\t// ── additionalProperties ──\n\tif (sup.additionalProperties !== undefined) {\n\t\tif (sup.additionalProperties === false) {\n\t\t\t// sup forbids additional properties\n\t\t\tif (\n\t\t\t\tsub.additionalProperties === undefined ||\n\t\t\t\tsub.additionalProperties === true\n\t\t\t) {\n\t\t\t\t// sub allows them → incompatible\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: \"additionalProperties: false\",\n\t\t\t\t\treceived: \"additional properties allowed\",\n\t\t\t\t});\n\t\t\t} else if (\n\t\t\t\ttypeof sub.additionalProperties === \"object\" &&\n\t\t\t\tsub.additionalProperties !== null\n\t\t\t) {\n\t\t\t\t// sub has a schema for additional properties → still allows them\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: \"additionalProperties: false\",\n\t\t\t\t\treceived: \"additionalProperties: schema\",\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (\n\t\t\ttypeof sup.additionalProperties === \"object\" &&\n\t\t\tsup.additionalProperties !== null\n\t\t) {\n\t\t\t// sup has a schema for additionalProperties\n\t\t\tif (\n\t\t\t\tsub.additionalProperties === undefined ||\n\t\t\t\tsub.additionalProperties === true\n\t\t\t) {\n\t\t\t\t// sub allows anything → more permissive\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: `additionalProperties: ${formatSchemaType(sup.additionalProperties as JSONSchema7Definition)}`,\n\t\t\t\t\treceived: \"additional properties allowed\",\n\t\t\t\t});\n\t\t\t} else if (\n\t\t\t\ttypeof sub.additionalProperties === \"object\" &&\n\t\t\t\tsub.additionalProperties !== null\n\t\t\t) {\n\t\t\t\t// Both have schema-form additionalProperties — recurse\n\t\t\t\tconst apPath = path\n\t\t\t\t\t? `${path}.<additionalProperties>`\n\t\t\t\t\t: \"<additionalProperties>\";\n\t\t\t\tconst apErrors = computeSemanticErrors(\n\t\t\t\t\tsub.additionalProperties as JSONSchema7Definition,\n\t\t\t\t\tsup.additionalProperties as JSONSchema7Definition,\n\t\t\t\t\tapPath,\n\t\t\t\t);\n\t\t\t\terrors.push(...apErrors);\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── minProperties / maxProperties ──\n\tcheckMinConstraint(\n\t\tsub.minProperties,\n\t\tsup.minProperties,\n\t\t\"minProperties\",\n\t\tpath,\n\t\terrors,\n\t);\n\tcheckMaxConstraint(\n\t\tsub.maxProperties,\n\t\tsup.maxProperties,\n\t\t\"maxProperties\",\n\t\tpath,\n\t\terrors,\n\t);\n\n\t// ── propertyNames ──\n\tif (sup.propertyNames !== undefined) {\n\t\tif (sub.propertyNames === undefined) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: `propertyNames: ${formatSchemaType(sup.propertyNames)}`,\n\t\t\t\treceived: \"no propertyNames constraint\",\n\t\t\t});\n\t\t} else {\n\t\t\t// Both have propertyNames — recurse\n\t\t\tconst pnErrors = computeSemanticErrors(\n\t\t\t\tsub.propertyNames as JSONSchema7Definition,\n\t\t\t\tsup.propertyNames as JSONSchema7Definition,\n\t\t\t\tpath ? `${path}.<propertyNames>` : \"<propertyNames>\",\n\t\t\t);\n\t\t\terrors.push(...pnErrors);\n\t\t}\n\t}\n\n\t// ── dependencies ──\n\tif (isPlainObj(sup.dependencies)) {\n\t\tconst supDeps = sup.dependencies as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t\tconst subDeps = isPlainObj(sub.dependencies)\n\t\t\t? (sub.dependencies as Record<string, JSONSchema7Definition | string[]>)\n\t\t\t: null;\n\n\t\tfor (const key of Object.keys(supDeps)) {\n\t\t\tconst supDep = supDeps[key];\n\t\t\tconst subDep = subDeps?.[key];\n\n\t\t\tif (subDep === undefined) {\n\t\t\t\t// sup requires a dependency that sub doesn't have\n\t\t\t\tif (Array.isArray(supDep)) {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\t\texpected: `dependency: ${key} requires ${supDep.join(\", \")}`,\n\t\t\t\t\t\treceived: `no dependency for ${key}`,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\t\texpected: `dependency: ${key} requires schema`,\n\t\t\t\t\t\treceived: `no dependency for ${key}`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (Array.isArray(supDep) && Array.isArray(subDep)) {\n\t\t\t\t// Both are array form — check if sub includes all required props from sup\n\t\t\t\tconst missing = supDep.filter((d) => !subDep.includes(d));\n\t\t\t\tif (missing.length > 0) {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\t\texpected: `dependency: ${key} requires ${supDep.join(\", \")}`,\n\t\t\t\t\t\treceived: `dependency: ${key} requires ${subDep.join(\", \")}`,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else if (!Array.isArray(supDep) && !Array.isArray(subDep)) {\n\t\t\t\t// Both are schema form — recurse\n\t\t\t\tconst depPath = path\n\t\t\t\t\t? `${path}.<dependency:${key}>`\n\t\t\t\t\t: `<dependency:${key}>`;\n\t\t\t\tconst depErrors = computeSemanticErrors(\n\t\t\t\t\tsubDep as JSONSchema7Definition,\n\t\t\t\t\tsupDep as JSONSchema7Definition,\n\t\t\t\t\tdepPath,\n\t\t\t\t);\n\t\t\t\terrors.push(...depErrors);\n\t\t\t} else {\n\t\t\t\t// Mixed forms (one array, one schema) — report mismatch\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: Array.isArray(supDep)\n\t\t\t\t\t\t? `dependency: ${key} requires ${supDep.join(\", \")}`\n\t\t\t\t\t\t: `dependency: ${key} requires schema`,\n\t\t\t\t\treceived: Array.isArray(subDep)\n\t\t\t\t\t\t? `dependency: ${key} requires ${subDep.join(\", \")}`\n\t\t\t\t\t\t: `dependency: ${key} requires schema`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── patternProperties ──\n\tif (isPlainObj(sup.patternProperties)) {\n\t\tconst supPP = sup.patternProperties as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tconst subPP = isPlainObj(sub.patternProperties)\n\t\t\t? (sub.patternProperties as Record<string, JSONSchema7Definition>)\n\t\t\t: null;\n\n\t\tfor (const pattern of Object.keys(supPP)) {\n\t\t\tconst supPropDef = supPP[pattern];\n\t\t\tif (supPropDef === undefined) continue;\n\n\t\t\tconst subPropDef = subPP?.[pattern];\n\t\t\tconst ppPath = path\n\t\t\t\t? `${path}.<patternProperties:${pattern}>`\n\t\t\t\t: `<patternProperties:${pattern}>`;\n\n\t\t\tif (subPropDef === undefined) {\n\t\t\t\t// sub doesn't constrain this pattern at all — more permissive\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: ppPath,\n\t\t\t\t\texpected: formatSchemaType(supPropDef),\n\t\t\t\t\treceived: \"no constraint for this pattern\",\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Both define the same pattern — recurse\n\t\t\t\tconst ppErrors = computeSemanticErrors(subPropDef, supPropDef, ppPath);\n\t\t\t\terrors.push(...ppErrors);\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Compares array constraints (excluding items) between sub and sup.\n */\nfunction checkArrayConstraints(\n\tsub: JSONSchema7,\n\tsup: JSONSchema7,\n\tpath: string,\n\terrors: SchemaError[],\n): void {\n\tcheckMinConstraint(sub.minItems, sup.minItems, \"minItems\", path, errors);\n\tcheckMaxConstraint(sub.maxItems, sup.maxItems, \"maxItems\", path, errors);\n\n\t// ── uniqueItems ──\n\tif (sup.uniqueItems === true && sub.uniqueItems !== true) {\n\t\terrors.push({\n\t\t\tkey: path || \"$root\",\n\t\t\texpected: \"uniqueItems: true\",\n\t\t\treceived: fmtConstraint(\"uniqueItems\", sub.uniqueItems ?? false),\n\t\t});\n\t}\n\n\t// ── contains ──\n\tif (sup.contains !== undefined) {\n\t\tif (sub.contains === undefined) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: `contains: ${formatSchemaType(sup.contains as JSONSchema7Definition)}`,\n\t\t\t\treceived: \"no contains constraint\",\n\t\t\t});\n\t\t} else {\n\t\t\t// Both have contains — recurse to compare the contained schemas\n\t\t\tconst containsPath = path ? `${path}.<contains>` : \"<contains>\";\n\t\t\tconst containsErrors = computeSemanticErrors(\n\t\t\t\tsub.contains as JSONSchema7Definition,\n\t\t\t\tsup.contains as JSONSchema7Definition,\n\t\t\t\tcontainsPath,\n\t\t\t);\n\t\t\terrors.push(...containsErrors);\n\t\t}\n\t}\n}\n\n/**\n * Detects whether a schema has a numeric type.\n */\nfunction isNumericType(t: string | string[] | undefined): boolean {\n\tif (t === undefined) return false;\n\tif (typeof t === \"string\") return t === \"number\" || t === \"integer\";\n\treturn t.some((v) => v === \"number\" || v === \"integer\");\n}\n\n/**\n * Detects whether a schema has a string type.\n */\nfunction isStringType(t: string | string[] | undefined): boolean {\n\tif (t === undefined) return false;\n\tif (typeof t === \"string\") return t === \"string\";\n\treturn t.includes(\"string\");\n}\n\n/**\n * Detects whether a schema has an object type.\n */\nfunction isObjectType(t: string | string[] | undefined): boolean {\n\tif (t === undefined) return false;\n\tif (typeof t === \"string\") return t === \"object\";\n\treturn t.includes(\"object\");\n}\n\n/**\n * Detects whether a schema has an array type.\n */\nfunction isArrayType(t: string | string[] | undefined): boolean {\n\tif (t === undefined) return false;\n\tif (typeof t === \"string\") return t === \"array\";\n\treturn t.includes(\"array\");\n}\n\n// ─── Keyword-based implicit type detection ───────────────────────────────────\n//\n// propertyNames schemas (e.g. { minLength: 1 }) don't always carry an explicit\n// `type`, yet their keywords unambiguously imply a type family. These helpers\n// let us trigger the right constraint checks even when `getEffectiveType`\n// returns `undefined`.\n\nfunction hasNumericKeywords(s: JSONSchema7): boolean {\n\treturn (\n\t\ts.minimum !== undefined ||\n\t\ts.maximum !== undefined ||\n\t\ts.exclusiveMinimum !== undefined ||\n\t\ts.exclusiveMaximum !== undefined ||\n\t\ts.multipleOf !== undefined\n\t);\n}\n\nfunction hasStringKeywords(s: JSONSchema7): boolean {\n\treturn (\n\t\ts.minLength !== undefined ||\n\t\ts.maxLength !== undefined ||\n\t\ts.pattern !== undefined ||\n\t\ts.format !== undefined\n\t);\n}\n\nfunction hasObjectKeywords(s: JSONSchema7): boolean {\n\treturn (\n\t\ts.minProperties !== undefined ||\n\t\ts.maxProperties !== undefined ||\n\t\ts.propertyNames !== undefined ||\n\t\ts.additionalProperties !== undefined ||\n\t\tisPlainObj(s.patternProperties) ||\n\t\tisPlainObj(s.dependencies)\n\t);\n}\n\nfunction hasArrayKeywords(s: JSONSchema7): boolean {\n\treturn (\n\t\ts.minItems !== undefined ||\n\t\ts.maxItems !== undefined ||\n\t\ts.uniqueItems !== undefined ||\n\t\ts.contains !== undefined\n\t);\n}\n\n// ─── Core Comparison ─────────────────────────────────────────────────────────\n\n/**\n * Compares two schemas and produces semantic errors.\n *\n * @param sub The source schema (what is produced / received)\n * @param sup The target schema (what is expected)\n * @param path The current normalized path\n * @returns List of semantic errors\n */\nexport function computeSemanticErrors(\n\tsub: JSONSchema7Definition,\n\tsup: JSONSchema7Definition,\n\tpath = \"\",\n): SchemaError[] {\n\t// ── Boolean schemas ──\n\tif (typeof sup === \"boolean\") {\n\t\tif (sup === false) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: \"never\",\n\t\t\t\t\treceived: formatSchemaType(sub),\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t\treturn []; // sup = true accepts everything\n\t}\n\tif (typeof sub === \"boolean\") {\n\t\tif (sub === true) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: formatSchemaType(sup),\n\t\t\t\t\treceived: \"any\",\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t\treturn []; // sub = false produces nothing, trivially subset\n\t}\n\n\tconst subSchema = sub as JSONSchema7;\n\tconst supSchema = sup as JSONSchema7;\n\n\tconst errors: SchemaError[] = [];\n\n\t// ── Handle `not` keyword ──\n\t// Check sup.not: sub must not satisfy the not-schema for sub ⊆ sup.\n\t// Check sub.not: if sub has a not that sup doesn't, sub is more constrained (OK).\n\t// if sup has a not that sub doesn't, sub may be too permissive.\n\tif (\n\t\thasOwn(supSchema, \"not\") &&\n\t\tisPlainObj(supSchema.not) &&\n\t\ttypeof supSchema.not !== \"boolean\"\n\t) {\n\t\tconst notSchema = supSchema.not as JSONSchema7;\n\t\tconst notFormatted = formatSchemaType(notSchema);\n\n\t\tif (!hasOwn(subSchema, \"not\")) {\n\t\t\t// sup excludes something, sub doesn't → sub is more permissive\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: `not ${notFormatted}`,\n\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t});\n\t\t} else if (\n\t\t\tisPlainObj(subSchema.not) &&\n\t\t\ttypeof subSchema.not !== \"boolean\"\n\t\t) {\n\t\t\t// Both have not — compare the not schemas\n\t\t\t// For sub ⊆ sup, sub.not must be at least as broad as sup.not\n\t\t\t// (i.e. sub excludes at least as much). We report if they differ.\n\t\t\tconst subNotSchema = subSchema.not as JSONSchema7;\n\t\t\tif (!deepEqual(subNotSchema, notSchema)) {\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: `not ${notFormatted}`,\n\t\t\t\t\treceived: `not ${formatSchemaType(subNotSchema)}`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\t// ── Get effective types ──\n\tconst subType = getEffectiveType(subSchema);\n\tconst supType = getEffectiveType(supSchema);\n\n\t// ── Handle anyOf/oneOf in sup ──\n\t// If sup has branches, try to find the best matching one for error reporting\n\tconst supBranches = supSchema.anyOf ?? supSchema.oneOf;\n\tif (Array.isArray(supBranches) && supBranches.length > 0 && !supSchema.type) {\n\t\treturn computeErrorsAgainstBranches(subSchema, supBranches, path);\n\t}\n\n\t// ── Handle anyOf/oneOf in sub ──\n\tconst subBranches = subSchema.anyOf ?? subSchema.oneOf;\n\tif (Array.isArray(subBranches) && subBranches.length > 0 && !subSchema.type) {\n\t\tconst branchErrors: SchemaError[] = [];\n\t\tfor (const branch of subBranches) {\n\t\t\tconst errs = computeSemanticErrors(branch, sup, path);\n\t\t\tbranchErrors.push(...errs);\n\t\t}\n\t\treturn branchErrors;\n\t}\n\n\t// ── Both are object types → compare properties + object constraints ──\n\tconst supProps = getProperties(supSchema);\n\tconst subProps = getProperties(subSchema);\n\n\tif (supProps !== null || isObjectType(supType)) {\n\t\t// sup is an object schema\n\t\tif (subType !== undefined && !typeIncludes(subType, \"object\")) {\n\t\t\t// sub is not an object at all\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: formatSchemaType(supSchema),\n\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t});\n\t\t\treturn errors;\n\t\t}\n\n\t\tif (supProps !== null) {\n\t\t\tconst supRequired = getRequired(supSchema);\n\t\t\tconst subRequired = getRequired(subSchema);\n\n\t\t\tfor (const key of Object.keys(supProps)) {\n\t\t\t\tconst propPath = joinPath(path, key);\n\t\t\t\tconst supPropDef = supProps[key];\n\t\t\t\tconst subPropDef = subProps?.[key];\n\n\t\t\t\tif (supPropDef === undefined) continue;\n\n\t\t\t\tconst isRequiredInSup = supRequired.includes(key);\n\n\t\t\t\t// ── Missing property (required in sup, absent in sub) ──\n\t\t\t\tif (subPropDef === undefined) {\n\t\t\t\t\tif (isRequiredInSup) {\n\t\t\t\t\t\terrors.push({\n\t\t\t\t\t\t\tkey: propPath,\n\t\t\t\t\t\t\texpected: formatSchemaType(supPropDef),\n\t\t\t\t\t\t\treceived: \"undefined\",\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// ── Optionality mismatch (required in sup, optional in sub) ──\n\t\t\t\tif (isRequiredInSup && !subRequired.includes(key)) {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tkey: propPath,\n\t\t\t\t\t\texpected: \"not optional\",\n\t\t\t\t\t\treceived: \"optional\",\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// ── Recurse into the property schemas ──\n\t\t\t\tconst propErrors = comparePropertySchemas(\n\t\t\t\t\tsubPropDef,\n\t\t\t\t\tsupPropDef,\n\t\t\t\t\tpropPath,\n\t\t\t\t);\n\t\t\t\terrors.push(...propErrors);\n\t\t\t}\n\t\t}\n\n\t\t// ── Object-level constraints ──\n\t\tcheckObjectConstraints(subSchema, supSchema, path, errors);\n\n\t\treturn errors;\n\t}\n\n\t// ── Both are array types → compare items + array constraints ──\n\tif (\n\t\t(supType === \"array\" || supSchema.items !== undefined) &&\n\t\t(subType === \"array\" || subSchema.items !== undefined)\n\t) {\n\t\t// Check items compatibility\n\t\tif (supSchema.items !== undefined && typeof supSchema.items !== \"boolean\") {\n\t\t\tif (\n\t\t\t\tsubSchema.items !== undefined &&\n\t\t\t\ttypeof subSchema.items !== \"boolean\"\n\t\t\t) {\n\t\t\t\t// Both have items schemas — recurse\n\t\t\t\tif (Array.isArray(supSchema.items) && Array.isArray(subSchema.items)) {\n\t\t\t\t\t// Tuple comparison\n\t\t\t\t\tconst maxLen = Math.max(\n\t\t\t\t\t\tsupSchema.items.length,\n\t\t\t\t\t\tsubSchema.items.length,\n\t\t\t\t\t);\n\t\t\t\t\tfor (let i = 0; i < maxLen; i++) {\n\t\t\t\t\t\tconst supItem = supSchema.items[i];\n\t\t\t\t\t\tconst subItem = subSchema.items[i];\n\t\t\t\t\t\tconst itemPath = joinPath(path, `[${i}]`);\n\t\t\t\t\t\tif (supItem !== undefined && subItem === undefined) {\n\t\t\t\t\t\t\terrors.push({\n\t\t\t\t\t\t\t\tkey: itemPath,\n\t\t\t\t\t\t\t\texpected: formatSchemaType(supItem),\n\t\t\t\t\t\t\t\treceived: \"undefined\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else if (supItem !== undefined && subItem !== undefined) {\n\t\t\t\t\t\t\terrors.push(...computeSemanticErrors(subItem, supItem, itemPath));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else if (\n\t\t\t\t\t!Array.isArray(supSchema.items) &&\n\t\t\t\t\t!Array.isArray(subSchema.items)\n\t\t\t\t) {\n\t\t\t\t\t// Single items schema — recurse with [] path\n\t\t\t\t\tconst itemPath = arrayPath(path);\n\t\t\t\t\tconst itemErrors = computeSemanticErrors(\n\t\t\t\t\t\tsubSchema.items as JSONSchema7Definition,\n\t\t\t\t\t\tsupSchema.items as JSONSchema7Definition,\n\t\t\t\t\t\titemPath,\n\t\t\t\t\t);\n\t\t\t\t\terrors.push(...itemErrors);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// sup has items schema but sub doesn't\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: formatSchemaType(supSchema),\n\t\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\t// ── Array-level constraints ──\n\t\tcheckArrayConstraints(subSchema, supSchema, path, errors);\n\n\t\treturn errors;\n\t}\n\n\t// ── Type mismatch at current level ──\n\tif (subType !== undefined && supType !== undefined) {\n\t\tif (!typesAreCompatible(subType, supType)) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: formatSchemaType(supSchema),\n\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t});\n\t\t\treturn errors;\n\t\t}\n\t}\n\n\t// ── Enum comparison ──\n\tif (Array.isArray(supSchema.enum)) {\n\t\tif (Array.isArray(subSchema.enum)) {\n\t\t\t// Both have enums — check if sub.enum ⊆ sup.enum\n\t\t\tconst subExtra = subSchema.enum.filter(\n\t\t\t\t(v) => !supSchema.enum?.some((sv) => deepEqual(v, sv)),\n\t\t\t);\n\t\t\tif (subExtra.length > 0) {\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: formatEnumValues(supSchema.enum),\n\t\t\t\t\treceived: formatEnumValues(subSchema.enum),\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (hasOwn(subSchema, \"const\")) {\n\t\t\t// sub has const, sup has enum — check inclusion\n\t\t\tconst constInEnum = supSchema.enum.some((v) =>\n\t\t\t\tdeepEqual(v, subSchema.const),\n\t\t\t);\n\t\t\tif (!constInEnum) {\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: path || \"$root\",\n\t\t\t\t\texpected: formatEnumValues(supSchema.enum),\n\t\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\t// sup has enum but sub is a plain type (no enum restriction)\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: formatEnumValues(supSchema.enum),\n\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t});\n\t\t}\n\t\treturn errors;\n\t}\n\n\t// ── Const comparison ──\n\tif (hasOwn(supSchema, \"const\") && hasOwn(subSchema, \"const\")) {\n\t\tif (!deepEqual(supSchema.const, subSchema.const)) {\n\t\t\terrors.push({\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: formatSchemaType(supSchema),\n\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t});\n\t\t}\n\t\treturn errors;\n\t}\n\n\t// ── Same-type constraint comparison ──\n\t// Types are compatible (or unspecified), now check individual keywords.\n\n\tif (\n\t\tisNumericType(subType) ||\n\t\tisNumericType(supType) ||\n\t\thasNumericKeywords(supSchema) ||\n\t\thasNumericKeywords(subSchema)\n\t) {\n\t\tcheckNumericConstraints(subSchema, supSchema, path, errors);\n\t}\n\n\tif (\n\t\tisStringType(subType) ||\n\t\tisStringType(supType) ||\n\t\thasStringKeywords(supSchema) ||\n\t\thasStringKeywords(subSchema)\n\t) {\n\t\tcheckStringConstraints(subSchema, supSchema, path, errors);\n\t}\n\n\t// Object-level constraints when sup doesn't have explicit properties\n\t// but still has object constraints (e.g., just { type: \"object\", minProperties: 3 })\n\tif (\n\t\tisObjectType(subType) ||\n\t\tisObjectType(supType) ||\n\t\thasObjectKeywords(supSchema) ||\n\t\thasObjectKeywords(subSchema)\n\t) {\n\t\tcheckObjectConstraints(subSchema, supSchema, path, errors);\n\t}\n\n\t// Array-level constraints when sup doesn't have explicit items\n\t// but still has array constraints (e.g., just { type: \"array\", minItems: 2 })\n\tif (\n\t\tisArrayType(subType) ||\n\t\tisArrayType(supType) ||\n\t\thasArrayKeywords(supSchema) ||\n\t\thasArrayKeywords(subSchema)\n\t) {\n\t\tcheckArrayConstraints(subSchema, supSchema, path, errors);\n\t}\n\n\tif (errors.length > 0) {\n\t\treturn errors;\n\t}\n\n\t// ── Fallback: generic incompatibility ──\n\t// If we get here, there's an incompatibility we couldn't pinpoint precisely.\n\t// Produce a root-level error with the formatted types.\n\tconst expectedStr = formatSchemaType(supSchema);\n\tconst receivedStr = formatSchemaType(subSchema);\n\tif (expectedStr !== receivedStr) {\n\t\terrors.push({\n\t\t\tkey: path || \"$root\",\n\t\t\texpected: expectedStr,\n\t\t\treceived: receivedStr,\n\t\t});\n\t}\n\n\treturn errors;\n}\n\n// ─── Property Schema Comparison ──────────────────────────────────────────────\n\n/**\n * Compares two property schemas and produces errors.\n * Handles recursion into nested objects and arrays.\n */\nfunction comparePropertySchemas(\n\tsubDef: JSONSchema7Definition,\n\tsupDef: JSONSchema7Definition,\n\tpath: string,\n): SchemaError[] {\n\tif (typeof subDef === \"boolean\" || typeof supDef === \"boolean\") {\n\t\tif (subDef !== supDef) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkey: path,\n\t\t\t\t\texpected: formatSchemaType(supDef),\n\t\t\t\t\treceived: formatSchemaType(subDef),\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t\treturn [];\n\t}\n\n\tconst subSchema = subDef as JSONSchema7;\n\tconst supSchema = supDef as JSONSchema7;\n\n\tconst subType = getEffectiveType(subSchema);\n\tconst supType = getEffectiveType(supSchema);\n\n\t// ── Enum comparison (before type check, as enums can cross types) ──\n\tif (Array.isArray(supSchema.enum)) {\n\t\tif (Array.isArray(subSchema.enum)) {\n\t\t\tconst subExtra = subSchema.enum.filter(\n\t\t\t\t(v) => !supSchema.enum?.some((sv) => deepEqual(v, sv)),\n\t\t\t);\n\t\t\tif (subExtra.length > 0) {\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: path,\n\t\t\t\t\t\texpected: formatEnumValues(supSchema.enum),\n\t\t\t\t\t\treceived: formatEnumValues(subSchema.enum),\n\t\t\t\t\t},\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn [];\n\t\t}\n\t\tif (hasOwn(subSchema, \"const\")) {\n\t\t\tconst constInEnum = supSchema.enum.some((v) =>\n\t\t\t\tdeepEqual(v, subSchema.const),\n\t\t\t);\n\t\t\tif (!constInEnum) {\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: path,\n\t\t\t\t\t\texpected: formatEnumValues(supSchema.enum),\n\t\t\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t\t\t},\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn [];\n\t\t}\n\t\t// sup has enum, sub is a plain type\n\t\treturn [\n\t\t\t{\n\t\t\t\tkey: path,\n\t\t\t\texpected: formatEnumValues(supSchema.enum),\n\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t},\n\t\t];\n\t}\n\n\t// ── Const comparison ──\n\tif (hasOwn(supSchema, \"const\") && hasOwn(subSchema, \"const\")) {\n\t\tif (!deepEqual(supSchema.const, subSchema.const)) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkey: path,\n\t\t\t\t\texpected: formatSchemaType(supSchema),\n\t\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t\treturn [];\n\t}\n\n\t// ── Type mismatch ──\n\tif (subType !== undefined && supType !== undefined) {\n\t\tif (!typesAreCompatible(subType, supType)) {\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tkey: path,\n\t\t\t\t\texpected: formatSchemaType(supSchema),\n\t\t\t\t\treceived: formatSchemaType(subSchema),\n\t\t\t\t},\n\t\t\t];\n\t\t}\n\t}\n\n\t// ── If same types, recurse deeper ──\n\treturn computeSemanticErrors(subDef, supDef, path);\n}\n\n// ─── Branch Error Computation ────────────────────────────────────────────────\n\n/**\n * When sup has branches (anyOf/oneOf), attempts to find the closest\n * matching branch and generates errors against it.\n *\n * Strategy: compute errors for each branch and return those from the\n * branch with the fewest errors (best match).\n */\nfunction computeErrorsAgainstBranches(\n\tsub: JSONSchema7,\n\tbranches: JSONSchema7Definition[],\n\tpath: string,\n): SchemaError[] {\n\tlet bestErrors: SchemaError[] | null = null;\n\n\tfor (const branch of branches) {\n\t\tconst errors = computeSemanticErrors(sub, branch, path);\n\t\tif (errors.length === 0) return [];\n\t\tif (bestErrors === null || errors.length < bestErrors.length) {\n\t\t\tbestErrors = errors;\n\t\t}\n\t}\n\n\treturn (\n\t\tbestErrors ?? [\n\t\t\t{\n\t\t\t\tkey: path || \"$root\",\n\t\t\t\texpected: formatSchemaType({ anyOf: branches } as JSONSchema7),\n\t\t\t\treceived: formatSchemaType(sub),\n\t\t\t},\n\t\t]\n\t);\n}\n"],"names":["computeSemanticErrors","formatSchemaType","formatEnumValues","values","parts","map","v","JSON","stringify","length","last","pop","join","def","formatSchemaTypeInternal","undefined","schema","hasOwn","const","Array","isArray","enum","branches","anyOf","oneOf","b","type","items","itemSchema","itemBranches","t","itemType","isPlainObj","properties","not","joinPath","parent","key","arrayPath","getProperties","getRequired","required","getEffectiveType","typeIncludes","schemaType","target","includes","typesAreCompatible","subType","supType","some","every","st","supt","fmtConstraint","name","value","checkMinConstraint","subVal","supVal","path","errors","push","expected","received","checkMaxConstraint","checkNumericConstraints","sub","sup","minimum","maximum","exclusiveMinimum","exclusiveMaximum","multipleOf","checkStringConstraints","minLength","maxLength","pattern","format","checkObjectConstraints","additionalProperties","apPath","apErrors","minProperties","maxProperties","propertyNames","pnErrors","dependencies","supDeps","subDeps","Object","keys","supDep","subDep","missing","filter","d","depPath","depErrors","patternProperties","supPP","subPP","supPropDef","subPropDef","ppPath","ppErrors","checkArrayConstraints","minItems","maxItems","uniqueItems","contains","containsPath","containsErrors","isNumericType","isStringType","isObjectType","isArrayType","hasNumericKeywords","s","hasStringKeywords","hasObjectKeywords","hasArrayKeywords","subSchema","supSchema","notSchema","notFormatted","subNotSchema","deepEqual","supBranches","computeErrorsAgainstBranches","subBranches","branchErrors","branch","errs","supProps","subProps","supRequired","subRequired","propPath","isRequiredInSup","propErrors","comparePropertySchemas","maxLen","Math","max","i","supItem","subItem","itemPath","itemErrors","subExtra","sv","constInEnum","expectedStr","receivedStr","subDef","supDef","bestErrors"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{isDataValidForSchema}from"./runtime-validator.js";import{deepEqual,hasOwn,isPlainObj,mergeConstraints,omitKeys,unionStrings}from"./utils.js";const SPECIAL_MERGE_KEYS=new Set(["required","properties","dependencies"]);const SUB_SCHEMA_KEYS=new Set(["additionalProperties","items","contains","propertyNames","not"]);const MIN_KEYS=new Set(["minimum","exclusiveMinimum","minLength","minItems","minProperties"]);const MAX_KEYS=new Set(["maximum","exclusiveMaximum","maxLength","maxItems","maxProperties"]);function evaluateCondition(ifSchema,data){return isDataValidForSchema(ifSchema,data)}const DISCRIMINANT_INDICATORS=["const","enum","minimum","maximum","exclusiveMinimum","exclusiveMaximum","pattern","minLength","maxLength","multipleOf","minItems","maxItems","format"];function extractDiscriminants(ifSchema,data,out){if(!isPlainObj(ifSchema.properties))return;const props=ifSchema.properties;for(const key of Object.keys(props)){const propDef=props[key];if(typeof propDef==="boolean")continue;const prop=propDef;const hasIndicator=DISCRIMINANT_INDICATORS.some(indicator=>hasOwn(prop,indicator));if(hasIndicator&&hasOwn(data,key)){out[key]=data[key]}}}function mergeBranchInto(resolved,branchDef,engine){if(typeof branchDef==="boolean")return;const branchSchema=branchDef;if(Array.isArray(branchSchema.required)){resolved.required=unionStrings(resolved.required??[],branchSchema.required)}if(isPlainObj(branchSchema.properties)){const branchProps=branchSchema.properties;const mergedProps={...resolved.properties??{}};for(const key of Object.keys(branchProps)){const branchProp=branchProps[key];if(branchProp===undefined)continue;const existing=resolved.properties?.[key];if(existing!==undefined&&typeof existing!=="boolean"&&typeof branchProp!=="boolean"){const merged=engine.merge(existing,branchProp);mergedProps[key]=
|
|
1
|
+
import{isDataValidForSchema}from"./runtime-validator.js";import{deepEqual,hasOwn,isPlainObj,mergeConstraints,omitKeys,unionStrings}from"./utils.js";const SPECIAL_MERGE_KEYS=new Set(["required","properties","dependencies"]);const SUB_SCHEMA_KEYS=new Set(["additionalProperties","items","contains","propertyNames","not"]);const MIN_KEYS=new Set(["minimum","exclusiveMinimum","minLength","minItems","minProperties"]);const MAX_KEYS=new Set(["maximum","exclusiveMaximum","maxLength","maxItems","maxProperties"]);function evaluateCondition(ifSchema,data){return isDataValidForSchema(ifSchema,data)}const DISCRIMINANT_INDICATORS=["const","enum","minimum","maximum","exclusiveMinimum","exclusiveMaximum","pattern","minLength","maxLength","multipleOf","minItems","maxItems","format"];function extractDiscriminants(ifSchema,data,out){if(!isPlainObj(ifSchema.properties))return;const props=ifSchema.properties;for(const key of Object.keys(props)){const propDef=props[key];if(typeof propDef==="boolean")continue;const prop=propDef;const hasIndicator=DISCRIMINANT_INDICATORS.some(indicator=>hasOwn(prop,indicator));if(hasIndicator&&hasOwn(data,key)){out[key]=data[key]}}}function mergeBranchInto(resolved,branchDef,engine){if(typeof branchDef==="boolean")return;const branchSchema=branchDef;if(Array.isArray(branchSchema.required)){resolved.required=unionStrings(resolved.required??[],branchSchema.required)}if(isPlainObj(branchSchema.properties)){const branchProps=branchSchema.properties;const mergedProps={...resolved.properties??{}};for(const key of Object.keys(branchProps)){const branchProp=branchProps[key];if(branchProp===undefined)continue;const existing=resolved.properties?.[key];if(existing!==undefined&&typeof existing!=="boolean"&&typeof branchProp!=="boolean"){const merged=engine.merge(existing,branchProp);let mergedProp=merged??branchProp;if(typeof mergedProp!=="boolean"){const existingObj=existing;const branchObj=branchProp;const unionedConstraints=mergeConstraints(existingObj.constraints,branchObj.constraints);if(unionedConstraints!==undefined){mergedProp={...mergedProp,constraints:unionedConstraints}}}mergedProps[key]=mergedProp}else{mergedProps[key]=branchProp}}resolved.properties=mergedProps}if(isPlainObj(branchSchema.dependencies)){const resolvedDeps=resolved.dependencies??{};const branchDeps=branchSchema.dependencies;const acc={...resolvedDeps};for(const depKey of Object.keys(branchDeps)){const branchVal=branchDeps[depKey];if(branchVal===undefined)continue;const existingVal=acc[depKey];if(existingVal===undefined){acc[depKey]=branchVal}else if(Array.isArray(existingVal)&&Array.isArray(branchVal)){acc[depKey]=unionStrings(existingVal,branchVal)}else if(isPlainObj(existingVal)&&isPlainObj(branchVal)){const merged=engine.merge(existingVal,branchVal);acc[depKey]=merged??branchVal}else{acc[depKey]=branchVal}}resolved.dependencies=acc}for(const key of Object.keys(branchSchema)){if(SPECIAL_MERGE_KEYS.has(key))continue;const branchVal=branchSchema[key];const resolvedVal=resolved[key];if(resolvedVal===undefined){resolved[key]=branchVal;continue}if(deepEqual(resolvedVal,branchVal))continue;if(SUB_SCHEMA_KEYS.has(key)){const merged=engine.merge(resolvedVal,branchVal);if(merged!==null){resolved[key]=merged}else{resolved[key]=branchVal}continue}if(MIN_KEYS.has(key)){if(typeof resolvedVal==="number"&&typeof branchVal==="number"){resolved[key]=Math.max(resolvedVal,branchVal)}else{resolved[key]=branchVal}continue}if(MAX_KEYS.has(key)){if(typeof resolvedVal==="number"&&typeof branchVal==="number"){resolved[key]=Math.min(resolvedVal,branchVal)}else{resolved[key]=branchVal}continue}if(key==="uniqueItems"){resolved[key]=resolvedVal===true||branchVal===true;continue}if(key==="pattern"||key==="format"){resolved[key]=branchVal;continue}if(key==="constraints"){const merged=mergeConstraints(resolvedVal,branchVal);if(merged!==undefined){resolved[key]=merged}continue}const base={[key]:resolvedVal};const branch={[key]:branchVal};const merged=engine.merge(base,branch);if(merged&&typeof merged!=="boolean"&&hasOwn(merged,key)){resolved[key]=merged[key]}else{resolved[key]=branchVal}}}export function resolveConditions(schema,data,engine){let branch=null;const discriminant={};const hasTopLevelIf=schema.if!==undefined;const hasAllOfConditions=Array.isArray(schema.allOf)&&schema.allOf.some(e=>typeof e!=="boolean"&&hasOwn(e,"if"));if(!hasTopLevelIf&&!hasAllOfConditions){const resolved=resolveNestedProperties(schema,data,engine,discriminant);return{resolved,branch,discriminant}}let resolved={...schema};if(hasAllOfConditions){resolved=resolveAllOfConditions(resolved,data,engine,discriminant)}if(resolved.if!==undefined){const ifSchema=resolved.if;const matches=evaluateCondition(ifSchema,data);extractDiscriminants(ifSchema,data,discriminant);const applicableBranch=matches?resolved.then:resolved.else;branch=matches?"then":"else";if(applicableBranch){mergeBranchInto(resolved,applicableBranch,engine)}delete resolved.if;delete resolved.then;delete resolved.else}resolved=resolveNestedProperties(resolved,data,engine,discriminant);return{resolved,branch,discriminant}}function resolveAllOfConditions(resolved,data,engine,discriminant){if(!Array.isArray(resolved.allOf))return resolved;const remainingAllOf=[];for(const entry of resolved.allOf){if(typeof entry==="boolean"){remainingAllOf.push(entry);continue}const subSchema=entry;if(subSchema.if===undefined){remainingAllOf.push(entry);continue}const ifSchema=subSchema.if;const matches=evaluateCondition(ifSchema,data);extractDiscriminants(ifSchema,data,discriminant);const applicableBranch=matches?subSchema.then:subSchema.else;if(applicableBranch){mergeBranchInto(resolved,applicableBranch,engine)}const remaining=omitKeys(subSchema,["if","then","else"]);if(Object.keys(remaining).length>0){remainingAllOf.push(remaining)}}resolved={...resolved};if(remainingAllOf.length===0){delete resolved.allOf}else{resolved.allOf=remainingAllOf}return resolved}function resolveNestedProperties(resolved,data,engine,discriminant){if(!isPlainObj(resolved.properties))return resolved;const props=resolved.properties;const propKeys=Object.keys(props);let changed=false;const resolvedProps={};for(const key of propKeys){const propDef=props[key];if(propDef===undefined)continue;if(typeof propDef==="boolean"){resolvedProps[key]=propDef;continue}const propSchema=propDef;const hasConditions=propSchema.if!==undefined||Array.isArray(propSchema.allOf)&&propSchema.allOf.some(e=>typeof e!=="boolean"&&hasOwn(e,"if"));if(!hasConditions){resolvedProps[key]=propDef;continue}const nestedData=isPlainObj(data[key])?data[key]:{};const nested=resolveConditions(propSchema,nestedData,engine);for(const dk of Object.keys(nested.discriminant)){discriminant[`${key}.${dk}`]=nested.discriminant[dk]}resolvedProps[key]=nested.resolved;changed=true}return changed?{...resolved,properties:resolvedProps}:resolved}
|
|
2
2
|
//# sourceMappingURL=condition-resolver.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/condition-resolver.ts"],"sourcesContent":["import type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\nimport type { MergeEngine } from \"./merge-engine.ts\";\nimport { isDataValidForSchema } from \"./runtime-validator.ts\";\nimport type { ResolvedConditionResult } from \"./types.ts\";\nimport {\n\tdeepEqual,\n\thasOwn,\n\tisPlainObj,\n\tmergeConstraints,\n\tomitKeys,\n\tunionStrings,\n} from \"./utils.ts\";\n\n// ─── Condition Resolver ──────────────────────────────────────────────────────\n//\n// Resolves `if/then/else` in a schema by evaluating the `if` against\n// partial data (discriminants).\n//\n// Strategy:\n// 1. Evaluate whether partial data satisfies the `if`\n// 2. Merge the applicable branch (`then` or `else`) into the base schema\n// 3. Remove the `if/then/else` keywords from the result\n// 4. Recurse into `properties` to resolve nested conditions\n//\n// The `if` evaluation relies on a shared runtime validator\n// to avoid duplicating partial validation logic.\n// The resolver continues to orchestrate:\n// - evaluation of `if/then/else` branches\n// - merging the applicable branch\n// - recursive resolution of nested properties\n//\n// Uses custom utilities from `utils.ts`:\n// - `hasOwn` / `isPlainObj` for safe property access and type checks\n// - `unionStrings` for merging string arrays (required, deps)\n// - `omitKeys` for excluding keys from objects\n\n// ─── Keywords classification ─────────────────────────────────────────────────\n\n/** Keywords that must not be processed by the generic loop in mergeBranchInto */\nconst SPECIAL_MERGE_KEYS = new Set([\"required\", \"properties\", \"dependencies\"]);\n\n/** Keywords containing a single sub-schema (mergeable via engine.merge) */\nconst SUB_SCHEMA_KEYS = new Set([\n\t\"additionalProperties\",\n\t\"items\",\n\t\"contains\",\n\t\"propertyNames\",\n\t\"not\",\n]);\n\n/** Numeric keywords of \"minimum\" type (take the max to be more restrictive) */\nconst MIN_KEYS = new Set([\n\t\"minimum\",\n\t\"exclusiveMinimum\",\n\t\"minLength\",\n\t\"minItems\",\n\t\"minProperties\",\n]);\n\n/** Numeric keywords of \"maximum\" type (take the min to be more restrictive) */\nconst MAX_KEYS = new Set([\n\t\"maximum\",\n\t\"exclusiveMaximum\",\n\t\"maxLength\",\n\t\"maxItems\",\n\t\"maxProperties\",\n]);\n\n// ─── Condition evaluation (internal) ─────────────────────────────────────────\n\n/**\n * Evaluates whether partial data satisfies an `if` schema.\n *\n * This version delegates runtime validation to the shared validator.\n * Only the resolver semantics are kept here:\n * if the data matches the `if`, apply `then`, otherwise `else`.\n */\nfunction evaluateCondition(\n\tifSchema: JSONSchema7,\n\tdata: Record<string, unknown>,\n): boolean {\n\treturn isDataValidForSchema(ifSchema, data);\n}\n\n// ─── Discriminant extraction ─────────────────────────────────────────────────\n\n/**\n * Keywords that indicate a property is a discriminant\n * (its value in the data is used for resolution).\n *\n * Point 5 — Extended with numeric/string/pattern constraints.\n */\nconst DISCRIMINANT_INDICATORS = [\n\t\"const\",\n\t\"enum\",\n\t\"minimum\",\n\t\"maximum\",\n\t\"exclusiveMinimum\",\n\t\"exclusiveMaximum\",\n\t\"pattern\",\n\t\"minLength\",\n\t\"maxLength\",\n\t\"multipleOf\",\n\t\"minItems\",\n\t\"maxItems\",\n\t\"format\",\n] as const;\n\n/**\n * Extracts discriminant values used in an `if` schema from partial data.\n *\n * Point 5 — Also collects discriminants for new constraints\n * (minimum, maximum, pattern, etc.).\n */\nfunction extractDiscriminants(\n\tifSchema: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tout: Record<string, unknown>,\n): void {\n\tif (!isPlainObj(ifSchema.properties)) return;\n\n\tconst props = ifSchema.properties as Record<string, JSONSchema7Definition>;\n\tfor (const key of Object.keys(props)) {\n\t\tconst propDef = props[key];\n\t\tif (typeof propDef === \"boolean\") continue;\n\t\tconst prop = propDef as JSONSchema7;\n\n\t\t// Collect if at least one discriminant indicator is present\n\t\tconst hasIndicator = DISCRIMINANT_INDICATORS.some((indicator) =>\n\t\t\thasOwn(prop, indicator),\n\t\t);\n\n\t\tif (hasIndicator && hasOwn(data, key)) {\n\t\t\tout[key] = data[key];\n\t\t}\n\t}\n}\n\n// ─── Branch merging (deduplicated) ───────────────────────────────────────────\n\n/**\n * Merges a conditional branch (`then` or `else`) into the resolved schema.\n *\n * Point 4 — Fix first-writer-wins:\n * Instead of ignoring keywords already present in `resolved`,\n * attempts a smart merge depending on the keyword type:\n *\n * - `properties` → individual merge via engine.merge\n * - `dependencies` → Point 3: union of arrays (form 1),\n * merge of schemas (form 2)\n * - Sub-schema keys → merge via engine.merge\n * - Min keys → `Math.max` (more restrictive)\n * - Max keys → `Math.min` (more restrictive)\n * - `uniqueItems` → `true` wins over `false`\n * - `pattern` / `format` → branch wins (more context-specific)\n * - Others → attempt merge via engine, otherwise branch wins\n *\n * Uses custom utilities from `utils.ts` for each merge operation.\n */\nfunction mergeBranchInto(\n\tresolved: JSONSchema7,\n\tbranchDef: JSONSchema7Definition,\n\tengine: MergeEngine,\n): void {\n\tif (typeof branchDef === \"boolean\") return;\n\n\tconst branchSchema = branchDef as JSONSchema7;\n\n\t// ── Merge required via unionStrings (deduplicated automatically) ──\n\tif (Array.isArray(branchSchema.required)) {\n\t\tresolved.required = unionStrings(\n\t\t\tresolved.required ?? [],\n\t\t\tbranchSchema.required,\n\t\t);\n\t}\n\n\t// ── Merge properties ──\n\tif (isPlainObj(branchSchema.properties)) {\n\t\tconst branchProps = branchSchema.properties as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tconst mergedProps: Record<string, JSONSchema7Definition> = {\n\t\t\t...(resolved.properties ?? {}),\n\t\t};\n\t\tfor (const key of Object.keys(branchProps)) {\n\t\t\tconst branchProp = branchProps[key];\n\t\t\tif (branchProp === undefined) continue;\n\t\t\tconst existing = resolved.properties?.[key];\n\t\t\tif (\n\t\t\t\texisting !== undefined &&\n\t\t\t\ttypeof existing !== \"boolean\" &&\n\t\t\t\ttypeof branchProp !== \"boolean\"\n\t\t\t) {\n\t\t\t\tconst merged = engine.merge(\n\t\t\t\t\texisting as JSONSchema7Definition,\n\t\t\t\t\tbranchProp as JSONSchema7Definition,\n\t\t\t\t);\n\t\t\t\tmergedProps[key] = (merged ?? branchProp) as JSONSchema7Definition;\n\t\t\t} else {\n\t\t\t\tmergedProps[key] = branchProp;\n\t\t\t}\n\t\t}\n\t\tresolved.properties = mergedProps;\n\t}\n\n\t// ── Merge dependencies (Point 3) ──\n\tif (isPlainObj(branchSchema.dependencies)) {\n\t\tconst resolvedDeps = (resolved.dependencies ?? {}) as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t\tconst branchDeps = branchSchema.dependencies as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\n\t\tconst acc = { ...resolvedDeps };\n\t\tfor (const depKey of Object.keys(branchDeps)) {\n\t\t\tconst branchVal = branchDeps[depKey] as\n\t\t\t\t| JSONSchema7Definition\n\t\t\t\t| string[]\n\t\t\t\t| undefined;\n\t\t\tif (branchVal === undefined) continue;\n\t\t\tconst existingVal = acc[depKey] as\n\t\t\t\t| JSONSchema7Definition\n\t\t\t\t| string[]\n\t\t\t\t| undefined;\n\n\t\t\tif (existingVal === undefined) {\n\t\t\t\t// No existing value → copy directly\n\t\t\t\tacc[depKey] = branchVal;\n\t\t\t} else if (Array.isArray(existingVal) && Array.isArray(branchVal)) {\n\t\t\t\t// Form 1: deduplicated union of string arrays\n\t\t\t\tacc[depKey] = unionStrings(\n\t\t\t\t\texistingVal as string[],\n\t\t\t\t\tbranchVal as string[],\n\t\t\t\t);\n\t\t\t} else if (isPlainObj(existingVal) && isPlainObj(branchVal)) {\n\t\t\t\t// Form 2: merge sub-schemas\n\t\t\t\tconst merged = engine.merge(\n\t\t\t\t\texistingVal as JSONSchema7Definition,\n\t\t\t\t\tbranchVal as JSONSchema7Definition,\n\t\t\t\t);\n\t\t\t\tacc[depKey] = (merged ?? branchVal) as JSONSchema7Definition;\n\t\t\t} else {\n\t\t\t\t// Incompatible types (array vs schema) → branch wins\n\t\t\t\tacc[depKey] = branchVal;\n\t\t\t}\n\t\t}\n\t\tresolved.dependencies = acc as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t}\n\n\t// ── Merge remaining keywords (Point 4 — fix first-writer-wins) ──\n\tfor (const key of Object.keys(branchSchema) as (keyof JSONSchema7)[]) {\n\t\t// Skip keys already handled above\n\t\tif (SPECIAL_MERGE_KEYS.has(key)) continue;\n\n\t\tconst branchVal = branchSchema[key];\n\t\tconst resolvedVal = resolved[key];\n\n\t\t// If resolved doesn't have this key → copy directly\n\t\tif (resolvedVal === undefined) {\n\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// If both have the same value → nothing to do\n\t\tif (deepEqual(resolvedVal, branchVal)) continue;\n\n\t\t// ── Sub-schema keys → merge via engine ──\n\t\tif (SUB_SCHEMA_KEYS.has(key)) {\n\t\t\tconst merged = engine.merge(\n\t\t\t\tresolvedVal as JSONSchema7Definition,\n\t\t\t\tbranchVal as JSONSchema7Definition,\n\t\t\t);\n\t\t\tif (merged !== null) {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = merged;\n\t\t\t} else {\n\t\t\t\t// Merge impossible → branch wins (conditional context)\n\t\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ── Min keys → Math.max (more restrictive) ──\n\t\tif (MIN_KEYS.has(key)) {\n\t\t\tif (typeof resolvedVal === \"number\" && typeof branchVal === \"number\") {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = Math.max(\n\t\t\t\t\tresolvedVal,\n\t\t\t\t\tbranchVal,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ── Max keys → Math.min (more restrictive) ──\n\t\tif (MAX_KEYS.has(key)) {\n\t\t\tif (typeof resolvedVal === \"number\" && typeof branchVal === \"number\") {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = Math.min(\n\t\t\t\t\tresolvedVal,\n\t\t\t\t\tbranchVal,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ── uniqueItems → true wins over false ──\n\t\tif (key === \"uniqueItems\") {\n\t\t\t(resolved as Record<string, unknown>)[key] =\n\t\t\t\tresolvedVal === true || branchVal === true;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ── pattern / format → branch wins (more context-specific) ──\n\t\tif (key === \"pattern\" || key === \"format\") {\n\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ── constraints → union + dedup (intersection semantics) ──\n\t\t// Constraints follow allOf semantics: both the base and the branch\n\t\t// constraints must be satisfied. This is the same logic used by\n\t\t// the merge engine's applyConstraintsMerge post-processor.\n\t\tif (key === \"constraints\") {\n\t\t\tconst merged = mergeConstraints(resolvedVal, branchVal);\n\t\t\tif (merged !== undefined) {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = merged;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ── Fallback: attempt merge via engine for remaining cases ──\n\t\tconst base = { [key]: resolvedVal } as JSONSchema7Definition;\n\t\tconst branch = { [key]: branchVal } as JSONSchema7Definition;\n\t\tconst merged = engine.merge(base, branch);\n\t\tif (\n\t\t\tmerged &&\n\t\t\ttypeof merged !== \"boolean\" &&\n\t\t\thasOwn(merged as object, key)\n\t\t) {\n\t\t\t(resolved as Record<string, unknown>)[key] = (\n\t\t\t\tmerged as unknown as Record<string, unknown>\n\t\t\t)[key];\n\t\t} else {\n\t\t\t// Merge failed → branch wins (applicable conditional context)\n\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t}\n\t}\n}\n\n// ─── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Resolves `if/then/else` in a schema by evaluating the `if` against\n * partial data (discriminants).\n *\n * @param schema The schema potentially containing if/then/else\n * @param data Partial data used to evaluate the conditions\n * @param engine The MergeEngine for merging branches\n *\n * @example\n * ```ts\n * const form = {\n * type: \"object\",\n * properties: { accountType: { type: \"string\" }, ... },\n * if: { properties: { accountType: { const: \"business\" } } },\n * then: { required: [\"companyName\"] },\n * else: { required: [\"firstName\"] },\n * };\n *\n * const { resolved } = resolveConditions(form, { accountType: \"business\" }, engine);\n * // → resolved no longer has if/then/else, but has required: [\"companyName\"]\n * ```\n */\nexport function resolveConditions(\n\tschema: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tengine: MergeEngine,\n): ResolvedConditionResult {\n\tlet branch: \"then\" | \"else\" | null = null;\n\tconst discriminant: Record<string, unknown> = {};\n\n\t// ── Fast path: no conditions at all ──\n\t// If there's no `if` and no `allOf` with conditions, skip the copy entirely.\n\tconst hasTopLevelIf = schema.if !== undefined;\n\tconst hasAllOfConditions =\n\t\tArray.isArray(schema.allOf) &&\n\t\tschema.allOf.some(\n\t\t\t(e) => typeof e !== \"boolean\" && hasOwn(e as object, \"if\"),\n\t\t);\n\n\tif (!hasTopLevelIf && !hasAllOfConditions) {\n\t\t// Phase 3 only: check nested properties (resolveNestedProperties\n\t\t// already returns the original if nothing changes)\n\t\tconst resolved = resolveNestedProperties(\n\t\t\tschema,\n\t\t\tdata,\n\t\t\tengine,\n\t\t\tdiscriminant,\n\t\t);\n\t\treturn { resolved, branch, discriminant };\n\t}\n\n\t// ── Copy-on-write: only copy when mutations are needed ──\n\tlet resolved = { ...schema };\n\n\t// ── Phase 1: Resolve if/then/else in allOf ──\n\tif (hasAllOfConditions) {\n\t\tresolved = resolveAllOfConditions(resolved, data, engine, discriminant);\n\t}\n\n\t// ── Phase 2: Resolve if/then/else at this level ──\n\tif (resolved.if !== undefined) {\n\t\tconst ifSchema = resolved.if as JSONSchema7;\n\t\tconst matches = evaluateCondition(ifSchema, data);\n\n\t\textractDiscriminants(ifSchema, data, discriminant);\n\n\t\tconst applicableBranch = matches ? resolved.then : resolved.else;\n\t\tbranch = matches ? \"then\" : \"else\";\n\n\t\tif (applicableBranch) {\n\t\t\tmergeBranchInto(\n\t\t\t\tresolved,\n\t\t\t\tapplicableBranch as JSONSchema7Definition,\n\t\t\t\tengine,\n\t\t\t);\n\t\t}\n\n\t\tdelete resolved.if;\n\t\tdelete resolved.then;\n\t\tdelete resolved.else;\n\t}\n\n\t// ── Phase 3: Recurse into properties ──\n\tresolved = resolveNestedProperties(resolved, data, engine, discriminant);\n\n\treturn { resolved, branch, discriminant };\n}\n\n// ─── Internal phases ─────────────────────────────────────────────────────────\n\n/**\n * Phase 1: Iterates over `allOf` entries and resolves those containing\n * an `if/then/else`. Non-conditional entries are preserved.\n *\n\n */\nfunction resolveAllOfConditions(\n\tresolved: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tengine: MergeEngine,\n\tdiscriminant: Record<string, unknown>,\n): JSONSchema7 {\n\tif (!Array.isArray(resolved.allOf)) return resolved;\n\n\tconst remainingAllOf: JSONSchema7Definition[] = [];\n\n\tfor (const entry of resolved.allOf) {\n\t\tif (typeof entry === \"boolean\") {\n\t\t\tremainingAllOf.push(entry);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst subSchema = entry as JSONSchema7;\n\n\t\tif (subSchema.if === undefined) {\n\t\t\tremainingAllOf.push(entry);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Resolve the condition of this allOf entry\n\t\tconst ifSchema = subSchema.if as JSONSchema7;\n\t\tconst matches = evaluateCondition(ifSchema, data);\n\n\t\textractDiscriminants(ifSchema, data, discriminant);\n\n\t\tconst applicableBranch = matches ? subSchema.then : subSchema.else;\n\n\t\tif (applicableBranch) {\n\t\t\tmergeBranchInto(\n\t\t\t\tresolved,\n\t\t\t\tapplicableBranch as JSONSchema7Definition,\n\t\t\t\tengine,\n\t\t\t);\n\t\t}\n\n\t\t// Keep non-conditional parts of the allOf entry\n\t\tconst remaining = omitKeys(\n\t\t\tsubSchema as unknown as Record<string, unknown>,\n\t\t\t[\"if\", \"then\", \"else\"],\n\t\t);\n\t\tif (Object.keys(remaining).length > 0) {\n\t\t\tremainingAllOf.push(remaining as JSONSchema7);\n\t\t}\n\t}\n\n\tresolved = { ...resolved };\n\tif (remainingAllOf.length === 0) {\n\t\tdelete resolved.allOf;\n\t} else {\n\t\tresolved.allOf = remainingAllOf;\n\t}\n\n\treturn resolved;\n}\n\n/**\n * Phase 3: Recurses into the `properties` of the resolved schema to resolve\n * nested conditions (e.g. an object whose property has an if/then/else).\n *\n\n */\nfunction resolveNestedProperties(\n\tresolved: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tengine: MergeEngine,\n\tdiscriminant: Record<string, unknown>,\n): JSONSchema7 {\n\tif (!isPlainObj(resolved.properties)) return resolved;\n\n\tconst props = resolved.properties as Record<string, JSONSchema7Definition>;\n\tconst propKeys = Object.keys(props);\n\tlet changed = false;\n\tconst resolvedProps: Record<string, JSONSchema7Definition> = {};\n\n\tfor (const key of propKeys) {\n\t\tconst propDef = props[key];\n\t\tif (propDef === undefined) continue;\n\t\tif (typeof propDef === \"boolean\") {\n\t\t\tresolvedProps[key] = propDef;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst propSchema = propDef as JSONSchema7;\n\t\tconst hasConditions =\n\t\t\tpropSchema.if !== undefined ||\n\t\t\t(Array.isArray(propSchema.allOf) &&\n\t\t\t\tpropSchema.allOf.some(\n\t\t\t\t\t(e) => typeof e !== \"boolean\" && hasOwn(e as object, \"if\"),\n\t\t\t\t));\n\n\t\tif (!hasConditions) {\n\t\t\tresolvedProps[key] = propDef;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Nested data available → resolve recursively\n\t\tconst nestedData = isPlainObj(data[key])\n\t\t\t? (data[key] as Record<string, unknown>)\n\t\t\t: {};\n\n\t\tconst nested = resolveConditions(propSchema, nestedData, engine);\n\n\t\t// Propagate nested discriminants with prefix\n\t\tfor (const dk of Object.keys(nested.discriminant)) {\n\t\t\tdiscriminant[`${key}.${dk}`] = nested.discriminant[dk];\n\t\t}\n\n\t\tresolvedProps[key] = nested.resolved;\n\t\tchanged = true;\n\t}\n\n\treturn changed ? { ...resolved, properties: resolvedProps } : resolved;\n}\n"],"names":["isDataValidForSchema","deepEqual","hasOwn","isPlainObj","mergeConstraints","omitKeys","unionStrings","SPECIAL_MERGE_KEYS","Set","SUB_SCHEMA_KEYS","MIN_KEYS","MAX_KEYS","evaluateCondition","ifSchema","data","DISCRIMINANT_INDICATORS","extractDiscriminants","out","properties","props","key","Object","keys","propDef","prop","hasIndicator","some","indicator","mergeBranchInto","resolved","branchDef","engine","branchSchema","Array","isArray","required","branchProps","mergedProps","branchProp","undefined","existing","merged","merge","dependencies","resolvedDeps","branchDeps","acc","depKey","branchVal","existingVal","has","resolvedVal","Math","max","min","base","branch","resolveConditions","schema","discriminant","hasTopLevelIf","if","hasAllOfConditions","allOf","e","resolveNestedProperties","resolveAllOfConditions","matches","applicableBranch","then","else","remainingAllOf","entry","push","subSchema","remaining","length","propKeys","changed","resolvedProps","propSchema","hasConditions","nestedData","nested","dk"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/condition-resolver.ts"],"sourcesContent":["import type { JSONSchema7, JSONSchema7Definition } from \"json-schema\";\nimport type { MergeEngine } from \"./merge-engine.ts\";\nimport { isDataValidForSchema } from \"./runtime-validator.ts\";\nimport type { ResolvedConditionResult } from \"./types.ts\";\nimport {\n\tdeepEqual,\n\thasOwn,\n\tisPlainObj,\n\tmergeConstraints,\n\tomitKeys,\n\tunionStrings,\n} from \"./utils.ts\";\n\n// ─── Condition Resolver ──────────────────────────────────────────────────────\n//\n// Resolves `if/then/else` in a schema by evaluating the `if` against\n// partial data (discriminants).\n//\n// Strategy:\n// 1. Evaluate whether partial data satisfies the `if`\n// 2. Merge the applicable branch (`then` or `else`) into the base schema\n// 3. Remove the `if/then/else` keywords from the result\n// 4. Recurse into `properties` to resolve nested conditions\n//\n// The `if` evaluation relies on a shared runtime validator\n// to avoid duplicating partial validation logic.\n// The resolver continues to orchestrate:\n// - evaluation of `if/then/else` branches\n// - merging the applicable branch\n// - recursive resolution of nested properties\n//\n// Uses custom utilities from `utils.ts`:\n// - `hasOwn` / `isPlainObj` for safe property access and type checks\n// - `unionStrings` for merging string arrays (required, deps)\n// - `omitKeys` for excluding keys from objects\n\n// ─── Keywords classification ─────────────────────────────────────────────────\n\n/** Keywords that must not be processed by the generic loop in mergeBranchInto */\nconst SPECIAL_MERGE_KEYS = new Set([\"required\", \"properties\", \"dependencies\"]);\n\n/** Keywords containing a single sub-schema (mergeable via engine.merge) */\nconst SUB_SCHEMA_KEYS = new Set([\n\t\"additionalProperties\",\n\t\"items\",\n\t\"contains\",\n\t\"propertyNames\",\n\t\"not\",\n]);\n\n/** Numeric keywords of \"minimum\" type (take the max to be more restrictive) */\nconst MIN_KEYS = new Set([\n\t\"minimum\",\n\t\"exclusiveMinimum\",\n\t\"minLength\",\n\t\"minItems\",\n\t\"minProperties\",\n]);\n\n/** Numeric keywords of \"maximum\" type (take the min to be more restrictive) */\nconst MAX_KEYS = new Set([\n\t\"maximum\",\n\t\"exclusiveMaximum\",\n\t\"maxLength\",\n\t\"maxItems\",\n\t\"maxProperties\",\n]);\n\n// ─── Condition evaluation (internal) ─────────────────────────────────────────\n\n/**\n * Evaluates whether partial data satisfies an `if` schema.\n *\n * This version delegates runtime validation to the shared validator.\n * Only the resolver semantics are kept here:\n * if the data matches the `if`, apply `then`, otherwise `else`.\n */\nfunction evaluateCondition(\n\tifSchema: JSONSchema7,\n\tdata: Record<string, unknown>,\n): boolean {\n\treturn isDataValidForSchema(ifSchema, data);\n}\n\n// ─── Discriminant extraction ─────────────────────────────────────────────────\n\n/**\n * Keywords that indicate a property is a discriminant\n * (its value in the data is used for resolution).\n *\n * Point 5 — Extended with numeric/string/pattern constraints.\n */\nconst DISCRIMINANT_INDICATORS = [\n\t\"const\",\n\t\"enum\",\n\t\"minimum\",\n\t\"maximum\",\n\t\"exclusiveMinimum\",\n\t\"exclusiveMaximum\",\n\t\"pattern\",\n\t\"minLength\",\n\t\"maxLength\",\n\t\"multipleOf\",\n\t\"minItems\",\n\t\"maxItems\",\n\t\"format\",\n] as const;\n\n/**\n * Extracts discriminant values used in an `if` schema from partial data.\n *\n * Point 5 — Also collects discriminants for new constraints\n * (minimum, maximum, pattern, etc.).\n */\nfunction extractDiscriminants(\n\tifSchema: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tout: Record<string, unknown>,\n): void {\n\tif (!isPlainObj(ifSchema.properties)) return;\n\n\tconst props = ifSchema.properties as Record<string, JSONSchema7Definition>;\n\tfor (const key of Object.keys(props)) {\n\t\tconst propDef = props[key];\n\t\tif (typeof propDef === \"boolean\") continue;\n\t\tconst prop = propDef as JSONSchema7;\n\n\t\t// Collect if at least one discriminant indicator is present\n\t\tconst hasIndicator = DISCRIMINANT_INDICATORS.some((indicator) =>\n\t\t\thasOwn(prop, indicator),\n\t\t);\n\n\t\tif (hasIndicator && hasOwn(data, key)) {\n\t\t\tout[key] = data[key];\n\t\t}\n\t}\n}\n\n// ─── Branch merging (deduplicated) ───────────────────────────────────────────\n\n/**\n * Merges a conditional branch (`then` or `else`) into the resolved schema.\n *\n * Point 4 — Fix first-writer-wins:\n * Instead of ignoring keywords already present in `resolved`,\n * attempts a smart merge depending on the keyword type:\n *\n * - `properties` → individual merge via engine.merge\n * - `dependencies` → Point 3: union of arrays (form 1),\n * merge of schemas (form 2)\n * - Sub-schema keys → merge via engine.merge\n * - Min keys → `Math.max` (more restrictive)\n * - Max keys → `Math.min` (more restrictive)\n * - `uniqueItems` → `true` wins over `false`\n * - `pattern` / `format` → branch wins (more context-specific)\n * - Others → attempt merge via engine, otherwise branch wins\n *\n * Uses custom utilities from `utils.ts` for each merge operation.\n */\nfunction mergeBranchInto(\n\tresolved: JSONSchema7,\n\tbranchDef: JSONSchema7Definition,\n\tengine: MergeEngine,\n): void {\n\tif (typeof branchDef === \"boolean\") return;\n\n\tconst branchSchema = branchDef as JSONSchema7;\n\n\t// ── Merge required via unionStrings (deduplicated automatically) ──\n\tif (Array.isArray(branchSchema.required)) {\n\t\tresolved.required = unionStrings(\n\t\t\tresolved.required ?? [],\n\t\t\tbranchSchema.required,\n\t\t);\n\t}\n\n\t// ── Merge properties ──\n\tif (isPlainObj(branchSchema.properties)) {\n\t\tconst branchProps = branchSchema.properties as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition\n\t\t>;\n\t\tconst mergedProps: Record<string, JSONSchema7Definition> = {\n\t\t\t...(resolved.properties ?? {}),\n\t\t};\n\t\tfor (const key of Object.keys(branchProps)) {\n\t\t\tconst branchProp = branchProps[key];\n\t\t\tif (branchProp === undefined) continue;\n\t\t\tconst existing = resolved.properties?.[key];\n\t\t\tif (\n\t\t\t\texisting !== undefined &&\n\t\t\t\ttypeof existing !== \"boolean\" &&\n\t\t\t\ttypeof branchProp !== \"boolean\"\n\t\t\t) {\n\t\t\t\tconst merged = engine.merge(\n\t\t\t\t\texisting as JSONSchema7Definition,\n\t\t\t\t\tbranchProp as JSONSchema7Definition,\n\t\t\t\t);\n\t\t\t\tlet mergedProp = (merged ?? branchProp) as JSONSchema7Definition;\n\n\t\t\t\t// The merge engine does not handle the custom `constraints`\n\t\t\t\t// keyword — it uses identity/first-wins for unknown keywords.\n\t\t\t\t// We need to manually union + dedup constraints from both\n\t\t\t\t// the existing property and the branch property so that all\n\t\t\t\t// runtime constraints are preserved in the resolved schema.\n\t\t\t\tif (typeof mergedProp !== \"boolean\") {\n\t\t\t\t\tconst existingObj = existing as JSONSchema7;\n\t\t\t\t\tconst branchObj = branchProp as JSONSchema7;\n\t\t\t\t\tconst unionedConstraints = mergeConstraints(\n\t\t\t\t\t\texistingObj.constraints,\n\t\t\t\t\t\tbranchObj.constraints,\n\t\t\t\t\t);\n\t\t\t\t\tif (unionedConstraints !== undefined) {\n\t\t\t\t\t\tmergedProp = { ...mergedProp, constraints: unionedConstraints };\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmergedProps[key] = mergedProp;\n\t\t\t} else {\n\t\t\t\tmergedProps[key] = branchProp;\n\t\t\t}\n\t\t}\n\t\tresolved.properties = mergedProps;\n\t}\n\n\t// ── Merge dependencies (Point 3) ──\n\tif (isPlainObj(branchSchema.dependencies)) {\n\t\tconst resolvedDeps = (resolved.dependencies ?? {}) as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t\tconst branchDeps = branchSchema.dependencies as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\n\t\tconst acc = { ...resolvedDeps };\n\t\tfor (const depKey of Object.keys(branchDeps)) {\n\t\t\tconst branchVal = branchDeps[depKey] as\n\t\t\t\t| JSONSchema7Definition\n\t\t\t\t| string[]\n\t\t\t\t| undefined;\n\t\t\tif (branchVal === undefined) continue;\n\t\t\tconst existingVal = acc[depKey] as\n\t\t\t\t| JSONSchema7Definition\n\t\t\t\t| string[]\n\t\t\t\t| undefined;\n\n\t\t\tif (existingVal === undefined) {\n\t\t\t\t// No existing value → copy directly\n\t\t\t\tacc[depKey] = branchVal;\n\t\t\t} else if (Array.isArray(existingVal) && Array.isArray(branchVal)) {\n\t\t\t\t// Form 1: deduplicated union of string arrays\n\t\t\t\tacc[depKey] = unionStrings(\n\t\t\t\t\texistingVal as string[],\n\t\t\t\t\tbranchVal as string[],\n\t\t\t\t);\n\t\t\t} else if (isPlainObj(existingVal) && isPlainObj(branchVal)) {\n\t\t\t\t// Form 2: merge sub-schemas\n\t\t\t\tconst merged = engine.merge(\n\t\t\t\t\texistingVal as JSONSchema7Definition,\n\t\t\t\t\tbranchVal as JSONSchema7Definition,\n\t\t\t\t);\n\t\t\t\tacc[depKey] = (merged ?? branchVal) as JSONSchema7Definition;\n\t\t\t} else {\n\t\t\t\t// Incompatible types (array vs schema) → branch wins\n\t\t\t\tacc[depKey] = branchVal;\n\t\t\t}\n\t\t}\n\t\tresolved.dependencies = acc as Record<\n\t\t\tstring,\n\t\t\tJSONSchema7Definition | string[]\n\t\t>;\n\t}\n\n\t// ── Merge remaining keywords (Point 4 — fix first-writer-wins) ──\n\tfor (const key of Object.keys(branchSchema) as (keyof JSONSchema7)[]) {\n\t\t// Skip keys already handled above\n\t\tif (SPECIAL_MERGE_KEYS.has(key)) continue;\n\n\t\tconst branchVal = branchSchema[key];\n\t\tconst resolvedVal = resolved[key];\n\n\t\t// If resolved doesn't have this key → copy directly\n\t\tif (resolvedVal === undefined) {\n\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// If both have the same value → nothing to do\n\t\tif (deepEqual(resolvedVal, branchVal)) continue;\n\n\t\t// ── Sub-schema keys → merge via engine ──\n\t\tif (SUB_SCHEMA_KEYS.has(key)) {\n\t\t\tconst merged = engine.merge(\n\t\t\t\tresolvedVal as JSONSchema7Definition,\n\t\t\t\tbranchVal as JSONSchema7Definition,\n\t\t\t);\n\t\t\tif (merged !== null) {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = merged;\n\t\t\t} else {\n\t\t\t\t// Merge impossible → branch wins (conditional context)\n\t\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ── Min keys → Math.max (more restrictive) ──\n\t\tif (MIN_KEYS.has(key)) {\n\t\t\tif (typeof resolvedVal === \"number\" && typeof branchVal === \"number\") {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = Math.max(\n\t\t\t\t\tresolvedVal,\n\t\t\t\t\tbranchVal,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ── Max keys → Math.min (more restrictive) ──\n\t\tif (MAX_KEYS.has(key)) {\n\t\t\tif (typeof resolvedVal === \"number\" && typeof branchVal === \"number\") {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = Math.min(\n\t\t\t\t\tresolvedVal,\n\t\t\t\t\tbranchVal,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ── uniqueItems → true wins over false ──\n\t\tif (key === \"uniqueItems\") {\n\t\t\t(resolved as Record<string, unknown>)[key] =\n\t\t\t\tresolvedVal === true || branchVal === true;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ── pattern / format → branch wins (more context-specific) ──\n\t\tif (key === \"pattern\" || key === \"format\") {\n\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ── constraints → union + dedup (intersection semantics) ──\n\t\t// Constraints follow allOf semantics: both the base and the branch\n\t\t// constraints must be satisfied. This is the same logic used by\n\t\t// the merge engine's applyConstraintsMerge post-processor.\n\t\tif (key === \"constraints\") {\n\t\t\tconst merged = mergeConstraints(resolvedVal, branchVal);\n\t\t\tif (merged !== undefined) {\n\t\t\t\t(resolved as Record<string, unknown>)[key] = merged;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ── Fallback: attempt merge via engine for remaining cases ──\n\t\tconst base = { [key]: resolvedVal } as JSONSchema7Definition;\n\t\tconst branch = { [key]: branchVal } as JSONSchema7Definition;\n\t\tconst merged = engine.merge(base, branch);\n\t\tif (\n\t\t\tmerged &&\n\t\t\ttypeof merged !== \"boolean\" &&\n\t\t\thasOwn(merged as object, key)\n\t\t) {\n\t\t\t(resolved as Record<string, unknown>)[key] = (\n\t\t\t\tmerged as unknown as Record<string, unknown>\n\t\t\t)[key];\n\t\t} else {\n\t\t\t// Merge failed → branch wins (applicable conditional context)\n\t\t\t(resolved as Record<string, unknown>)[key] = branchVal;\n\t\t}\n\t}\n}\n\n// ─── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Resolves `if/then/else` in a schema by evaluating the `if` against\n * partial data (discriminants).\n *\n * @param schema The schema potentially containing if/then/else\n * @param data Partial data used to evaluate the conditions\n * @param engine The MergeEngine for merging branches\n *\n * @example\n * ```ts\n * const form = {\n * type: \"object\",\n * properties: { accountType: { type: \"string\" }, ... },\n * if: { properties: { accountType: { const: \"business\" } } },\n * then: { required: [\"companyName\"] },\n * else: { required: [\"firstName\"] },\n * };\n *\n * const { resolved } = resolveConditions(form, { accountType: \"business\" }, engine);\n * // → resolved no longer has if/then/else, but has required: [\"companyName\"]\n * ```\n */\nexport function resolveConditions(\n\tschema: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tengine: MergeEngine,\n): ResolvedConditionResult {\n\tlet branch: \"then\" | \"else\" | null = null;\n\tconst discriminant: Record<string, unknown> = {};\n\n\t// ── Fast path: no conditions at all ──\n\t// If there's no `if` and no `allOf` with conditions, skip the copy entirely.\n\tconst hasTopLevelIf = schema.if !== undefined;\n\tconst hasAllOfConditions =\n\t\tArray.isArray(schema.allOf) &&\n\t\tschema.allOf.some(\n\t\t\t(e) => typeof e !== \"boolean\" && hasOwn(e as object, \"if\"),\n\t\t);\n\n\tif (!hasTopLevelIf && !hasAllOfConditions) {\n\t\t// Phase 3 only: check nested properties (resolveNestedProperties\n\t\t// already returns the original if nothing changes)\n\t\tconst resolved = resolveNestedProperties(\n\t\t\tschema,\n\t\t\tdata,\n\t\t\tengine,\n\t\t\tdiscriminant,\n\t\t);\n\t\treturn { resolved, branch, discriminant };\n\t}\n\n\t// ── Copy-on-write: only copy when mutations are needed ──\n\tlet resolved = { ...schema };\n\n\t// ── Phase 1: Resolve if/then/else in allOf ──\n\tif (hasAllOfConditions) {\n\t\tresolved = resolveAllOfConditions(resolved, data, engine, discriminant);\n\t}\n\n\t// ── Phase 2: Resolve if/then/else at this level ──\n\tif (resolved.if !== undefined) {\n\t\tconst ifSchema = resolved.if as JSONSchema7;\n\t\tconst matches = evaluateCondition(ifSchema, data);\n\n\t\textractDiscriminants(ifSchema, data, discriminant);\n\n\t\tconst applicableBranch = matches ? resolved.then : resolved.else;\n\t\tbranch = matches ? \"then\" : \"else\";\n\n\t\tif (applicableBranch) {\n\t\t\tmergeBranchInto(\n\t\t\t\tresolved,\n\t\t\t\tapplicableBranch as JSONSchema7Definition,\n\t\t\t\tengine,\n\t\t\t);\n\t\t}\n\n\t\tdelete resolved.if;\n\t\tdelete resolved.then;\n\t\tdelete resolved.else;\n\t}\n\n\t// ── Phase 3: Recurse into properties ──\n\tresolved = resolveNestedProperties(resolved, data, engine, discriminant);\n\n\treturn { resolved, branch, discriminant };\n}\n\n// ─── Internal phases ─────────────────────────────────────────────────────────\n\n/**\n * Phase 1: Iterates over `allOf` entries and resolves those containing\n * an `if/then/else`. Non-conditional entries are preserved.\n *\n\n */\nfunction resolveAllOfConditions(\n\tresolved: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tengine: MergeEngine,\n\tdiscriminant: Record<string, unknown>,\n): JSONSchema7 {\n\tif (!Array.isArray(resolved.allOf)) return resolved;\n\n\tconst remainingAllOf: JSONSchema7Definition[] = [];\n\n\tfor (const entry of resolved.allOf) {\n\t\tif (typeof entry === \"boolean\") {\n\t\t\tremainingAllOf.push(entry);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst subSchema = entry as JSONSchema7;\n\n\t\tif (subSchema.if === undefined) {\n\t\t\tremainingAllOf.push(entry);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Resolve the condition of this allOf entry\n\t\tconst ifSchema = subSchema.if as JSONSchema7;\n\t\tconst matches = evaluateCondition(ifSchema, data);\n\n\t\textractDiscriminants(ifSchema, data, discriminant);\n\n\t\tconst applicableBranch = matches ? subSchema.then : subSchema.else;\n\n\t\tif (applicableBranch) {\n\t\t\tmergeBranchInto(\n\t\t\t\tresolved,\n\t\t\t\tapplicableBranch as JSONSchema7Definition,\n\t\t\t\tengine,\n\t\t\t);\n\t\t}\n\n\t\t// Keep non-conditional parts of the allOf entry\n\t\tconst remaining = omitKeys(\n\t\t\tsubSchema as unknown as Record<string, unknown>,\n\t\t\t[\"if\", \"then\", \"else\"],\n\t\t);\n\t\tif (Object.keys(remaining).length > 0) {\n\t\t\tremainingAllOf.push(remaining as JSONSchema7);\n\t\t}\n\t}\n\n\tresolved = { ...resolved };\n\tif (remainingAllOf.length === 0) {\n\t\tdelete resolved.allOf;\n\t} else {\n\t\tresolved.allOf = remainingAllOf;\n\t}\n\n\treturn resolved;\n}\n\n/**\n * Phase 3: Recurses into the `properties` of the resolved schema to resolve\n * nested conditions (e.g. an object whose property has an if/then/else).\n *\n\n */\nfunction resolveNestedProperties(\n\tresolved: JSONSchema7,\n\tdata: Record<string, unknown>,\n\tengine: MergeEngine,\n\tdiscriminant: Record<string, unknown>,\n): JSONSchema7 {\n\tif (!isPlainObj(resolved.properties)) return resolved;\n\n\tconst props = resolved.properties as Record<string, JSONSchema7Definition>;\n\tconst propKeys = Object.keys(props);\n\tlet changed = false;\n\tconst resolvedProps: Record<string, JSONSchema7Definition> = {};\n\n\tfor (const key of propKeys) {\n\t\tconst propDef = props[key];\n\t\tif (propDef === undefined) continue;\n\t\tif (typeof propDef === \"boolean\") {\n\t\t\tresolvedProps[key] = propDef;\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst propSchema = propDef as JSONSchema7;\n\t\tconst hasConditions =\n\t\t\tpropSchema.if !== undefined ||\n\t\t\t(Array.isArray(propSchema.allOf) &&\n\t\t\t\tpropSchema.allOf.some(\n\t\t\t\t\t(e) => typeof e !== \"boolean\" && hasOwn(e as object, \"if\"),\n\t\t\t\t));\n\n\t\tif (!hasConditions) {\n\t\t\tresolvedProps[key] = propDef;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Nested data available → resolve recursively\n\t\tconst nestedData = isPlainObj(data[key])\n\t\t\t? (data[key] as Record<string, unknown>)\n\t\t\t: {};\n\n\t\tconst nested = resolveConditions(propSchema, nestedData, engine);\n\n\t\t// Propagate nested discriminants with prefix\n\t\tfor (const dk of Object.keys(nested.discriminant)) {\n\t\t\tdiscriminant[`${key}.${dk}`] = nested.discriminant[dk];\n\t\t}\n\n\t\tresolvedProps[key] = nested.resolved;\n\t\tchanged = true;\n\t}\n\n\treturn changed ? { ...resolved, properties: resolvedProps } : resolved;\n}\n"],"names":["isDataValidForSchema","deepEqual","hasOwn","isPlainObj","mergeConstraints","omitKeys","unionStrings","SPECIAL_MERGE_KEYS","Set","SUB_SCHEMA_KEYS","MIN_KEYS","MAX_KEYS","evaluateCondition","ifSchema","data","DISCRIMINANT_INDICATORS","extractDiscriminants","out","properties","props","key","Object","keys","propDef","prop","hasIndicator","some","indicator","mergeBranchInto","resolved","branchDef","engine","branchSchema","Array","isArray","required","branchProps","mergedProps","branchProp","undefined","existing","merged","merge","mergedProp","existingObj","branchObj","unionedConstraints","constraints","dependencies","resolvedDeps","branchDeps","acc","depKey","branchVal","existingVal","has","resolvedVal","Math","max","min","base","branch","resolveConditions","schema","discriminant","hasTopLevelIf","if","hasAllOfConditions","allOf","e","resolveNestedProperties","resolveAllOfConditions","matches","applicableBranch","then","else","remainingAllOf","entry","push","subSchema","remaining","length","propKeys","changed","resolvedProps","propSchema","hasConditions","nestedData","nested","dk"],"mappings":"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"}
|
|
@@ -8,13 +8,13 @@ import type { ConstraintValidatorRegistry, SchemaError } from "./types.js";
|
|
|
8
8
|
* `items` (single schema and tuple form), `additionalProperties` (schema form),
|
|
9
9
|
* `dependencies` (schema form).
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* When a schema declares a constraint that is not present in the registry,
|
|
12
|
+
* an "unknown constraint (not registered)" error is produced. This ensures
|
|
13
|
+
* that unregistered constraints are never silently ignored at runtime.
|
|
14
14
|
*
|
|
15
15
|
* @param schema - The resolved/narrowed schema containing constraints
|
|
16
16
|
* @param data - The runtime data to validate
|
|
17
|
-
* @param registry - The constraint validator registry (
|
|
17
|
+
* @param registry - The constraint validator registry (may be empty)
|
|
18
18
|
* @param path - The current property path (for error reporting)
|
|
19
19
|
* @returns Array of schema errors (empty if all constraints pass)
|
|
20
20
|
*/
|