schema-components 1.20.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.
- package/dist/core/adapter.d.mts +9 -2
- package/dist/core/adapter.mjs +220 -64
- package/dist/core/constraints.d.mts +1 -1
- package/dist/core/constraints.mjs +0 -2
- package/dist/core/errors.d.mts +1 -1
- package/dist/core/errors.mjs +9 -15
- package/dist/core/fieldOrder.d.mts +1 -1
- package/dist/core/merge.d.mts +10 -1
- package/dist/core/merge.mjs +11 -0
- package/dist/core/normalise.d.mts +7 -1
- package/dist/core/normalise.mjs +1 -1
- package/dist/core/openapi30.d.mts +24 -1
- package/dist/core/openapi30.mjs +2 -2
- package/dist/core/ref.d.mts +1 -1
- package/dist/core/ref.mjs +34 -9
- package/dist/core/renderer.d.mts +1 -1
- package/dist/core/swagger2.mjs +1 -1
- package/dist/core/typeInference.d.mts +1 -1
- package/dist/core/types.d.mts +1 -1
- package/dist/core/walkBuilders.d.mts +12 -4
- package/dist/core/walkBuilders.mjs +11 -3
- package/dist/core/walker.d.mts +1 -1
- package/dist/core/walker.mjs +32 -25
- package/dist/{errors-C2iABcn9.d.mts → errors-QEwOtQAA.d.mts} +7 -11
- package/dist/html/a11y.d.mts +2 -2
- package/dist/html/renderToHtml.d.mts +2 -2
- package/dist/html/renderToHtmlStream.d.mts +2 -2
- package/dist/html/renderers.d.mts +2 -2
- package/dist/html/renderers.mjs +1 -1
- package/dist/html/streamRenderers.d.mts +2 -2
- package/dist/{normalise-CMMEl4cd.mjs → normalise-DaSrnr8g.mjs} +325 -28
- package/dist/openapi/ApiCallbacks.d.mts +1 -1
- package/dist/openapi/ApiLinks.d.mts +1 -1
- package/dist/openapi/ApiResponseHeaders.d.mts +1 -1
- package/dist/openapi/ApiSecurity.d.mts +1 -1
- package/dist/openapi/ApiSecurity.mjs +113 -7
- package/dist/openapi/components.d.mts +32 -10
- package/dist/openapi/components.mjs +22 -12
- package/dist/openapi/parser.d.mts +1 -1
- package/dist/openapi/parser.mjs +39 -4
- package/dist/openapi/resolve.d.mts +60 -9
- package/dist/openapi/resolve.mjs +86 -23
- package/dist/react/SchemaComponent.d.mts +4 -4
- package/dist/react/SchemaComponent.mjs +32 -4
- package/dist/react/SchemaView.d.mts +2 -2
- package/dist/react/fieldPath.d.mts +1 -1
- package/dist/react/headless.d.mts +1 -1
- package/dist/react/headlessRenderers.d.mts +2 -2
- package/dist/react/headlessRenderers.mjs +1 -1
- package/dist/{ref-C8JbwfiS.d.mts → ref-si8ViYun.d.mts} +6 -1
- package/dist/{renderer-SOIbJBtk.d.mts → renderer-DI6ZYf7a.d.mts} +1 -1
- package/dist/themes/mantine.d.mts +1 -1
- package/dist/themes/mui.d.mts +1 -1
- package/dist/themes/radix.d.mts +1 -1
- package/dist/themes/shadcn.d.mts +1 -1
- package/dist/{typeInference-CDoD_LZ_.d.mts → typeInference-Bxw3NOG1.d.mts} +162 -48
- package/dist/{types-C9zw9wbX.d.mts → types-BnxPEElk.d.mts} +12 -2
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as FieldOverrides, u as FieldOverride } from "./types-
|
|
1
|
+
import { d as FieldOverrides, u as FieldOverride } from "./types-BnxPEElk.mjs";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
|
|
4
4
|
//#region src/core/typeInference.d.ts
|
|
@@ -24,20 +24,51 @@ type UnrepresentableZodType = z.ZodBigInt | z.ZodDate | z.ZodMap | z.ZodSet | z.
|
|
|
24
24
|
interface UnrepresentableZodSchemaError {
|
|
25
25
|
readonly __schemaComponentsError: "Zod 4 type has no JSON Schema representation. See SchemaNormalisationError code 'zod-type-unrepresentable'.";
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Recursively unwrap Zod 4 wrappers that hold an inner schema —
|
|
29
|
+
* `ZodOptional`, `ZodNullable`, `ZodReadonly`, `ZodLazy`, and `ZodPipe`.
|
|
30
|
+
*
|
|
31
|
+
* The runtime conversion still throws for `z.optional(z.bigint())`,
|
|
32
|
+
* `z.lazy(() => z.bigint())`, `z.nullable(z.bigint())`,
|
|
33
|
+
* `z.bigint().readonly()`, and `z.bigint().pipe(z.bigint())` because
|
|
34
|
+
* `z.toJSONSchema()` walks into the wrapped schema before reporting the
|
|
35
|
+
* unrepresentable type. The compile-time rejection must therefore peel
|
|
36
|
+
* those wrappers off before checking against the rejection list, or the
|
|
37
|
+
* brand would never surface for wrapped inputs.
|
|
38
|
+
*
|
|
39
|
+
* `ZodCodec` is short-circuited at the top because it is itself listed
|
|
40
|
+
* in {@link UnrepresentableZodType}. It extends `ZodPipe` structurally,
|
|
41
|
+
* so without the early exit the `ZodPipe` branch would unwrap a bare
|
|
42
|
+
* codec into its two sides and the rejection would no longer fire for
|
|
43
|
+
* `z.codec(...)`.
|
|
44
|
+
*
|
|
45
|
+
* `ZodPipe` (non-codec) has two slots (`in` and `out`); both are
|
|
46
|
+
* unwrapped into a union so a single unrepresentable side surfaces via
|
|
47
|
+
* {@link AnyMemberIsUnrepresentable}.
|
|
48
|
+
*/
|
|
49
|
+
type UnwrapZodWrapper<T> = T extends z.ZodCodec ? T : T extends z.ZodOptional<infer Inner> ? UnwrapZodWrapper<Inner> : T extends z.ZodNullable<infer Inner> ? UnwrapZodWrapper<Inner> : T extends z.ZodReadonly<infer Inner> ? UnwrapZodWrapper<Inner> : T extends z.ZodLazy<infer Inner> ? UnwrapZodWrapper<Inner> : T extends z.ZodPipe<infer InnerIn, infer InnerOut> ? UnwrapZodWrapper<InnerIn> | UnwrapZodWrapper<InnerOut> : T;
|
|
50
|
+
/**
|
|
51
|
+
* True when any member of the (possibly unioned) input extends one of
|
|
52
|
+
* the unrepresentable Zod types. Distribution over the union ensures a
|
|
53
|
+
* single unrepresentable member triggers true — matching runtime
|
|
54
|
+
* semantics for `ZodPipe`, whose two sides expand to a union via
|
|
55
|
+
* {@link UnwrapZodWrapper}.
|
|
56
|
+
*/
|
|
57
|
+
type AnyMemberIsUnrepresentable<T> = (T extends UnrepresentableZodType ? true : false) extends false ? false : true;
|
|
27
58
|
/**
|
|
28
59
|
* Reject Zod 4 inputs whose runtime conversion is known to throw.
|
|
29
60
|
*
|
|
30
|
-
* - When `T`
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
61
|
+
* - When `T` (or any inner schema wrapped by `ZodOptional`,
|
|
62
|
+
* `ZodNullable`, `ZodReadonly`, `ZodLazy`, or `ZodPipe`) is one of
|
|
63
|
+
* the {@link UnrepresentableZodType} variants, the resolved type is
|
|
64
|
+
* {@link UnrepresentableZodSchemaError}, which is not assignable from
|
|
65
|
+
* any legitimate Zod / JSON Schema / OpenAPI input — so the prop
|
|
66
|
+
* fails to typecheck.
|
|
34
67
|
* - Anything else (Zod 4 schemas that DO convert, JSON Schema literals,
|
|
35
68
|
* OpenAPI documents, `unknown` for runtime inputs) passes through
|
|
36
69
|
* unchanged.
|
|
37
|
-
*
|
|
38
|
-
* Wrapped in a tuple to suppress distribution over union types.
|
|
39
70
|
*/
|
|
40
|
-
type RejectUnrepresentableZod<T> =
|
|
71
|
+
type RejectUnrepresentableZod<T> = AnyMemberIsUnrepresentable<UnwrapZodWrapper<T>> extends true ? UnrepresentableZodSchemaError : T;
|
|
41
72
|
/**
|
|
42
73
|
* Convert a readonly tuple/array of values to a union type.
|
|
43
74
|
* Handles both `as const` readonly tuples and mutable arrays.
|
|
@@ -66,7 +97,7 @@ type ArrayToUnion<A> = A extends readonly unknown[] ? A[number] : never;
|
|
|
66
97
|
* - not -> unknown (negation not expressible in TS)
|
|
67
98
|
* - patternProperties -> merged into loose index signature
|
|
68
99
|
*/
|
|
69
|
-
type FromJSONSchema<S, Defs extends Record<string, unknown> = Record<string, never
|
|
100
|
+
type FromJSONSchema<S, Defs extends Record<string, unknown> = Record<string, never>, Depth extends readonly unknown[] = []> = MergeRootDefs<S, Defs> extends infer MergedDefs extends Record<string, unknown> ? S extends {
|
|
70
101
|
nullable: true;
|
|
71
102
|
} ?
|
|
72
103
|
/**
|
|
@@ -77,21 +108,21 @@ type FromJSONSchema<S, Defs extends Record<string, unknown> = Record<string, nev
|
|
|
77
108
|
* `FromJSONSchema` level means nested fields inside refs preserve
|
|
78
109
|
* nullability when resolved.
|
|
79
110
|
*/
|
|
80
|
-
FromJSONSchema<Omit<S, "nullable">,
|
|
111
|
+
FromJSONSchema<Omit<S, "nullable">, MergedDefs, Depth> | null : S extends {
|
|
81
112
|
$ref: infer R extends string;
|
|
82
|
-
} ? ResolveSchemaRef<R,
|
|
113
|
+
} ? ResolveSchemaRef<R, MergedDefs, Depth> : S extends {
|
|
83
114
|
$recursiveRef: string;
|
|
84
115
|
} ? unknown : S extends {
|
|
85
116
|
$dynamicRef: infer R extends string;
|
|
86
|
-
} ? ResolveSchemaRef<R,
|
|
117
|
+
} ? ResolveSchemaRef<R, MergedDefs, Depth> : S extends {
|
|
87
118
|
allOf: infer A;
|
|
88
|
-
} ? AllOfToType<A,
|
|
119
|
+
} ? AllOfToType<A, MergedDefs, Depth> : S extends {
|
|
89
120
|
anyOf: infer A;
|
|
90
|
-
} ? UnionOfMembers<A,
|
|
121
|
+
} ? UnionOfMembers<A, MergedDefs, Depth> : S extends {
|
|
91
122
|
oneOf: infer A;
|
|
92
|
-
} ? UnionOfMembers<A,
|
|
123
|
+
} ? UnionOfMembers<A, MergedDefs, Depth> : S extends {
|
|
93
124
|
if: unknown;
|
|
94
|
-
} ? FromJSONSchema<Omit<S, "if" | "then" | "else">,
|
|
125
|
+
} ? FromJSONSchema<Omit<S, "if" | "then" | "else">, MergedDefs, Depth> : S extends {
|
|
95
126
|
not: unknown;
|
|
96
127
|
} ? unknown : S extends {
|
|
97
128
|
const: infer V;
|
|
@@ -99,7 +130,68 @@ FromJSONSchema<Omit<S, "nullable">, Defs> | null : S extends {
|
|
|
99
130
|
enum: infer E;
|
|
100
131
|
} ? ArrayToUnion<E> : S extends {
|
|
101
132
|
type: infer T;
|
|
102
|
-
} ? TypeToTs<T, S,
|
|
133
|
+
} ? TypeToTs<T, S, MergedDefs, Depth> : S extends readonly (infer E)[] ? E : unknown : unknown;
|
|
134
|
+
/**
|
|
135
|
+
* Merge `$defs` / `definitions` declared at the current schema position with
|
|
136
|
+
* the caller-supplied `Defs` map BEFORE the ref/allOf/anyOf/oneOf dispatch.
|
|
137
|
+
*
|
|
138
|
+
* SOURCE-OF-TRUTH: parity with the runtime walker, which uses `rootDocument`
|
|
139
|
+
* (see `packages/core/src/core/ref.ts` line 91) to resolve any `$ref` against
|
|
140
|
+
* the full document — including sibling definitions colocated with the
|
|
141
|
+
* reference. Without this merge, a legal schema like
|
|
142
|
+
* `{ $ref: "#/definitions/Foo", definitions: { Foo: {...} } }` would lose
|
|
143
|
+
* its sibling defs because the ref branch fires before `ExtractDefs` runs
|
|
144
|
+
* inside `ObjectSchemaToTs`.
|
|
145
|
+
*
|
|
146
|
+
* Merge semantics (per-key resolution via {@link CollisionSafeMerge}):
|
|
147
|
+
* - Parent-only keys: parent value wins
|
|
148
|
+
* - Local-only keys: local value wins
|
|
149
|
+
* - Shared keys: parent value wins (caller / inherited context takes
|
|
150
|
+
* precedence over a deeper redeclaration)
|
|
151
|
+
*
|
|
152
|
+
* When the current schema declares no local defs (`HasLocalDefs<S>` is
|
|
153
|
+
* `false`), `ParentDefs` is returned unchanged so the inherited context
|
|
154
|
+
* is never poisoned by the empty index-signature sentinel.
|
|
155
|
+
*/
|
|
156
|
+
type MergeRootDefs<S, ParentDefs extends Record<string, unknown>> = HasLocalDefs<S> extends true ? ExtractRawDefs<S> extends infer RawDefs extends Record<string, unknown> ? CollisionSafeMerge<CollisionSafeMerge<RawDefs, ExtractAnchors<RawDefs>>, ParentDefs> : ParentDefs : ParentDefs;
|
|
157
|
+
/**
|
|
158
|
+
* Merge two record-shaped types where keys present in `B` always take
|
|
159
|
+
* precedence over the same key in `A`.
|
|
160
|
+
*
|
|
161
|
+
* The empty default `Record<string, never>` is detected explicitly via
|
|
162
|
+
* {@link IsEmptyDefs}: when either side is the sentinel, the other side
|
|
163
|
+
* is returned unchanged. This avoids two pitfalls of the naive
|
|
164
|
+
* `Omit<A, keyof B> & B` approach:
|
|
165
|
+
*
|
|
166
|
+
* 1. `keyof Record<string, never>` is the entire `string` type, so
|
|
167
|
+
* `Omit<A, string>` would strip every key from `A`.
|
|
168
|
+
* 2. Iterating a mapped type over `keyof A | keyof B` where either side
|
|
169
|
+
* contributes `string` collapses every entry to the index-signature
|
|
170
|
+
* value (`never` in the sentinel), wiping the literal keys from the
|
|
171
|
+
* other side.
|
|
172
|
+
*
|
|
173
|
+
* Only when both sides hold concrete literal keys does the per-key
|
|
174
|
+
* mapped merge run.
|
|
175
|
+
*/
|
|
176
|
+
type CollisionSafeMerge<A, B> = IsEmptyDefs<A> extends true ? B : IsEmptyDefs<B> extends true ? A : { [K in keyof A | keyof B]: K extends keyof B ? B[K] : K extends keyof A ? A[K] : never };
|
|
177
|
+
/**
|
|
178
|
+
* True for the empty-default `Record<string, never>` sentinel used as the
|
|
179
|
+
* initial `Defs` map — i.e. an open index signature `[string]: never`
|
|
180
|
+
* with no literal keys. Distinguished from a record with at least one
|
|
181
|
+
* literal key by checking that `string extends keyof T`.
|
|
182
|
+
*/
|
|
183
|
+
type IsEmptyDefs<T> = [keyof T] extends [never] ? true : string extends keyof T ? true : false;
|
|
184
|
+
/**
|
|
185
|
+
* True when the schema declares `$defs` or `definitions` as an object,
|
|
186
|
+
* false otherwise. Used by {@link MergeRootDefs} and {@link ExtractDefs}
|
|
187
|
+
* to avoid intersecting the parent context with an empty
|
|
188
|
+
* index-signature sentinel.
|
|
189
|
+
*/
|
|
190
|
+
type HasLocalDefs<S> = S extends {
|
|
191
|
+
$defs: Record<string, unknown>;
|
|
192
|
+
} ? true : S extends {
|
|
193
|
+
definitions: Record<string, unknown>;
|
|
194
|
+
} ? true : false;
|
|
103
195
|
/**
|
|
104
196
|
* Marker type emitted when OpenAPI $ref resolution hits the type-level
|
|
105
197
|
* recursion depth limit. Instead of silently falling back to
|
|
@@ -137,18 +229,23 @@ type DetectRecursiveFallback<T> = unknown extends T ? __SchemaInferenceFellBack
|
|
|
137
229
|
*
|
|
138
230
|
* The TypeScript type system imposes its own recursion limit; without an
|
|
139
231
|
* explicit bound a cyclic schema graph would exhaust it and degrade to
|
|
140
|
-
* `any`/`unknown` silently.
|
|
141
|
-
* — see `
|
|
142
|
-
*
|
|
232
|
+
* `any`/`unknown` silently. This number is the runtime walker's parallel
|
|
233
|
+
* — see `resolveRef` in `packages/core/src/core/ref.ts` (line 119), whose
|
|
234
|
+
* default `maxDepth` is `64`. Matching the runtime bound here means a
|
|
235
|
+
* schema that the runtime resolves successfully is never silently dropped
|
|
236
|
+
* to `__SchemaInferenceFellBack` at compile time purely because the
|
|
237
|
+
* type-level limit was lower.
|
|
143
238
|
*
|
|
144
239
|
* A fixed bound is used here rather than a derived one because the type
|
|
145
240
|
* system has no way to count distinct strings across a recursive `Defs`
|
|
146
241
|
* map without itself recursing — which is the problem the bound exists
|
|
147
|
-
* to solve.
|
|
148
|
-
*
|
|
149
|
-
*
|
|
242
|
+
* to solve. Real-world OpenAPI documents (Stripe, GitHub, AWS) routinely
|
|
243
|
+
* contain 30-100+ distinct `$ref` strings, so a low ceiling would mask
|
|
244
|
+
* legitimate references. Deeper graphs surface as
|
|
245
|
+
* `__SchemaInferenceFellBack` so consumers can detect the limit
|
|
246
|
+
* explicitly.
|
|
150
247
|
*/
|
|
151
|
-
type DEFAULT_MAX_DEPTH =
|
|
248
|
+
type DEFAULT_MAX_DEPTH = 64;
|
|
152
249
|
/**
|
|
153
250
|
* Resolve a $ref against the local definitions context.
|
|
154
251
|
*
|
|
@@ -170,11 +267,11 @@ type DEFAULT_MAX_DEPTH = 10;
|
|
|
170
267
|
* a Zod-converted or hand-written JSON Schema that points into the
|
|
171
268
|
* OpenAPI component tree, this branch produces the corresponding type.
|
|
172
269
|
*/
|
|
173
|
-
type ResolveSchemaRef<R extends string, Defs extends Record<string, unknown>, Depth extends
|
|
270
|
+
type ResolveSchemaRef<R extends string, Defs extends Record<string, unknown>, Depth extends readonly unknown[] = []> = Depth["length"] extends DEFAULT_MAX_DEPTH ? __SchemaInferenceFellBack : R extends "#" ? unknown : R extends `#/$defs/${infer Name}` ? Name extends keyof Defs ? DetectRecursiveFallback<FromJSONSchema<Defs[Name], Defs, [unknown, ...Depth]>> : unknown : R extends `#/definitions/${infer Name}` ? Name extends keyof Defs ? DetectRecursiveFallback<FromJSONSchema<Defs[Name], Defs, [unknown, ...Depth]>> : unknown : R extends `#/components/schemas/${infer Name}` ? Name extends keyof Defs ? DetectRecursiveFallback<FromJSONSchema<Defs[Name], Defs, [unknown, ...Depth]>> : unknown : R extends `#${infer AnchorName}` ? AnchorName extends keyof Defs ? DetectRecursiveFallback<FromJSONSchema<Defs[AnchorName], Defs, [unknown, ...Depth]>> : unknown : unknown;
|
|
174
271
|
/**
|
|
175
272
|
* Merge an allOf array into an intersection type.
|
|
176
273
|
*/
|
|
177
|
-
type AllOfToType<A, Defs extends Record<string, unknown
|
|
274
|
+
type AllOfToType<A, Defs extends Record<string, unknown>, Depth extends readonly unknown[] = []> = A extends readonly unknown[] ? UnionToIntersection<FromJSONSchema<A[number], Defs, Depth>> : unknown;
|
|
178
275
|
/**
|
|
179
276
|
* Convert an anyOf/oneOf array into a union type.
|
|
180
277
|
*
|
|
@@ -195,7 +292,7 @@ type AllOfToType<A, Defs extends Record<string, unknown>> = A extends readonly u
|
|
|
195
292
|
* nullable when at least one null member is present — mirrors the
|
|
196
293
|
* walker's `normaliseAnyOf`.
|
|
197
294
|
*/
|
|
198
|
-
type UnionOfMembers<A, Defs extends Record<string, unknown
|
|
295
|
+
type UnionOfMembers<A, Defs extends Record<string, unknown>, Depth extends readonly unknown[] = []> = A extends readonly unknown[] ? HasNullMember<A> extends true ? Exclude<FromJSONSchema<A[number], Defs, Depth>, null> | null : FromJSONSchema<A[number], Defs, Depth> : unknown;
|
|
199
296
|
/**
|
|
200
297
|
* Check whether an anyOf/oneOf array contains a `{ type: "null" }` member.
|
|
201
298
|
*
|
|
@@ -212,12 +309,12 @@ type HasNullMember<A> = A extends readonly unknown[] ? null extends A[number] ?
|
|
|
212
309
|
* Dispatch on a `type` value -- handles single types, type arrays,
|
|
213
310
|
* and delegates to the appropriate type-specific resolver.
|
|
214
311
|
*/
|
|
215
|
-
type TypeToTs<T, S, Defs extends Record<string, unknown
|
|
312
|
+
type TypeToTs<T, S, Defs extends Record<string, unknown>, Depth extends readonly unknown[] = []> = T extends "string" ? string : T extends "number" | "integer" ? number : T extends "boolean" ? boolean : T extends "null" ? null : T extends "array" ? ArraySchemaToTs<S, Defs, Depth> : T extends "object" ? ObjectSchemaToTs<S, Defs, Depth> : T extends readonly (infer E)[] ? TypeArrayToTs<E, S, Defs, Depth> : unknown;
|
|
216
313
|
/**
|
|
217
314
|
* Handle `type` as an array (Draft 04-07): `["string", "null"]`.
|
|
218
315
|
* Filters out "null" and makes the result nullable.
|
|
219
316
|
*/
|
|
220
|
-
type TypeArrayToTs<E, S, Defs extends Record<string, unknown
|
|
317
|
+
type TypeArrayToTs<E, S, Defs extends Record<string, unknown>, Depth extends readonly 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, Depth>, S> : E extends "object" ? NullableResult<ObjectSchemaToTs<OmitArrayHelpers<S>, Defs, Depth>, S> : unknown;
|
|
221
318
|
/**
|
|
222
319
|
* Make a type nullable if the original schema `type` array includes "null".
|
|
223
320
|
* Detects nullable from the type array directly.
|
|
@@ -243,17 +340,17 @@ type OmitArrayHelpers<S> = Omit<S, "prefixItems" | "items" | "additionalProperti
|
|
|
243
340
|
* `contains` / `minContains` / `maxContains` constrain elements at runtime
|
|
244
341
|
* but don't change the compile-time array element type.
|
|
245
342
|
*/
|
|
246
|
-
type ArraySchemaToTs<S, Defs extends Record<string, unknown
|
|
343
|
+
type ArraySchemaToTs<S, Defs extends Record<string, unknown>, Depth extends readonly unknown[] = []> = S extends {
|
|
247
344
|
prefixItems: infer P;
|
|
248
|
-
} ? PrefixItemsToTuple<P, Defs> : S extends {
|
|
345
|
+
} ? PrefixItemsToTuple<P, Defs, Depth> : S extends {
|
|
249
346
|
items: infer I extends readonly unknown[];
|
|
250
|
-
} ? PrefixItemsToTuple<I, Defs> : S extends {
|
|
347
|
+
} ? PrefixItemsToTuple<I, Defs, Depth> : S extends {
|
|
251
348
|
items: infer I;
|
|
252
|
-
} ? FromJSONSchema<I, Defs>[] : unknown[];
|
|
349
|
+
} ? FromJSONSchema<I, Defs, Depth>[] : unknown[];
|
|
253
350
|
/**
|
|
254
351
|
* Convert a prefixItems array to a TypeScript tuple type.
|
|
255
352
|
*/
|
|
256
|
-
type PrefixItemsToTuple<P, Defs extends Record<string, unknown
|
|
353
|
+
type PrefixItemsToTuple<P, Defs extends Record<string, unknown>, Depth extends readonly unknown[] = []> = P extends readonly [infer First, ...infer Rest] ? [FromJSONSchema<First, Defs, Depth>, ...PrefixItemsToTuple<Rest, Defs, Depth>] : [];
|
|
257
354
|
/**
|
|
258
355
|
* Parse an object schema: properties + required -> specific object,
|
|
259
356
|
* additionalProperties -> Record, or empty object.
|
|
@@ -267,24 +364,24 @@ type PrefixItemsToTuple<P, Defs extends Record<string, unknown>> = P extends rea
|
|
|
267
364
|
* - `dependentSchemas` / `dependentRequired` -> ignored (runtime-only conditionals)
|
|
268
365
|
* - `unevaluatedProperties` -> ignored (runtime-only)
|
|
269
366
|
*/
|
|
270
|
-
type ObjectSchemaToTs<S, Defs extends Record<string, unknown
|
|
367
|
+
type ObjectSchemaToTs<S, Defs extends Record<string, unknown>, Depth extends readonly unknown[] = []> = S extends {
|
|
271
368
|
type: "object";
|
|
272
369
|
properties: infer P;
|
|
273
|
-
} ? 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 {
|
|
370
|
+
} ? 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, Depth> } & { [K in keyof P as K extends RequiredKeysOf<S> ? never : K]?: FromJSONSchema<P[K], D, Depth> }, S, D, Depth> : never : S extends {
|
|
274
371
|
additionalProperties: infer V;
|
|
275
|
-
} ? Record<string, FromJSONSchema<V, Defs>> : Record<string, unknown>;
|
|
372
|
+
} ? Record<string, FromJSONSchema<V, Defs, Depth>> : Record<string, unknown>;
|
|
276
373
|
/**
|
|
277
374
|
* If the schema has `patternProperties`, intersect the base object type
|
|
278
375
|
* with a `Record<string, T>` index signature covering all pattern values.
|
|
279
376
|
* If no `patternProperties`, return the base type unchanged.
|
|
280
377
|
*/
|
|
281
|
-
type MergePatternProps<Base, S, Defs extends Record<string, unknown
|
|
378
|
+
type MergePatternProps<Base, S, Defs extends Record<string, unknown>, Depth extends readonly unknown[] = []> = S extends {
|
|
282
379
|
patternProperties: infer PP;
|
|
283
|
-
} ? PP extends Record<string, unknown> ? Base & Record<string, UnionOfPatternValues<PP, Defs>> : Base : Base;
|
|
380
|
+
} ? PP extends Record<string, unknown> ? Base & Record<string, UnionOfPatternValues<PP, Defs, Depth>> : Base : Base;
|
|
284
381
|
/**
|
|
285
382
|
* Extract the union of all pattern property value types.
|
|
286
383
|
*/
|
|
287
|
-
type UnionOfPatternValues<PP extends Record<string, unknown>, Defs extends Record<string, unknown
|
|
384
|
+
type UnionOfPatternValues<PP extends Record<string, unknown>, Defs extends Record<string, unknown>, Depth extends readonly unknown[] = []> = { [K in keyof PP]: FromJSONSchema<PP[K], Defs, Depth> }[keyof PP];
|
|
288
385
|
/**
|
|
289
386
|
* Extract the `required` array from a schema as a union of string literals.
|
|
290
387
|
* Handles both readonly `as const` arrays and mutable arrays.
|
|
@@ -294,11 +391,16 @@ type RequiredKeysOf<S> = S extends {
|
|
|
294
391
|
} ? R extends readonly string[] ? R[number] : never : never;
|
|
295
392
|
/**
|
|
296
393
|
* Extract $defs / definitions from a schema for $ref resolution context.
|
|
297
|
-
* Also indexes schemas with `$anchor` or `$dynamicAnchor` by their anchor
|
|
298
|
-
* enabling `#SomeName` ref resolution.
|
|
299
|
-
*
|
|
394
|
+
* Also indexes schemas with `$anchor` or `$dynamicAnchor` by their anchor
|
|
395
|
+
* name, enabling `#SomeName` ref resolution.
|
|
396
|
+
*
|
|
397
|
+
* Shares merge semantics with {@link MergeRootDefs}: caller-supplied
|
|
398
|
+
* (`ParentDefs`) entries win on key collision, the empty-default
|
|
399
|
+
* sentinel is detected so it does not poison the parent context, and the
|
|
400
|
+
* `HasLocalDefs` guard short-circuits when the current node declares no
|
|
401
|
+
* defs of its own.
|
|
300
402
|
*/
|
|
301
|
-
type ExtractDefs<S, ParentDefs extends Record<string, unknown>> = ExtractRawDefs<S> extends infer RawDefs extends Record<string, unknown> ? RawDefs
|
|
403
|
+
type ExtractDefs<S, ParentDefs extends Record<string, unknown>> = HasLocalDefs<S> extends true ? ExtractRawDefs<S> extends infer RawDefs extends Record<string, unknown> ? CollisionSafeMerge<CollisionSafeMerge<RawDefs, ExtractAnchors<RawDefs>>, ParentDefs> : ParentDefs : ParentDefs;
|
|
302
404
|
/** Extract raw $defs / definitions maps. */
|
|
303
405
|
type ExtractRawDefs<S> = S extends {
|
|
304
406
|
$defs: infer D;
|
|
@@ -441,9 +543,11 @@ type ParameterNamesOf<Doc, Path extends string, Method extends string> = Operati
|
|
|
441
543
|
* Detect whether a document is Swagger 2.0 (OpenAPI 2.0).
|
|
442
544
|
*
|
|
443
545
|
* SOURCE-OF-TRUTH: mirrors runtime `isSwagger2` in
|
|
444
|
-
* `packages/core/src/core/version.ts
|
|
445
|
-
*
|
|
446
|
-
*
|
|
546
|
+
* `packages/core/src/core/version.ts` (line 305), which parses the
|
|
547
|
+
* `swagger` field via `detectOpenApiVersion` (line 264) and returns true
|
|
548
|
+
* for any document whose major version is `2`. Runtime therefore accepts
|
|
549
|
+
* `"2.0"`, `"2.0.0"`, `"2.1"`, and any other `2.x` form — so the
|
|
550
|
+
* type-level detector must too.
|
|
447
551
|
*
|
|
448
552
|
* Type-level Swagger 2.0 documents cannot be fully normalised at compile
|
|
449
553
|
* time — the rewrite reorders the document tree (definitions →
|
|
@@ -451,9 +555,19 @@ type ParameterNamesOf<Doc, Path extends string, Method extends string> = Operati
|
|
|
451
555
|
* TypeScript's mapped-type machinery cannot express. Detecting the
|
|
452
556
|
* version is tractable, so we surface `__SchemaInferenceFellBack`
|
|
453
557
|
* deliberately rather than silently producing `unknown`.
|
|
558
|
+
*
|
|
559
|
+
* Two shapes are accepted:
|
|
560
|
+
* - `{ swagger: "2.<anything>" }` — the on-the-wire string form
|
|
561
|
+
* - `{ swagger: { major: 2, ... } }` — the parsed `OpenApiVersionInfo`
|
|
562
|
+
* object form, mirroring the runtime's tolerance for pre-parsed
|
|
563
|
+
* version metadata
|
|
454
564
|
*/
|
|
455
565
|
type IsSwagger2Doc<Doc> = Doc extends {
|
|
456
|
-
swagger:
|
|
566
|
+
swagger: `2.${string}`;
|
|
567
|
+
} ? true : Doc extends {
|
|
568
|
+
swagger: {
|
|
569
|
+
major: 2;
|
|
570
|
+
};
|
|
457
571
|
} ? true : false;
|
|
458
572
|
/**
|
|
459
573
|
* Infer the TypeScript type of an OpenAPI operation's request body.
|
|
@@ -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
|
}
|
|
@@ -190,6 +194,12 @@ interface TupleField extends FieldBase {
|
|
|
190
194
|
* absent, additional items are permitted but unconstrained.
|
|
191
195
|
*/
|
|
192
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;
|
|
193
203
|
}
|
|
194
204
|
interface RecordField extends FieldBase {
|
|
195
205
|
type: "record";
|