schema-components 1.19.0 → 1.21.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 (70) hide show
  1. package/dist/core/adapter.d.mts +10 -3
  2. package/dist/core/adapter.mjs +237 -31
  3. package/dist/core/constraints.d.mts +2 -2
  4. package/dist/core/constraints.mjs +0 -2
  5. package/dist/core/diagnostics.d.mts +1 -1
  6. package/dist/core/errors.d.mts +1 -1
  7. package/dist/core/errors.mjs +10 -8
  8. package/dist/core/fieldOrder.d.mts +1 -1
  9. package/dist/core/formats.d.mts +21 -14
  10. package/dist/core/formats.mjs +88 -4
  11. package/dist/core/merge.d.mts +11 -2
  12. package/dist/core/merge.mjs +11 -0
  13. package/dist/core/normalise.d.mts +9 -3
  14. package/dist/core/normalise.mjs +1 -1
  15. package/dist/core/openapi30.d.mts +24 -1
  16. package/dist/core/openapi30.mjs +2 -2
  17. package/dist/core/ref.d.mts +1 -1
  18. package/dist/core/ref.mjs +34 -9
  19. package/dist/core/renderer.d.mts +1 -1
  20. package/dist/core/swagger2.d.mts +1 -1
  21. package/dist/core/swagger2.mjs +1 -1
  22. package/dist/core/typeInference.d.mts +2 -2
  23. package/dist/core/types.d.mts +1 -1
  24. package/dist/core/uri.d.mts +41 -0
  25. package/dist/core/uri.mjs +76 -0
  26. package/dist/core/version.d.mts +2 -2
  27. package/dist/core/version.mjs +25 -1
  28. package/dist/core/walkBuilders.d.mts +13 -5
  29. package/dist/core/walkBuilders.mjs +11 -3
  30. package/dist/core/walker.d.mts +1 -1
  31. package/dist/core/walker.mjs +80 -26
  32. package/dist/{diagnostics-VgEKI_Ct.d.mts → diagnostics-CbBPsxSt.d.mts} +1 -1
  33. package/dist/{errors-CnGjT1cg.d.mts → errors-QEwOtQAA.d.mts} +8 -5
  34. package/dist/html/a11y.d.mts +2 -2
  35. package/dist/html/renderToHtml.d.mts +2 -2
  36. package/dist/html/renderToHtmlStream.d.mts +2 -2
  37. package/dist/html/renderers.d.mts +2 -2
  38. package/dist/html/renderers.mjs +9 -2
  39. package/dist/html/streamRenderers.d.mts +2 -2
  40. package/dist/{normalise-C0ofw3W6.mjs → normalise-DaSrnr8g.mjs} +574 -40
  41. package/dist/openapi/ApiCallbacks.d.mts +1 -1
  42. package/dist/openapi/ApiLinks.d.mts +1 -1
  43. package/dist/openapi/ApiResponseHeaders.d.mts +1 -1
  44. package/dist/openapi/ApiSecurity.d.mts +1 -1
  45. package/dist/openapi/ApiSecurity.mjs +113 -7
  46. package/dist/openapi/bundle.mjs +2 -0
  47. package/dist/openapi/components.d.mts +32 -10
  48. package/dist/openapi/components.mjs +37 -16
  49. package/dist/openapi/parser.d.mts +1 -1
  50. package/dist/openapi/parser.mjs +41 -4
  51. package/dist/openapi/resolve.d.mts +70 -9
  52. package/dist/openapi/resolve.mjs +124 -24
  53. package/dist/react/SchemaComponent.d.mts +21 -9
  54. package/dist/react/SchemaComponent.mjs +32 -4
  55. package/dist/react/SchemaView.d.mts +3 -3
  56. package/dist/react/fieldPath.d.mts +1 -1
  57. package/dist/react/headless.d.mts +1 -1
  58. package/dist/react/headlessRenderers.d.mts +2 -2
  59. package/dist/react/headlessRenderers.mjs +18 -6
  60. package/dist/{ref-Bb43ZURY.d.mts → ref-si8ViYun.d.mts} +7 -2
  61. package/dist/{renderer-BQqiXUYP.d.mts → renderer-DI6ZYf7a.d.mts} +1 -1
  62. package/dist/themes/mantine.d.mts +1 -1
  63. package/dist/themes/mui.d.mts +1 -1
  64. package/dist/themes/radix.d.mts +1 -1
  65. package/dist/themes/shadcn.d.mts +1 -1
  66. package/dist/typeInference-Bxw3NOG1.d.mts +647 -0
  67. package/dist/{types-D_5ST7SS.d.mts → types-BnxPEElk.d.mts} +18 -2
  68. package/dist/{version-XNH7PRGP.d.mts → version-D-u7aMfy.d.mts} +36 -1
  69. package/package.json +1 -1
  70. package/dist/typeInference-5JiqIZ8t.d.mts +0 -388
@@ -1,13 +1,19 @@
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>;
6
6
  /**
7
7
  * Deep-normalise a JSON Schema object by applying a per-node transform
8
8
  * and recursing into every sub-schema location.
9
+ *
10
+ * The optional `visited` set guards against shared object references and
11
+ * cycles introduced upstream (e.g. by the OpenAPI bundler's
12
+ * `structuredClone`-based inlining of external refs). The walk skips
13
+ * already-seen nodes by returning the original reference rather than
14
+ * recursing forever.
9
15
  */
10
- declare function deepNormalise(schema: Record<string, unknown>, transform: NodeTransform): Record<string, unknown>;
16
+ declare function deepNormalise(schema: Record<string, unknown>, transform: NodeTransform, visited?: WeakSet<object>): Record<string, unknown>;
11
17
  /**
12
18
  * Per-node context threaded through `deepNormaliseWithContext`.
13
19
  *
@@ -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-DaSrnr8g.mjs";
2
2
  export { deepNormalise, deepNormaliseWithContext, normaliseDraft04Node, normaliseJsonSchema, normaliseOpenApiSchemas };
@@ -23,6 +23,29 @@ declare function normaliseOpenApi30Node(node: Record<string, unknown>): Record<s
23
23
  * `mapping` or infers them from `$ref` fragment names.
24
24
  */
25
25
  declare function normaliseOpenApi30Discriminator(node: Record<string, unknown>): Record<string, unknown>;
26
+ /**
27
+ * Document-level pre-pass for OpenAPI discriminators that are declared
28
+ * on a base schema and inherited by subtypes via `allOf`.
29
+ *
30
+ * The per-node {@link normaliseOpenApi30Discriminator} only handles
31
+ * discriminators that already sit alongside `oneOf`/`anyOf`. For the
32
+ * canonical "Cat extends Pet" pattern — where `Pet` carries the
33
+ * discriminator and `Cat`/`Dog` reference `Pet` via `allOf` — the
34
+ * discriminator is silently lost. This pre-pass:
35
+ *
36
+ * 1. Injects the discriminator `const` on each subtype's local
37
+ * `properties` (so a direct render of the subtype validates the
38
+ * discriminator value correctly).
39
+ * 2. Synthesises a `oneOf` on the base whenever it lacks one, listing
40
+ * each subtype as `{ $ref, properties: { propertyName: { const } } }`.
41
+ * The per-node discriminator transform then sees `oneOf` and clears
42
+ * the `discriminator` keyword, and the walker's
43
+ * `detectDiscriminated` finds the per-option `const`s.
44
+ *
45
+ * Mutates a shallow clone of `components/schemas` — the input document
46
+ * is never modified.
47
+ */
48
+ declare function applyDiscriminatorAllOfPrepass(doc: Record<string, unknown>): Record<string, unknown>;
26
49
  /**
27
50
  * Combined OpenAPI 3.0.x node transform: Draft 04 + nullable + discriminator.
28
51
  * Applied to every schema node in an OpenAPI 3.0 document.
@@ -67,4 +90,4 @@ declare function deepNormaliseOpenApiDoc(doc: Record<string, unknown>, normalise
67
90
  */
68
91
  declare function deepNormaliseOpenApi30Doc(doc: Record<string, unknown>, deepNormalise: (schema: Record<string, unknown>, transform: NodeTransform) => Record<string, unknown>): Record<string, unknown>;
69
92
  //#endregion
70
- export { deepNormaliseOpenApi30Doc, deepNormaliseOpenApiDoc, normaliseOpenApi30Combined, normaliseOpenApi30Discriminator, normaliseOpenApi30Node };
93
+ export { applyDiscriminatorAllOfPrepass, deepNormaliseOpenApi30Doc, deepNormaliseOpenApiDoc, normaliseOpenApi30Combined, normaliseOpenApi30Discriminator, normaliseOpenApi30Node };
@@ -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";
2
- export { deepNormaliseOpenApi30Doc, deepNormaliseOpenApiDoc, normaliseOpenApi30Combined, normaliseOpenApi30Discriminator, normaliseOpenApi30Node };
1
+ import { c as deepNormaliseOpenApi30Doc, d as normaliseOpenApi30Discriminator, f as normaliseOpenApi30Node, l as deepNormaliseOpenApiDoc, s as applyDiscriminatorAllOfPrepass, u as normaliseOpenApi30Combined } from "../normalise-DaSrnr8g.mjs";
2
+ export { applyDiscriminatorAllOfPrepass, 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-si8ViYun.mjs";
2
2
  export { ExternalResolver, RefOptions, countDistinctRefs, dereference, findAnchor, resolveRef };
package/dist/core/ref.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import { isObject } from "./guards.mjs";
2
2
  import { emitDiagnostic } from "./diagnostics.mjs";
3
+ import { isPrototypePollutingKey } from "./uri.mjs";
3
4
  //#region src/core/ref.ts
4
5
  /**
5
6
  * $ref resolution for JSON Schema.
@@ -18,15 +19,27 @@ function getString(obj, key) {
18
19
  */
19
20
  function countDistinctRefs(root) {
20
21
  const refs = /* @__PURE__ */ new Set();
21
- collectRefs(root, refs);
22
+ collectRefs(root, refs, /* @__PURE__ */ new WeakSet());
22
23
  return Math.max(refs.size, 1);
23
24
  }
24
- function collectRefs(node, refs) {
25
+ /**
26
+ * The OpenAPI bundler (`bundleOpenApiDoc`) inlines external refs via
27
+ * `structuredClone`, which preserves shared object references and cycles.
28
+ * Without the `visited` set this walk would recurse forever on cyclic or
29
+ * diamond-shaped input. The set is a no-op for tree-shaped documents.
30
+ */
31
+ function collectRefs(node, refs, visited) {
25
32
  if (!isObject(node)) return;
33
+ if (visited.has(node)) return;
34
+ visited.add(node);
26
35
  const ref = node.$ref;
27
36
  if (typeof ref === "string") refs.add(ref);
28
- for (const value of Object.values(node)) if (isObject(value)) collectRefs(value, refs);
29
- else if (Array.isArray(value)) for (const item of value) collectRefs(item, refs);
37
+ for (const value of Object.values(node)) if (isObject(value)) collectRefs(value, refs, visited);
38
+ else if (Array.isArray(value)) {
39
+ if (visited.has(value)) continue;
40
+ visited.add(value);
41
+ for (const item of value) collectRefs(item, refs, visited);
42
+ }
30
43
  }
31
44
  /**
32
45
  * Resolve a `$ref` in a schema against a root document.
@@ -134,6 +147,7 @@ function dereference(ref, root) {
134
147
  for (const part of parts) {
135
148
  if (!isObject(current)) return void 0;
136
149
  const decoded = part.replace(/~1/g, "/").replace(/~0/g, "~");
150
+ if (isPrototypePollutingKey(decoded)) return void 0;
137
151
  current = current[decoded];
138
152
  }
139
153
  return isObject(current) ? current : void 0;
@@ -146,18 +160,29 @@ function dereference(ref, root) {
146
160
  /**
147
161
  * Recursively scan a schema document for a `$anchor` matching the given name.
148
162
  * Returns the schema object containing the anchor, or undefined.
163
+ *
164
+ * The optional `visited` set guards against shared object references and
165
+ * cycles introduced by the OpenAPI bundler's `structuredClone`-based
166
+ * inlining of external refs. Without it a recursive document would stack
167
+ * overflow before reaching the matching anchor.
149
168
  */
150
- function findAnchor(node, anchorName) {
169
+ function findAnchor(node, anchorName, visited = /* @__PURE__ */ new WeakSet()) {
151
170
  if (!isObject(node)) return void 0;
171
+ if (visited.has(node)) return void 0;
172
+ visited.add(node);
152
173
  if (node.$anchor === anchorName) return node;
153
174
  for (const value of Object.values(node)) {
154
175
  if (isObject(value)) {
155
- const found = findAnchor(value, anchorName);
176
+ const found = findAnchor(value, anchorName, visited);
156
177
  if (found !== void 0) return found;
157
178
  }
158
- if (Array.isArray(value)) for (const item of value) {
159
- const found = findAnchor(item, anchorName);
160
- if (found !== void 0) return found;
179
+ if (Array.isArray(value)) {
180
+ if (visited.has(value)) continue;
181
+ visited.add(value);
182
+ for (const item of value) {
183
+ const found = findAnchor(item, anchorName, visited);
184
+ if (found !== void 0) return found;
185
+ }
161
186
  }
162
187
  }
163
188
  }
@@ -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-DI6ZYf7a.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-DaSrnr8g.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-Bxw3NOG1.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-BnxPEElk.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-BnxPEElk.mjs";
2
+ import { i as DiagnosticsOptions } from "../diagnostics-CbBPsxSt.mjs";
3
+ import { t as ExternalResolver } from "../ref-si8ViYun.mjs";
4
4
 
5
5
  //#region src/core/walkBuilders.d.ts
6
6
  declare function getString(obj: Record<string, unknown>, key: string): string | undefined;
@@ -52,8 +52,16 @@ declare function buildBooleanField(schema: Record<string, unknown>, ctx: WalkCon
52
52
  declare function buildNullField(schema: Record<string, unknown>, ctx: WalkContext): NullField;
53
53
  declare function buildUnknownField(schema: Record<string, unknown>, ctx: WalkContext): UnknownField;
54
54
  declare function buildFileField(schema: Record<string, unknown>, ctx: WalkContext): FileField;
55
- /** Walk a map of sub-schemas (patternProperties, dependentSchemas). */
56
- declare function walkSubSchemaMap<T>(map: Record<string, unknown>, walkNode: (schema: Record<string, unknown>, ctx: WalkContext) => T, ctx: WalkContext): Record<string, T>;
55
+ /**
56
+ * Walk a map of sub-schemas (patternProperties, dependentSchemas, $defs).
57
+ *
58
+ * The callback receives each value as `unknown` so the caller can route
59
+ * boolean schemas (`true`/`false`, valid per Draft 06+) through the
60
+ * walker's boolean dispatch alongside object schemas. Non-schema values
61
+ * (numbers, strings, arrays, undefined) are silently skipped — they
62
+ * cannot represent a JSON Schema and have no walk-time meaning.
63
+ */
64
+ declare function walkSubSchemaMap<T>(map: Record<string, unknown>, walkSubSchema: (schema: unknown, ctx: WalkContext) => T, ctx: WalkContext): Record<string, T>;
57
65
  /** Walk a dependentRequired map (Record<string, string[]>). */
58
66
  declare function walkDependentRequiredMap(map: Record<string, unknown>): Record<string, string[]>;
59
67
  /**
@@ -124,10 +124,18 @@ function buildFileField(schema, ctx) {
124
124
  constraints: extractFileConstraints(schema)
125
125
  };
126
126
  }
127
- /** Walk a map of sub-schemas (patternProperties, dependentSchemas). */
128
- function walkSubSchemaMap(map, walkNode, ctx) {
127
+ /**
128
+ * Walk a map of sub-schemas (patternProperties, dependentSchemas, $defs).
129
+ *
130
+ * The callback receives each value as `unknown` so the caller can route
131
+ * boolean schemas (`true`/`false`, valid per Draft 06+) through the
132
+ * walker's boolean dispatch alongside object schemas. Non-schema values
133
+ * (numbers, strings, arrays, undefined) are silently skipped — they
134
+ * cannot represent a JSON Schema and have no walk-time meaning.
135
+ */
136
+ function walkSubSchemaMap(map, walkSubSchema, ctx) {
129
137
  const result = {};
130
- for (const [key, value] of Object.entries(map)) if (isObject(value)) result[key] = walkNode(value, ctx);
138
+ for (const [key, value] of Object.entries(map)) if (isObject(value) || typeof value === "boolean") result[key] = walkSubSchema(value, ctx);
131
139
  return result;
132
140
  }
133
141
  /** Walk a dependentRequired map (Record<string, string[]>). */
@@ -1,4 +1,4 @@
1
- import { M as WalkedField } from "../types-D_5ST7SS.mjs";
1
+ import { M as WalkedField } from "../types-BnxPEElk.mjs";
2
2
  import { WalkOptions } from "./walkBuilders.mjs";
3
3
 
4
4
  //#region src/core/walker.d.ts
@@ -1,5 +1,6 @@
1
1
  import { isObject } from "./guards.mjs";
2
2
  import { appendPointer, emitDiagnostic } from "./diagnostics.mjs";
3
+ import { isPrototypePollutingKey } from "./uri.mjs";
3
4
  import { countDistinctRefs, resolveRef } from "./ref.mjs";
4
5
  import { extractArrayConstraints, extractObjectConstraints, stripInapplicableConstraints } from "./constraints.mjs";
5
6
  import { ANNOTATION_SIBLINGS, detectDiscriminated, mergeAllOf, mergeRefSiblings, normaliseAnyOf } from "./merge.mjs";
@@ -74,7 +75,11 @@ function walk(schema, options = {}) {
74
75
  }
75
76
  function walkNode(schema, ctx) {
76
77
  const allOf = getArray(schema, "allOf");
77
- if (allOf !== void 0 && allOf.length > 0) return walkNode(mergeAllOf(allOf, ctx.diagnostics, ctx.pointer), ctx);
78
+ if (allOf !== void 0 && allOf.length > 0) {
79
+ const merged = mergeAllOf(allOf, ctx.diagnostics, ctx.pointer);
80
+ if (merged === false) return walkBooleanSchema(false);
81
+ return walkNode(merged, ctx);
82
+ }
78
83
  const anyOf = getArray(schema, "anyOf");
79
84
  if (anyOf !== void 0) {
80
85
  const nullable = normaliseAnyOf(anyOf);
@@ -86,6 +91,11 @@ function walkNode(schema, ctx) {
86
91
  }
87
92
  const oneOf = getArray(schema, "oneOf");
88
93
  if (oneOf !== void 0) {
94
+ const nullable = normaliseAnyOf(oneOf);
95
+ if (nullable !== void 0) return walkNode(nullable.inner, {
96
+ ...ctx,
97
+ isNullable: true
98
+ });
89
99
  const discriminated = detectDiscriminated(oneOf, ctx.diagnostics, ctx.pointer);
90
100
  if (discriminated !== void 0) return walkDiscriminatedUnion(discriminated, ctx);
91
101
  return walkUnion(oneOf, ctx);
@@ -111,32 +121,27 @@ function walkNode(schema, ctx) {
111
121
  Object.assign(placeholder, result);
112
122
  return placeholder;
113
123
  }
114
- const ifSchema = getObject(schema, "if");
115
- if (ifSchema !== void 0) {
124
+ if ("if" in schema) {
116
125
  emitDiagnostic(ctx.diagnostics, {
117
126
  code: "conditional-fallback",
118
127
  message: "if/then/else rendered as base schema; conditionals require runtime evaluation",
119
128
  pointer: ctx.pointer
120
129
  });
121
- const base = buildBase(withoutKeys(schema, [
122
- "if",
123
- "then",
124
- "else"
125
- ]), ctx);
126
- const thenSchema = getObject(schema, "then");
127
- const elseSchema = getObject(schema, "else");
128
130
  const conditional = {
129
- ...base,
131
+ ...buildBase(withoutKeys(schema, [
132
+ "if",
133
+ "then",
134
+ "else"
135
+ ]), ctx),
130
136
  type: "conditional",
131
137
  constraints: {},
132
- ifClause: walkNode(ifSchema, ctx)
138
+ ifClause: walkSubSchema(schema.if, ctx)
133
139
  };
134
- if (thenSchema !== void 0) conditional.thenClause = walkNode(thenSchema, ctx);
135
- if (elseSchema !== void 0) conditional.elseClause = walkNode(elseSchema, ctx);
140
+ if ("then" in schema) conditional.thenClause = walkSubSchema(schema.then, ctx);
141
+ if ("else" in schema) conditional.elseClause = walkSubSchema(schema.else, ctx);
136
142
  return conditional;
137
143
  }
138
- const notSchema = getObject(schema, "not");
139
- if (notSchema !== void 0) {
144
+ if ("not" in schema) {
140
145
  emitDiagnostic(ctx.diagnostics, {
141
146
  code: "type-negation-fallback",
142
147
  message: "not schema rendered as negation; TypeScript cannot negate types",
@@ -146,7 +151,7 @@ function walkNode(schema, ctx) {
146
151
  ...buildBase(withoutKeys(schema, ["not"]), ctx),
147
152
  type: "negation",
148
153
  constraints: {},
149
- negated: walkNode(notSchema, ctx)
154
+ negated: walkSubSchema(schema.not, ctx)
150
155
  };
151
156
  }
152
157
  const enumValues = getArray(schema, "enum");
@@ -236,11 +241,28 @@ function walkBoolean(schema, ctx) {
236
241
  return buildBooleanField(schema, ctx);
237
242
  }
238
243
  function walkEnum(schema, enumValues, ctx) {
244
+ const accepted = [];
245
+ for (let i = 0; i < enumValues.length; i++) {
246
+ const v = enumValues[i];
247
+ if (isPrimitive(v)) {
248
+ accepted.push(v);
249
+ continue;
250
+ }
251
+ emitDiagnostic(ctx.diagnostics, {
252
+ code: "enum-value-filtered",
253
+ message: `enum value at index ${String(i)} is not a primitive (${v === void 0 ? "undefined" : typeof v}); dropping the entry`,
254
+ pointer: appendPointer(ctx.pointer, `enum/${String(i)}`),
255
+ detail: {
256
+ index: i,
257
+ value: v
258
+ }
259
+ });
260
+ }
239
261
  return {
240
262
  ...buildBase(schema, ctx),
241
263
  type: "enum",
242
264
  constraints: {},
243
- enumValues: enumValues.filter((v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean" || v === null)
265
+ enumValues: accepted
244
266
  };
245
267
  }
246
268
  function walkLiteral(schema, ctx) {
@@ -254,9 +276,35 @@ function walkLiteral(schema, ctx) {
254
276
  };
255
277
  }
256
278
  function walkObject(schema, properties, ctx) {
257
- const requiredFields = getArray(schema, "required")?.filter((r) => typeof r === "string") ?? [];
279
+ const required = getArray(schema, "required");
280
+ const requiredFields = [];
281
+ if (required !== void 0) for (let i = 0; i < required.length; i++) {
282
+ const r = required[i];
283
+ if (typeof r === "string") {
284
+ requiredFields.push(r);
285
+ continue;
286
+ }
287
+ emitDiagnostic(ctx.diagnostics, {
288
+ code: "required-non-string",
289
+ message: `required[${String(i)}] is not a string (${r === null ? "null" : typeof r}); dropping the entry`,
290
+ pointer: appendPointer(ctx.pointer, `required/${String(i)}`),
291
+ detail: {
292
+ index: i,
293
+ value: r
294
+ }
295
+ });
296
+ }
258
297
  const fields = {};
259
298
  for (const [key, propSchema] of Object.entries(properties)) {
299
+ if (isPrototypePollutingKey(key)) {
300
+ emitDiagnostic(ctx.diagnostics, {
301
+ code: "prototype-polluting-property",
302
+ message: `Refusing to register prototype-polluting property name: ${key}`,
303
+ pointer: appendPointer(ctx.pointer, key),
304
+ detail: { propertyName: key }
305
+ });
306
+ continue;
307
+ }
260
308
  const childOverride = extractChildOverride(ctx.fieldOverrides, key);
261
309
  const isRequired = requiredFields.includes(key);
262
310
  const childCtx = {
@@ -277,7 +325,7 @@ function walkObject(schema, properties, ctx) {
277
325
  };
278
326
  }
279
327
  const patternProps = getObject(schema, "patternProperties");
280
- const walkedPatternProps = patternProps !== void 0 ? walkSubSchemaMap(patternProps, walkNode, ctx) : void 0;
328
+ const walkedPatternProps = patternProps !== void 0 ? walkSubSchemaMap(patternProps, walkSubSchema, ctx) : void 0;
281
329
  let additionalPropertiesClosed;
282
330
  let additionalPropertiesSchema;
283
331
  const additionalProps = schema.additionalProperties;
@@ -290,7 +338,7 @@ function walkObject(schema, properties, ctx) {
290
338
  };
291
339
  else if (isObject(additionalProps)) additionalPropertiesSchema = walkNode(additionalProps, ctx);
292
340
  const depSchemas = getObject(schema, "dependentSchemas");
293
- const walkedDepSchemas = depSchemas !== void 0 ? walkSubSchemaMap(depSchemas, walkNode, ctx) : void 0;
341
+ const walkedDepSchemas = depSchemas !== void 0 ? walkSubSchemaMap(depSchemas, walkSubSchema, ctx) : void 0;
294
342
  const depReq = getObject(schema, "dependentRequired");
295
343
  const walkedDepReq = depReq !== void 0 ? walkDependentRequiredMap(depReq) : void 0;
296
344
  let unevaluatedProperties;
@@ -304,8 +352,7 @@ function walkObject(schema, properties, ctx) {
304
352
  constraints: {}
305
353
  };
306
354
  else if (isObject(unevalProps)) unevaluatedProperties = walkNode(unevalProps, ctx);
307
- const propertyNamesSchema = getObject(schema, "propertyNames");
308
- const walkedPropertyNames = propertyNamesSchema !== void 0 ? walkNode(propertyNamesSchema, ctx) : void 0;
355
+ const walkedPropertyNames = "propertyNames" in schema ? walkSubSchema(schema.propertyNames, ctx) : void 0;
309
356
  return {
310
357
  ...buildBase(schema, ctx),
311
358
  type: "object",
@@ -340,14 +387,19 @@ function walkRecord(schema, valueSchema, ctx) {
340
387
  };
341
388
  }
342
389
  function walkArray(schema, ctx) {
390
+ const walkedContains = "contains" in schema ? walkSubSchema(schema.contains, ctx) : void 0;
343
391
  const prefixItems = getArray(schema, "prefixItems");
344
392
  if (prefixItems !== void 0) {
345
393
  const walkedItems = prefixItems.filter(isObject).map((item) => walkNode(item, ctx));
394
+ const restSchema = getObject(schema, "items");
395
+ const restItems = restSchema !== void 0 ? walkNode(restSchema, ctx) : void 0;
346
396
  return {
347
397
  ...buildBase(schema, ctx),
348
398
  type: "tuple",
349
399
  constraints: extractArrayConstraints(schema),
350
- prefixItems: walkedItems
400
+ prefixItems: walkedItems,
401
+ ...restItems !== void 0 ? { restItems } : {},
402
+ ...walkedContains !== void 0 ? { contains: walkedContains } : {}
351
403
  };
352
404
  }
353
405
  const unevaluatedItemsSchema = getObject(schema, "unevaluatedItems");
@@ -363,14 +415,16 @@ function walkArray(schema, ctx) {
363
415
  ...ctx,
364
416
  fieldOverrides: elementOverride
365
417
  }),
366
- ...walkedUnevaluatedItems !== void 0 ? { unevaluatedItems: walkedUnevaluatedItems } : {}
418
+ ...walkedUnevaluatedItems !== void 0 ? { unevaluatedItems: walkedUnevaluatedItems } : {},
419
+ ...walkedContains !== void 0 ? { contains: walkedContains } : {}
367
420
  };
368
421
  }
369
422
  return {
370
423
  ...buildBase(schema, ctx),
371
424
  type: "array",
372
425
  constraints: extractArrayConstraints(schema),
373
- ...walkedUnevaluatedItems !== void 0 ? { unevaluatedItems: walkedUnevaluatedItems } : {}
426
+ ...walkedUnevaluatedItems !== void 0 ? { unevaluatedItems: walkedUnevaluatedItems } : {},
427
+ ...walkedContains !== void 0 ? { contains: walkedContains } : {}
374
428
  };
375
429
  }
376
430
  function walkUnion(options, ctx) {
@@ -16,7 +16,7 @@
16
16
  * Machine-readable codes identifying each class of diagnostic.
17
17
  * Stable across releases — consumers can pattern-match on these.
18
18
  */
19
- type DiagnosticCode = "unresolved-ref" | "unknown-keyword" | "unknown-format" | "invalid-const" | "unsupported-type" | "dropped-swagger-feature" | "external-ref" | "type-negation-fallback" | "conditional-fallback" | "assumed-draft" | "depth-exceeded" | "allof-conflict" | "discriminator-inconsistent" | "divisible-by-conflict" | "legacy-dependencies-split" | "dependent-required-invalid";
19
+ type DiagnosticCode = "unresolved-ref" | "unknown-keyword" | "unknown-format" | "invalid-const" | "unsupported-type" | "dropped-swagger-feature" | "external-ref" | "type-negation-fallback" | "conditional-fallback" | "assumed-draft" | "depth-exceeded" | "allof-conflict" | "discriminator-inconsistent" | "divisible-by-conflict" | "legacy-dependencies-split" | "dependent-required-invalid" | "unknown-json-schema-dialect" | "relative-ref-resolved" | "bare-exclusive-bound" | "enum-value-filtered" | "required-non-string" | "pattern-invalid" | "duplicate-body-parameter" | "prototype-polluting-property";
20
20
  /**
21
21
  * A single diagnostic emitted during schema processing.
22
22
  */