@orpc/zod 0.0.0-next.f22c7ec → 0.0.0-next.f4d410a

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.mjs ADDED
@@ -0,0 +1,822 @@
1
+ import { custom, ZodFirstPartyTypeKind } from 'zod';
2
+ import wcmatch from 'wildcard-match';
3
+ import { isObject, guard } from '@orpc/shared';
4
+ import { JSONSchemaFormat } from '@orpc/openapi';
5
+ import escapeStringRegexp from 'escape-string-regexp';
6
+
7
+ const CUSTOM_JSON_SCHEMA_SYMBOL = Symbol("ORPC_CUSTOM_JSON_SCHEMA");
8
+ const CUSTOM_JSON_SCHEMA_INPUT_SYMBOL = Symbol("ORPC_CUSTOM_JSON_SCHEMA_INPUT");
9
+ const CUSTOM_JSON_SCHEMA_OUTPUT_SYMBOL = Symbol("ORPC_CUSTOM_JSON_SCHEMA_OUTPUT");
10
+ function getCustomJsonSchema(def, options) {
11
+ if (options.strategy === "input" && CUSTOM_JSON_SCHEMA_INPUT_SYMBOL in def) {
12
+ return def[CUSTOM_JSON_SCHEMA_INPUT_SYMBOL];
13
+ }
14
+ if (options.strategy === "output" && CUSTOM_JSON_SCHEMA_OUTPUT_SYMBOL in def) {
15
+ return def[CUSTOM_JSON_SCHEMA_OUTPUT_SYMBOL];
16
+ }
17
+ if (CUSTOM_JSON_SCHEMA_SYMBOL in def) {
18
+ return def[CUSTOM_JSON_SCHEMA_SYMBOL];
19
+ }
20
+ return void 0;
21
+ }
22
+ function customJsonSchema(schema, custom, options = {}) {
23
+ const SYMBOL = options.strategy === "input" ? CUSTOM_JSON_SCHEMA_INPUT_SYMBOL : options.strategy === "output" ? CUSTOM_JSON_SCHEMA_OUTPUT_SYMBOL : CUSTOM_JSON_SCHEMA_SYMBOL;
24
+ const This = schema.constructor;
25
+ const newSchema = new This({
26
+ ...schema._def,
27
+ [SYMBOL]: custom
28
+ });
29
+ return newSchema;
30
+ }
31
+
32
+ const CUSTOM_ZOD_DEF_SYMBOL = Symbol("ORPC_CUSTOM_ZOD_DEF");
33
+ function setCustomZodDef(def, custom) {
34
+ Object.assign(def, { [CUSTOM_ZOD_DEF_SYMBOL]: custom });
35
+ }
36
+ function getCustomZodDef(def) {
37
+ return def[CUSTOM_ZOD_DEF_SYMBOL];
38
+ }
39
+ function composeParams(defaultMessage, params) {
40
+ return (val) => {
41
+ const message = defaultMessage(val);
42
+ if (!params) {
43
+ return {
44
+ message
45
+ };
46
+ }
47
+ if (typeof params === "function") {
48
+ return {
49
+ message,
50
+ ...params(val)
51
+ };
52
+ }
53
+ if (typeof params === "object") {
54
+ return {
55
+ message,
56
+ ...params
57
+ };
58
+ }
59
+ return {
60
+ message: params
61
+ };
62
+ };
63
+ }
64
+
65
+ function blob(params) {
66
+ const schema = custom(
67
+ (val) => val instanceof Blob,
68
+ composeParams(
69
+ () => "Input is not a blob",
70
+ params
71
+ )
72
+ );
73
+ setCustomZodDef(schema._def, { type: "blob" });
74
+ return schema;
75
+ }
76
+
77
+ function file(params) {
78
+ const schema = custom(
79
+ (val) => val instanceof File,
80
+ composeParams(
81
+ () => "Input is not a file",
82
+ params
83
+ )
84
+ );
85
+ setCustomZodDef(schema._def, { type: "file" });
86
+ return Object.assign(schema, {
87
+ type: (mimeType, params2) => {
88
+ const isMatch = wcmatch(mimeType);
89
+ const refinedSchema = schema.refine(
90
+ (val) => isMatch(val.type.split(";")[0]),
91
+ composeParams(
92
+ (val) => `Expected a file of type ${mimeType} but got a file of type ${val.type || "unknown"}`,
93
+ params2
94
+ )
95
+ );
96
+ setCustomZodDef(refinedSchema._def, { type: "file", mimeType });
97
+ return refinedSchema;
98
+ }
99
+ });
100
+ }
101
+
102
+ function regexp(params) {
103
+ const schema = custom(
104
+ (val) => val instanceof RegExp,
105
+ composeParams(
106
+ () => "Input is not a regexp",
107
+ params
108
+ )
109
+ );
110
+ setCustomZodDef(schema._def, { type: "regexp" });
111
+ return schema;
112
+ }
113
+
114
+ function url(params) {
115
+ const schema = custom(
116
+ (val) => val instanceof URL,
117
+ composeParams(
118
+ () => "Input is not a URL",
119
+ params
120
+ )
121
+ );
122
+ setCustomZodDef(schema._def, { type: "url" });
123
+ return schema;
124
+ }
125
+
126
+ class ZodSmartCoercionPlugin {
127
+ init(options) {
128
+ options.clientInterceptors ??= [];
129
+ options.clientInterceptors.unshift((options2) => {
130
+ const inputSchema = options2.procedure["~orpc"].inputSchema;
131
+ if (!inputSchema || inputSchema["~standard"].vendor !== "zod") {
132
+ return options2.next();
133
+ }
134
+ const coercedInput = zodCoerceInternal(inputSchema, options2.input);
135
+ return options2.next({ ...options2, input: coercedInput });
136
+ });
137
+ }
138
+ }
139
+ function zodCoerceInternal(schema, value) {
140
+ const customZodDef = getCustomZodDef(schema._def);
141
+ switch (customZodDef?.type) {
142
+ case "regexp": {
143
+ if (typeof value === "string") {
144
+ return safeToRegExp(value);
145
+ }
146
+ return value;
147
+ }
148
+ case "url": {
149
+ if (typeof value === "string") {
150
+ return safeToURL(value);
151
+ }
152
+ return value;
153
+ }
154
+ }
155
+ const typeName = schema._def.typeName;
156
+ switch (typeName) {
157
+ case ZodFirstPartyTypeKind.ZodNumber: {
158
+ if (typeof value === "string") {
159
+ return safeToNumber(value);
160
+ }
161
+ return value;
162
+ }
163
+ case ZodFirstPartyTypeKind.ZodBigInt: {
164
+ if (typeof value === "string") {
165
+ return safeToBigInt(value);
166
+ }
167
+ return value;
168
+ }
169
+ case ZodFirstPartyTypeKind.ZodBoolean: {
170
+ if (typeof value === "string") {
171
+ return safeToBoolean(value);
172
+ }
173
+ return value;
174
+ }
175
+ case ZodFirstPartyTypeKind.ZodDate: {
176
+ if (typeof value === "string") {
177
+ return safeToDate(value);
178
+ }
179
+ return value;
180
+ }
181
+ case ZodFirstPartyTypeKind.ZodLiteral: {
182
+ const schema_ = schema;
183
+ const expectedValue = schema_._def.value;
184
+ if (typeof value === "string" && typeof expectedValue !== "string") {
185
+ if (typeof expectedValue === "bigint") {
186
+ return safeToBigInt(value);
187
+ } else if (typeof expectedValue === "number") {
188
+ return safeToNumber(value);
189
+ } else if (typeof expectedValue === "boolean") {
190
+ return safeToBoolean(value);
191
+ }
192
+ }
193
+ return value;
194
+ }
195
+ case ZodFirstPartyTypeKind.ZodNativeEnum: {
196
+ const schema_ = schema;
197
+ if (Object.values(schema_._def.values).includes(value)) {
198
+ return value;
199
+ }
200
+ if (typeof value === "string") {
201
+ for (const expectedValue of Object.values(schema_._def.values)) {
202
+ if (expectedValue.toString() === value) {
203
+ return expectedValue;
204
+ }
205
+ }
206
+ }
207
+ return value;
208
+ }
209
+ case ZodFirstPartyTypeKind.ZodObject: {
210
+ const schema_ = schema;
211
+ if (isObject(value)) {
212
+ const newObj = {};
213
+ const keys = /* @__PURE__ */ new Set([
214
+ ...Object.keys(value),
215
+ ...Object.keys(schema_.shape)
216
+ ]);
217
+ for (const k of keys) {
218
+ newObj[k] = zodCoerceInternal(
219
+ schema_.shape[k] ?? schema_._def.catchall,
220
+ value[k]
221
+ );
222
+ }
223
+ return newObj;
224
+ }
225
+ return value;
226
+ }
227
+ case ZodFirstPartyTypeKind.ZodRecord: {
228
+ const schema_ = schema;
229
+ if (isObject(value)) {
230
+ const newObj = {};
231
+ for (const [k, v] of Object.entries(value)) {
232
+ const key = zodCoerceInternal(schema_._def.keyType, k);
233
+ const val = zodCoerceInternal(schema_._def.valueType, v);
234
+ newObj[key] = val;
235
+ }
236
+ return newObj;
237
+ }
238
+ return value;
239
+ }
240
+ case ZodFirstPartyTypeKind.ZodArray: {
241
+ const schema_ = schema;
242
+ if (Array.isArray(value)) {
243
+ return value.map((v) => zodCoerceInternal(schema_._def.type, v));
244
+ }
245
+ return value;
246
+ }
247
+ case ZodFirstPartyTypeKind.ZodTuple: {
248
+ const schema_ = schema;
249
+ if (Array.isArray(value)) {
250
+ return value.map((v, i) => {
251
+ const s = schema_._def.items[i] ?? schema_._def.rest;
252
+ return s ? zodCoerceInternal(s, v) : v;
253
+ });
254
+ }
255
+ return value;
256
+ }
257
+ case ZodFirstPartyTypeKind.ZodSet: {
258
+ const schema_ = schema;
259
+ if (Array.isArray(value)) {
260
+ return new Set(
261
+ value.map((v) => zodCoerceInternal(schema_._def.valueType, v))
262
+ );
263
+ }
264
+ return value;
265
+ }
266
+ case ZodFirstPartyTypeKind.ZodMap: {
267
+ const schema_ = schema;
268
+ if (Array.isArray(value) && value.every((i) => Array.isArray(i) && i.length === 2)) {
269
+ return new Map(
270
+ value.map(([k, v]) => [
271
+ zodCoerceInternal(schema_._def.keyType, k),
272
+ zodCoerceInternal(schema_._def.valueType, v)
273
+ ])
274
+ );
275
+ }
276
+ return value;
277
+ }
278
+ case ZodFirstPartyTypeKind.ZodUnion:
279
+ case ZodFirstPartyTypeKind.ZodDiscriminatedUnion: {
280
+ const schema_ = schema;
281
+ if (schema_.safeParse(value).success) {
282
+ return value;
283
+ }
284
+ const results = [];
285
+ for (const s of schema_._def.options) {
286
+ const newValue = zodCoerceInternal(s, value);
287
+ const result = schema_.safeParse(newValue);
288
+ if (result.success) {
289
+ return newValue;
290
+ }
291
+ results.push([newValue, result.error.issues.length]);
292
+ }
293
+ if (results.length === 0) {
294
+ return value;
295
+ }
296
+ return results.sort((a, b) => a[1] - b[1])[0][0];
297
+ }
298
+ case ZodFirstPartyTypeKind.ZodIntersection: {
299
+ const schema_ = schema;
300
+ return zodCoerceInternal(
301
+ schema_._def.right,
302
+ zodCoerceInternal(schema_._def.left, value)
303
+ );
304
+ }
305
+ case ZodFirstPartyTypeKind.ZodReadonly: {
306
+ const schema_ = schema;
307
+ return zodCoerceInternal(schema_._def.innerType, value);
308
+ }
309
+ case ZodFirstPartyTypeKind.ZodPipeline: {
310
+ const schema_ = schema;
311
+ return zodCoerceInternal(schema_._def.in, value);
312
+ }
313
+ case ZodFirstPartyTypeKind.ZodEffects: {
314
+ const schema_ = schema;
315
+ return zodCoerceInternal(schema_._def.schema, value);
316
+ }
317
+ case ZodFirstPartyTypeKind.ZodBranded: {
318
+ const schema_ = schema;
319
+ return zodCoerceInternal(schema_._def.type, value);
320
+ }
321
+ case ZodFirstPartyTypeKind.ZodCatch: {
322
+ const schema_ = schema;
323
+ return zodCoerceInternal(schema_._def.innerType, value);
324
+ }
325
+ case ZodFirstPartyTypeKind.ZodDefault: {
326
+ const schema_ = schema;
327
+ return zodCoerceInternal(schema_._def.innerType, value);
328
+ }
329
+ case ZodFirstPartyTypeKind.ZodNullable: {
330
+ if (value === null) {
331
+ return null;
332
+ }
333
+ const schema_ = schema;
334
+ return zodCoerceInternal(schema_._def.innerType, value);
335
+ }
336
+ case ZodFirstPartyTypeKind.ZodOptional: {
337
+ if (value === void 0) {
338
+ return void 0;
339
+ }
340
+ const schema_ = schema;
341
+ return zodCoerceInternal(schema_._def.innerType, value);
342
+ }
343
+ case ZodFirstPartyTypeKind.ZodLazy: {
344
+ const schema_ = schema;
345
+ if (value !== void 0) {
346
+ return zodCoerceInternal(schema_._def.getter(), value);
347
+ }
348
+ return value;
349
+ }
350
+ }
351
+ return value;
352
+ }
353
+ function safeToBigInt(value) {
354
+ return guard(() => BigInt(value)) ?? value;
355
+ }
356
+ function safeToNumber(value) {
357
+ const num = Number(value);
358
+ return Number.isNaN(num) || num.toString() !== value ? value : num;
359
+ }
360
+ function safeToBoolean(value) {
361
+ const lower = value.toLowerCase();
362
+ if (lower === "false" || lower === "off" || lower === "f") {
363
+ return false;
364
+ }
365
+ if (lower === "true" || lower === "on" || lower === "t") {
366
+ return true;
367
+ }
368
+ return value;
369
+ }
370
+ function safeToRegExp(value) {
371
+ if (value.startsWith("/")) {
372
+ const match = value.match(/^\/(.*)\/([a-z]*)$/);
373
+ if (match) {
374
+ const [, pattern, flags] = match;
375
+ return new RegExp(pattern, flags);
376
+ }
377
+ }
378
+ return value;
379
+ }
380
+ function safeToURL(value) {
381
+ return guard(() => new URL(value)) ?? value;
382
+ }
383
+ function safeToDate(value) {
384
+ const date = new Date(value);
385
+ if (!Number.isNaN(date.getTime()) && date.toISOString().startsWith(value)) {
386
+ return date;
387
+ }
388
+ return value;
389
+ }
390
+
391
+ class ZodToJsonSchemaConverter {
392
+ maxLazyDepth;
393
+ unsupportedJsonSchema;
394
+ anyJsonSchema;
395
+ constructor(options = {}) {
396
+ this.maxLazyDepth = options.maxLazyDepth ?? 3;
397
+ this.unsupportedJsonSchema = options.unsupportedJsonSchema ?? { not: {} };
398
+ this.anyJsonSchema = options.anyJsonSchema ?? {};
399
+ }
400
+ condition(schema) {
401
+ return schema !== void 0 && schema["~standard"].vendor === "zod";
402
+ }
403
+ convert(schema, options, lazyDepth = 0, isHandledCustomJSONSchema = false, isHandledZodDescription = false) {
404
+ const def = schema._def;
405
+ if (!isHandledZodDescription && "description" in def && typeof def.description === "string") {
406
+ const [required, json] = this.convert(
407
+ schema,
408
+ options,
409
+ lazyDepth,
410
+ isHandledCustomJSONSchema,
411
+ true
412
+ );
413
+ return [required, { ...json, description: def.description }];
414
+ }
415
+ if (!isHandledCustomJSONSchema) {
416
+ const customJSONSchema = getCustomJsonSchema(def, options);
417
+ if (customJSONSchema) {
418
+ const [required, json] = this.convert(
419
+ schema,
420
+ options,
421
+ lazyDepth,
422
+ true,
423
+ isHandledZodDescription
424
+ );
425
+ return [required, { ...json, ...customJSONSchema }];
426
+ }
427
+ }
428
+ const customSchema = this.#handleCustomZodDef(def);
429
+ if (customSchema) {
430
+ return [true, customSchema];
431
+ }
432
+ const typeName = this.#getZodTypeName(def);
433
+ switch (typeName) {
434
+ case ZodFirstPartyTypeKind.ZodString: {
435
+ const schema_ = schema;
436
+ const json = { type: "string" };
437
+ for (const check of schema_._def.checks) {
438
+ switch (check.kind) {
439
+ case "base64":
440
+ json.contentEncoding = "base64";
441
+ break;
442
+ case "cuid":
443
+ json.pattern = "^[0-9A-HJKMNP-TV-Z]{26}$";
444
+ break;
445
+ case "email":
446
+ json.format = JSONSchemaFormat.Email;
447
+ break;
448
+ case "url":
449
+ json.format = JSONSchemaFormat.URI;
450
+ break;
451
+ case "uuid":
452
+ json.format = JSONSchemaFormat.UUID;
453
+ break;
454
+ case "regex":
455
+ json.pattern = check.regex.source;
456
+ break;
457
+ case "min":
458
+ json.minLength = check.value;
459
+ break;
460
+ case "max":
461
+ json.maxLength = check.value;
462
+ break;
463
+ case "length":
464
+ json.minLength = check.value;
465
+ json.maxLength = check.value;
466
+ break;
467
+ case "includes":
468
+ json.pattern = escapeStringRegexp(check.value);
469
+ break;
470
+ case "startsWith":
471
+ json.pattern = `^${escapeStringRegexp(check.value)}`;
472
+ break;
473
+ case "endsWith":
474
+ json.pattern = `${escapeStringRegexp(check.value)}$`;
475
+ break;
476
+ case "emoji":
477
+ json.pattern = "^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$";
478
+ break;
479
+ case "nanoid":
480
+ json.pattern = "^[a-zA-Z0-9_-]{21}$";
481
+ break;
482
+ case "cuid2":
483
+ json.pattern = "^[0-9a-z]+$";
484
+ break;
485
+ case "ulid":
486
+ json.pattern = "^[0-9A-HJKMNP-TV-Z]{26}$";
487
+ break;
488
+ case "datetime":
489
+ json.format = JSONSchemaFormat.DateTime;
490
+ break;
491
+ case "date":
492
+ json.format = JSONSchemaFormat.Date;
493
+ break;
494
+ case "time":
495
+ json.format = JSONSchemaFormat.Time;
496
+ break;
497
+ case "duration":
498
+ json.format = JSONSchemaFormat.Duration;
499
+ break;
500
+ case "ip": {
501
+ if (check.version === "v4") {
502
+ json.format = JSONSchemaFormat.IPv4;
503
+ } else if (check.version === "v6") {
504
+ json.format = JSONSchemaFormat.IPv6;
505
+ } else {
506
+ json.anyOf = [
507
+ { format: JSONSchemaFormat.IPv4 },
508
+ { format: JSONSchemaFormat.IPv6 }
509
+ ];
510
+ }
511
+ break;
512
+ }
513
+ case "jwt":
514
+ json.pattern = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$";
515
+ break;
516
+ case "base64url":
517
+ json.pattern = "^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$";
518
+ break;
519
+ default: {
520
+ check.kind;
521
+ }
522
+ }
523
+ }
524
+ return [true, json];
525
+ }
526
+ case ZodFirstPartyTypeKind.ZodNumber: {
527
+ const schema_ = schema;
528
+ const json = { type: "number" };
529
+ for (const check of schema_._def.checks) {
530
+ switch (check.kind) {
531
+ case "int":
532
+ json.type = "integer";
533
+ break;
534
+ case "min":
535
+ json.minimum = check.value;
536
+ break;
537
+ case "max":
538
+ json.maximum = check.value;
539
+ break;
540
+ case "multipleOf":
541
+ json.multipleOf = check.value;
542
+ break;
543
+ default: {
544
+ check.kind;
545
+ }
546
+ }
547
+ }
548
+ return [true, json];
549
+ }
550
+ case ZodFirstPartyTypeKind.ZodBigInt: {
551
+ const json = { type: "string", pattern: "^-?[0-9]+$" };
552
+ return [true, json];
553
+ }
554
+ case ZodFirstPartyTypeKind.ZodNaN: {
555
+ return options.strategy === "input" ? [true, this.unsupportedJsonSchema] : [true, { type: "null" }];
556
+ }
557
+ case ZodFirstPartyTypeKind.ZodBoolean: {
558
+ return [true, { type: "boolean" }];
559
+ }
560
+ case ZodFirstPartyTypeKind.ZodDate: {
561
+ const schema2 = { type: "string", format: JSONSchemaFormat.DateTime };
562
+ return [true, schema2];
563
+ }
564
+ case ZodFirstPartyTypeKind.ZodNull: {
565
+ return [true, { type: "null" }];
566
+ }
567
+ case ZodFirstPartyTypeKind.ZodLiteral: {
568
+ const schema_ = schema;
569
+ if (schema_._def.value === void 0) {
570
+ return [false, this.unsupportedJsonSchema];
571
+ }
572
+ return [true, { const: schema_._def.value }];
573
+ }
574
+ case ZodFirstPartyTypeKind.ZodVoid:
575
+ case ZodFirstPartyTypeKind.ZodUndefined: {
576
+ return [false, this.unsupportedJsonSchema];
577
+ }
578
+ case ZodFirstPartyTypeKind.ZodUnknown:
579
+ case ZodFirstPartyTypeKind.ZodAny: {
580
+ return [false, this.anyJsonSchema];
581
+ }
582
+ case ZodFirstPartyTypeKind.ZodEnum: {
583
+ const schema_ = schema;
584
+ return [true, { enum: schema_._def.values }];
585
+ }
586
+ case ZodFirstPartyTypeKind.ZodNativeEnum: {
587
+ const schema_ = schema;
588
+ return [true, { enum: Object.values(schema_._def.values) }];
589
+ }
590
+ case ZodFirstPartyTypeKind.ZodArray: {
591
+ const schema_ = schema;
592
+ const def2 = schema_._def;
593
+ const json = { type: "array" };
594
+ const [itemRequired, itemJson] = this.convert(def2.type, options, lazyDepth, false, false);
595
+ json.items = this.#toArrayItemJsonSchema(itemRequired, itemJson, options.strategy);
596
+ if (def2.exactLength) {
597
+ json.maxItems = def2.exactLength.value;
598
+ json.minItems = def2.exactLength.value;
599
+ }
600
+ if (def2.minLength) {
601
+ json.minItems = def2.minLength.value;
602
+ }
603
+ if (def2.maxLength) {
604
+ json.maxItems = def2.maxLength.value;
605
+ }
606
+ return [true, json];
607
+ }
608
+ case ZodFirstPartyTypeKind.ZodTuple: {
609
+ const schema_ = schema;
610
+ const prefixItems = [];
611
+ const json = { type: "array" };
612
+ for (const item of schema_._def.items) {
613
+ const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false);
614
+ prefixItems.push(
615
+ this.#toArrayItemJsonSchema(itemRequired, itemJson, options.strategy)
616
+ );
617
+ }
618
+ if (prefixItems?.length) {
619
+ json.prefixItems = prefixItems;
620
+ }
621
+ if (schema_._def.rest) {
622
+ const [itemRequired, itemJson] = this.convert(schema_._def.rest, options, lazyDepth, false, false);
623
+ json.items = this.#toArrayItemJsonSchema(itemRequired, itemJson, options.strategy);
624
+ }
625
+ return [true, json];
626
+ }
627
+ case ZodFirstPartyTypeKind.ZodObject: {
628
+ const schema_ = schema;
629
+ const json = { type: "object" };
630
+ const properties = {};
631
+ const required = [];
632
+ for (const [key, value] of Object.entries(schema_.shape)) {
633
+ const [itemRequired, itemJson] = this.convert(value, options, lazyDepth, false, false);
634
+ properties[key] = itemJson;
635
+ if (itemRequired) {
636
+ required.push(key);
637
+ }
638
+ }
639
+ if (Object.keys(properties).length) {
640
+ json.properties = properties;
641
+ }
642
+ if (required.length) {
643
+ json.required = required;
644
+ }
645
+ const catchAllTypeName = this.#getZodTypeName(schema_._def.catchall._def);
646
+ if (catchAllTypeName === ZodFirstPartyTypeKind.ZodNever) {
647
+ if (schema_._def.unknownKeys === "strict") {
648
+ json.additionalProperties = false;
649
+ }
650
+ } else {
651
+ const [_, addJson] = this.convert(schema_._def.catchall, options, lazyDepth, false, false);
652
+ json.additionalProperties = addJson;
653
+ }
654
+ return [true, json];
655
+ }
656
+ case ZodFirstPartyTypeKind.ZodRecord: {
657
+ const schema_ = schema;
658
+ const json = { type: "object" };
659
+ const [__, keyJson] = this.convert(schema_._def.keyType, options, lazyDepth, false, false);
660
+ if (Object.entries(keyJson).some(([k, v]) => k !== "type" || v !== "string")) {
661
+ json.propertyNames = keyJson;
662
+ }
663
+ const [_, itemJson] = this.convert(schema_._def.valueType, options, lazyDepth, false, false);
664
+ json.additionalProperties = itemJson;
665
+ return [true, json];
666
+ }
667
+ case ZodFirstPartyTypeKind.ZodSet: {
668
+ const schema_ = schema;
669
+ const json = { type: "array", uniqueItems: true };
670
+ const [itemRequired, itemJson] = this.convert(schema_._def.valueType, options, lazyDepth, false, false);
671
+ json.items = this.#toArrayItemJsonSchema(itemRequired, itemJson, options.strategy);
672
+ return [true, json];
673
+ }
674
+ case ZodFirstPartyTypeKind.ZodMap: {
675
+ const schema_ = schema;
676
+ const [keyRequired, keyJson] = this.convert(schema_._def.keyType, options, lazyDepth, false, false);
677
+ const [valueRequired, valueJson] = this.convert(schema_._def.valueType, options, lazyDepth, false, false);
678
+ return [true, {
679
+ type: "array",
680
+ items: {
681
+ type: "array",
682
+ prefixItems: [
683
+ this.#toArrayItemJsonSchema(keyRequired, keyJson, options.strategy),
684
+ this.#toArrayItemJsonSchema(valueRequired, valueJson, options.strategy)
685
+ ],
686
+ maxItems: 2,
687
+ minItems: 2
688
+ }
689
+ }];
690
+ }
691
+ case ZodFirstPartyTypeKind.ZodUnion:
692
+ case ZodFirstPartyTypeKind.ZodDiscriminatedUnion: {
693
+ const schema_ = schema;
694
+ const anyOf = [];
695
+ let required = true;
696
+ for (const item of schema_._def.options) {
697
+ const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false);
698
+ if (!itemRequired) {
699
+ required = false;
700
+ if (itemJson !== this.unsupportedJsonSchema) {
701
+ anyOf.push(itemJson);
702
+ }
703
+ } else {
704
+ anyOf.push(itemJson);
705
+ }
706
+ }
707
+ if (anyOf.length === 1) {
708
+ return [required, anyOf[0]];
709
+ }
710
+ return [required, { anyOf }];
711
+ }
712
+ case ZodFirstPartyTypeKind.ZodIntersection: {
713
+ const schema_ = schema;
714
+ const allOf = [];
715
+ let required = false;
716
+ for (const item of [schema_._def.left, schema_._def.right]) {
717
+ const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false);
718
+ allOf.push(itemJson);
719
+ if (itemRequired) {
720
+ required = true;
721
+ }
722
+ }
723
+ return [required, { allOf }];
724
+ }
725
+ case ZodFirstPartyTypeKind.ZodLazy: {
726
+ if (lazyDepth >= this.maxLazyDepth) {
727
+ return [false, this.anyJsonSchema];
728
+ }
729
+ const schema_ = schema;
730
+ return this.convert(schema_._def.getter(), options, lazyDepth + 1, false, false);
731
+ }
732
+ case ZodFirstPartyTypeKind.ZodOptional: {
733
+ const schema_ = schema;
734
+ const [_, inner] = this.convert(schema_._def.innerType, options, lazyDepth, false, false);
735
+ return [false, inner];
736
+ }
737
+ case ZodFirstPartyTypeKind.ZodReadonly: {
738
+ const schema_ = schema;
739
+ const [required, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false);
740
+ return [required, { ...json, readOnly: true }];
741
+ }
742
+ case ZodFirstPartyTypeKind.ZodDefault: {
743
+ const schema_ = schema;
744
+ const [_, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false);
745
+ return [false, { default: schema_._def.defaultValue(), ...json }];
746
+ }
747
+ case ZodFirstPartyTypeKind.ZodEffects: {
748
+ const schema_ = schema;
749
+ if (schema_._def.effect.type === "transform" && options.strategy === "output") {
750
+ return [false, this.anyJsonSchema];
751
+ }
752
+ return this.convert(schema_._def.schema, options, lazyDepth, false, false);
753
+ }
754
+ case ZodFirstPartyTypeKind.ZodCatch: {
755
+ const schema_ = schema;
756
+ return this.convert(schema_._def.innerType, options, lazyDepth, false, false);
757
+ }
758
+ case ZodFirstPartyTypeKind.ZodBranded: {
759
+ const schema_ = schema;
760
+ return this.convert(schema_._def.type, options, lazyDepth, false, false);
761
+ }
762
+ case ZodFirstPartyTypeKind.ZodPipeline: {
763
+ const schema_ = schema;
764
+ return this.convert(
765
+ options.strategy === "input" ? schema_._def.in : schema_._def.out,
766
+ options,
767
+ lazyDepth,
768
+ false,
769
+ false
770
+ );
771
+ }
772
+ case ZodFirstPartyTypeKind.ZodNullable: {
773
+ const schema_ = schema;
774
+ const [required, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false);
775
+ return [required, { anyOf: [{ type: "null" }, json] }];
776
+ }
777
+ }
778
+ return [true, this.unsupportedJsonSchema];
779
+ }
780
+ #handleCustomZodDef(def) {
781
+ const customZodDef = getCustomZodDef(def);
782
+ if (!customZodDef) {
783
+ return void 0;
784
+ }
785
+ switch (customZodDef.type) {
786
+ case "blob": {
787
+ return { type: "string", contentMediaType: "*/*" };
788
+ }
789
+ case "file": {
790
+ return { type: "string", contentMediaType: customZodDef.mimeType ?? "*/*" };
791
+ }
792
+ case "regexp": {
793
+ return {
794
+ type: "string",
795
+ pattern: "^\\/(.*)\\/([a-z]*)$"
796
+ };
797
+ }
798
+ case "url": {
799
+ return { type: "string", format: JSONSchemaFormat.URI };
800
+ }
801
+ }
802
+ }
803
+ #getZodTypeName(def) {
804
+ return def.typeName;
805
+ }
806
+ #toArrayItemJsonSchema(required, schema, strategy) {
807
+ if (required) {
808
+ return schema;
809
+ }
810
+ return strategy === "input" ? { anyOf: [schema, this.unsupportedJsonSchema] } : { anyOf: [schema, { type: "null" }] };
811
+ }
812
+ }
813
+
814
+ const oz = {
815
+ file,
816
+ blob,
817
+ url,
818
+ regexp,
819
+ openapi: customJsonSchema
820
+ };
821
+
822
+ export { ZodSmartCoercionPlugin, ZodToJsonSchemaConverter, blob, composeParams, customJsonSchema, file, getCustomJsonSchema, getCustomZodDef, oz, regexp, setCustomZodDef, url };