schema-components 1.19.0 → 1.20.0

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.
Files changed (62) hide show
  1. package/dist/core/adapter.d.mts +2 -2
  2. package/dist/core/adapter.mjs +59 -9
  3. package/dist/core/constraints.d.mts +2 -2
  4. package/dist/core/diagnostics.d.mts +1 -1
  5. package/dist/core/errors.d.mts +1 -1
  6. package/dist/core/errors.mjs +9 -1
  7. package/dist/core/fieldOrder.d.mts +1 -1
  8. package/dist/core/formats.d.mts +21 -14
  9. package/dist/core/formats.mjs +88 -4
  10. package/dist/core/merge.d.mts +1 -1
  11. package/dist/core/normalise.d.mts +2 -2
  12. package/dist/core/normalise.mjs +1 -1
  13. package/dist/core/openapi30.mjs +1 -1
  14. package/dist/core/ref.d.mts +1 -1
  15. package/dist/core/renderer.d.mts +1 -1
  16. package/dist/core/swagger2.d.mts +1 -1
  17. package/dist/core/swagger2.mjs +1 -1
  18. package/dist/core/typeInference.d.mts +2 -2
  19. package/dist/core/types.d.mts +1 -1
  20. package/dist/core/uri.d.mts +41 -0
  21. package/dist/core/uri.mjs +76 -0
  22. package/dist/core/version.d.mts +2 -2
  23. package/dist/core/version.mjs +25 -1
  24. package/dist/core/walkBuilders.d.mts +3 -3
  25. package/dist/core/walker.d.mts +1 -1
  26. package/dist/core/walker.mjs +50 -3
  27. package/dist/{diagnostics-VgEKI_Ct.d.mts → diagnostics-CbBPsxSt.d.mts} +1 -1
  28. package/dist/{errors-CnGjT1cg.d.mts → errors-C2iABcn9.d.mts} +8 -1
  29. package/dist/html/a11y.d.mts +2 -2
  30. package/dist/html/renderToHtml.d.mts +2 -2
  31. package/dist/html/renderToHtmlStream.d.mts +2 -2
  32. package/dist/html/renderers.d.mts +2 -2
  33. package/dist/html/renderers.mjs +9 -2
  34. package/dist/html/streamRenderers.d.mts +2 -2
  35. package/dist/{normalise-C0ofw3W6.mjs → normalise-CMMEl4cd.mjs} +255 -18
  36. package/dist/openapi/ApiCallbacks.d.mts +1 -1
  37. package/dist/openapi/ApiLinks.d.mts +1 -1
  38. package/dist/openapi/ApiResponseHeaders.d.mts +1 -1
  39. package/dist/openapi/ApiSecurity.d.mts +1 -1
  40. package/dist/openapi/bundle.mjs +2 -0
  41. package/dist/openapi/components.d.mts +2 -2
  42. package/dist/openapi/components.mjs +16 -5
  43. package/dist/openapi/parser.d.mts +1 -1
  44. package/dist/openapi/parser.mjs +2 -0
  45. package/dist/openapi/resolve.d.mts +11 -1
  46. package/dist/openapi/resolve.mjs +39 -2
  47. package/dist/react/SchemaComponent.d.mts +21 -9
  48. package/dist/react/SchemaView.d.mts +3 -3
  49. package/dist/react/fieldPath.d.mts +1 -1
  50. package/dist/react/headless.d.mts +1 -1
  51. package/dist/react/headlessRenderers.d.mts +2 -2
  52. package/dist/react/headlessRenderers.mjs +18 -6
  53. package/dist/{ref-Bb43ZURY.d.mts → ref-C8JbwfiS.d.mts} +1 -1
  54. package/dist/{renderer-BQqiXUYP.d.mts → renderer-SOIbJBtk.d.mts} +1 -1
  55. package/dist/themes/mantine.d.mts +1 -1
  56. package/dist/themes/mui.d.mts +1 -1
  57. package/dist/themes/radix.d.mts +1 -1
  58. package/dist/themes/shadcn.d.mts +1 -1
  59. package/dist/{typeInference-5JiqIZ8t.d.mts → typeInference-CDoD_LZ_.d.mts} +187 -42
  60. package/dist/{types-D_5ST7SS.d.mts → types-C9zw9wbX.d.mts} +6 -0
  61. package/dist/{version-XNH7PRGP.d.mts → version-D-u7aMfy.d.mts} +36 -1
  62. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
- import { T as SchemaMeta, m as JsonObject } from "../types-D_5ST7SS.mjs";
2
- import { i as DiagnosticsOptions } from "../diagnostics-VgEKI_Ct.mjs";
1
+ import { T as SchemaMeta, m as JsonObject } from "../types-C9zw9wbX.mjs";
2
+ import { i as DiagnosticsOptions } from "../diagnostics-CbBPsxSt.mjs";
3
3
 
4
4
  //#region src/core/adapter.d.ts
5
5
  type SchemaInput = Record<string, unknown>;
@@ -3,7 +3,7 @@ import { SchemaNormalisationError } from "./errors.mjs";
3
3
  import { emitDiagnostic } from "./diagnostics.mjs";
4
4
  import { dereference } from "./ref.mjs";
5
5
  import { detectOpenApiVersion, inferJsonSchemaDraftWithReason, isSwagger2, matchJsonSchemaDraftUri } from "./version.mjs";
6
- import { a as normaliseOpenApiSchemas, i as normaliseJsonSchema$1 } from "../normalise-C0ofw3W6.mjs";
6
+ import { a as normaliseOpenApiSchemas, i as normaliseJsonSchema$1 } from "../normalise-CMMEl4cd.mjs";
7
7
  import { z } from "zod";
8
8
  //#region src/core/adapter.ts
9
9
  /**
@@ -39,9 +39,19 @@ function detectSchemaKind(input) {
39
39
  * - Nested Zod 3 schemas inside a Zod 4 tree (which surface as
40
40
  * "Cannot read properties of undefined (reading 'def')") → zod3-unsupported
41
41
  * - Transforms ("Transforms cannot be represented") → zod-transform-unsupported
42
- * - Unrepresentable types ("BigInt cannot be represented", "Date cannot be
43
- * represented", etc.) → zod-type-unrepresentable
42
+ * - Dynamic catch values whose handler throws ("Dynamic catch values are not
43
+ * supported") → zod-type-unrepresentable with zodType "dynamic-catch"
44
+ * - Unrepresentable types — bigint, date, map, set, symbol, function, custom,
45
+ * undefined, void, NaN, and the literal-only forms `z.literal(undefined)`
46
+ * ("undefined-literal") and `z.literal(<bigint>)` ("bigint-literal") →
47
+ * zod-type-unrepresentable
48
+ * - The catch-all "Non-representable type encountered: <type>" fallback Zod
49
+ * emits for any new schema kind without a registered processor →
50
+ * zod-type-unrepresentable with zodType set to the offending def.type
44
51
  * - Anything else → zod-conversion-failed
52
+ *
53
+ * The original error is preserved on each classified error via the `cause`
54
+ * field so consumers can still inspect the Zod stack trace.
45
55
  */
46
56
  function callToJsonSchema(schema) {
47
57
  try {
@@ -55,20 +65,53 @@ function callToJsonSchema(schema) {
55
65
  * Mapping is exact-prefix on the message and the corresponding Zod type name
56
66
  * surfaced to the consumer via SchemaNormalisationError.zodType.
57
67
  *
58
- * Source: zod/src/v4/core/to-json-schema.ts ("cannot be represented" messages).
68
+ * Sources (verbatim message prefixes):
69
+ * - zod/src/v4/core/json-schema-processors.ts L104 (bigint), L110 (symbol),
70
+ * L126 (undefined), L132 (void), L150 (date), L169 (literal-undefined),
71
+ * L175 (literal-bigint), L204 (NaN), L246 (custom), L252 (function),
72
+ * L264 (map), L270 (set), L521 (dynamic catch).
73
+ * - zod/src/v4/core/to-json-schema.ts L182 (non-representable type fallback).
74
+ *
75
+ * The kept message prefix is the shortest substring that uniquely identifies
76
+ * the source — the test in tests/zod-error-wording-contract.unit.test.ts
77
+ * asserts each prefix is still present in the live Zod output so a Zod
78
+ * patch upgrade that changes wording fails the build.
79
+ *
80
+ * Note: the more specific literal-* prefixes precede the generic "BigInt"
81
+ * prefix so the literal classifications win. JavaScript object iteration
82
+ * order preserves insertion order, and the loop short-circuits on first
83
+ * match, so ordering here is load-bearing.
59
84
  */
60
85
  const UNREPRESENTABLE_ZOD_TYPES = [
86
+ ["Literal `undefined` cannot be represented", "undefined-literal"],
87
+ ["BigInt literals cannot be represented", "bigint-literal"],
61
88
  ["BigInt cannot be represented", "bigint"],
62
89
  ["Date cannot be represented", "date"],
63
90
  ["Map cannot be represented", "map"],
64
91
  ["Set cannot be represented", "set"],
65
92
  ["Symbols cannot be represented", "symbol"],
66
93
  ["Function types cannot be represented", "function"],
94
+ ["Custom types cannot be represented", "custom"],
67
95
  ["Undefined cannot be represented", "undefined"],
68
96
  ["Void cannot be represented", "void"],
69
97
  ["NaN cannot be represented", "nan"]
70
98
  ];
71
99
  /**
100
+ * Marker for Zod's catch-all message when a brand-new schema type has no
101
+ * registered processor (e.g. ahead of a Zod patch adding a new schema kind).
102
+ *
103
+ * Source: zod/src/v4/core/to-json-schema.ts L182
104
+ * `[toJSONSchema]: Non-representable type encountered: ${def.type}`
105
+ */
106
+ const NON_REPRESENTABLE_TYPE_MARKER = "[toJSONSchema]: Non-representable type encountered:";
107
+ /**
108
+ * Marker for dynamic catch failures — Zod throws when `def.catchValue(...)`
109
+ * itself throws while building the JSON Schema default.
110
+ *
111
+ * Source: zod/src/v4/core/json-schema-processors.ts L521
112
+ */
113
+ const DYNAMIC_CATCH_MARKER = "Dynamic catch values are not supported";
114
+ /**
72
115
  * The cryptic error produced when z.toJSONSchema encounters a nested Zod 3
73
116
  * schema (one without `_zod.def`). Reproduced verbatim from Node's TypeError
74
117
  * for property access on undefined.
@@ -76,10 +119,17 @@ const UNREPRESENTABLE_ZOD_TYPES = [
76
119
  const NESTED_ZOD3_MARKER = "Cannot read properties of undefined";
77
120
  function classifyZodConversionError(err, schema) {
78
121
  const message = err instanceof Error ? err.message : String(err);
79
- if (message.includes(NESTED_ZOD3_MARKER)) return new SchemaNormalisationError("A nested Zod 3 schema was found inside a Zod 4 schema. schema-components requires Zod 4 throughout the schema tree. See the Zod 4 migration guide at https://zod.dev/v4/migration or run: pnpm add zod@^4", schema, "zod3-unsupported");
80
- if (message.includes("Transforms cannot be represented")) return new SchemaNormalisationError("Zod transforms cannot be represented in JSON Schema. Remove the .transform() call, or pre-transform the input before passing it to the component.", schema, "zod-transform-unsupported");
81
- for (const [prefix, typeName] of UNREPRESENTABLE_ZOD_TYPES) if (message.includes(prefix)) return new SchemaNormalisationError(`Zod type ${typeName} cannot be represented in JSON Schema and is not supported by schema-components. Original message: ${message}`, schema, "zod-type-unrepresentable", typeName);
82
- return new SchemaNormalisationError(`z.toJSONSchema() failed: ${message}`, schema, "zod-conversion-failed");
122
+ if (message.includes(NESTED_ZOD3_MARKER)) return new SchemaNormalisationError("A nested Zod 3 schema was found inside a Zod 4 schema. schema-components requires Zod 4 throughout the schema tree. See the Zod 4 migration guide at https://zod.dev/v4/migration or run: pnpm add zod@^4", schema, "zod3-unsupported", void 0, err);
123
+ if (message.includes("Transforms cannot be represented")) return new SchemaNormalisationError("Zod transforms cannot be represented in JSON Schema. Remove the .transform() call, or pre-transform the input before passing it to the component.", schema, "zod-transform-unsupported", void 0, err);
124
+ if (message.includes(DYNAMIC_CATCH_MARKER)) return new SchemaNormalisationError("Zod catch values that depend on runtime computation cannot be represented in JSON Schema. Provide a static catch value or remove the .catch() call.", schema, "zod-type-unrepresentable", "dynamic-catch", err);
125
+ for (const [prefix, typeName] of UNREPRESENTABLE_ZOD_TYPES) if (message.includes(prefix)) return new SchemaNormalisationError(`Zod type ${typeName} cannot be represented in JSON Schema and is not supported by schema-components. Original message: ${message}`, schema, "zod-type-unrepresentable", typeName, err);
126
+ const nonReprIndex = message.indexOf(NON_REPRESENTABLE_TYPE_MARKER);
127
+ if (nonReprIndex !== -1) {
128
+ const trailing = message.slice(nonReprIndex + 51).trim();
129
+ const typeName = trailing.length > 0 ? trailing.split(/\s+/)[0] : void 0;
130
+ return new SchemaNormalisationError(`Zod encountered a schema kind${typeName !== void 0 ? ` "${typeName}"` : ""} with no JSON Schema processor registered. This usually means Zod added a new schema type that schema-components does not yet support. Original message: ${message}`, schema, "zod-type-unrepresentable", typeName, err);
131
+ }
132
+ return new SchemaNormalisationError(`z.toJSONSchema() failed: ${message}`, schema, "zod-conversion-failed", void 0, err);
83
133
  }
84
134
  function normaliseSchema(input, ref, options) {
85
135
  if (ref === void 0 && isObject(input)) {
@@ -206,7 +256,7 @@ function resolveOpenApiRef(doc, ref) {
206
256
  if (!isObject(resolved)) throw new Error(`OpenAPI ref not found: ${ref}`);
207
257
  return resolved;
208
258
  }
209
- const pathMatch = /^\/(.+)\/(get|post|put|patch|delete)$/.exec(ref);
259
+ const pathMatch = /^\/(.+)\/(get|post|put|patch|delete|head|options|trace)$/.exec(ref);
210
260
  if (pathMatch?.[1] !== void 0 && pathMatch[2] !== void 0) {
211
261
  const pathStr = pathMatch[1];
212
262
  const method = pathMatch[2];
@@ -1,5 +1,5 @@
1
- import { D as StringConstraints, f as FileConstraints, t as ArrayConstraints, x as ObjectConstraints, y as NumberConstraints } from "../types-D_5ST7SS.mjs";
2
- import { i as DiagnosticsOptions } from "../diagnostics-VgEKI_Ct.mjs";
1
+ import { D as StringConstraints, f as FileConstraints, t as ArrayConstraints, x as ObjectConstraints, y as NumberConstraints } from "../types-C9zw9wbX.mjs";
2
+ import { i as DiagnosticsOptions } from "../diagnostics-CbBPsxSt.mjs";
3
3
 
4
4
  //#region src/core/constraints.d.ts
5
5
  declare function extractStringConstraints(schema: Record<string, unknown>, diagnostics?: DiagnosticsOptions, pointer?: string): StringConstraints;
@@ -1,2 +1,2 @@
1
- import { a as appendPointer, i as DiagnosticsOptions, n as DiagnosticCode, o as emitDiagnostic, r as DiagnosticSink, t as Diagnostic } from "../diagnostics-VgEKI_Ct.mjs";
1
+ import { a as appendPointer, i as DiagnosticsOptions, n as DiagnosticCode, o as emitDiagnostic, r as DiagnosticSink, t as Diagnostic } from "../diagnostics-CbBPsxSt.mjs";
2
2
  export { Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticsOptions, appendPointer, emitDiagnostic };
@@ -1,2 +1,2 @@
1
- import { i as SchemaRenderError, n as SchemaFieldError, r as SchemaNormalisationError, t as SchemaError } from "../errors-CnGjT1cg.mjs";
1
+ import { i as SchemaRenderError, n as SchemaFieldError, r as SchemaNormalisationError, t as SchemaError } from "../errors-C2iABcn9.mjs";
2
2
  export { SchemaError, SchemaFieldError, SchemaNormalisationError, SchemaRenderError };
@@ -37,11 +37,19 @@ var SchemaNormalisationError = class extends SchemaError {
37
37
  * (e.g. "bigint", "date", "map", "set"). `undefined` for other kinds.
38
38
  */
39
39
  zodType;
40
- constructor(message, schema, kind, zodType) {
40
+ /**
41
+ * The original underlying error, when this normalisation error wraps
42
+ * another exception (typically the error thrown by `z.toJSONSchema()`).
43
+ * Preserves the source stack trace so the root cause is not lost when
44
+ * the classifier translates the message.
45
+ */
46
+ cause;
47
+ constructor(message, schema, kind, zodType, cause) {
41
48
  super(message, schema);
42
49
  this.name = "SchemaNormalisationError";
43
50
  this.kind = kind;
44
51
  this.zodType = zodType;
52
+ this.cause = cause;
45
53
  }
46
54
  };
47
55
  /**
@@ -1,4 +1,4 @@
1
- import { M as WalkedField } from "../types-D_5ST7SS.mjs";
1
+ import { M as WalkedField } from "../types-C9zw9wbX.mjs";
2
2
 
3
3
  //#region src/core/fieldOrder.d.ts
4
4
  /**
@@ -1,18 +1,14 @@
1
+ import { i as DiagnosticsOptions } from "../diagnostics-CbBPsxSt.mjs";
2
+
1
3
  //#region src/core/formats.d.ts
2
4
  /**
3
- * Built-in format patterns for JSON Schema string validation.
4
- *
5
- * Maps standard JSON Schema/OpenAPI `format` values to RegExp patterns
6
- * or predicate validators. Used by the constraint extractor to derive
7
- * `formatPattern` alongside the existing `format` string, and by the
8
- * `validate` helper for runtime format checking.
9
- *
10
- * Formats that cannot be validated by regex (iri, regex) use predicate
11
- * functions instead. `validateFormat` dispatches to whichever is available.
12
- *
13
- * The user's explicit `pattern` constraint always takes precedence —
14
- * `formatPattern` is exposed as a separate field for renderers.
5
+ * Maximum length of a string that will be compiled by `new RegExp(...)`.
6
+ * Patterns that exceed this cap are rejected without compilation. A
7
+ * pathological pattern (e.g. `(a+)+`) doesn't need to be long to hang,
8
+ * but the cap is cheap defence and stops obviously hostile input before
9
+ * it reaches the regex engine.
15
10
  */
11
+ declare const MAX_REGEX_PATTERN_LENGTH = 500;
16
12
  /**
17
13
  * A format validator: either a RegExp pattern or a predicate function.
18
14
  */
@@ -21,13 +17,24 @@ type FormatValidator = RegExp | ((value: string) => boolean);
21
17
  * Recognised JSON Schema formats with their validation patterns.
22
18
  * Unknown formats emit an `unknown-format` diagnostic and skip derivation.
23
19
  */
20
+ /**
21
+ * Email format pattern, exported as a named const so callers that need a
22
+ * guaranteed `RegExp` (rather than the `RegExp | undefined` shape of
23
+ * `FORMAT_PATTERNS[name]` under `noUncheckedIndexedAccess`) can import it
24
+ * directly. Used by the URI safety helpers for mailto address checks.
25
+ */
26
+ declare const EMAIL_FORMAT_PATTERN: RegExp;
24
27
  declare const FORMAT_PATTERNS: Readonly<Record<string, RegExp>>;
25
28
  /**
26
29
  * Validate a string value against format constraints.
27
30
  * Returns `true` when the value matches the format,
28
31
  * `false` when it does not, and `undefined` when the format
29
32
  * is not recognised (no validator available).
33
+ *
34
+ * `diagnostics` and `pointer` are forwarded to validators that can
35
+ * surface structured diagnostics — currently the `regex` format, which
36
+ * emits `pattern-invalid` for over-length or malformed input.
30
37
  */
31
- declare function validateFormat(value: string, format: string): boolean | undefined;
38
+ declare function validateFormat(value: string, format: string, diagnostics?: DiagnosticsOptions, pointer?: string): boolean | undefined;
32
39
  //#endregion
33
- export { FORMAT_PATTERNS, FormatValidator, validateFormat };
40
+ export { EMAIL_FORMAT_PATTERN, FORMAT_PATTERNS, FormatValidator, MAX_REGEX_PATTERN_LENGTH, validateFormat };
@@ -1,11 +1,27 @@
1
+ import { emitDiagnostic } from "./diagnostics.mjs";
1
2
  //#region src/core/formats.ts
2
3
  /**
4
+ * Maximum length of a string that will be compiled by `new RegExp(...)`.
5
+ * Patterns that exceed this cap are rejected without compilation. A
6
+ * pathological pattern (e.g. `(a+)+`) doesn't need to be long to hang,
7
+ * but the cap is cheap defence and stops obviously hostile input before
8
+ * it reaches the regex engine.
9
+ */
10
+ const MAX_REGEX_PATTERN_LENGTH = 500;
11
+ /**
3
12
  * Recognised JSON Schema formats with their validation patterns.
4
13
  * Unknown formats emit an `unknown-format` diagnostic and skip derivation.
5
14
  */
15
+ /**
16
+ * Email format pattern, exported as a named const so callers that need a
17
+ * guaranteed `RegExp` (rather than the `RegExp | undefined` shape of
18
+ * `FORMAT_PATTERNS[name]` under `noUncheckedIndexedAccess`) can import it
19
+ * directly. Used by the URI safety helpers for mailto address checks.
20
+ */
21
+ const EMAIL_FORMAT_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
6
22
  const FORMAT_PATTERNS = {
7
23
  uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
8
- email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
24
+ email: EMAIL_FORMAT_PATTERN,
9
25
  "date-time": /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/,
10
26
  date: /^\d{4}-\d{2}-\d{2}$/,
11
27
  time: /^\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?$/,
@@ -27,11 +43,22 @@ const FORMAT_PATTERNS = {
27
43
  cidrv6: /^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|::|([0-9a-fA-F]{1,4})?::([0-9a-fA-F]{1,4}:?){0,6})\/(12[0-8]|1[01][0-9]|[1-9]?[0-9])$/,
28
44
  base64: /^$|^(?:[0-9a-zA-Z+/]{4})*(?:(?:[0-9a-zA-Z+/]{2}==)|(?:[0-9a-zA-Z+/]{3}=))?$/,
29
45
  base64url: /^[A-Za-z0-9_-]*$/,
30
- e164: /^\+[1-9]\d{6,14}$/
46
+ e164: /^\+[1-9]\d{6,14}$/,
47
+ emoji: /^(\p{Extended_Pictographic}|\p{Emoji_Component})+$/u,
48
+ ulid: /^[0-9A-HJKMNP-TV-Za-hjkmnp-tv-z]{26}$/,
49
+ xid: /^[0-9a-vA-V]{20}$/,
50
+ ksuid: /^[A-Za-z0-9]{27}$/,
51
+ lowercase: /^[^A-Z]*$/,
52
+ uppercase: /^[^a-z]*$/,
53
+ jwt: /^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]*$/
31
54
  };
32
55
  /**
33
56
  * Format validators that use predicate functions instead of regex.
34
57
  * These are checked in `validateFormat` when no regex pattern exists.
58
+ *
59
+ * The `regex` format is intentionally absent here — it requires a
60
+ * length cap and structured diagnostic emission and is handled via
61
+ * {@link validateRegexFormat} directly from {@link validateFormat}.
35
62
  */
36
63
  const PREDICATE_VALIDATORS = {
37
64
  iri: (value) => {
@@ -57,19 +84,76 @@ const PREDICATE_VALIDATORS = {
57
84
  } catch {
58
85
  return false;
59
86
  }
87
+ },
88
+ "json-string": (value) => {
89
+ try {
90
+ JSON.parse(value);
91
+ return true;
92
+ } catch {
93
+ return false;
94
+ }
60
95
  }
61
96
  };
62
97
  /**
98
+ * Validate that a string is a syntactically valid regular expression.
99
+ *
100
+ * Hardened against ReDoS-style abuse:
101
+ * - Values longer than {@link MAX_REGEX_PATTERN_LENGTH} are treated as
102
+ * "format unmatched" without ever being compiled.
103
+ * - Any `SyntaxError` thrown by `new RegExp(...)` (malformed pattern,
104
+ * invalid flags, unbalanced groups) is caught and treated as "format
105
+ * unmatched".
106
+ *
107
+ * In both cases a diagnostic is emitted when a sink is supplied so
108
+ * callers can surface the offending value to the schema author.
109
+ */
110
+ function validateRegexFormat(value, diagnostics, pointer) {
111
+ if (value.length > 500) {
112
+ emitDiagnostic(diagnostics, {
113
+ code: "pattern-invalid",
114
+ message: `Pattern length (${String(value.length)}) exceeds maximum (${String(500)}); treating as unmatched`,
115
+ pointer,
116
+ detail: {
117
+ reason: "length-exceeded",
118
+ length: value.length,
119
+ maxLength: 500
120
+ }
121
+ });
122
+ return false;
123
+ }
124
+ try {
125
+ new RegExp(value);
126
+ return true;
127
+ } catch (error) {
128
+ const message = error instanceof Error ? error.message : String(error);
129
+ emitDiagnostic(diagnostics, {
130
+ code: "pattern-invalid",
131
+ message: `Failed to compile pattern as RegExp: ${message}; treating as unmatched`,
132
+ pointer,
133
+ detail: {
134
+ reason: "compile-error",
135
+ error: message
136
+ }
137
+ });
138
+ return false;
139
+ }
140
+ }
141
+ /**
63
142
  * Validate a string value against format constraints.
64
143
  * Returns `true` when the value matches the format,
65
144
  * `false` when it does not, and `undefined` when the format
66
145
  * is not recognised (no validator available).
146
+ *
147
+ * `diagnostics` and `pointer` are forwarded to validators that can
148
+ * surface structured diagnostics — currently the `regex` format, which
149
+ * emits `pattern-invalid` for over-length or malformed input.
67
150
  */
68
- function validateFormat(value, format) {
151
+ function validateFormat(value, format, diagnostics, pointer = "") {
69
152
  const pattern = FORMAT_PATTERNS[format];
70
153
  if (pattern !== void 0) return pattern.test(value);
154
+ if (format === "regex") return validateRegexFormat(value, diagnostics, pointer);
71
155
  const predicate = PREDICATE_VALIDATORS[format];
72
156
  if (predicate !== void 0) return predicate(value);
73
157
  }
74
158
  //#endregion
75
- export { FORMAT_PATTERNS, validateFormat };
159
+ export { EMAIL_FORMAT_PATTERN, FORMAT_PATTERNS, MAX_REGEX_PATTERN_LENGTH, validateFormat };
@@ -1,4 +1,4 @@
1
- import { i as DiagnosticsOptions } from "../diagnostics-VgEKI_Ct.mjs";
1
+ import { i as DiagnosticsOptions } from "../diagnostics-CbBPsxSt.mjs";
2
2
 
3
3
  //#region src/core/merge.d.ts
4
4
  /**
@@ -1,5 +1,5 @@
1
- import { i as DiagnosticsOptions } from "../diagnostics-VgEKI_Ct.mjs";
2
- import { n as JsonSchemaDraft, r as OpenApiVersionInfo } from "../version-XNH7PRGP.mjs";
1
+ import { i as DiagnosticsOptions } from "../diagnostics-CbBPsxSt.mjs";
2
+ import { i as OpenApiVersionInfo, r as JsonSchemaDraft } from "../version-D-u7aMfy.mjs";
3
3
 
4
4
  //#region src/core/normalise.d.ts
5
5
  type NodeTransform = (node: Record<string, unknown>) => Record<string, unknown>;
@@ -1,2 +1,2 @@
1
- import { a as normaliseOpenApiSchemas, i as normaliseJsonSchema, n as deepNormaliseWithContext, r as normaliseDraft04Node, t as deepNormalise } from "../normalise-C0ofw3W6.mjs";
1
+ import { a as normaliseOpenApiSchemas, i as normaliseJsonSchema, n as deepNormaliseWithContext, r as normaliseDraft04Node, t as deepNormalise } from "../normalise-CMMEl4cd.mjs";
2
2
  export { deepNormalise, deepNormaliseWithContext, normaliseDraft04Node, normaliseJsonSchema, normaliseOpenApiSchemas };
@@ -1,2 +1,2 @@
1
- import { c as deepNormaliseOpenApiDoc, d as normaliseOpenApi30Node, l as normaliseOpenApi30Combined, s as deepNormaliseOpenApi30Doc, u as normaliseOpenApi30Discriminator } from "../normalise-C0ofw3W6.mjs";
1
+ import { c as deepNormaliseOpenApiDoc, d as normaliseOpenApi30Node, l as normaliseOpenApi30Combined, s as deepNormaliseOpenApi30Doc, u as normaliseOpenApi30Discriminator } from "../normalise-CMMEl4cd.mjs";
2
2
  export { deepNormaliseOpenApi30Doc, deepNormaliseOpenApiDoc, normaliseOpenApi30Combined, normaliseOpenApi30Discriminator, normaliseOpenApi30Node };
@@ -1,2 +1,2 @@
1
- import { a as findAnchor, i as dereference, n as RefOptions, o as resolveRef, r as countDistinctRefs, t as ExternalResolver } from "../ref-Bb43ZURY.mjs";
1
+ import { a as findAnchor, i as dereference, n as RefOptions, o as resolveRef, r as countDistinctRefs, t as ExternalResolver } from "../ref-C8JbwfiS.mjs";
2
2
  export { ExternalResolver, RefOptions, countDistinctRefs, dereference, findAnchor, resolveRef };
@@ -1,2 +1,2 @@
1
- import { a as HtmlRenderProps, c as RenderFunction, d as getHtmlRenderFn, f as getRenderFunction, h as typeToKey, i as HtmlRenderFunction, l as RenderProps, m as mergeResolvers, n as BaseFieldProps, o as HtmlResolver, p as mergeHtmlResolvers, r as ComponentResolver, s as RESOLVER_KEYS, t as AllConstraints, u as buildRenderProps } from "../renderer-BQqiXUYP.mjs";
1
+ import { a as HtmlRenderProps, c as RenderFunction, d as getHtmlRenderFn, f as getRenderFunction, h as typeToKey, i as HtmlRenderFunction, l as RenderProps, m as mergeResolvers, n as BaseFieldProps, o as HtmlResolver, p as mergeHtmlResolvers, r as ComponentResolver, s as RESOLVER_KEYS, t as AllConstraints, u as buildRenderProps } from "../renderer-SOIbJBtk.mjs";
2
2
  export { AllConstraints, BaseFieldProps, ComponentResolver, HtmlRenderFunction, HtmlRenderProps, HtmlResolver, RESOLVER_KEYS, RenderFunction, RenderProps, buildRenderProps, getHtmlRenderFn, getRenderFunction, mergeHtmlResolvers, mergeResolvers, typeToKey };
@@ -1,4 +1,4 @@
1
- import { i as DiagnosticsOptions } from "../diagnostics-VgEKI_Ct.mjs";
1
+ import { i as DiagnosticsOptions } from "../diagnostics-CbBPsxSt.mjs";
2
2
  import { NodeTransform } from "./normalise.mjs";
3
3
 
4
4
  //#region src/core/swagger2.d.ts
@@ -1,2 +1,2 @@
1
- import { o as normaliseSwagger2Document } from "../normalise-C0ofw3W6.mjs";
1
+ import { o as normaliseSwagger2Document } from "../normalise-CMMEl4cd.mjs";
2
2
  export { normaliseSwagger2Document };
@@ -1,2 +1,2 @@
1
- import { a as InferResponseFields, c as PathOfType, d as UnsafeFields, f as __SchemaInferenceFellBack, i as InferRequestBodyFields, l as ResolveOpenAPIRef, n as FromJSONSchema, o as OpenAPIRequestBodyType, r as InferParameterOverrides, s as OpenAPIResponseType, t as DEFAULT_MAX_DEPTH, u as TypeAtPath } from "../typeInference-5JiqIZ8t.mjs";
2
- export { DEFAULT_MAX_DEPTH, FromJSONSchema, InferParameterOverrides, InferRequestBodyFields, InferResponseFields, OpenAPIRequestBodyType, OpenAPIResponseType, PathOfType, ResolveOpenAPIRef, TypeAtPath, UnsafeFields, __SchemaInferenceFellBack };
1
+ import { a as InferResponseFields, c as PathOfType, d as TypeAtPath, f as UnrepresentableZodSchemaError, h as __SchemaInferenceFellBack, i as InferRequestBodyFields, l as RejectUnrepresentableZod, m as UnsafeFields, n as FromJSONSchema, o as OpenAPIRequestBodyType, p as UnrepresentableZodType, r as InferParameterOverrides, s as OpenAPIResponseType, t as DEFAULT_MAX_DEPTH, u as ResolveOpenAPIRef } from "../typeInference-CDoD_LZ_.mjs";
2
+ export { DEFAULT_MAX_DEPTH, FromJSONSchema, InferParameterOverrides, InferRequestBodyFields, InferResponseFields, OpenAPIRequestBodyType, OpenAPIResponseType, PathOfType, RejectUnrepresentableZod, ResolveOpenAPIRef, TypeAtPath, UnrepresentableZodSchemaError, UnrepresentableZodType, UnsafeFields, __SchemaInferenceFellBack };
@@ -1,2 +1,2 @@
1
- import { A as UnionField, B as isNegationField, C as RecordField, D as StringConstraints, E as SchemaType, F as isConditionalField, G as isRecordField, H as isNullField, I as isDiscriminatedUnionField, J as isTupleField, K as isRecursiveField, L as isEnumField, M as WalkedField, N as isArrayField, O as StringField, P as isBooleanField, R as isFileField, S as ObjectField, T as SchemaMeta, U as isNumberField, V as isNeverField, W as isObjectField, X as isUnknownField, Y as isUnionField, Z as resolveEditability, _ as NeverField, a as DiscriminatedUnionField, b as NumberField, c as FieldBase, d as FieldOverrides, f as FileConstraints, g as NegationField, h as LiteralField, i as ConditionalField, j as UnknownField, k as TupleField, l as FieldConstraints, m as JsonObject, n as ArrayField, o as Editability, p as FileField, q as isStringField, r as BooleanField, s as EnumField, t as ArrayConstraints, u as FieldOverride, v as NullField, w as RecursiveField, x as ObjectConstraints, y as NumberConstraints, z as isLiteralField } from "../types-D_5ST7SS.mjs";
1
+ import { A as UnionField, B as isNegationField, C as RecordField, D as StringConstraints, E as SchemaType, F as isConditionalField, G as isRecordField, H as isNullField, I as isDiscriminatedUnionField, J as isTupleField, K as isRecursiveField, L as isEnumField, M as WalkedField, N as isArrayField, O as StringField, P as isBooleanField, R as isFileField, S as ObjectField, T as SchemaMeta, U as isNumberField, V as isNeverField, W as isObjectField, X as isUnknownField, Y as isUnionField, Z as resolveEditability, _ as NeverField, a as DiscriminatedUnionField, b as NumberField, c as FieldBase, d as FieldOverrides, f as FileConstraints, g as NegationField, h as LiteralField, i as ConditionalField, j as UnknownField, k as TupleField, l as FieldConstraints, m as JsonObject, n as ArrayField, o as Editability, p as FileField, q as isStringField, r as BooleanField, s as EnumField, t as ArrayConstraints, u as FieldOverride, v as NullField, w as RecursiveField, x as ObjectConstraints, y as NumberConstraints, z as isLiteralField } from "../types-C9zw9wbX.mjs";
2
2
  export { ArrayConstraints, ArrayField, BooleanField, ConditionalField, DiscriminatedUnionField, Editability, EnumField, FieldBase, FieldConstraints, FieldOverride, FieldOverrides, FileConstraints, FileField, JsonObject, LiteralField, NegationField, NeverField, NullField, NumberConstraints, NumberField, ObjectConstraints, ObjectField, RecordField, RecursiveField, SchemaMeta, SchemaType, StringConstraints, StringField, TupleField, UnionField, UnknownField, WalkedField, isArrayField, isBooleanField, isConditionalField, isDiscriminatedUnionField, isEnumField, isFileField, isLiteralField, isNegationField, isNeverField, isNullField, isNumberField, isObjectField, isRecordField, isRecursiveField, isStringField, isTupleField, isUnionField, isUnknownField, resolveEditability };
@@ -0,0 +1,41 @@
1
+ //#region src/core/uri.d.ts
2
+ /**
3
+ * URI safety helpers shared by HTML and React renderers.
4
+ *
5
+ * User-supplied URI values flow into anchor `href` attributes. Without
6
+ * scheme validation a value such as `javascript:alert(1)` becomes a
7
+ * clickable XSS sink — HTML escaping does not help, since the dangerous
8
+ * payload sits inside the scheme rather than the body of the attribute.
9
+ *
10
+ * These helpers exist so the HTML renderer (`html/renderers.ts`) and the
11
+ * React renderer (`react/headlessRenderers.tsx`) apply identical rules
12
+ * when deciding whether a string is safe to render as an `href`.
13
+ */
14
+ /**
15
+ * Decide whether `value` is safe to use as an anchor `href`.
16
+ *
17
+ * Returns `true` when the value is either a relative reference (no scheme
18
+ * component) or an absolute URI using `http`/`https`. Returns `false`
19
+ * for any other scheme, including dangerous ones like `javascript:` and
20
+ * `data:`.
21
+ */
22
+ declare function isSafeHyperlink(value: string): boolean;
23
+ /**
24
+ * Decide whether `value` is safe to interpolate into a `mailto:` URI.
25
+ *
26
+ * The check rejects values that do not match the standard email format
27
+ * pattern. The format pattern excludes whitespace, which means a CRLF
28
+ * sequence (or its percent-encoded form embedded by the caller) cannot
29
+ * pass — eliminating the SMTP/`mailto` header-injection vector.
30
+ */
31
+ declare function isSafeMailtoAddress(value: string): boolean;
32
+ /**
33
+ * Decide whether `key` is one of the prototype-polluting property names
34
+ * (`__proto__`, `constructor`, `prototype`).
35
+ *
36
+ * Used by JSON Pointer resolvers and by the JSON Schema `properties`
37
+ * walker to refuse traversal into these names.
38
+ */
39
+ declare function isPrototypePollutingKey(key: string): boolean;
40
+ //#endregion
41
+ export { isPrototypePollutingKey, isSafeHyperlink, isSafeMailtoAddress };
@@ -0,0 +1,76 @@
1
+ import { EMAIL_FORMAT_PATTERN } from "./formats.mjs";
2
+ //#region src/core/uri.ts
3
+ /**
4
+ * URI safety helpers shared by HTML and React renderers.
5
+ *
6
+ * User-supplied URI values flow into anchor `href` attributes. Without
7
+ * scheme validation a value such as `javascript:alert(1)` becomes a
8
+ * clickable XSS sink — HTML escaping does not help, since the dangerous
9
+ * payload sits inside the scheme rather than the body of the attribute.
10
+ *
11
+ * These helpers exist so the HTML renderer (`html/renderers.ts`) and the
12
+ * React renderer (`react/headlessRenderers.tsx`) apply identical rules
13
+ * when deciding whether a string is safe to render as an `href`.
14
+ */
15
+ /**
16
+ * Match the scheme portion of an absolute URI (RFC 3986 production
17
+ * `scheme ":"`). Leading ASCII whitespace is tolerated because browsers
18
+ * strip it before parsing the scheme; any other prefix (including raw
19
+ * control characters) keeps the value out of the safe-scheme branch.
20
+ */
21
+ const ABSOLUTE_URI_SCHEME = /^\s*([a-z][a-z0-9+\-.]*):/i;
22
+ /**
23
+ * Schemes safe to emit unmodified into an `href` attribute. Anything
24
+ * outside this set — most importantly `javascript:`, `data:`, `vbscript:`
25
+ * and `file:` — is rejected and rendered as text.
26
+ */
27
+ const SAFE_HYPERLINK_SCHEMES = new Set(["http", "https"]);
28
+ /**
29
+ * Decide whether `value` is safe to use as an anchor `href`.
30
+ *
31
+ * Returns `true` when the value is either a relative reference (no scheme
32
+ * component) or an absolute URI using `http`/`https`. Returns `false`
33
+ * for any other scheme, including dangerous ones like `javascript:` and
34
+ * `data:`.
35
+ */
36
+ function isSafeHyperlink(value) {
37
+ const match = ABSOLUTE_URI_SCHEME.exec(value);
38
+ if (match === null) return true;
39
+ const scheme = match[1];
40
+ if (scheme === void 0) return false;
41
+ return SAFE_HYPERLINK_SCHEMES.has(scheme.toLowerCase());
42
+ }
43
+ /**
44
+ * Decide whether `value` is safe to interpolate into a `mailto:` URI.
45
+ *
46
+ * The check rejects values that do not match the standard email format
47
+ * pattern. The format pattern excludes whitespace, which means a CRLF
48
+ * sequence (or its percent-encoded form embedded by the caller) cannot
49
+ * pass — eliminating the SMTP/`mailto` header-injection vector.
50
+ */
51
+ function isSafeMailtoAddress(value) {
52
+ return EMAIL_FORMAT_PATTERN.test(value);
53
+ }
54
+ /**
55
+ * Property names that must never be traversed via dynamic indexing on an
56
+ * untrusted object. Walking into any of these returns `Object.prototype`
57
+ * (or similar) and lets an attacker plant fields visible to every plain
58
+ * object in the runtime.
59
+ */
60
+ const PROTOTYPE_POLLUTING_KEYS = new Set([
61
+ "__proto__",
62
+ "constructor",
63
+ "prototype"
64
+ ]);
65
+ /**
66
+ * Decide whether `key` is one of the prototype-polluting property names
67
+ * (`__proto__`, `constructor`, `prototype`).
68
+ *
69
+ * Used by JSON Pointer resolvers and by the JSON Schema `properties`
70
+ * walker to refuse traversal into these names.
71
+ */
72
+ function isPrototypePollutingKey(key) {
73
+ return PROTOTYPE_POLLUTING_KEYS.has(key);
74
+ }
75
+ //#endregion
76
+ export { isPrototypePollutingKey, isSafeHyperlink, isSafeMailtoAddress };
@@ -1,2 +1,2 @@
1
- import { a as detectOpenApiVersion, c as isOpenApi30, d as matchJsonSchemaDraftUri, i as detectJsonSchemaDraft, l as isOpenApi31, n as JsonSchemaDraft, o as inferJsonSchemaDraft, r as OpenApiVersionInfo, s as inferJsonSchemaDraftWithReason, t as InferredDraft, u as isSwagger2 } from "../version-XNH7PRGP.mjs";
2
- export { InferredDraft, JsonSchemaDraft, OpenApiVersionInfo, detectJsonSchemaDraft, detectOpenApiVersion, inferJsonSchemaDraft, inferJsonSchemaDraftWithReason, isOpenApi30, isOpenApi31, isSwagger2, matchJsonSchemaDraftUri };
1
+ import { a as detectJsonSchemaDraft, c as inferJsonSchemaDraftWithReason, d as isSwagger2, f as matchJsonSchemaDraftUri, i as OpenApiVersionInfo, l as isOpenApi30, n as JsonSchemaDialectInfo, o as detectOpenApiVersion, p as readJsonSchemaDialect, r as JsonSchemaDraft, s as inferJsonSchemaDraft, t as InferredDraft, u as isOpenApi31 } from "../version-D-u7aMfy.mjs";
2
+ export { InferredDraft, JsonSchemaDialectInfo, JsonSchemaDraft, OpenApiVersionInfo, detectJsonSchemaDraft, detectOpenApiVersion, inferJsonSchemaDraft, inferJsonSchemaDraftWithReason, isOpenApi30, isOpenApi31, isSwagger2, matchJsonSchemaDraftUri, readJsonSchemaDialect };
@@ -157,5 +157,29 @@ function isOpenApi31(version) {
157
157
  function isSwagger2(version) {
158
158
  return version.major === 2;
159
159
  }
160
+ /**
161
+ * Inspect an OpenAPI 3.1 document for a `jsonSchemaDialect` declaration.
162
+ *
163
+ * Per the OpenAPI 3.1 spec, an OpenAPI document may declare the default
164
+ * JSON Schema dialect for its Schema Objects via the top-level
165
+ * `jsonSchemaDialect` URI. Real-world 3.1 documents overwhelmingly omit
166
+ * the keyword and rely on the spec-defined Draft 2020-12 default — this
167
+ * helper surfaces the declaration so the normaliser can either honour a
168
+ * known dialect or emit a diagnostic for an unknown one.
169
+ */
170
+ function readJsonSchemaDialect(doc) {
171
+ const value = doc.jsonSchemaDialect;
172
+ if (typeof value !== "string") return { kind: "absent" };
173
+ const draft = matchJsonSchemaDraftUri(value);
174
+ if (draft === void 0) return {
175
+ kind: "unknown",
176
+ uri: value
177
+ };
178
+ return {
179
+ kind: "known",
180
+ uri: value,
181
+ draft
182
+ };
183
+ }
160
184
  //#endregion
161
- export { detectJsonSchemaDraft, detectOpenApiVersion, inferJsonSchemaDraft, inferJsonSchemaDraftWithReason, isOpenApi30, isOpenApi31, isSwagger2, matchJsonSchemaDraftUri };
185
+ export { detectJsonSchemaDraft, detectOpenApiVersion, inferJsonSchemaDraft, inferJsonSchemaDraftWithReason, isOpenApi30, isOpenApi31, isSwagger2, matchJsonSchemaDraftUri, readJsonSchemaDialect };
@@ -1,6 +1,6 @@
1
- import { M as WalkedField, O as StringField, T as SchemaMeta, b as NumberField, c as FieldBase, j as UnknownField, o as Editability, p as FileField, r as BooleanField, v as NullField } from "../types-D_5ST7SS.mjs";
2
- import { i as DiagnosticsOptions } from "../diagnostics-VgEKI_Ct.mjs";
3
- import { t as ExternalResolver } from "../ref-Bb43ZURY.mjs";
1
+ import { M as WalkedField, O as StringField, T as SchemaMeta, b as NumberField, c as FieldBase, j as UnknownField, o as Editability, p as FileField, r as BooleanField, v as NullField } from "../types-C9zw9wbX.mjs";
2
+ import { i as DiagnosticsOptions } from "../diagnostics-CbBPsxSt.mjs";
3
+ import { t as ExternalResolver } from "../ref-C8JbwfiS.mjs";
4
4
 
5
5
  //#region src/core/walkBuilders.d.ts
6
6
  declare function getString(obj: Record<string, unknown>, key: string): string | undefined;
@@ -1,4 +1,4 @@
1
- import { M as WalkedField } from "../types-D_5ST7SS.mjs";
1
+ import { M as WalkedField } from "../types-C9zw9wbX.mjs";
2
2
  import { WalkOptions } from "./walkBuilders.mjs";
3
3
 
4
4
  //#region src/core/walker.d.ts