schema-components 1.21.0 → 1.23.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 (91) hide show
  1. package/README.md +3 -1
  2. package/dist/core/adapter.d.mts +115 -4
  3. package/dist/core/adapter.mjs +405 -75
  4. package/dist/core/constraints.d.mts +2 -2
  5. package/dist/core/constraints.mjs +0 -7
  6. package/dist/core/cssClasses.d.mts +52 -0
  7. package/dist/core/cssClasses.mjs +51 -0
  8. package/dist/core/diagnostics.d.mts +1 -1
  9. package/dist/core/errors.d.mts +1 -1
  10. package/dist/core/errors.mjs +5 -13
  11. package/dist/core/fieldOrder.d.mts +1 -1
  12. package/dist/core/formats.d.mts +30 -2
  13. package/dist/core/formats.mjs +33 -1
  14. package/dist/core/idPath.d.mts +54 -0
  15. package/dist/core/idPath.mjs +66 -0
  16. package/dist/core/limits.d.mts +2 -0
  17. package/dist/core/limits.mjs +23 -0
  18. package/dist/core/merge.d.mts +10 -1
  19. package/dist/core/merge.mjs +49 -10
  20. package/dist/core/normalise.d.mts +40 -3
  21. package/dist/core/normalise.mjs +2 -2
  22. package/dist/core/openapi30.d.mts +15 -1
  23. package/dist/core/openapi30.mjs +2 -2
  24. package/dist/core/openapiConstants.d.mts +67 -0
  25. package/dist/core/openapiConstants.mjs +90 -0
  26. package/dist/core/ref.d.mts +2 -2
  27. package/dist/core/ref.mjs +85 -6
  28. package/dist/core/refChain.d.mts +70 -0
  29. package/dist/core/refChain.mjs +44 -0
  30. package/dist/core/renderer.d.mts +1 -1
  31. package/dist/core/renderer.mjs +0 -2
  32. package/dist/core/swagger2.d.mts +1 -1
  33. package/dist/core/swagger2.mjs +1 -1
  34. package/dist/core/typeInference.d.mts +982 -2
  35. package/dist/core/types.d.mts +2 -2
  36. package/dist/core/types.mjs +1 -4
  37. package/dist/core/unionMatch.d.mts +36 -0
  38. package/dist/core/unionMatch.mjs +53 -0
  39. package/dist/core/version.d.mts +1 -1
  40. package/dist/core/version.mjs +29 -17
  41. package/dist/core/walkBuilders.d.mts +23 -4
  42. package/dist/core/walkBuilders.mjs +27 -7
  43. package/dist/core/walker.d.mts +1 -1
  44. package/dist/core/walker.mjs +123 -47
  45. package/dist/{diagnostics-CbBPsxSt.d.mts → diagnostics-BS2kaUyE.d.mts} +1 -1
  46. package/dist/{errors-QEwOtQAA.d.mts → errors-g_MCTQel.d.mts} +10 -16
  47. package/dist/html/a11y.d.mts +9 -4
  48. package/dist/html/a11y.mjs +10 -12
  49. package/dist/html/renderToHtml.d.mts +10 -3
  50. package/dist/html/renderToHtml.mjs +13 -3
  51. package/dist/html/renderToHtmlStream.d.mts +2 -2
  52. package/dist/html/renderToHtmlStream.mjs +12 -1
  53. package/dist/html/renderers.d.mts +43 -8
  54. package/dist/html/renderers.mjs +136 -116
  55. package/dist/html/streamRenderers.d.mts +6 -6
  56. package/dist/html/streamRenderers.mjs +129 -89
  57. package/dist/limits-Cw5QZND8.d.mts +29 -0
  58. package/dist/{normalise-DaSrnr8g.mjs → normalise-DCYp06Sr.mjs} +770 -227
  59. package/dist/openapi/ApiCallbacks.d.mts +1 -1
  60. package/dist/openapi/ApiLinks.d.mts +1 -1
  61. package/dist/openapi/ApiResponseHeaders.d.mts +1 -1
  62. package/dist/openapi/ApiSecurity.d.mts +1 -1
  63. package/dist/openapi/ApiSecurity.mjs +16 -2
  64. package/dist/openapi/components.d.mts +234 -23
  65. package/dist/openapi/components.mjs +183 -52
  66. package/dist/openapi/parser.d.mts +9 -8
  67. package/dist/openapi/parser.mjs +252 -70
  68. package/dist/openapi/resolve.d.mts +31 -15
  69. package/dist/openapi/resolve.mjs +260 -40
  70. package/dist/react/SchemaComponent.d.mts +126 -36
  71. package/dist/react/SchemaComponent.mjs +95 -57
  72. package/dist/react/SchemaView.d.mts +30 -10
  73. package/dist/react/SchemaView.mjs +2 -2
  74. package/dist/react/a11y.d.mts +21 -0
  75. package/dist/react/a11y.mjs +24 -0
  76. package/dist/react/fieldPath.d.mts +1 -1
  77. package/dist/react/headless.d.mts +1 -1
  78. package/dist/react/headless.mjs +1 -2
  79. package/dist/react/headlessRenderers.d.mts +9 -11
  80. package/dist/react/headlessRenderers.mjs +51 -102
  81. package/dist/{ref-si8ViYun.d.mts → ref-DjLEKa_E.d.mts} +38 -3
  82. package/dist/{renderer-DI6ZYf7a.d.mts → renderer-CXJ8y0qw.d.mts} +2 -2
  83. package/dist/themes/mantine.d.mts +1 -1
  84. package/dist/themes/mui.d.mts +1 -1
  85. package/dist/themes/radix.d.mts +1 -1
  86. package/dist/themes/shadcn.d.mts +1 -1
  87. package/dist/themes/shadcn.mjs +2 -1
  88. package/dist/{types-BnxPEElk.d.mts → types-BTB73MB8.d.mts} +35 -14
  89. package/dist/{version-D-u7aMfy.d.mts → version-BFTVLsdb.d.mts} +7 -1
  90. package/package.json +1 -3
  91. package/dist/typeInference-Bxw3NOG1.d.mts +0 -647
@@ -0,0 +1,67 @@
1
+ //#region src/core/openapiConstants.d.ts
2
+ /**
3
+ * Shared OpenAPI / Swagger constants and helpers.
4
+ *
5
+ * Single source of truth for HTTP method tuples, default content types, and
6
+ * the Swagger 2.0 → OpenAPI 3.x reference-prefix rewriting table. Consumers
7
+ * import the named exports rather than hand-maintaining sibling copies that
8
+ * silently drift when methods or prefixes change.
9
+ */
10
+ /**
11
+ * Canonical OpenAPI 3.x HTTP method tuple in path-item iteration order.
12
+ * Spec: https://spec.openapis.org/oas/v3.1.1#path-item-object
13
+ */
14
+ declare const HTTP_METHODS: readonly ["get", "put", "post", "delete", "options", "head", "patch", "trace"];
15
+ type HttpMethod = (typeof HTTP_METHODS)[number];
16
+ /**
17
+ * Swagger 2.0 omits `trace` — the keyword was introduced in OpenAPI 3.0.
18
+ * Derived from `HTTP_METHODS` so adding a method to the canonical tuple
19
+ * automatically propagates here (after which the filter may need updating).
20
+ */
21
+ declare const SWAGGER_2_METHODS: readonly Exclude<HttpMethod, "trace">[];
22
+ /**
23
+ * Default media type used when an OpenAPI document elides `consumes` /
24
+ * `produces` or a Schema Object stands alone (no parent Media Type).
25
+ */
26
+ declare const DEFAULT_OPENAPI_CONTENT_TYPE = "application/json";
27
+ /**
28
+ * Canonical `$ref` prefix table for the JSON Pointer locations used by
29
+ * OpenAPI 3.x and Swagger 2.0 documents.
30
+ */
31
+ declare const REF_PREFIXES: {
32
+ /** OpenAPI 3.x — most schemas live under `components.schemas`. */readonly components: {
33
+ readonly schemas: "#/components/schemas/";
34
+ readonly parameters: "#/components/parameters/";
35
+ readonly responses: "#/components/responses/";
36
+ readonly requestBodies: "#/components/requestBodies/";
37
+ readonly headers: "#/components/headers/";
38
+ readonly examples: "#/components/examples/";
39
+ readonly links: "#/components/links/";
40
+ readonly callbacks: "#/components/callbacks/";
41
+ readonly securitySchemes: "#/components/securitySchemes/";
42
+ readonly pathItems: "#/components/pathItems/";
43
+ }; /** Swagger 2.0 legacy prefixes. */
44
+ readonly swagger2: {
45
+ readonly definitions: "#/definitions/";
46
+ readonly parameters: "#/parameters/";
47
+ readonly responses: "#/responses/";
48
+ };
49
+ };
50
+ /**
51
+ * Swagger 2.0 → OpenAPI 3.x `$ref` prefix mapping. Applied during the
52
+ * 2.0 → 3.x lift to rewrite legacy pointer prefixes onto their components
53
+ * counterparts. Order matters: longer prefixes first prevents `#/parameters/`
54
+ * from shadowing `#/components/parameters/` during a partial migration.
55
+ */
56
+ declare const REF_REWRITES: readonly {
57
+ readonly from: string;
58
+ readonly to: string;
59
+ }[];
60
+ /**
61
+ * Rewrite a Swagger 2.0 ref prefix onto the equivalent OpenAPI 3.x location.
62
+ * Returns the ref unchanged when no prefix matches. Pure string operation —
63
+ * does not validate that the target exists.
64
+ */
65
+ declare function rewriteSwaggerRefPrefix(ref: string): string;
66
+ //#endregion
67
+ export { DEFAULT_OPENAPI_CONTENT_TYPE, HTTP_METHODS, HttpMethod, REF_PREFIXES, REF_REWRITES, SWAGGER_2_METHODS, rewriteSwaggerRefPrefix };
@@ -0,0 +1,90 @@
1
+ //#region src/core/openapiConstants.ts
2
+ /**
3
+ * Shared OpenAPI / Swagger constants and helpers.
4
+ *
5
+ * Single source of truth for HTTP method tuples, default content types, and
6
+ * the Swagger 2.0 → OpenAPI 3.x reference-prefix rewriting table. Consumers
7
+ * import the named exports rather than hand-maintaining sibling copies that
8
+ * silently drift when methods or prefixes change.
9
+ */
10
+ /**
11
+ * Canonical OpenAPI 3.x HTTP method tuple in path-item iteration order.
12
+ * Spec: https://spec.openapis.org/oas/v3.1.1#path-item-object
13
+ */
14
+ const HTTP_METHODS = [
15
+ "get",
16
+ "put",
17
+ "post",
18
+ "delete",
19
+ "options",
20
+ "head",
21
+ "patch",
22
+ "trace"
23
+ ];
24
+ /**
25
+ * Swagger 2.0 omits `trace` — the keyword was introduced in OpenAPI 3.0.
26
+ * Derived from `HTTP_METHODS` so adding a method to the canonical tuple
27
+ * automatically propagates here (after which the filter may need updating).
28
+ */
29
+ const SWAGGER_2_METHODS = HTTP_METHODS.filter((m) => m !== "trace");
30
+ /**
31
+ * Default media type used when an OpenAPI document elides `consumes` /
32
+ * `produces` or a Schema Object stands alone (no parent Media Type).
33
+ */
34
+ const DEFAULT_OPENAPI_CONTENT_TYPE = "application/json";
35
+ /**
36
+ * Canonical `$ref` prefix table for the JSON Pointer locations used by
37
+ * OpenAPI 3.x and Swagger 2.0 documents.
38
+ */
39
+ const REF_PREFIXES = {
40
+ /** OpenAPI 3.x — most schemas live under `components.schemas`. */
41
+ components: {
42
+ schemas: "#/components/schemas/",
43
+ parameters: "#/components/parameters/",
44
+ responses: "#/components/responses/",
45
+ requestBodies: "#/components/requestBodies/",
46
+ headers: "#/components/headers/",
47
+ examples: "#/components/examples/",
48
+ links: "#/components/links/",
49
+ callbacks: "#/components/callbacks/",
50
+ securitySchemes: "#/components/securitySchemes/",
51
+ pathItems: "#/components/pathItems/"
52
+ },
53
+ /** Swagger 2.0 legacy prefixes. */
54
+ swagger2: {
55
+ definitions: "#/definitions/",
56
+ parameters: "#/parameters/",
57
+ responses: "#/responses/"
58
+ }
59
+ };
60
+ /**
61
+ * Swagger 2.0 → OpenAPI 3.x `$ref` prefix mapping. Applied during the
62
+ * 2.0 → 3.x lift to rewrite legacy pointer prefixes onto their components
63
+ * counterparts. Order matters: longer prefixes first prevents `#/parameters/`
64
+ * from shadowing `#/components/parameters/` during a partial migration.
65
+ */
66
+ const REF_REWRITES = [
67
+ {
68
+ from: REF_PREFIXES.swagger2.definitions,
69
+ to: REF_PREFIXES.components.schemas
70
+ },
71
+ {
72
+ from: REF_PREFIXES.swagger2.parameters,
73
+ to: REF_PREFIXES.components.parameters
74
+ },
75
+ {
76
+ from: REF_PREFIXES.swagger2.responses,
77
+ to: REF_PREFIXES.components.responses
78
+ }
79
+ ];
80
+ /**
81
+ * Rewrite a Swagger 2.0 ref prefix onto the equivalent OpenAPI 3.x location.
82
+ * Returns the ref unchanged when no prefix matches. Pure string operation —
83
+ * does not validate that the target exists.
84
+ */
85
+ function rewriteSwaggerRefPrefix(ref) {
86
+ for (const { from, to } of REF_REWRITES) if (ref.startsWith(from)) return `${to}${ref.slice(from.length)}`;
87
+ return ref;
88
+ }
89
+ //#endregion
90
+ export { DEFAULT_OPENAPI_CONTENT_TYPE, HTTP_METHODS, REF_PREFIXES, REF_REWRITES, SWAGGER_2_METHODS, rewriteSwaggerRefPrefix };
@@ -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-si8ViYun.mjs";
2
- export { ExternalResolver, RefOptions, countDistinctRefs, dereference, findAnchor, resolveRef };
1
+ import { a as dereference, i as countDistinctRefs, n as RECURSIVE_ANCHOR_SENTINEL, o as findAnchor, r as RefOptions, s as resolveRef, t as ExternalResolver } from "../ref-DjLEKa_E.mjs";
2
+ export { ExternalResolver, RECURSIVE_ANCHOR_SENTINEL, RefOptions, countDistinctRefs, dereference, findAnchor, resolveRef };
package/dist/core/ref.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { isObject } from "./guards.mjs";
2
+ import "./limits.mjs";
2
3
  import { emitDiagnostic } from "./diagnostics.mjs";
3
4
  import { isPrototypePollutingKey } from "./uri.mjs";
4
5
  //#region src/core/ref.ts
@@ -8,6 +9,31 @@ import { isPrototypePollutingKey } from "./uri.mjs";
8
9
  * Handles JSON Pointer dereference, $anchor lookup, cycle detection,
9
10
  * and depth limiting derived from the document's own $ref count.
10
11
  */
12
+ /**
13
+ * The canonical recursive `$anchor` name synthesised by the Draft
14
+ * 2019-09 `$recursiveAnchor: true` rewrite. Re-exported here so the
15
+ * collision check in {@link findAnchor} stays aligned with the
16
+ * rewriter in `core/normalise.ts`.
17
+ */
18
+ const RECURSIVE_ANCHOR_SENTINEL = "__recursive__";
19
+ /**
20
+ * Translate a boolean sub-schema (Draft 06+) into a `Record<string,unknown>`
21
+ * the walker can interpret with no semantic loss:
22
+ *
23
+ * `true` → `{}` (always-valid schema)
24
+ * `false` → `{ not: {} }` (never-valid schema)
25
+ *
26
+ * Used by {@link resolveRef} so callers that expect an object schema
27
+ * can continue without per-call-site boolean handling.
28
+ *
29
+ * TODO(round7-integration): once Agent D widens the walker's resolved-
30
+ * ref handling to dispatch through `walkSubSchema`, drop this
31
+ * translation and surface the boolean directly.
32
+ */
33
+ function booleanSchemaToObject(value) {
34
+ if (value) return {};
35
+ return { not: {} };
36
+ }
11
37
  function getString(obj, key) {
12
38
  const value = obj[key];
13
39
  return typeof value === "string" ? value : void 0;
@@ -96,6 +122,7 @@ function resolveRef(schema, rootDocument, visited, diagnostics, maxDepth, extern
96
122
  if (target !== void 0) {
97
123
  const nextVisited = new Set(visited);
98
124
  nextVisited.add(ref);
125
+ if (typeof target === "boolean") return booleanSchemaToObject(target);
99
126
  return resolveRef(target, externalDoc, nextVisited, diagnostics, maxDepth, externalResolver);
100
127
  }
101
128
  }
@@ -130,6 +157,7 @@ function resolveRef(schema, rootDocument, visited, diagnostics, maxDepth, extern
130
157
  constraints: {}
131
158
  };
132
159
  }
160
+ if (typeof resolved === "boolean") return booleanSchemaToObject(resolved);
133
161
  const nextVisited = new Set(visited);
134
162
  nextVisited.add(ref);
135
163
  return resolveRef(resolved, rootDocument, nextVisited, diagnostics, maxDepth, externalResolver);
@@ -137,6 +165,15 @@ function resolveRef(schema, rootDocument, visited, diagnostics, maxDepth, extern
137
165
  /**
138
166
  * Dereference a JSON Pointer fragment (`#/path/to/schema`) or an
139
167
  * `$anchor` (`#SomeName`) against a root document.
168
+ *
169
+ * Returns the resolved sub-schema, which may be a JSON object or — per
170
+ * Draft 06+ — a boolean (`true` for the always-valid schema, `false`
171
+ * for the never-valid schema). Returns `undefined` when the pointer or
172
+ * anchor cannot be resolved.
173
+ *
174
+ * JSON Pointer segments are percent-decoded per RFC 6901 §6 before the
175
+ * `~1`/`~0` token expansion; this allows pointers such as
176
+ * `#/paths/~1pets%20store` to resolve a path containing a literal space.
140
177
  */
141
178
  function dereference(ref, root) {
142
179
  if (ref === "#") return root;
@@ -144,11 +181,21 @@ function dereference(ref, root) {
144
181
  const parts = ref.slice(2).split("/");
145
182
  if (parts.length === 1 && parts[0] === "") return root;
146
183
  let current = root;
147
- for (const part of parts) {
148
- if (!isObject(current)) return void 0;
149
- const decoded = part.replace(/~1/g, "/").replace(/~0/g, "~");
184
+ for (let i = 0; i < parts.length; i++) {
185
+ const part = parts[i];
186
+ if (part === void 0) return void 0;
187
+ let percentDecoded;
188
+ try {
189
+ percentDecoded = decodeURIComponent(part);
190
+ } catch {
191
+ return;
192
+ }
193
+ const decoded = percentDecoded.replace(/~1/g, "/").replace(/~0/g, "~");
150
194
  if (isPrototypePollutingKey(decoded)) return void 0;
151
- current = current[decoded];
195
+ if (!isObject(current)) return void 0;
196
+ const next = current[decoded];
197
+ if (i === parts.length - 1 && typeof next === "boolean") return next;
198
+ current = next;
152
199
  }
153
200
  return isObject(current) ? current : void 0;
154
201
  }
@@ -161,18 +208,39 @@ function dereference(ref, root) {
161
208
  * Recursively scan a schema document for a `$anchor` matching the given name.
162
209
  * Returns the schema object containing the anchor, or undefined.
163
210
  *
211
+ * Per JSON Schema 2020-12 §8.2, `$anchor` is scoped to the resource
212
+ * defined by the nearest enclosing `$id`. A bare DFS would happily
213
+ * cross resource boundaries and resolve to an anchor declared in an
214
+ * unrelated sub-resource — that violates the spec and produces wrong
215
+ * walker input when two sub-schemas use the same anchor name within
216
+ * their own `$id` scope.
217
+ *
218
+ * The walk skips into any sub-tree that introduces a new `$id` value:
219
+ * such a sub-tree is a separate resource and its `$anchor`s belong to
220
+ * that resource, not the caller's. Anchors declared at the same `$id`
221
+ * scope (or in nested sub-schemas without their own `$id`) remain
222
+ * reachable.
223
+ *
164
224
  * The optional `visited` set guards against shared object references and
165
225
  * cycles introduced by the OpenAPI bundler's `structuredClone`-based
166
226
  * inlining of external refs. Without it a recursive document would stack
167
227
  * overflow before reaching the matching anchor.
228
+ *
229
+ * When `crossResourceBoundary` is `true` the walker is currently
230
+ * recursing into a sub-tree that introduced its own `$id`; we still
231
+ * recurse so a nested `$anchor` declared inside that same sub-resource
232
+ * is reachable from the caller that owns that resource, but we skip
233
+ * further nested resources for the same reason as above.
168
234
  */
169
235
  function findAnchor(node, anchorName, visited = /* @__PURE__ */ new WeakSet()) {
170
236
  if (!isObject(node)) return void 0;
171
237
  if (visited.has(node)) return void 0;
172
238
  visited.add(node);
173
239
  if (node.$anchor === anchorName) return node;
174
- for (const value of Object.values(node)) {
240
+ for (const [key, value] of Object.entries(node)) {
241
+ if (key === "$id") continue;
175
242
  if (isObject(value)) {
243
+ if (introducesNewResource(value)) continue;
176
244
  const found = findAnchor(value, anchorName, visited);
177
245
  if (found !== void 0) return found;
178
246
  }
@@ -180,11 +248,22 @@ function findAnchor(node, anchorName, visited = /* @__PURE__ */ new WeakSet()) {
180
248
  if (visited.has(value)) continue;
181
249
  visited.add(value);
182
250
  for (const item of value) {
251
+ if (isObject(item) && introducesNewResource(item)) continue;
183
252
  const found = findAnchor(item, anchorName, visited);
184
253
  if (found !== void 0) return found;
185
254
  }
186
255
  }
187
256
  }
188
257
  }
258
+ /**
259
+ * A sub-tree introduces a new resource when it carries a non-empty
260
+ * string `$id`. JSON Schema 2020-12 treats such a sub-tree as the
261
+ * root of a separate resource — its `$anchor` declarations live in
262
+ * that resource's scope, not the enclosing one.
263
+ */
264
+ function introducesNewResource(node) {
265
+ const id = node.$id;
266
+ return typeof id === "string" && id.length > 0;
267
+ }
189
268
  //#endregion
190
- export { countDistinctRefs, dereference, findAnchor, resolveRef };
269
+ export { RECURSIVE_ANCHOR_SENTINEL, countDistinctRefs, dereference, findAnchor, resolveRef };
@@ -0,0 +1,70 @@
1
+ //#region src/core/refChain.d.ts
2
+ /**
3
+ * Generic single-pass `$ref` chain resolver.
4
+ *
5
+ * Several OpenAPI / JSON Schema code paths follow `$ref` indirection with
6
+ * cycle and depth protection — Path Item refs, Parameter / Response refs,
7
+ * Reference Object → Reference Object chains, etc. Each call site previously
8
+ * hand-rolled the loop; this helper centralises the discipline so cycle
9
+ * detection, depth-cap behaviour, and the lookup boundary are consistent.
10
+ *
11
+ * The helper is intentionally lookup-shape agnostic: it walks `string` refs
12
+ * via a user-supplied `lookup`, recording each ref string in a `Set` to
13
+ * detect cycles, and tracking hop count against `maxHops`. The caller chooses
14
+ * what to do on cycle or depth-cap via `onCycle` / `onDepthExceeded`.
15
+ */
16
+ /** Maximum number of `$ref` hops permitted by default. */
17
+ declare const DEFAULT_REF_CHAIN_MAX_HOPS = 8;
18
+ /**
19
+ * Configuration for a single chain resolution.
20
+ *
21
+ * `lookup(ref)` returns the dereferenced node for a given `$ref` string, or
22
+ * `undefined` when the ref cannot be resolved. The chain follows further
23
+ * `$ref` indirection on the returned node until either:
24
+ *
25
+ * - The node is not a ref wrapper (final value reached) → returns the node.
26
+ * - The same ref string is encountered twice → calls `onCycle(ref)`.
27
+ * - The hop count exceeds `maxHops` → calls `onDepthExceeded(ref)`.
28
+ * - `lookup` returns `undefined` → returns `undefined`.
29
+ *
30
+ * Callers decide whether `onCycle` / `onDepthExceeded` should throw, emit
31
+ * a diagnostic, or return a fallback value.
32
+ */
33
+ interface ResolveRefChainOptions<T> {
34
+ /** Resolve a `$ref` string to its target node, or `undefined`. */
35
+ readonly lookup: (ref: string) => T | undefined;
36
+ /**
37
+ * Extract a `$ref` string from a node, or `undefined` when the node is
38
+ * not a ref wrapper. The default reads `node.$ref` when `node` is an
39
+ * object with a string `$ref` property.
40
+ */
41
+ readonly extractRef?: (node: T) => string | undefined;
42
+ /**
43
+ * Called when a previously-visited `$ref` is encountered. Returns the
44
+ * value the resolver should return in place of further resolution.
45
+ */
46
+ readonly onCycle?: (ref: string) => T | undefined;
47
+ /**
48
+ * Called when `maxHops` is exceeded. Returns the value the resolver
49
+ * should return in place of further resolution.
50
+ */
51
+ readonly onDepthExceeded?: (ref: string) => T | undefined;
52
+ /**
53
+ * Maximum number of `$ref` hops permitted before `onDepthExceeded` fires.
54
+ * Defaults to `DEFAULT_REF_CHAIN_MAX_HOPS`.
55
+ */
56
+ readonly maxHops?: number;
57
+ /**
58
+ * Pre-seeded visited-set. Useful when the caller has already followed
59
+ * one or more hops outside this helper.
60
+ */
61
+ readonly visited?: Set<string>;
62
+ }
63
+ /**
64
+ * Resolve a `$ref` chain starting from `initial`. See `ResolveRefChainOptions`
65
+ * for the contract. Returns the final dereferenced node, the cycle/depth
66
+ * fallback, or `undefined` when a hop cannot be resolved.
67
+ */
68
+ declare function resolveRefChain<T>(initial: T, options: ResolveRefChainOptions<T>): T | undefined;
69
+ //#endregion
70
+ export { DEFAULT_REF_CHAIN_MAX_HOPS, ResolveRefChainOptions, resolveRefChain };
@@ -0,0 +1,44 @@
1
+ //#region src/core/refChain.ts
2
+ /**
3
+ * Generic single-pass `$ref` chain resolver.
4
+ *
5
+ * Several OpenAPI / JSON Schema code paths follow `$ref` indirection with
6
+ * cycle and depth protection — Path Item refs, Parameter / Response refs,
7
+ * Reference Object → Reference Object chains, etc. Each call site previously
8
+ * hand-rolled the loop; this helper centralises the discipline so cycle
9
+ * detection, depth-cap behaviour, and the lookup boundary are consistent.
10
+ *
11
+ * The helper is intentionally lookup-shape agnostic: it walks `string` refs
12
+ * via a user-supplied `lookup`, recording each ref string in a `Set` to
13
+ * detect cycles, and tracking hop count against `maxHops`. The caller chooses
14
+ * what to do on cycle or depth-cap via `onCycle` / `onDepthExceeded`.
15
+ */
16
+ /** Maximum number of `$ref` hops permitted by default. */
17
+ const DEFAULT_REF_CHAIN_MAX_HOPS = 8;
18
+ function defaultExtractRef(node) {
19
+ if (typeof node !== "object" || node === null) return void 0;
20
+ if (!("$ref" in node)) return void 0;
21
+ const { $ref } = node;
22
+ return typeof $ref === "string" ? $ref : void 0;
23
+ }
24
+ /**
25
+ * Resolve a `$ref` chain starting from `initial`. See `ResolveRefChainOptions`
26
+ * for the contract. Returns the final dereferenced node, the cycle/depth
27
+ * fallback, or `undefined` when a hop cannot be resolved.
28
+ */
29
+ function resolveRefChain(initial, options) {
30
+ const { lookup, extractRef = defaultExtractRef, onCycle, onDepthExceeded, maxHops = 8, visited = /* @__PURE__ */ new Set() } = options;
31
+ let current = initial;
32
+ let hops = 0;
33
+ while (current !== void 0) {
34
+ const ref = extractRef(current);
35
+ if (ref === void 0) return current;
36
+ if (visited.has(ref)) return onCycle !== void 0 ? onCycle(ref) : void 0;
37
+ visited.add(ref);
38
+ if (hops >= maxHops) return onDepthExceeded !== void 0 ? onDepthExceeded(ref) : void 0;
39
+ hops += 1;
40
+ current = lookup(ref);
41
+ }
42
+ }
43
+ //#endregion
44
+ export { DEFAULT_REF_CHAIN_MAX_HOPS, resolveRefChain };
@@ -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-DI6ZYf7a.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-CXJ8y0qw.mjs";
2
2
  export { AllConstraints, BaseFieldProps, ComponentResolver, HtmlRenderFunction, HtmlRenderProps, HtmlResolver, RESOLVER_KEYS, RenderFunction, RenderProps, buildRenderProps, getHtmlRenderFn, getRenderFunction, mergeHtmlResolvers, mergeResolvers, typeToKey };
@@ -43,7 +43,6 @@ const RESOLVER_KEYS = [
43
43
  "discriminatedUnion",
44
44
  "conditional",
45
45
  "negation",
46
- "recursive",
47
46
  "literal",
48
47
  "file",
49
48
  "never",
@@ -70,7 +69,6 @@ function typeToKey(type) {
70
69
  case "discriminatedUnion":
71
70
  case "conditional":
72
71
  case "negation":
73
- case "recursive":
74
72
  case "literal":
75
73
  case "file":
76
74
  case "never":
@@ -1,4 +1,4 @@
1
- import { i as DiagnosticsOptions } from "../diagnostics-CbBPsxSt.mjs";
1
+ import { i as DiagnosticsOptions } from "../diagnostics-BS2kaUyE.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-DaSrnr8g.mjs";
1
+ import { c as normaliseSwagger2Document } from "../normalise-DCYp06Sr.mjs";
2
2
  export { normaliseSwagger2Document };