@orpc/openapi 0.10.0 → 0.11.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/index.js +0 -1
- package/dist/src/generator.d.ts +0 -1
- package/dist/src/index.d.ts +0 -1
- package/dist/src/zod-to-json-schema.d.ts +0 -1
- package/package.json +13 -17
- package/dist/index.js.map +0 -1
- package/dist/src/generator.d.ts.map +0 -1
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/zod-to-json-schema.d.ts.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/src/generator.test.ts +0 -643
- package/src/generator.ts +0 -338
- package/src/index.ts +0 -3
- package/src/zod-to-json-schema.test.ts +0 -391
- package/src/zod-to-json-schema.ts +0 -655
|
@@ -1,655 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getCustomJSONSchema,
|
|
3
|
-
getCustomZodFileMimeType,
|
|
4
|
-
getCustomZodType,
|
|
5
|
-
} from '@orpc/zod'
|
|
6
|
-
import escapeStringRegexp from 'escape-string-regexp'
|
|
7
|
-
import {
|
|
8
|
-
Format,
|
|
9
|
-
type JSONSchema,
|
|
10
|
-
type keywords,
|
|
11
|
-
} from 'json-schema-typed/draft-2020-12'
|
|
12
|
-
import {
|
|
13
|
-
type EnumLike,
|
|
14
|
-
type KeySchema,
|
|
15
|
-
type ZodAny,
|
|
16
|
-
type ZodArray,
|
|
17
|
-
type ZodBranded,
|
|
18
|
-
type ZodCatch,
|
|
19
|
-
type ZodDefault,
|
|
20
|
-
type ZodDiscriminatedUnion,
|
|
21
|
-
type ZodEffects,
|
|
22
|
-
type ZodEnum,
|
|
23
|
-
ZodFirstPartyTypeKind,
|
|
24
|
-
type ZodIntersection,
|
|
25
|
-
type ZodLazy,
|
|
26
|
-
type ZodLiteral,
|
|
27
|
-
type ZodMap,
|
|
28
|
-
type ZodNativeEnum,
|
|
29
|
-
type ZodNullable,
|
|
30
|
-
type ZodNumber,
|
|
31
|
-
type ZodObject,
|
|
32
|
-
type ZodOptional,
|
|
33
|
-
type ZodPipeline,
|
|
34
|
-
type ZodRawShape,
|
|
35
|
-
type ZodReadonly,
|
|
36
|
-
type ZodRecord,
|
|
37
|
-
type ZodSet,
|
|
38
|
-
type ZodString,
|
|
39
|
-
type ZodTuple,
|
|
40
|
-
type ZodTypeAny,
|
|
41
|
-
type ZodUnion,
|
|
42
|
-
type ZodUnionOptions,
|
|
43
|
-
} from 'zod'
|
|
44
|
-
|
|
45
|
-
export const NON_LOGIC_KEYWORDS = [
|
|
46
|
-
// Core Documentation Keywords
|
|
47
|
-
'$anchor',
|
|
48
|
-
'$comment',
|
|
49
|
-
'$defs',
|
|
50
|
-
'$id',
|
|
51
|
-
'title',
|
|
52
|
-
'description',
|
|
53
|
-
|
|
54
|
-
// Value Keywords
|
|
55
|
-
'default',
|
|
56
|
-
'deprecated',
|
|
57
|
-
'examples',
|
|
58
|
-
|
|
59
|
-
// Metadata Keywords
|
|
60
|
-
'$schema',
|
|
61
|
-
'definitions', // Legacy, but still used
|
|
62
|
-
'readOnly',
|
|
63
|
-
'writeOnly',
|
|
64
|
-
|
|
65
|
-
// Display and UI Hints
|
|
66
|
-
'contentMediaType',
|
|
67
|
-
'contentEncoding',
|
|
68
|
-
'format',
|
|
69
|
-
|
|
70
|
-
// Custom Extensions
|
|
71
|
-
'$vocabulary',
|
|
72
|
-
'$dynamicAnchor',
|
|
73
|
-
'$dynamicRef',
|
|
74
|
-
] satisfies (typeof keywords)[number][]
|
|
75
|
-
|
|
76
|
-
export const UNSUPPORTED_JSON_SCHEMA = { not: {} }
|
|
77
|
-
export const UNDEFINED_JSON_SCHEMA = { const: 'undefined' }
|
|
78
|
-
|
|
79
|
-
export interface ZodToJsonSchemaOptions {
|
|
80
|
-
/**
|
|
81
|
-
* Max depth of lazy type, if it exceeds.
|
|
82
|
-
*
|
|
83
|
-
* Used `{}` when reach max depth
|
|
84
|
-
*
|
|
85
|
-
* @default 5
|
|
86
|
-
*/
|
|
87
|
-
maxLazyDepth?: number
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* The length used to track the depth of lazy type
|
|
91
|
-
*
|
|
92
|
-
* @internal
|
|
93
|
-
*/
|
|
94
|
-
lazyDepth?: number
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* The expected json schema for input or output zod schema
|
|
98
|
-
*
|
|
99
|
-
* @default input
|
|
100
|
-
*/
|
|
101
|
-
mode?: 'input' | 'output'
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Track if current level schema is handled custom json schema to prevent recursive
|
|
105
|
-
*
|
|
106
|
-
* @internal
|
|
107
|
-
*/
|
|
108
|
-
isHandledCustomJSONSchema?: boolean
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export function zodToJsonSchema(
|
|
112
|
-
schema: ZodTypeAny,
|
|
113
|
-
options?: ZodToJsonSchemaOptions,
|
|
114
|
-
): Exclude<JSONSchema, boolean> {
|
|
115
|
-
if (!options?.isHandledCustomJSONSchema) {
|
|
116
|
-
const customJSONSchema = getCustomJSONSchema(schema._def, options)
|
|
117
|
-
|
|
118
|
-
if (customJSONSchema) {
|
|
119
|
-
const json = zodToJsonSchema(schema, {
|
|
120
|
-
...options,
|
|
121
|
-
isHandledCustomJSONSchema: true,
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
return {
|
|
125
|
-
...json,
|
|
126
|
-
...customJSONSchema,
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const childOptions = { ...options, isHandledCustomJSONSchema: false }
|
|
132
|
-
|
|
133
|
-
const customType = getCustomZodType(schema._def)
|
|
134
|
-
|
|
135
|
-
switch (customType) {
|
|
136
|
-
case 'Blob': {
|
|
137
|
-
return { type: 'string', contentMediaType: '*/*' }
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
case 'File': {
|
|
141
|
-
const mimeType = getCustomZodFileMimeType(schema._def) ?? '*/*'
|
|
142
|
-
|
|
143
|
-
return { type: 'string', contentMediaType: mimeType }
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
case 'Invalid Date': {
|
|
147
|
-
return { const: 'Invalid Date' }
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
case 'RegExp': {
|
|
151
|
-
return {
|
|
152
|
-
type: 'string',
|
|
153
|
-
pattern: '^\\/(.*)\\/([a-z]*)$',
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
case 'URL': {
|
|
158
|
-
return { type: 'string', format: Format.URI }
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const _expectedCustomType: undefined = customType
|
|
163
|
-
|
|
164
|
-
const typeName = schema._def.typeName as ZodFirstPartyTypeKind | undefined
|
|
165
|
-
|
|
166
|
-
switch (typeName) {
|
|
167
|
-
case ZodFirstPartyTypeKind.ZodString: {
|
|
168
|
-
const schema_ = schema as ZodString
|
|
169
|
-
|
|
170
|
-
const json: JSONSchema = { type: 'string' }
|
|
171
|
-
|
|
172
|
-
for (const check of schema_._def.checks) {
|
|
173
|
-
switch (check.kind) {
|
|
174
|
-
case 'base64':
|
|
175
|
-
json.contentEncoding = 'base64'
|
|
176
|
-
break
|
|
177
|
-
case 'cuid':
|
|
178
|
-
json.pattern = '^[0-9A-HJKMNP-TV-Z]{26}$'
|
|
179
|
-
break
|
|
180
|
-
case 'email':
|
|
181
|
-
json.format = Format.Email
|
|
182
|
-
break
|
|
183
|
-
case 'url':
|
|
184
|
-
json.format = Format.URI
|
|
185
|
-
break
|
|
186
|
-
case 'uuid':
|
|
187
|
-
json.format = Format.UUID
|
|
188
|
-
break
|
|
189
|
-
case 'regex':
|
|
190
|
-
json.pattern = check.regex.source
|
|
191
|
-
break
|
|
192
|
-
case 'min':
|
|
193
|
-
json.minLength = check.value
|
|
194
|
-
break
|
|
195
|
-
case 'max':
|
|
196
|
-
json.maxLength = check.value
|
|
197
|
-
break
|
|
198
|
-
case 'length':
|
|
199
|
-
json.minLength = check.value
|
|
200
|
-
json.maxLength = check.value
|
|
201
|
-
break
|
|
202
|
-
case 'includes':
|
|
203
|
-
json.pattern = escapeStringRegexp(check.value)
|
|
204
|
-
break
|
|
205
|
-
case 'startsWith':
|
|
206
|
-
json.pattern = `^${escapeStringRegexp(check.value)}`
|
|
207
|
-
break
|
|
208
|
-
case 'endsWith':
|
|
209
|
-
json.pattern = `${escapeStringRegexp(check.value)}$`
|
|
210
|
-
break
|
|
211
|
-
case 'emoji':
|
|
212
|
-
json.pattern
|
|
213
|
-
= '^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$'
|
|
214
|
-
break
|
|
215
|
-
case 'nanoid':
|
|
216
|
-
json.pattern = '^[a-zA-Z0-9_-]{21}$'
|
|
217
|
-
break
|
|
218
|
-
case 'cuid2':
|
|
219
|
-
json.pattern = '^[0-9a-z]+$'
|
|
220
|
-
break
|
|
221
|
-
case 'ulid':
|
|
222
|
-
json.pattern = '^[0-9A-HJKMNP-TV-Z]{26}$'
|
|
223
|
-
break
|
|
224
|
-
case 'datetime':
|
|
225
|
-
json.format = Format.DateTime
|
|
226
|
-
break
|
|
227
|
-
case 'date':
|
|
228
|
-
json.format = Format.Date
|
|
229
|
-
break
|
|
230
|
-
case 'time':
|
|
231
|
-
json.format = Format.Time
|
|
232
|
-
break
|
|
233
|
-
case 'duration':
|
|
234
|
-
json.format = Format.Duration
|
|
235
|
-
break
|
|
236
|
-
case 'ip':
|
|
237
|
-
json.format = Format.IPv4
|
|
238
|
-
break
|
|
239
|
-
default: {
|
|
240
|
-
const _expect: 'toLowerCase' | 'toUpperCase' | 'trim' = check.kind
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return json
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
case ZodFirstPartyTypeKind.ZodNumber: {
|
|
249
|
-
const schema_ = schema as ZodNumber
|
|
250
|
-
|
|
251
|
-
const json: JSONSchema = { type: 'number' }
|
|
252
|
-
|
|
253
|
-
for (const check of schema_._def.checks) {
|
|
254
|
-
switch (check.kind) {
|
|
255
|
-
case 'int':
|
|
256
|
-
json.type = 'integer'
|
|
257
|
-
break
|
|
258
|
-
case 'min':
|
|
259
|
-
json.minimum = check.value
|
|
260
|
-
break
|
|
261
|
-
case 'max':
|
|
262
|
-
json.maximum = check.value
|
|
263
|
-
break
|
|
264
|
-
case 'multipleOf':
|
|
265
|
-
json.multipleOf = check.value
|
|
266
|
-
break
|
|
267
|
-
default: {
|
|
268
|
-
const _expect: 'finite' = check.kind
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
return json
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
case ZodFirstPartyTypeKind.ZodNaN: {
|
|
277
|
-
return { const: 'NaN' }
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
case ZodFirstPartyTypeKind.ZodBigInt: {
|
|
281
|
-
const json: JSONSchema = { type: 'string', pattern: '^-?[0-9]+$' }
|
|
282
|
-
|
|
283
|
-
// WARN: ignore checks
|
|
284
|
-
|
|
285
|
-
return json
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
case ZodFirstPartyTypeKind.ZodBoolean: {
|
|
289
|
-
return { type: 'boolean' }
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
case ZodFirstPartyTypeKind.ZodDate: {
|
|
293
|
-
const jsonSchema: JSONSchema = { type: 'string', format: Format.Date }
|
|
294
|
-
|
|
295
|
-
// WARN: ignore checks
|
|
296
|
-
|
|
297
|
-
return jsonSchema
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
case ZodFirstPartyTypeKind.ZodNull: {
|
|
301
|
-
return { type: 'null' }
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
case ZodFirstPartyTypeKind.ZodVoid:
|
|
305
|
-
case ZodFirstPartyTypeKind.ZodUndefined: {
|
|
306
|
-
return UNDEFINED_JSON_SCHEMA
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
case ZodFirstPartyTypeKind.ZodLiteral: {
|
|
310
|
-
const schema_ = schema as ZodLiteral<unknown>
|
|
311
|
-
return { const: schema_._def.value }
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
case ZodFirstPartyTypeKind.ZodEnum: {
|
|
315
|
-
const schema_ = schema as ZodEnum<[string, ...string[]]>
|
|
316
|
-
|
|
317
|
-
return {
|
|
318
|
-
enum: schema_._def.values,
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
case ZodFirstPartyTypeKind.ZodNativeEnum: {
|
|
323
|
-
const schema_ = schema as ZodNativeEnum<EnumLike>
|
|
324
|
-
|
|
325
|
-
return {
|
|
326
|
-
enum: Object.values(schema_._def.values),
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
case ZodFirstPartyTypeKind.ZodArray: {
|
|
331
|
-
const schema_ = schema as ZodArray<ZodTypeAny>
|
|
332
|
-
const def = schema_._def
|
|
333
|
-
|
|
334
|
-
const json: JSONSchema = { type: 'array' }
|
|
335
|
-
|
|
336
|
-
if (def.exactLength) {
|
|
337
|
-
json.maxItems = def.exactLength.value
|
|
338
|
-
json.minItems = def.exactLength.value
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if (def.minLength) {
|
|
342
|
-
json.minItems = def.minLength.value
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
if (def.maxLength) {
|
|
346
|
-
json.maxItems = def.maxLength.value
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
return json
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
case ZodFirstPartyTypeKind.ZodTuple: {
|
|
353
|
-
const schema_ = schema as ZodTuple<
|
|
354
|
-
[ZodTypeAny, ...ZodTypeAny[]],
|
|
355
|
-
ZodTypeAny | null
|
|
356
|
-
>
|
|
357
|
-
|
|
358
|
-
const prefixItems: JSONSchema[] = []
|
|
359
|
-
const json: JSONSchema = { type: 'array' }
|
|
360
|
-
|
|
361
|
-
for (const item of schema_._def.items) {
|
|
362
|
-
prefixItems.push(zodToJsonSchema(item, childOptions))
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
if (prefixItems?.length) {
|
|
366
|
-
json.prefixItems = prefixItems
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
if (schema_._def.rest) {
|
|
370
|
-
const items = zodToJsonSchema(schema_._def.rest, childOptions)
|
|
371
|
-
if (items) {
|
|
372
|
-
json.items = items
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
return json
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
case ZodFirstPartyTypeKind.ZodObject: {
|
|
380
|
-
const schema_ = schema as ZodObject<ZodRawShape>
|
|
381
|
-
|
|
382
|
-
const json: JSONSchema = { type: 'object' }
|
|
383
|
-
const properties: Record<string, JSONSchema> = {}
|
|
384
|
-
const required: string[] = []
|
|
385
|
-
|
|
386
|
-
for (const [key, value] of Object.entries(schema_.shape)) {
|
|
387
|
-
const { schema, matches } = extractJSONSchema(
|
|
388
|
-
zodToJsonSchema(value, childOptions),
|
|
389
|
-
schema => schema === UNDEFINED_JSON_SCHEMA,
|
|
390
|
-
)
|
|
391
|
-
|
|
392
|
-
if (schema) {
|
|
393
|
-
properties[key] = schema
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
if (matches.length === 0) {
|
|
397
|
-
required.push(key)
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
if (Object.keys(properties).length) {
|
|
402
|
-
json.properties = properties
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
if (required.length) {
|
|
406
|
-
json.required = required
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
const additionalProperties = zodToJsonSchema(
|
|
410
|
-
schema_._def.catchall,
|
|
411
|
-
childOptions,
|
|
412
|
-
)
|
|
413
|
-
if (schema_._def.unknownKeys === 'strict') {
|
|
414
|
-
json.additionalProperties
|
|
415
|
-
= additionalProperties === UNSUPPORTED_JSON_SCHEMA
|
|
416
|
-
? false
|
|
417
|
-
: additionalProperties
|
|
418
|
-
}
|
|
419
|
-
else {
|
|
420
|
-
if (
|
|
421
|
-
additionalProperties
|
|
422
|
-
&& additionalProperties !== UNSUPPORTED_JSON_SCHEMA
|
|
423
|
-
) {
|
|
424
|
-
json.additionalProperties = additionalProperties
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
return json
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
case ZodFirstPartyTypeKind.ZodRecord: {
|
|
432
|
-
const schema_ = schema as ZodRecord<KeySchema, ZodAny>
|
|
433
|
-
|
|
434
|
-
const json: JSONSchema = { type: 'object' }
|
|
435
|
-
|
|
436
|
-
json.additionalProperties = zodToJsonSchema(
|
|
437
|
-
schema_._def.valueType,
|
|
438
|
-
childOptions,
|
|
439
|
-
)
|
|
440
|
-
|
|
441
|
-
return json
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
case ZodFirstPartyTypeKind.ZodSet: {
|
|
445
|
-
const schema_ = schema as ZodSet
|
|
446
|
-
|
|
447
|
-
return {
|
|
448
|
-
type: 'array',
|
|
449
|
-
items: zodToJsonSchema(schema_._def.valueType, childOptions),
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
case ZodFirstPartyTypeKind.ZodMap: {
|
|
454
|
-
const schema_ = schema as ZodMap
|
|
455
|
-
|
|
456
|
-
return {
|
|
457
|
-
type: 'array',
|
|
458
|
-
items: {
|
|
459
|
-
type: 'array',
|
|
460
|
-
prefixItems: [
|
|
461
|
-
zodToJsonSchema(schema_._def.keyType, childOptions),
|
|
462
|
-
zodToJsonSchema(schema_._def.valueType, childOptions),
|
|
463
|
-
],
|
|
464
|
-
maxItems: 2,
|
|
465
|
-
minItems: 2,
|
|
466
|
-
},
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
case ZodFirstPartyTypeKind.ZodUnion:
|
|
471
|
-
case ZodFirstPartyTypeKind.ZodDiscriminatedUnion: {
|
|
472
|
-
const schema_ = schema as
|
|
473
|
-
| ZodUnion<ZodUnionOptions>
|
|
474
|
-
| ZodDiscriminatedUnion<string, [ZodObject<any>, ...ZodObject<any>[]]>
|
|
475
|
-
|
|
476
|
-
const anyOf: JSONSchema[] = []
|
|
477
|
-
|
|
478
|
-
for (const s of schema_._def.options) {
|
|
479
|
-
anyOf.push(zodToJsonSchema(s, childOptions))
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
return { anyOf }
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
case ZodFirstPartyTypeKind.ZodIntersection: {
|
|
486
|
-
const schema_ = schema as ZodIntersection<ZodTypeAny, ZodTypeAny>
|
|
487
|
-
|
|
488
|
-
const allOf: JSONSchema[] = []
|
|
489
|
-
|
|
490
|
-
for (const s of [schema_._def.left, schema_._def.right]) {
|
|
491
|
-
allOf.push(zodToJsonSchema(s, childOptions))
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
return { allOf }
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
case ZodFirstPartyTypeKind.ZodLazy: {
|
|
498
|
-
const schema_ = schema as ZodLazy<ZodTypeAny>
|
|
499
|
-
|
|
500
|
-
const maxLazyDepth = childOptions?.maxLazyDepth ?? 5
|
|
501
|
-
const lazyDepth = childOptions?.lazyDepth ?? 0
|
|
502
|
-
|
|
503
|
-
if (lazyDepth > maxLazyDepth) {
|
|
504
|
-
return {}
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
return zodToJsonSchema(schema_._def.getter(), {
|
|
508
|
-
...childOptions,
|
|
509
|
-
lazyDepth: lazyDepth + 1,
|
|
510
|
-
})
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
case ZodFirstPartyTypeKind.ZodUnknown:
|
|
514
|
-
case ZodFirstPartyTypeKind.ZodAny:
|
|
515
|
-
case undefined: {
|
|
516
|
-
return {}
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
case ZodFirstPartyTypeKind.ZodOptional: {
|
|
520
|
-
const schema_ = schema as ZodOptional<ZodTypeAny>
|
|
521
|
-
|
|
522
|
-
const inner = zodToJsonSchema(schema_._def.innerType, childOptions)
|
|
523
|
-
|
|
524
|
-
return {
|
|
525
|
-
anyOf: [UNDEFINED_JSON_SCHEMA, inner],
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
case ZodFirstPartyTypeKind.ZodReadonly: {
|
|
530
|
-
const schema_ = schema as ZodReadonly<ZodTypeAny>
|
|
531
|
-
return zodToJsonSchema(schema_._def.innerType, childOptions)
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
case ZodFirstPartyTypeKind.ZodDefault: {
|
|
535
|
-
const schema_ = schema as ZodDefault<ZodTypeAny>
|
|
536
|
-
return zodToJsonSchema(schema_._def.innerType, childOptions)
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
case ZodFirstPartyTypeKind.ZodEffects: {
|
|
540
|
-
const schema_ = schema as ZodEffects<ZodTypeAny>
|
|
541
|
-
|
|
542
|
-
if (
|
|
543
|
-
schema_._def.effect.type === 'transform'
|
|
544
|
-
&& childOptions?.mode === 'output'
|
|
545
|
-
) {
|
|
546
|
-
return {}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
return zodToJsonSchema(schema_._def.schema, childOptions)
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
case ZodFirstPartyTypeKind.ZodCatch: {
|
|
553
|
-
const schema_ = schema as ZodCatch<ZodTypeAny>
|
|
554
|
-
return zodToJsonSchema(schema_._def.innerType, childOptions)
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
case ZodFirstPartyTypeKind.ZodBranded: {
|
|
558
|
-
const schema_ = schema as ZodBranded<ZodTypeAny, string | number | symbol>
|
|
559
|
-
return zodToJsonSchema(schema_._def.type, childOptions)
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
case ZodFirstPartyTypeKind.ZodPipeline: {
|
|
563
|
-
const schema_ = schema as ZodPipeline<ZodTypeAny, ZodTypeAny>
|
|
564
|
-
return zodToJsonSchema(
|
|
565
|
-
childOptions?.mode === 'output' ? schema_._def.out : schema_._def.in,
|
|
566
|
-
childOptions,
|
|
567
|
-
)
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
case ZodFirstPartyTypeKind.ZodNullable: {
|
|
571
|
-
const schema_ = schema as ZodNullable<ZodTypeAny>
|
|
572
|
-
|
|
573
|
-
const inner = zodToJsonSchema(schema_._def.innerType, childOptions)
|
|
574
|
-
|
|
575
|
-
return {
|
|
576
|
-
anyOf: [{ type: 'null' }, inner],
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
const _expected:
|
|
582
|
-
| ZodFirstPartyTypeKind.ZodPromise
|
|
583
|
-
| ZodFirstPartyTypeKind.ZodSymbol
|
|
584
|
-
| ZodFirstPartyTypeKind.ZodFunction
|
|
585
|
-
| ZodFirstPartyTypeKind.ZodNever = typeName
|
|
586
|
-
|
|
587
|
-
return UNSUPPORTED_JSON_SCHEMA
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
export function extractJSONSchema(
|
|
591
|
-
schema: JSONSchema,
|
|
592
|
-
check: (schema: JSONSchema) => boolean,
|
|
593
|
-
matches: JSONSchema[] = [],
|
|
594
|
-
): { schema: JSONSchema | undefined, matches: JSONSchema[] } {
|
|
595
|
-
if (check(schema)) {
|
|
596
|
-
matches.push(schema)
|
|
597
|
-
return { schema: undefined, matches }
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
if (typeof schema === 'boolean') {
|
|
601
|
-
return { schema, matches }
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
// TODO: $ref
|
|
605
|
-
|
|
606
|
-
if (
|
|
607
|
-
schema.anyOf
|
|
608
|
-
&& Object.keys(schema).every(
|
|
609
|
-
k => k === 'anyOf' || NON_LOGIC_KEYWORDS.includes(k as any),
|
|
610
|
-
)
|
|
611
|
-
) {
|
|
612
|
-
const anyOf = schema.anyOf
|
|
613
|
-
.map(s => extractJSONSchema(s, check, matches).schema)
|
|
614
|
-
.filter(v => !!v)
|
|
615
|
-
|
|
616
|
-
if (anyOf.length === 1 && typeof anyOf[0] === 'object') {
|
|
617
|
-
return { schema: { ...schema, anyOf: undefined, ...anyOf[0] }, matches }
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
return {
|
|
621
|
-
schema: {
|
|
622
|
-
...schema,
|
|
623
|
-
anyOf,
|
|
624
|
-
},
|
|
625
|
-
matches,
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
// TODO: $ref
|
|
630
|
-
|
|
631
|
-
if (
|
|
632
|
-
schema.oneOf
|
|
633
|
-
&& Object.keys(schema).every(
|
|
634
|
-
k => k === 'oneOf' || NON_LOGIC_KEYWORDS.includes(k as any),
|
|
635
|
-
)
|
|
636
|
-
) {
|
|
637
|
-
const oneOf = schema.oneOf
|
|
638
|
-
.map(s => extractJSONSchema(s, check, matches).schema)
|
|
639
|
-
.filter(v => !!v)
|
|
640
|
-
|
|
641
|
-
if (oneOf.length === 1 && typeof oneOf[0] === 'object') {
|
|
642
|
-
return { schema: { ...schema, oneOf: undefined, ...oneOf[0] }, matches }
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
return {
|
|
646
|
-
schema: {
|
|
647
|
-
...schema,
|
|
648
|
-
oneOf,
|
|
649
|
-
},
|
|
650
|
-
matches,
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
return { schema, matches }
|
|
655
|
-
}
|