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
@@ -84,8 +84,6 @@ interface ArrayConstraints {
84
84
  minItems?: number;
85
85
  maxItems?: number;
86
86
  uniqueItems?: boolean;
87
- /** Schema that at least one array item must match. */
88
- contains?: Record<string, unknown>;
89
87
  minContains?: number;
90
88
  maxContains?: number;
91
89
  /** Constraint schema for unevaluated items. */
@@ -176,6 +174,12 @@ interface ArrayField extends FieldBase {
176
174
  constraints: ArrayConstraints;
177
175
  /** The element sub-schema. */
178
176
  element?: WalkedField;
177
+ /**
178
+ * Walked schema that at least one array item must match
179
+ * (`contains` keyword). Constrains element membership at runtime;
180
+ * paired with `minContains`/`maxContains` for cardinality.
181
+ */
182
+ contains?: WalkedField;
179
183
  /** Walked schema for unevaluated items. */
180
184
  unevaluatedItems?: WalkedField;
181
185
  }
@@ -184,6 +188,18 @@ interface TupleField extends FieldBase {
184
188
  constraints: ArrayConstraints;
185
189
  /** Positional element schemas from `prefixItems`. */
186
190
  prefixItems: WalkedField[];
191
+ /**
192
+ * Schema for items beyond the `prefixItems` length. In Draft 2020-12,
193
+ * `items` adjacent to `prefixItems` describes the rest element. When
194
+ * absent, additional items are permitted but unconstrained.
195
+ */
196
+ restItems?: WalkedField;
197
+ /**
198
+ * Walked schema that at least one array item must match
199
+ * (`contains` keyword). Tuples may declare it alongside positional
200
+ * element schemas to require the presence of a specific element.
201
+ */
202
+ contains?: WalkedField;
187
203
  }
188
204
  interface RecordField extends FieldBase {
189
205
  type: "record";
@@ -72,5 +72,40 @@ declare function isOpenApi31(version: OpenApiVersionInfo): boolean;
72
72
  * Check if a document is Swagger 2.0.
73
73
  */
74
74
  declare function isSwagger2(version: OpenApiVersionInfo): boolean;
75
+ /**
76
+ * Result of inspecting a document for the OpenAPI 3.1 `jsonSchemaDialect`
77
+ * keyword.
78
+ *
79
+ * - `kind: "absent"`: the keyword is not declared. The walker assumes
80
+ * Draft 2020-12, which is the spec-defined default.
81
+ * - `kind: "known"`: the declared dialect URI matches one of the
82
+ * supported drafts. The corresponding `JsonSchemaDraft` is returned so
83
+ * the normaliser can route to the matching per-node transforms.
84
+ * - `kind: "unknown"`: the keyword is present but its URI does not
85
+ * match any supported draft. The caller should emit an
86
+ * `unknown-json-schema-dialect` diagnostic and fall back to
87
+ * Draft 2020-12.
88
+ */
89
+ type JsonSchemaDialectInfo = {
90
+ kind: "absent";
91
+ } | {
92
+ kind: "known";
93
+ uri: string;
94
+ draft: JsonSchemaDraft;
95
+ } | {
96
+ kind: "unknown";
97
+ uri: string;
98
+ };
99
+ /**
100
+ * Inspect an OpenAPI 3.1 document for a `jsonSchemaDialect` declaration.
101
+ *
102
+ * Per the OpenAPI 3.1 spec, an OpenAPI document may declare the default
103
+ * JSON Schema dialect for its Schema Objects via the top-level
104
+ * `jsonSchemaDialect` URI. Real-world 3.1 documents overwhelmingly omit
105
+ * the keyword and rely on the spec-defined Draft 2020-12 default — this
106
+ * helper surfaces the declaration so the normaliser can either honour a
107
+ * known dialect or emit a diagnostic for an unknown one.
108
+ */
109
+ declare function readJsonSchemaDialect(doc: Record<string, unknown>): JsonSchemaDialectInfo;
75
110
  //#endregion
76
- export { detectOpenApiVersion as a, isOpenApi30 as c, matchJsonSchemaDraftUri as d, detectJsonSchemaDraft as i, isOpenApi31 as l, JsonSchemaDraft as n, inferJsonSchemaDraft as o, OpenApiVersionInfo as r, inferJsonSchemaDraftWithReason as s, InferredDraft as t, isSwagger2 as u };
111
+ export { detectJsonSchemaDraft as a, inferJsonSchemaDraftWithReason as c, isSwagger2 as d, matchJsonSchemaDraftUri as f, OpenApiVersionInfo as i, isOpenApi30 as l, JsonSchemaDialectInfo as n, detectOpenApiVersion as o, readJsonSchemaDialect as p, JsonSchemaDraft as r, inferJsonSchemaDraft as s, InferredDraft as t, isOpenApi31 as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "schema-components",
3
- "version": "1.19.0",
3
+ "version": "1.21.0",
4
4
  "description": "React components that render UI from Zod schemas, JSON Schema, and OpenAPI documents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.mjs",
@@ -1,388 +0,0 @@
1
- import { d as FieldOverrides, u as FieldOverride } from "./types-D_5ST7SS.mjs";
2
-
3
- //#region src/core/typeInference.d.ts
4
- /**
5
- * Convert a readonly tuple/array of values to a union type.
6
- * Handles both `as const` readonly tuples and mutable arrays.
7
- */
8
- type ArrayToUnion<A> = A extends readonly unknown[] ? A[number] : never;
9
- /**
10
- * Maps a JSON Schema structure to a TypeScript type.
11
- * Works with `as const` literals -- provides full autocomplete for `fields`.
12
- *
13
- * Supports all JSON Schema draft versions (04-2020-12) and OpenAPI 3.x:
14
- * - Primitive types: string, number, integer, boolean, null
15
- * - type as array: `["string", "null"]` -> `string | null` (nullable)
16
- * - enum -> union of literal types
17
- * - const -> literal type
18
- * - object with properties/required -> specific object type
19
- * - object with additionalProperties -> Record<string, T>
20
- * - array with items -> T[]
21
- * - array with prefixItems -> tuple type
22
- * - allOf -> intersection type
23
- * - anyOf -> union type
24
- * - oneOf -> union type
25
- * - $ref -> resolved via $defs/definitions/$anchor context
26
- * - $dynamicRef -> resolved via $dynamicAnchor in definitions
27
- * - $recursiveRef -> unknown (recursive types not expressible in TS)
28
- * - if/then/else -> base schema (conditionals not expressible in TS)
29
- * - not -> unknown (negation not expressible in TS)
30
- * - patternProperties -> merged into loose index signature
31
- */
32
- type FromJSONSchema<S, Defs extends Record<string, unknown> = Record<string, never>> = S extends {
33
- $ref: infer R extends string;
34
- } ? ResolveSchemaRef<R, Defs> : S extends {
35
- $recursiveRef: string;
36
- } ? unknown : S extends {
37
- $dynamicRef: infer R extends string;
38
- } ? ResolveSchemaRef<R, Defs> : S extends {
39
- allOf: infer A;
40
- } ? AllOfToType<A, Defs> : S extends {
41
- anyOf: infer A;
42
- } ? UnionOfMembers<A, Defs> : S extends {
43
- oneOf: infer A;
44
- } ? UnionOfMembers<A, Defs> : S extends {
45
- if: unknown;
46
- } ? FromJSONSchema<Omit<S, "if" | "then" | "else">, Defs> : S extends {
47
- not: unknown;
48
- } ? unknown : S extends {
49
- const: infer V;
50
- } ? V : S extends {
51
- enum: infer E;
52
- } ? ArrayToUnion<E> : S extends {
53
- type: infer T;
54
- } ? TypeToTs<T, S, Defs> : S extends readonly (infer E)[] ? E : unknown;
55
- /**
56
- * Marker type emitted when OpenAPI $ref resolution hits the type-level
57
- * recursion depth limit. Instead of silently falling back to
58
- * `Record<string, FieldOverride>`, produces this branded type so
59
- * consumers can detect it via conditional types.
60
- *
61
- * Usage:
62
- * ```ts
63
- * type Fields = InferRequestBodyFields<Doc, "/users", "post">;
64
- * type IsFallback = Fields extends __SchemaInferenceFellBack ? true : false;
65
- * ```
66
- */
67
- interface __SchemaInferenceFellBack {
68
- readonly __schemaInferenceFallback: unique symbol;
69
- }
70
- /**
71
- * Escape hatch for recursive schemas where type-level inference
72
- * cannot proceed. Typed as `Record<string, FieldOverride>` but
73
- * explicitly branded so callers know they are using the unsafe path.
74
- *
75
- * JSDoc trade-off note: This bypasses field-level type safety.
76
- * Prefer restructuring the schema to avoid deep $ref chains
77
- * when possible.
78
- */
79
- type UnsafeFields = Record<string, FieldOverride> & {
80
- /** Marks this as the unsafe fallback for recursive schemas. */readonly __unsafe?: true;
81
- };
82
- /**
83
- * Convert a `FromJSONSchema` result to `unknown` when recursion is detected.
84
- * Returns the original type when the schema is non-recursive.
85
- */
86
- type DetectRecursiveFallback<T> = unknown extends T ? __SchemaInferenceFellBack : T;
87
- /**
88
- * Type-level recursion bound for $ref resolution.
89
- *
90
- * The TypeScript type system imposes its own recursion limit; without an
91
- * explicit bound a cyclic schema graph would exhaust it and degrade to
92
- * `any`/`unknown` silently. Ten levels is the runtime walker's parallel
93
- * — see `countDistinctRefs` in `ref.ts` (lines 52-55), which derives its
94
- * bound from the number of distinct `$ref` strings in the document.
95
- *
96
- * A fixed bound is used here rather than a derived one because the type
97
- * system has no way to count distinct strings across a recursive `Defs`
98
- * map without itself recursing — which is the problem the bound exists
99
- * to solve. Ten covers every realistic schema graph encountered in
100
- * practice; deeper graphs surface as `__SchemaInferenceFellBack` so
101
- * consumers can detect the limit explicitly.
102
- */
103
- type DEFAULT_MAX_DEPTH = 10;
104
- /**
105
- * Resolve a $ref against the local definitions context.
106
- *
107
- * SOURCE-OF-TRUTH: mirrors runtime `resolveRef` in
108
- * `packages/core/src/core/ref.ts` (line 90). Any change to the runtime
109
- * ref-resolution rules (new ref forms, different cycle handling) must be
110
- * reflected here and pinned in
111
- * `packages/core/tests/typeInference-walker-parity.test.ts`.
112
- *
113
- * Supports:
114
- * - `#` (root)
115
- * - `#/$defs/Name` and `#/definitions/Name` (named definitions)
116
- * - `#SomeName` ($anchor, $dynamicAnchor resolved from definitions)
117
- */
118
- type ResolveSchemaRef<R extends string, Defs extends Record<string, unknown>, Depth extends number = 0> = Depth extends DEFAULT_MAX_DEPTH ? __SchemaInferenceFellBack : R extends "#" ? unknown : R extends `#/$defs/${infer Name}` ? Name extends keyof Defs ? DetectRecursiveFallback<FromJSONSchema<Defs[Name], Defs>> : unknown : R extends `#/definitions/${infer Name}` ? Name extends keyof Defs ? DetectRecursiveFallback<FromJSONSchema<Defs[Name], Defs>> : unknown : R extends `#${infer AnchorName}` ? AnchorName extends keyof Defs ? DetectRecursiveFallback<FromJSONSchema<Defs[AnchorName], Defs>> : unknown : unknown;
119
- /**
120
- * Merge an allOf array into an intersection type.
121
- */
122
- type AllOfToType<A, Defs extends Record<string, unknown>> = A extends readonly unknown[] ? UnionToIntersection<FromJSONSchema<A[number], Defs>> : unknown;
123
- /**
124
- * Convert an anyOf/oneOf array into a union type.
125
- *
126
- * SOURCE-OF-TRUTH: mirrors runtime `walkUnion` (and the
127
- * `walkDiscriminatedUnion` fast path) in
128
- * `packages/core/src/core/walker.ts` (lines 723-752), together with
129
- * `detectDiscriminated` and `normaliseAnyOf` in
130
- * `packages/core/src/core/merge.ts` (lines 190-260).
131
- *
132
- * Deliberate divergence: the walker collapses qualifying `oneOf` members
133
- * into a `discriminatedUnion` field at runtime. The type-level helper
134
- * produces a plain TypeScript union because a discriminated union and a
135
- * plain union over the same members are structurally indistinguishable
136
- * at the type level. Parity is pinned in
137
- * `packages/core/tests/typeInference-walker-parity.test.ts`.
138
- *
139
- * Filters out `{ type: "null" }` members and instead makes the result
140
- * nullable when at least one null member is present — mirrors the
141
- * walker's `normaliseAnyOf`.
142
- */
143
- type UnionOfMembers<A, Defs extends Record<string, unknown>> = A extends readonly unknown[] ? HasNullMember<A> extends true ? Exclude<FromJSONSchema<A[number], Defs>, null> | null : FromJSONSchema<A[number], Defs> : unknown;
144
- /**
145
- * Check whether an anyOf/oneOf array contains a `{ type: "null" }` member.
146
- *
147
- * SOURCE-OF-TRUTH: mirrors runtime `normaliseAnyOf` in
148
- * `packages/core/src/core/merge.ts` (lines 190-209). Both implementations
149
- * only recognise schema-shaped null members (`{ type: "null" }`); a bare
150
- * `null` literal in the array is treated as non-nullable. Parity is
151
- * pinned in `packages/core/tests/typeInference-walker-parity.test.ts`.
152
- */
153
- type HasNullMember<A> = A extends readonly unknown[] ? null extends A[number] ? false : {
154
- type: "null";
155
- } extends A[number] ? true : false : false;
156
- /**
157
- * Dispatch on a `type` value -- handles single types, type arrays,
158
- * and delegates to the appropriate type-specific resolver.
159
- */
160
- type TypeToTs<T, S, Defs extends Record<string, unknown>> = T extends "string" ? string : T extends "number" | "integer" ? number : T extends "boolean" ? boolean : T extends "null" ? null : T extends "array" ? ArraySchemaToTs<S, Defs> : T extends "object" ? ObjectSchemaToTs<S, Defs> : T extends readonly (infer E)[] ? TypeArrayToTs<E, S, Defs> : unknown;
161
- /**
162
- * Handle `type` as an array (Draft 04-07): `["string", "null"]`.
163
- * Filters out "null" and makes the result nullable.
164
- */
165
- type TypeArrayToTs<E, S, Defs extends Record<string, unknown>> = E extends "null" ? null : E extends "string" ? NullableResult<string, S> : E extends "number" | "integer" ? NullableResult<number, S> : E extends "boolean" ? NullableResult<boolean, S> : E extends "array" ? NullableResult<ArraySchemaToTs<OmitArrayHelpers<S>, Defs>, S> : E extends "object" ? NullableResult<ObjectSchemaToTs<OmitArrayHelpers<S>, Defs>, S> : unknown;
166
- /**
167
- * Make a type nullable if the original schema `type` array includes "null".
168
- * Detects nullable from the type array directly.
169
- */
170
- type NullableResult<Base, S> = S extends {
171
- type: readonly (infer T)[];
172
- } ? "null" extends T ? Base | null : Base : Base;
173
- /**
174
- * Omit array-utility keys that interfere with object/array matching
175
- * when re-parsing a schema for a single type from a type array.
176
- */
177
- type OmitArrayHelpers<S> = Omit<S, "prefixItems" | "items" | "additionalProperties">;
178
- /**
179
- * Parse an array schema: prefixItems -> tuple, items -> T[], or unknown[].
180
- *
181
- * `contains` / `minContains` / `maxContains` constrain elements at runtime
182
- * but don't change the compile-time array element type.
183
- */
184
- type ArraySchemaToTs<S, Defs extends Record<string, unknown>> = S extends {
185
- prefixItems: infer P;
186
- } ? PrefixItemsToTuple<P, Defs> : S extends {
187
- items: infer I;
188
- } ? FromJSONSchema<I, Defs>[] : unknown[];
189
- /**
190
- * Convert a prefixItems array to a TypeScript tuple type.
191
- */
192
- type PrefixItemsToTuple<P, Defs extends Record<string, unknown>> = P extends readonly [infer First, ...infer Rest] ? [FromJSONSchema<First, Defs>, ...PrefixItemsToTuple<Rest, Defs>] : [];
193
- /**
194
- * Parse an object schema: properties + required -> specific object,
195
- * additionalProperties -> Record, or empty object.
196
- *
197
- * Handles:
198
- * - `properties` + `required` -> specific object type with required/optional keys
199
- * - `additionalProperties` as schema -> Record<string, T>
200
- * - `patternProperties` -> merged into a loose index signature alongside specific props
201
- * (TypeScript cannot express regex-keyed properties)
202
- * - `propertyNames` -> ignored at type level (TS cannot validate key shapes)
203
- * - `dependentSchemas` / `dependentRequired` -> ignored (runtime-only conditionals)
204
- * - `unevaluatedProperties` -> ignored (runtime-only)
205
- */
206
- type ObjectSchemaToTs<S, Defs extends Record<string, unknown>> = S extends {
207
- type: "object";
208
- properties: infer P;
209
- } ? ExtractDefs<S, Defs> extends infer D extends Record<string, unknown> ? MergePatternProps<{ [K in keyof P as K extends RequiredKeysOf<S> ? K : never]: FromJSONSchema<P[K], D> } & { [K in keyof P as K extends RequiredKeysOf<S> ? never : K]?: FromJSONSchema<P[K], D> }, S, D> : never : S extends {
210
- additionalProperties: infer V;
211
- } ? Record<string, FromJSONSchema<V, Defs>> : Record<string, unknown>;
212
- /**
213
- * If the schema has `patternProperties`, intersect the base object type
214
- * with a `Record<string, T>` index signature covering all pattern values.
215
- * If no `patternProperties`, return the base type unchanged.
216
- */
217
- type MergePatternProps<Base, S, Defs extends Record<string, unknown>> = S extends {
218
- patternProperties: infer PP;
219
- } ? PP extends Record<string, unknown> ? Base & Record<string, UnionOfPatternValues<PP, Defs>> : Base : Base;
220
- /**
221
- * Extract the union of all pattern property value types.
222
- */
223
- type UnionOfPatternValues<PP extends Record<string, unknown>, Defs extends Record<string, unknown>> = { [K in keyof PP]: FromJSONSchema<PP[K], Defs> }[keyof PP];
224
- /**
225
- * Extract the `required` array from a schema as a union of string literals.
226
- * Handles both readonly `as const` arrays and mutable arrays.
227
- */
228
- type RequiredKeysOf<S> = S extends {
229
- required: infer R;
230
- } ? R extends readonly string[] ? R[number] : never : never;
231
- /**
232
- * Extract $defs / definitions from a schema for $ref resolution context.
233
- * Also indexes schemas with `$anchor` or `$dynamicAnchor` by their anchor name,
234
- * enabling `#SomeName` ref resolution.
235
- * Merges with the existing Defs context from parent schemas.
236
- */
237
- type ExtractDefs<S, ParentDefs extends Record<string, unknown>> = ExtractRawDefs<S> extends infer RawDefs extends Record<string, unknown> ? RawDefs & ParentDefs & ExtractAnchors<RawDefs> : ParentDefs;
238
- /** Extract raw $defs / definitions maps. */
239
- type ExtractRawDefs<S> = S extends {
240
- $defs: infer D;
241
- } ? D extends Record<string, unknown> ? D : Record<string, never> : S extends {
242
- definitions: infer D;
243
- } ? D extends Record<string, unknown> ? D : Record<string, never> : Record<string, never>;
244
- /**
245
- * Build a map of `$anchor` name -> schema from a definitions block.
246
- * Scans each definition value for `$anchor` or `$dynamicAnchor` and
247
- * creates entries like `{ Tree: <schema-with-$anchor-Tree> }`.
248
- */
249
- type ExtractAnchors<D extends Record<string, unknown>> = { [K in keyof D as D[K] extends {
250
- $anchor: infer A extends string;
251
- } ? A : D[K] extends {
252
- $dynamicAnchor: infer A extends string;
253
- } ? A : never]: D[K] };
254
- /**
255
- * Convert a union to an intersection.
256
- * `A | B` -> `A & B`. Used for allOf merging.
257
- */
258
- type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
259
- /**
260
- * Resolves an OpenAPI `ref` string to its JSON Schema, then parses it.
261
- *
262
- * SOURCE-OF-TRUTH: mirrors runtime `resolveRef` in
263
- * `packages/core/src/core/ref.ts` (line 90), which is invoked by the
264
- * walker entry point in `packages/core/src/core/walker.ts` (lines
265
- * 144-154) for OpenAPI documents. Any change to the runtime ref-resolution
266
- * rules (new ref forms, different cycle handling, JSON Pointer decoding)
267
- * must be reflected here and pinned in
268
- * `packages/core/tests/typeInference-walker-parity.test.ts`.
269
- *
270
- * Handles:
271
- * - `#/components/schemas/Name` (OpenAPI 3.x)
272
- * - `#/definitions/Name` (Swagger 2.0)
273
- * - `#/paths/...` (path-based refs, navigating the document tree)
274
- */
275
- type ResolveOpenAPIRef<Spec extends Record<string, unknown>, Ref extends string> = Ref extends `#/components/schemas/${infer Name}` ? Spec["components"] extends Record<string, unknown> ? Spec["components"]["schemas"] extends Record<string, unknown> ? Name extends keyof Spec["components"]["schemas"] ? FromJSONSchema<Spec["components"]["schemas"][Name]> : unknown : unknown : unknown : Ref extends `#/definitions/${infer Name}` ? Spec["definitions"] extends Record<string, unknown> ? Name extends keyof Spec["definitions"] ? FromJSONSchema<Spec["definitions"][Name]> : unknown : unknown : Ref extends `#/paths/${infer PathRest}` ? ResolvePathBasedRef<Spec, PathRest> : unknown;
276
- /**
277
- * Resolve a path-based $ref after the `#/paths/` prefix.
278
- * Splits on `/` and navigates the document tree.
279
- *
280
- * Note: JSON Pointer tilde encoding (~1 for /, ~0 for ~) is not decoded
281
- * at the type level. For `as const` literals, use the literal path
282
- * character directly (e.g. `#/paths//pets/get/...`).
283
- */
284
- type ResolvePathBasedRef<Spec extends Record<string, unknown>, PathRest extends string> = Spec["paths"] extends Record<string, unknown> ? ResolvePathSegments<Spec["paths"], SplitPath<PathRest>> : unknown;
285
- /**
286
- * Split a path string on `/` into a tuple of segments.
287
- * The first segment is the path key (may be empty for `/pets` -> `""` / `"pets"`).
288
- */
289
- type SplitPath<S extends string> = S extends `${infer Head}/${infer Tail}` ? [Head, ...SplitPath<Tail>] : [S];
290
- /**
291
- * Recursively navigate into a document object by path segments.
292
- */
293
- type ResolvePathSegments<Doc, Segs extends string[]> = Segs extends [infer Head extends string, ...infer Rest extends string[]] ? Doc extends Record<string, unknown> ? Rest extends [] ? Doc[Head] : ResolvePathSegments<Doc[Head], Rest> : unknown : unknown;
294
- /** Navigate to a path item in an OpenAPI document. */
295
- type PathItemOf<Doc, Path extends string> = Doc extends {
296
- paths: Record<string, unknown>;
297
- } ? Path extends keyof Doc["paths"] ? Doc["paths"][Path] : unknown : unknown;
298
- /** Navigate to an operation within a path item. */
299
- type OperationOf<PathItem, Method extends string> = PathItem extends Record<string, unknown> ? Method extends keyof PathItem ? PathItem[Method] : unknown : unknown;
300
- /** Extract the schema from request body content (any media type). */
301
- type RequestBodySchemaOf<Op> = Op extends {
302
- requestBody: {
303
- content: Record<string, {
304
- schema: infer S;
305
- }>;
306
- };
307
- } ? S : Op extends {
308
- requestBody: {
309
- content: {
310
- "application/json": {
311
- schema: infer S;
312
- };
313
- };
314
- };
315
- } ? S : unknown;
316
- /** Extract the schema from response content (any media type). */
317
- type ResponseSchemaOf<Op, Status extends string> = Op extends {
318
- responses: Record<string, unknown>;
319
- } ? Status extends keyof Op["responses"] ? Op["responses"][Status] extends {
320
- content: Record<string, {
321
- schema: infer S;
322
- }>;
323
- } ? S : Op["responses"][Status] extends {
324
- content: {
325
- "application/json": {
326
- schema: infer S;
327
- };
328
- };
329
- } ? S : unknown : unknown : unknown;
330
- /** Resolve a schema that may be a $ref pointer. */
331
- type ResolveMaybeRef<Doc, S> = S extends {
332
- $ref: infer R extends string;
333
- } ? ResolveOpenAPIRef<Doc & Record<string, unknown>, R> : S extends {
334
- nullable: true;
335
- } & Record<string, unknown> ? FromJSONSchema<Omit<S, "nullable">> | null : S extends Record<string, unknown> ? FromJSONSchema<S> : unknown;
336
- /** Extract parameter names from an operation. */
337
- type ParameterNamesOf<Doc, Path extends string, Method extends string> = OperationOf<PathItemOf<Doc, Path>, Method> extends {
338
- parameters: readonly unknown[];
339
- } ? OperationOf<PathItemOf<Doc, Path>, Method>["parameters"][number] extends {
340
- name: infer N;
341
- } ? N extends string ? N : never : never : never;
342
- /**
343
- * Infer the TypeScript type of an OpenAPI operation's request body.
344
- */
345
- type OpenAPIRequestBodyType<Doc, Path extends string, Method extends string> = ResolveMaybeRef<Doc, RequestBodySchemaOf<OperationOf<PathItemOf<Doc, Path>, Method>>>;
346
- /**
347
- * Infer the TypeScript type of an OpenAPI operation's response.
348
- */
349
- type OpenAPIResponseType<Doc, Path extends string, Method extends string, Status extends string> = ResolveMaybeRef<Doc, ResponseSchemaOf<OperationOf<PathItemOf<Doc, Path>, Method>, Status>>;
350
- /**
351
- * Infer the fields prop type for ApiRequestBody.
352
- * Surfaces `__SchemaInferenceFellBack` when the schema contains
353
- * recursive $ref chains that exceed type-level depth limits.
354
- * Falls back to `Record<string, FieldOverride>` for runtime documents.
355
- */
356
- type InferRequestBodyFields<Doc, Path extends string, Method extends string> = unknown extends OpenAPIRequestBodyType<Doc, Path, Method> ? OpenAPIRequestBodyType<Doc, Path, Method> extends __SchemaInferenceFellBack ? __SchemaInferenceFellBack : Record<string, FieldOverride> : FieldOverrides<OpenAPIRequestBodyType<Doc, Path, Method>>;
357
- /**
358
- * Infer the fields prop type for ApiResponse.
359
- * Surfaces `__SchemaInferenceFellBack` when the schema contains
360
- * recursive $ref chains that exceed type-level depth limits.
361
- * Falls back to `Record<string, FieldOverride>` for runtime documents.
362
- */
363
- type InferResponseFields<Doc, Path extends string, Method extends string, Status extends string> = unknown extends OpenAPIResponseType<Doc, Path, Method, Status> ? OpenAPIResponseType<Doc, Path, Method, Status> extends __SchemaInferenceFellBack ? __SchemaInferenceFellBack : Record<string, FieldOverride> : FieldOverrides<OpenAPIResponseType<Doc, Path, Method, Status>>;
364
- /**
365
- * Infer the overrides prop type for ApiParameters.
366
- * Falls back to `Record<string, FieldOverride>` for runtime documents.
367
- */
368
- type InferParameterOverrides<Doc, Path extends string, Method extends string> = string extends ParameterNamesOf<Doc, Path, Method> ? Record<string, FieldOverride> : Partial<Record<ParameterNamesOf<Doc, Path, Method>, FieldOverride>>;
369
- /**
370
- * Check if T is a "narrow" type (not wide like object, Record, or unknown).
371
- * Used to determine if we can enumerate keys for path inference.
372
- */
373
- type IsNarrowObject<T> = T extends string | number | boolean | null | undefined | unknown[] ? false : T extends object ? Record<string, never> extends T ? false : true : false;
374
- /**
375
- * Extract all valid dot-separated paths from an object type.
376
- * Produces paths like "name" | "address.city" | "address.postcode".
377
- * Stops at leaf types (string, number, boolean, null) and arrays.
378
- * Returns `string` for wide types (object, Record, unknown).
379
- * Handles optional/nullable fields by unwrapping T | undefined.
380
- */
381
- type PathOfType<T, Prefix extends string = ""> = IsNarrowObject<T> extends true ? { [K in keyof T & string]: T[K] extends string | number | boolean | null | undefined ? `${Prefix}${K}` : T[K] extends unknown[] ? `${Prefix}${K}` : T[K] extends object | undefined ? PathOfType<Exclude<T[K], undefined>, `${Prefix}${K}.`> | `${Prefix}${K}` : `${Prefix}${K}` }[keyof T & string] : string;
382
- /**
383
- * Extract the type at a given dot-separated path.
384
- * PathOfType<T> produces valid paths; TypeAtPath resolves the leaf type.
385
- */
386
- type TypeAtPath<T, P extends string> = P extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? TypeAtPath<T[Key], Rest> : unknown : P extends keyof T ? T[P] : unknown;
387
- //#endregion
388
- export { InferResponseFields as a, PathOfType as c, UnsafeFields as d, __SchemaInferenceFellBack as f, InferRequestBodyFields as i, ResolveOpenAPIRef as l, FromJSONSchema as n, OpenAPIRequestBodyType as o, InferParameterOverrides as r, OpenAPIResponseType as s, DEFAULT_MAX_DEPTH as t, TypeAtPath as u };