@orpc/zod 0.0.0-next.fd0ca3d → 0.0.0-next.fd13879
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/README.md +142 -0
- package/dist/index.d.mts +82 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.mjs +822 -0
- package/dist/zod4/index.d.mts +302 -0
- package/dist/zod4/index.d.ts +302 -0
- package/dist/zod4/index.mjs +660 -0
- package/package.json +19 -16
- package/dist/index.js +0 -980
- package/dist/src/coercer.d.ts +0 -12
- package/dist/src/converter.d.ts +0 -50
- package/dist/src/index.d.ts +0 -4
- package/dist/src/schemas.d.ts +0 -31
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 };
|