@orpc/zod 0.0.0-next.aa57fb6 → 0.0.0-next.ad0709a

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.js CHANGED
@@ -1,4 +1,362 @@
1
- // src/index.ts
1
+ // ../../node_modules/.pnpm/is-what@5.0.2/node_modules/is-what/dist/getType.js
2
+ function getType(payload) {
3
+ return Object.prototype.toString.call(payload).slice(8, -1);
4
+ }
5
+
6
+ // ../../node_modules/.pnpm/is-what@5.0.2/node_modules/is-what/dist/isPlainObject.js
7
+ function isPlainObject(payload) {
8
+ if (getType(payload) !== "Object")
9
+ return false;
10
+ const prototype = Object.getPrototypeOf(payload);
11
+ return !!prototype && prototype.constructor === Object && prototype === Object.prototype;
12
+ }
13
+
14
+ // ../../node_modules/.pnpm/radash@12.1.0/node_modules/radash/dist/esm/async.mjs
15
+ var guard = (func, shouldGuard) => {
16
+ const _guard = (err) => {
17
+ if (shouldGuard && !shouldGuard(err))
18
+ throw err;
19
+ return void 0;
20
+ };
21
+ const isPromise2 = (result) => result instanceof Promise;
22
+ try {
23
+ const result = func();
24
+ return isPromise2(result) ? result.catch(_guard) : result;
25
+ } catch (err) {
26
+ return _guard(err);
27
+ }
28
+ };
29
+
30
+ // src/coercer.ts
31
+ import {
32
+ ZodFirstPartyTypeKind
33
+ } from "zod";
34
+ var ZodCoercer = class {
35
+ coerce(schema, value) {
36
+ if (!schema || schema["~standard"].vendor !== "zod") {
37
+ return value;
38
+ }
39
+ const zodSchema = schema;
40
+ const coerced = zodCoerceInternal(zodSchema, value, { bracketNotation: true });
41
+ return coerced;
42
+ }
43
+ };
44
+ function zodCoerceInternal(schema, value, options) {
45
+ const isRoot = options?.isRoot ?? true;
46
+ const options_ = { ...options, isRoot: false };
47
+ if (isRoot && options?.bracketNotation && Array.isArray(value) && value.length === 1) {
48
+ const newValue = zodCoerceInternal(schema, value[0], options_);
49
+ if (schema.safeParse(newValue).success) {
50
+ return newValue;
51
+ }
52
+ return zodCoerceInternal(schema, value, options_);
53
+ }
54
+ const customType = getCustomZodType(schema._def);
55
+ if (customType === "Invalid Date") {
56
+ if (typeof value === "string" && value.toLocaleLowerCase() === "invalid date") {
57
+ return /* @__PURE__ */ new Date("Invalid Date");
58
+ }
59
+ } else if (customType === "RegExp") {
60
+ if (typeof value === "string" && value.startsWith("/")) {
61
+ const match = value.match(/^\/(.*)\/([a-z]*)$/);
62
+ if (match) {
63
+ const [, pattern, flags] = match;
64
+ return new RegExp(pattern, flags);
65
+ }
66
+ }
67
+ } else if (customType === "URL") {
68
+ if (typeof value === "string") {
69
+ const url2 = guard(() => new URL(value));
70
+ if (url2 !== void 0) {
71
+ return url2;
72
+ }
73
+ }
74
+ }
75
+ if (schema._def.typeName === void 0) {
76
+ return value;
77
+ }
78
+ const typeName = schema._def.typeName;
79
+ if (typeName === ZodFirstPartyTypeKind.ZodNumber) {
80
+ if (options_?.bracketNotation && typeof value === "string") {
81
+ const num = Number(value);
82
+ if (!Number.isNaN(num)) {
83
+ return num;
84
+ }
85
+ }
86
+ } else if (typeName === ZodFirstPartyTypeKind.ZodNaN) {
87
+ if (typeof value === "string" && value.toLocaleLowerCase() === "nan") {
88
+ return Number.NaN;
89
+ }
90
+ } else if (typeName === ZodFirstPartyTypeKind.ZodBoolean) {
91
+ if (options_?.bracketNotation && typeof value === "string") {
92
+ const lower = value.toLowerCase();
93
+ if (lower === "false" || lower === "off" || lower === "f") {
94
+ return false;
95
+ }
96
+ if (lower === "true" || lower === "on" || lower === "t") {
97
+ return true;
98
+ }
99
+ }
100
+ } else if (typeName === ZodFirstPartyTypeKind.ZodNull) {
101
+ if (options_?.bracketNotation && typeof value === "string" && value.toLowerCase() === "null") {
102
+ return null;
103
+ }
104
+ } else if (typeName === ZodFirstPartyTypeKind.ZodUndefined || typeName === ZodFirstPartyTypeKind.ZodVoid) {
105
+ if (typeof value === "string" && value.toLowerCase() === "undefined") {
106
+ return void 0;
107
+ }
108
+ } else if (typeName === ZodFirstPartyTypeKind.ZodDate) {
109
+ if (typeof value === "string" && (value.includes("-") || value.includes(":") || value.toLocaleLowerCase() === "invalid date")) {
110
+ return new Date(value);
111
+ }
112
+ } else if (typeName === ZodFirstPartyTypeKind.ZodBigInt) {
113
+ if (typeof value === "string") {
114
+ const num = guard(() => BigInt(value));
115
+ if (num !== void 0) {
116
+ return num;
117
+ }
118
+ }
119
+ } else if (typeName === ZodFirstPartyTypeKind.ZodArray || typeName === ZodFirstPartyTypeKind.ZodTuple) {
120
+ const schema_ = schema;
121
+ if (Array.isArray(value)) {
122
+ return value.map((v) => zodCoerceInternal(schema_._def.type, v, options_));
123
+ }
124
+ if (options_?.bracketNotation) {
125
+ if (value === void 0) {
126
+ return [];
127
+ }
128
+ if (isPlainObject(value) && Object.keys(value).every((k) => /^[1-9]\d*$/.test(k) || k === "0")) {
129
+ const indexes = Object.keys(value).map((k) => Number(k)).sort((a, b) => a - b);
130
+ const arr = Array.from({ length: (indexes.at(-1) ?? -1) + 1 });
131
+ for (const i of indexes) {
132
+ arr[i] = zodCoerceInternal(schema_._def.type, value[i], options_);
133
+ }
134
+ return arr;
135
+ }
136
+ }
137
+ } else if (typeName === ZodFirstPartyTypeKind.ZodObject) {
138
+ const schema_ = schema;
139
+ if (isPlainObject(value)) {
140
+ const newObj = {};
141
+ const keys = /* @__PURE__ */ new Set([
142
+ ...Object.keys(value),
143
+ ...Object.keys(schema_.shape)
144
+ ]);
145
+ for (const k of keys) {
146
+ if (!(k in value))
147
+ continue;
148
+ const v = value[k];
149
+ newObj[k] = zodCoerceInternal(
150
+ schema_.shape[k] ?? schema_._def.catchall,
151
+ v,
152
+ options_
153
+ );
154
+ }
155
+ return newObj;
156
+ }
157
+ if (options_?.bracketNotation) {
158
+ if (value === void 0) {
159
+ return {};
160
+ }
161
+ if (Array.isArray(value) && value.length === 1) {
162
+ const emptySchema = schema_.shape[""] ?? schema_._def.catchall;
163
+ return { "": zodCoerceInternal(emptySchema, value[0], options_) };
164
+ }
165
+ }
166
+ } else if (typeName === ZodFirstPartyTypeKind.ZodSet) {
167
+ const schema_ = schema;
168
+ if (Array.isArray(value)) {
169
+ return new Set(
170
+ value.map((v) => zodCoerceInternal(schema_._def.valueType, v, options_))
171
+ );
172
+ }
173
+ if (options_?.bracketNotation) {
174
+ if (value === void 0) {
175
+ return /* @__PURE__ */ new Set();
176
+ }
177
+ if (isPlainObject(value) && Object.keys(value).every((k) => /^[1-9]\d*$/.test(k) || k === "0")) {
178
+ const indexes = Object.keys(value).map((k) => Number(k)).sort((a, b) => a - b);
179
+ const arr = Array.from({ length: (indexes.at(-1) ?? -1) + 1 });
180
+ for (const i of indexes) {
181
+ arr[i] = zodCoerceInternal(schema_._def.valueType, value[i], options_);
182
+ }
183
+ return new Set(arr);
184
+ }
185
+ }
186
+ } else if (typeName === ZodFirstPartyTypeKind.ZodMap) {
187
+ const schema_ = schema;
188
+ if (Array.isArray(value) && value.every((i) => Array.isArray(i) && i.length === 2)) {
189
+ return new Map(
190
+ value.map(([k, v]) => [
191
+ zodCoerceInternal(schema_._def.keyType, k, options_),
192
+ zodCoerceInternal(schema_._def.valueType, v, options_)
193
+ ])
194
+ );
195
+ }
196
+ if (options_?.bracketNotation) {
197
+ if (value === void 0) {
198
+ return /* @__PURE__ */ new Map();
199
+ }
200
+ if (isPlainObject(value)) {
201
+ const arr = Array.from({ length: Object.keys(value).length }).fill(void 0).map(
202
+ (_, i) => isPlainObject(value[i]) && Object.keys(value[i]).length === 2 && "0" in value[i] && "1" in value[i] ? [value[i]["0"], value[i]["1"]] : void 0
203
+ );
204
+ if (arr.every((v) => !!v)) {
205
+ return new Map(
206
+ arr.map(([k, v]) => [
207
+ zodCoerceInternal(schema_._def.keyType, k, options_),
208
+ zodCoerceInternal(schema_._def.valueType, v, options_)
209
+ ])
210
+ );
211
+ }
212
+ }
213
+ }
214
+ } else if (typeName === ZodFirstPartyTypeKind.ZodRecord) {
215
+ const schema_ = schema;
216
+ if (isPlainObject(value)) {
217
+ const newObj = {};
218
+ for (const [k, v] of Object.entries(value)) {
219
+ const key = zodCoerceInternal(schema_._def.keyType, k, options_);
220
+ const val = zodCoerceInternal(schema_._def.valueType, v, options_);
221
+ newObj[key] = val;
222
+ }
223
+ return newObj;
224
+ }
225
+ } else if (typeName === ZodFirstPartyTypeKind.ZodUnion || typeName === ZodFirstPartyTypeKind.ZodDiscriminatedUnion) {
226
+ const schema_ = schema;
227
+ if (schema_.safeParse(value).success) {
228
+ return value;
229
+ }
230
+ const results = [];
231
+ for (const s of schema_._def.options) {
232
+ const newValue = zodCoerceInternal(s, value, { ...options_, isRoot });
233
+ if (newValue === value)
234
+ continue;
235
+ const result = schema_.safeParse(newValue);
236
+ if (result.success) {
237
+ return newValue;
238
+ }
239
+ results.push([newValue, result.error.issues.length]);
240
+ }
241
+ if (results.length === 0) {
242
+ return value;
243
+ }
244
+ return results.sort((a, b) => a[1] - b[1])[0]?.[0];
245
+ } else if (typeName === ZodFirstPartyTypeKind.ZodIntersection) {
246
+ const schema_ = schema;
247
+ return zodCoerceInternal(
248
+ schema_._def.right,
249
+ zodCoerceInternal(schema_._def.left, value, { ...options_, isRoot }),
250
+ { ...options_, isRoot }
251
+ );
252
+ } else if (typeName === ZodFirstPartyTypeKind.ZodReadonly) {
253
+ const schema_ = schema;
254
+ return zodCoerceInternal(schema_._def.innerType, value, { ...options_, isRoot });
255
+ } else if (typeName === ZodFirstPartyTypeKind.ZodPipeline) {
256
+ const schema_ = schema;
257
+ return zodCoerceInternal(schema_._def.in, value, { ...options_, isRoot });
258
+ } else if (typeName === ZodFirstPartyTypeKind.ZodLazy) {
259
+ const schema_ = schema;
260
+ return zodCoerceInternal(schema_._def.getter(), value, { ...options_, isRoot });
261
+ } else if (typeName === ZodFirstPartyTypeKind.ZodEffects) {
262
+ const schema_ = schema;
263
+ return zodCoerceInternal(schema_._def.schema, value, { ...options_, isRoot });
264
+ } else if (typeName === ZodFirstPartyTypeKind.ZodBranded) {
265
+ const schema_ = schema;
266
+ return zodCoerceInternal(schema_._def.type, value, { ...options_, isRoot });
267
+ } else if (typeName === ZodFirstPartyTypeKind.ZodCatch) {
268
+ const schema_ = schema;
269
+ return zodCoerceInternal(schema_._def.innerType, value, { ...options_, isRoot });
270
+ } else if (typeName === ZodFirstPartyTypeKind.ZodDefault) {
271
+ const schema_ = schema;
272
+ return zodCoerceInternal(schema_._def.innerType, value, { ...options_, isRoot });
273
+ } else if (typeName === ZodFirstPartyTypeKind.ZodNullable) {
274
+ const schema_ = schema;
275
+ if (value === null) {
276
+ return null;
277
+ }
278
+ if (typeof value === "string" && value.toLowerCase() === "null") {
279
+ return schema_.safeParse(value).success ? value : null;
280
+ }
281
+ return zodCoerceInternal(schema_._def.innerType, value, { ...options_, isRoot });
282
+ } else if (typeName === ZodFirstPartyTypeKind.ZodOptional) {
283
+ const schema_ = schema;
284
+ if (value === void 0) {
285
+ return void 0;
286
+ }
287
+ if (typeof value === "string" && value.toLowerCase() === "undefined") {
288
+ return schema_.safeParse(value).success ? value : void 0;
289
+ }
290
+ return zodCoerceInternal(schema_._def.innerType, value, { ...options_, isRoot });
291
+ } else if (typeName === ZodFirstPartyTypeKind.ZodNativeEnum) {
292
+ const schema_ = schema;
293
+ if (Object.values(schema_._def.values).includes(value)) {
294
+ return value;
295
+ }
296
+ if (options?.bracketNotation && typeof value === "string") {
297
+ for (const expectedValue of Object.values(schema_._def.values)) {
298
+ if (expectedValue.toString() === value) {
299
+ return expectedValue;
300
+ }
301
+ }
302
+ }
303
+ } else if (typeName === ZodFirstPartyTypeKind.ZodLiteral) {
304
+ const schema_ = schema;
305
+ const expectedValue = schema_._def.value;
306
+ if (typeof value === "string" && typeof expectedValue !== "string") {
307
+ if (typeof expectedValue === "bigint") {
308
+ const num = guard(() => BigInt(value));
309
+ if (num !== void 0) {
310
+ return num;
311
+ }
312
+ } else if (expectedValue === void 0) {
313
+ if (value.toLocaleLowerCase() === "undefined") {
314
+ return void 0;
315
+ }
316
+ } else if (options?.bracketNotation) {
317
+ if (typeof expectedValue === "number") {
318
+ const num = Number(value);
319
+ if (!Number.isNaN(num)) {
320
+ return num;
321
+ }
322
+ } else if (typeof expectedValue === "boolean") {
323
+ const lower = value.toLowerCase();
324
+ if (lower === "false" || lower === "off" || lower === "f") {
325
+ return false;
326
+ }
327
+ if (lower === "true" || lower === "on" || lower === "t") {
328
+ return true;
329
+ }
330
+ } else if (expectedValue === null) {
331
+ if (value.toLocaleLowerCase() === "null") {
332
+ return null;
333
+ }
334
+ }
335
+ }
336
+ }
337
+ } else {
338
+ const _expected = typeName;
339
+ }
340
+ return value;
341
+ }
342
+
343
+ // src/converter.ts
344
+ import { JSONSchemaFormat } from "@orpc/openapi";
345
+
346
+ // ../../node_modules/.pnpm/escape-string-regexp@5.0.0/node_modules/escape-string-regexp/index.js
347
+ function escapeStringRegexp(string) {
348
+ if (typeof string !== "string") {
349
+ throw new TypeError("Expected a string");
350
+ }
351
+ return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
352
+ }
353
+
354
+ // src/converter.ts
355
+ import {
356
+ ZodFirstPartyTypeKind as ZodFirstPartyTypeKind2
357
+ } from "zod";
358
+
359
+ // src/schemas.ts
2
360
  import wcmatch from "wildcard-match";
3
361
  import {
4
362
  custom
@@ -133,7 +491,474 @@ var oz = {
133
491
  regexp,
134
492
  url
135
493
  };
494
+
495
+ // src/converter.ts
496
+ var NON_LOGIC_KEYWORDS = [
497
+ // Core Documentation Keywords
498
+ "$anchor",
499
+ "$comment",
500
+ "$defs",
501
+ "$id",
502
+ "title",
503
+ "description",
504
+ // Value Keywords
505
+ "default",
506
+ "deprecated",
507
+ "examples",
508
+ // Metadata Keywords
509
+ "$schema",
510
+ "definitions",
511
+ // Legacy, but still used
512
+ "readOnly",
513
+ "writeOnly",
514
+ // Display and UI Hints
515
+ "contentMediaType",
516
+ "contentEncoding",
517
+ "format",
518
+ // Custom Extensions
519
+ "$vocabulary",
520
+ "$dynamicAnchor",
521
+ "$dynamicRef"
522
+ ];
523
+ var UNSUPPORTED_JSON_SCHEMA = { not: {} };
524
+ var UNDEFINED_JSON_SCHEMA = { const: "undefined" };
525
+ function zodToJsonSchema(schema, options) {
526
+ if (schema["~standard"].vendor !== "zod") {
527
+ console.warn(`Generate JSON schema not support ${schema["~standard"].vendor} yet`);
528
+ return {};
529
+ }
530
+ const schema__ = schema;
531
+ if (!options?.isHandledZodDescription && "description" in schema__._def) {
532
+ const json = zodToJsonSchema(schema__, {
533
+ ...options,
534
+ isHandledZodDescription: true
535
+ });
536
+ return {
537
+ description: schema__._def.description,
538
+ ...json
539
+ };
540
+ }
541
+ if (!options?.isHandledCustomJSONSchema) {
542
+ const customJSONSchema = getCustomJSONSchema(schema__._def, options);
543
+ if (customJSONSchema) {
544
+ const json = zodToJsonSchema(schema__, {
545
+ ...options,
546
+ isHandledCustomJSONSchema: true
547
+ });
548
+ return {
549
+ ...json,
550
+ ...customJSONSchema
551
+ };
552
+ }
553
+ }
554
+ const childOptions = { ...options, isHandledCustomJSONSchema: false, isHandledZodDescription: false };
555
+ const customType = getCustomZodType(schema__._def);
556
+ switch (customType) {
557
+ case "Blob": {
558
+ return { type: "string", contentMediaType: "*/*" };
559
+ }
560
+ case "File": {
561
+ const mimeType = getCustomZodFileMimeType(schema__._def) ?? "*/*";
562
+ return { type: "string", contentMediaType: mimeType };
563
+ }
564
+ case "Invalid Date": {
565
+ return { const: "Invalid Date" };
566
+ }
567
+ case "RegExp": {
568
+ return {
569
+ type: "string",
570
+ pattern: "^\\/(.*)\\/([a-z]*)$"
571
+ };
572
+ }
573
+ case "URL": {
574
+ return { type: "string", format: JSONSchemaFormat.URI };
575
+ }
576
+ }
577
+ const _expectedCustomType = customType;
578
+ const typeName = schema__._def.typeName;
579
+ switch (typeName) {
580
+ case ZodFirstPartyTypeKind2.ZodString: {
581
+ const schema_ = schema__;
582
+ const json = { type: "string" };
583
+ for (const check of schema_._def.checks) {
584
+ switch (check.kind) {
585
+ case "base64":
586
+ json.contentEncoding = "base64";
587
+ break;
588
+ case "cuid":
589
+ json.pattern = "^[0-9A-HJKMNP-TV-Z]{26}$";
590
+ break;
591
+ case "email":
592
+ json.format = JSONSchemaFormat.Email;
593
+ break;
594
+ case "url":
595
+ json.format = JSONSchemaFormat.URI;
596
+ break;
597
+ case "uuid":
598
+ json.format = JSONSchemaFormat.UUID;
599
+ break;
600
+ case "regex":
601
+ json.pattern = check.regex.source;
602
+ break;
603
+ case "min":
604
+ json.minLength = check.value;
605
+ break;
606
+ case "max":
607
+ json.maxLength = check.value;
608
+ break;
609
+ case "length":
610
+ json.minLength = check.value;
611
+ json.maxLength = check.value;
612
+ break;
613
+ case "includes":
614
+ json.pattern = escapeStringRegexp(check.value);
615
+ break;
616
+ case "startsWith":
617
+ json.pattern = `^${escapeStringRegexp(check.value)}`;
618
+ break;
619
+ case "endsWith":
620
+ json.pattern = `${escapeStringRegexp(check.value)}$`;
621
+ break;
622
+ case "emoji":
623
+ json.pattern = "^(\\p{Extended_Pictographic}|\\p{Emoji_Component})+$";
624
+ break;
625
+ case "nanoid":
626
+ json.pattern = "^[a-zA-Z0-9_-]{21}$";
627
+ break;
628
+ case "cuid2":
629
+ json.pattern = "^[0-9a-z]+$";
630
+ break;
631
+ case "ulid":
632
+ json.pattern = "^[0-9A-HJKMNP-TV-Z]{26}$";
633
+ break;
634
+ case "datetime":
635
+ json.format = JSONSchemaFormat.DateTime;
636
+ break;
637
+ case "date":
638
+ json.format = JSONSchemaFormat.Date;
639
+ break;
640
+ case "time":
641
+ json.format = JSONSchemaFormat.Time;
642
+ break;
643
+ case "duration":
644
+ json.format = JSONSchemaFormat.Duration;
645
+ break;
646
+ case "ip":
647
+ json.format = JSONSchemaFormat.IPv4;
648
+ break;
649
+ case "jwt":
650
+ json.pattern = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]*$";
651
+ break;
652
+ case "base64url":
653
+ json.pattern = "^([0-9a-zA-Z-_]{4})*(([0-9a-zA-Z-_]{2}(==)?)|([0-9a-zA-Z-_]{3}(=)?))?$";
654
+ break;
655
+ default: {
656
+ const _expect = check.kind;
657
+ }
658
+ }
659
+ }
660
+ return json;
661
+ }
662
+ case ZodFirstPartyTypeKind2.ZodNumber: {
663
+ const schema_ = schema__;
664
+ const json = { type: "number" };
665
+ for (const check of schema_._def.checks) {
666
+ switch (check.kind) {
667
+ case "int":
668
+ json.type = "integer";
669
+ break;
670
+ case "min":
671
+ json.minimum = check.value;
672
+ break;
673
+ case "max":
674
+ json.maximum = check.value;
675
+ break;
676
+ case "multipleOf":
677
+ json.multipleOf = check.value;
678
+ break;
679
+ default: {
680
+ const _expect = check.kind;
681
+ }
682
+ }
683
+ }
684
+ return json;
685
+ }
686
+ case ZodFirstPartyTypeKind2.ZodNaN: {
687
+ return { const: "NaN" };
688
+ }
689
+ case ZodFirstPartyTypeKind2.ZodBigInt: {
690
+ const json = { type: "string", pattern: "^-?[0-9]+$" };
691
+ return json;
692
+ }
693
+ case ZodFirstPartyTypeKind2.ZodBoolean: {
694
+ return { type: "boolean" };
695
+ }
696
+ case ZodFirstPartyTypeKind2.ZodDate: {
697
+ const schema2 = { type: "string", format: JSONSchemaFormat.Date };
698
+ return schema2;
699
+ }
700
+ case ZodFirstPartyTypeKind2.ZodNull: {
701
+ return { type: "null" };
702
+ }
703
+ case ZodFirstPartyTypeKind2.ZodVoid:
704
+ case ZodFirstPartyTypeKind2.ZodUndefined: {
705
+ return UNDEFINED_JSON_SCHEMA;
706
+ }
707
+ case ZodFirstPartyTypeKind2.ZodLiteral: {
708
+ const schema_ = schema__;
709
+ return { const: schema_._def.value };
710
+ }
711
+ case ZodFirstPartyTypeKind2.ZodEnum: {
712
+ const schema_ = schema__;
713
+ return {
714
+ enum: schema_._def.values
715
+ };
716
+ }
717
+ case ZodFirstPartyTypeKind2.ZodNativeEnum: {
718
+ const schema_ = schema__;
719
+ return {
720
+ enum: Object.values(schema_._def.values)
721
+ };
722
+ }
723
+ case ZodFirstPartyTypeKind2.ZodArray: {
724
+ const schema_ = schema__;
725
+ const def = schema_._def;
726
+ const json = { type: "array" };
727
+ json.items = zodToJsonSchema(def.type, childOptions);
728
+ if (def.exactLength) {
729
+ json.maxItems = def.exactLength.value;
730
+ json.minItems = def.exactLength.value;
731
+ }
732
+ if (def.minLength) {
733
+ json.minItems = def.minLength.value;
734
+ }
735
+ if (def.maxLength) {
736
+ json.maxItems = def.maxLength.value;
737
+ }
738
+ return json;
739
+ }
740
+ case ZodFirstPartyTypeKind2.ZodTuple: {
741
+ const schema_ = schema__;
742
+ const prefixItems = [];
743
+ const json = { type: "array" };
744
+ for (const item of schema_._def.items) {
745
+ prefixItems.push(zodToJsonSchema(item, childOptions));
746
+ }
747
+ if (prefixItems?.length) {
748
+ json.prefixItems = prefixItems;
749
+ }
750
+ if (schema_._def.rest) {
751
+ const items = zodToJsonSchema(schema_._def.rest, childOptions);
752
+ if (items) {
753
+ json.items = items;
754
+ }
755
+ }
756
+ return json;
757
+ }
758
+ case ZodFirstPartyTypeKind2.ZodObject: {
759
+ const schema_ = schema__;
760
+ const json = { type: "object" };
761
+ const properties = {};
762
+ const required = [];
763
+ for (const [key, value] of Object.entries(schema_.shape)) {
764
+ const { schema: schema2, matches } = extractJSONSchema(
765
+ zodToJsonSchema(value, childOptions),
766
+ (schema3) => schema3 === UNDEFINED_JSON_SCHEMA
767
+ );
768
+ if (schema2) {
769
+ properties[key] = schema2;
770
+ }
771
+ if (matches.length === 0) {
772
+ required.push(key);
773
+ }
774
+ }
775
+ if (Object.keys(properties).length) {
776
+ json.properties = properties;
777
+ }
778
+ if (required.length) {
779
+ json.required = required;
780
+ }
781
+ const additionalProperties = zodToJsonSchema(
782
+ schema_._def.catchall,
783
+ childOptions
784
+ );
785
+ if (schema_._def.unknownKeys === "strict") {
786
+ json.additionalProperties = additionalProperties === UNSUPPORTED_JSON_SCHEMA ? false : additionalProperties;
787
+ } else {
788
+ if (additionalProperties && additionalProperties !== UNSUPPORTED_JSON_SCHEMA) {
789
+ json.additionalProperties = additionalProperties;
790
+ }
791
+ }
792
+ return json;
793
+ }
794
+ case ZodFirstPartyTypeKind2.ZodRecord: {
795
+ const schema_ = schema__;
796
+ const json = { type: "object" };
797
+ json.additionalProperties = zodToJsonSchema(
798
+ schema_._def.valueType,
799
+ childOptions
800
+ );
801
+ return json;
802
+ }
803
+ case ZodFirstPartyTypeKind2.ZodSet: {
804
+ const schema_ = schema__;
805
+ return {
806
+ type: "array",
807
+ items: zodToJsonSchema(schema_._def.valueType, childOptions)
808
+ };
809
+ }
810
+ case ZodFirstPartyTypeKind2.ZodMap: {
811
+ const schema_ = schema__;
812
+ return {
813
+ type: "array",
814
+ items: {
815
+ type: "array",
816
+ prefixItems: [
817
+ zodToJsonSchema(schema_._def.keyType, childOptions),
818
+ zodToJsonSchema(schema_._def.valueType, childOptions)
819
+ ],
820
+ maxItems: 2,
821
+ minItems: 2
822
+ }
823
+ };
824
+ }
825
+ case ZodFirstPartyTypeKind2.ZodUnion:
826
+ case ZodFirstPartyTypeKind2.ZodDiscriminatedUnion: {
827
+ const schema_ = schema__;
828
+ const anyOf = [];
829
+ for (const s of schema_._def.options) {
830
+ anyOf.push(zodToJsonSchema(s, childOptions));
831
+ }
832
+ return { anyOf };
833
+ }
834
+ case ZodFirstPartyTypeKind2.ZodIntersection: {
835
+ const schema_ = schema__;
836
+ const allOf = [];
837
+ for (const s of [schema_._def.left, schema_._def.right]) {
838
+ allOf.push(zodToJsonSchema(s, childOptions));
839
+ }
840
+ return { allOf };
841
+ }
842
+ case ZodFirstPartyTypeKind2.ZodLazy: {
843
+ const schema_ = schema__;
844
+ const maxLazyDepth = childOptions?.maxLazyDepth ?? 5;
845
+ const lazyDepth = childOptions?.lazyDepth ?? 0;
846
+ if (lazyDepth > maxLazyDepth) {
847
+ return {};
848
+ }
849
+ return zodToJsonSchema(schema_._def.getter(), {
850
+ ...childOptions,
851
+ lazyDepth: lazyDepth + 1
852
+ });
853
+ }
854
+ case ZodFirstPartyTypeKind2.ZodUnknown:
855
+ case ZodFirstPartyTypeKind2.ZodAny:
856
+ case void 0: {
857
+ return {};
858
+ }
859
+ case ZodFirstPartyTypeKind2.ZodOptional: {
860
+ const schema_ = schema__;
861
+ const inner = zodToJsonSchema(schema_._def.innerType, childOptions);
862
+ return {
863
+ anyOf: [UNDEFINED_JSON_SCHEMA, inner]
864
+ };
865
+ }
866
+ case ZodFirstPartyTypeKind2.ZodReadonly: {
867
+ const schema_ = schema__;
868
+ return zodToJsonSchema(schema_._def.innerType, childOptions);
869
+ }
870
+ case ZodFirstPartyTypeKind2.ZodDefault: {
871
+ const schema_ = schema__;
872
+ return zodToJsonSchema(schema_._def.innerType, childOptions);
873
+ }
874
+ case ZodFirstPartyTypeKind2.ZodEffects: {
875
+ const schema_ = schema__;
876
+ if (schema_._def.effect.type === "transform" && childOptions?.mode === "output") {
877
+ return {};
878
+ }
879
+ return zodToJsonSchema(schema_._def.schema, childOptions);
880
+ }
881
+ case ZodFirstPartyTypeKind2.ZodCatch: {
882
+ const schema_ = schema__;
883
+ return zodToJsonSchema(schema_._def.innerType, childOptions);
884
+ }
885
+ case ZodFirstPartyTypeKind2.ZodBranded: {
886
+ const schema_ = schema__;
887
+ return zodToJsonSchema(schema_._def.type, childOptions);
888
+ }
889
+ case ZodFirstPartyTypeKind2.ZodPipeline: {
890
+ const schema_ = schema__;
891
+ return zodToJsonSchema(
892
+ childOptions?.mode === "output" ? schema_._def.out : schema_._def.in,
893
+ childOptions
894
+ );
895
+ }
896
+ case ZodFirstPartyTypeKind2.ZodNullable: {
897
+ const schema_ = schema__;
898
+ const inner = zodToJsonSchema(schema_._def.innerType, childOptions);
899
+ return {
900
+ anyOf: [{ type: "null" }, inner]
901
+ };
902
+ }
903
+ }
904
+ const _expected = typeName;
905
+ return UNSUPPORTED_JSON_SCHEMA;
906
+ }
907
+ function extractJSONSchema(schema, check, matches = []) {
908
+ if (check(schema)) {
909
+ matches.push(schema);
910
+ return { schema: void 0, matches };
911
+ }
912
+ if (typeof schema === "boolean") {
913
+ return { schema, matches };
914
+ }
915
+ if (schema.anyOf && Object.keys(schema).every(
916
+ (k) => k === "anyOf" || NON_LOGIC_KEYWORDS.includes(k)
917
+ )) {
918
+ const anyOf = schema.anyOf.map((s) => extractJSONSchema(s, check, matches).schema).filter((v) => !!v);
919
+ if (anyOf.length === 1 && typeof anyOf[0] === "object") {
920
+ return { schema: { ...schema, anyOf: void 0, ...anyOf[0] }, matches };
921
+ }
922
+ return {
923
+ schema: {
924
+ ...schema,
925
+ anyOf
926
+ },
927
+ matches
928
+ };
929
+ }
930
+ if (schema.oneOf && Object.keys(schema).every(
931
+ (k) => k === "oneOf" || NON_LOGIC_KEYWORDS.includes(k)
932
+ )) {
933
+ const oneOf = schema.oneOf.map((s) => extractJSONSchema(s, check, matches).schema).filter((v) => !!v);
934
+ if (oneOf.length === 1 && typeof oneOf[0] === "object") {
935
+ return { schema: { ...schema, oneOf: void 0, ...oneOf[0] }, matches };
936
+ }
937
+ return {
938
+ schema: {
939
+ ...schema,
940
+ oneOf
941
+ },
942
+ matches
943
+ };
944
+ }
945
+ return { schema, matches };
946
+ }
947
+ var ZodToJsonSchemaConverter = class {
948
+ condition(schema) {
949
+ return Boolean(schema && schema["~standard"].vendor === "zod");
950
+ }
951
+ convert(schema, options) {
952
+ const jsonSchema = schema;
953
+ return zodToJsonSchema(jsonSchema, { mode: options.strategy });
954
+ }
955
+ };
136
956
  export {
957
+ NON_LOGIC_KEYWORDS,
958
+ UNDEFINED_JSON_SCHEMA,
959
+ UNSUPPORTED_JSON_SCHEMA,
960
+ ZodCoercer,
961
+ ZodToJsonSchemaConverter,
137
962
  blob,
138
963
  file,
139
964
  getCustomJSONSchema,
@@ -143,6 +968,7 @@ export {
143
968
  openapi,
144
969
  oz,
145
970
  regexp,
146
- url
971
+ url,
972
+ zodToJsonSchema
147
973
  };
148
974
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,6 @@
1
+ import type { Schema } from '@orpc/contract';
2
+ import type { SchemaCoercer } from '@orpc/openapi/standard';
3
+ export declare class ZodCoercer implements SchemaCoercer {
4
+ coerce(schema: Schema, value: unknown): unknown;
5
+ }
6
+ //# sourceMappingURL=coercer.d.ts.map
@@ -0,0 +1,50 @@
1
+ import type { Schema } from '@orpc/contract';
2
+ import type { JSONSchema, SchemaConverter, SchemaConvertOptions } from '@orpc/openapi';
3
+ import type { StandardSchemaV1 } from '@standard-schema/spec';
4
+ export declare const NON_LOGIC_KEYWORDS: ("$anchor" | "$comment" | "$defs" | "$dynamicAnchor" | "$dynamicRef" | "$id" | "$schema" | "$vocabulary" | "contentEncoding" | "contentMediaType" | "default" | "definitions" | "deprecated" | "description" | "examples" | "format" | "readOnly" | "title" | "writeOnly")[];
5
+ export declare const UNSUPPORTED_JSON_SCHEMA: {
6
+ not: {};
7
+ };
8
+ export declare const UNDEFINED_JSON_SCHEMA: {
9
+ const: string;
10
+ };
11
+ export interface ZodToJsonSchemaOptions {
12
+ /**
13
+ * Max depth of lazy type, if it exceeds.
14
+ *
15
+ * Used `{}` when reach max depth
16
+ *
17
+ * @default 5
18
+ */
19
+ maxLazyDepth?: number;
20
+ /**
21
+ * The length used to track the depth of lazy type
22
+ *
23
+ * @internal
24
+ */
25
+ lazyDepth?: number;
26
+ /**
27
+ * The expected json schema for input or output zod schema
28
+ *
29
+ * @default input
30
+ */
31
+ mode?: 'input' | 'output';
32
+ /**
33
+ * Track if current level schema is handled custom json schema to prevent recursive
34
+ *
35
+ * @internal
36
+ */
37
+ isHandledCustomJSONSchema?: boolean;
38
+ /**
39
+ * Track if current level schema is handled zod description to prevent recursive
40
+ *
41
+ * @internal
42
+ */
43
+ isHandledZodDescription?: boolean;
44
+ }
45
+ export declare function zodToJsonSchema(schema: StandardSchemaV1, options?: ZodToJsonSchemaOptions): Exclude<JSONSchema.JSONSchema, boolean>;
46
+ export declare class ZodToJsonSchemaConverter implements SchemaConverter {
47
+ condition(schema: Schema): boolean;
48
+ convert(schema: Schema, options: SchemaConvertOptions): JSONSchema.JSONSchema;
49
+ }
50
+ //# sourceMappingURL=converter.d.ts.map
@@ -1,31 +1,4 @@
1
- import type { JSONSchema } from 'json-schema-typed/draft-2020-12';
2
- import { type CustomErrorParams, type input, type output, type ZodEffects, type ZodType, type ZodTypeAny, type ZodTypeDef } from 'zod';
3
- export type CustomZodType = 'File' | 'Blob' | 'Invalid Date' | 'RegExp' | 'URL';
4
- type CustomParams = CustomErrorParams & {
5
- fatal?: boolean;
6
- };
7
- export declare function getCustomZodType(def: ZodTypeDef): CustomZodType | undefined;
8
- export declare function getCustomZodFileMimeType(def: ZodTypeDef): string | undefined;
9
- export declare function getCustomJSONSchema(def: ZodTypeDef, options?: {
10
- mode?: 'input' | 'output';
11
- }): Exclude<JSONSchema, boolean> | undefined;
12
- export declare function file(params?: string | CustomParams | ((input: unknown) => CustomParams)): ZodType<InstanceType<typeof File>, ZodTypeDef, InstanceType<typeof File>> & {
13
- type: (mimeType: string, params?: string | CustomParams | ((input: unknown) => CustomParams)) => ZodEffects<ZodType<InstanceType<typeof File>, ZodTypeDef, InstanceType<typeof File>>, InstanceType<typeof File>, InstanceType<typeof File>>;
14
- };
15
- export declare function blob(params?: string | CustomParams | ((input: unknown) => CustomParams)): ZodType<InstanceType<typeof Blob>, ZodTypeDef, InstanceType<typeof Blob>>;
16
- export declare function invalidDate(params?: string | CustomParams | ((input: unknown) => CustomParams)): ZodType<Date, ZodTypeDef, Date>;
17
- export declare function regexp(options?: CustomParams): ZodType<RegExp, ZodTypeDef, RegExp>;
18
- export declare function url(options?: CustomParams): ZodType<URL, ZodTypeDef, URL>;
19
- export declare function openapi<T extends ZodTypeAny, TMode extends 'input' | 'output' | 'both' = 'both'>(schema: T, custom: Exclude<JSONSchema<TMode extends 'input' ? input<T> : TMode extends 'output' ? output<T> : input<T> & output<T>>, boolean>, options?: {
20
- mode: TMode;
21
- }): ReturnType<T['refine']>;
22
- export declare const oz: {
23
- openapi: typeof openapi;
24
- file: typeof file;
25
- blob: typeof blob;
26
- invalidDate: typeof invalidDate;
27
- regexp: typeof regexp;
28
- url: typeof url;
29
- };
30
- export {};
1
+ export * from './coercer';
2
+ export * from './converter';
3
+ export * from './schemas';
31
4
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,31 @@
1
+ import type { JSONSchema } from 'json-schema-typed/draft-2020-12';
2
+ import { type CustomErrorParams, type input, type output, type ZodEffects, type ZodType, type ZodTypeAny, type ZodTypeDef } from 'zod';
3
+ export type CustomZodType = 'File' | 'Blob' | 'Invalid Date' | 'RegExp' | 'URL';
4
+ type CustomParams = CustomErrorParams & {
5
+ fatal?: boolean;
6
+ };
7
+ export declare function getCustomZodType(def: ZodTypeDef): CustomZodType | undefined;
8
+ export declare function getCustomZodFileMimeType(def: ZodTypeDef): string | undefined;
9
+ export declare function getCustomJSONSchema(def: ZodTypeDef, options?: {
10
+ mode?: 'input' | 'output';
11
+ }): Exclude<JSONSchema, boolean> | undefined;
12
+ export declare function file(params?: string | CustomParams | ((input: unknown) => CustomParams)): ZodType<InstanceType<typeof File>, ZodTypeDef, InstanceType<typeof File>> & {
13
+ type(mimeType: string, params?: string | CustomParams | ((input: unknown) => CustomParams)): ZodEffects<ZodType<InstanceType<typeof File>, ZodTypeDef, InstanceType<typeof File>>, InstanceType<typeof File>, InstanceType<typeof File>>;
14
+ };
15
+ export declare function blob(params?: string | CustomParams | ((input: unknown) => CustomParams)): ZodType<InstanceType<typeof Blob>, ZodTypeDef, InstanceType<typeof Blob>>;
16
+ export declare function invalidDate(params?: string | CustomParams | ((input: unknown) => CustomParams)): ZodType<Date, ZodTypeDef, Date>;
17
+ export declare function regexp(options?: CustomParams): ZodType<RegExp, ZodTypeDef, RegExp>;
18
+ export declare function url(options?: CustomParams): ZodType<URL, ZodTypeDef, URL>;
19
+ export declare function openapi<T extends ZodTypeAny, TMode extends 'input' | 'output' | 'both' = 'both'>(schema: T, custom: Exclude<JSONSchema<TMode extends 'input' ? input<T> : TMode extends 'output' ? output<T> : input<T> & output<T>>, boolean>, options?: {
20
+ mode: TMode;
21
+ }): ReturnType<T['refine']>;
22
+ export declare const oz: {
23
+ openapi: typeof openapi;
24
+ file: typeof file;
25
+ blob: typeof blob;
26
+ invalidDate: typeof invalidDate;
27
+ regexp: typeof regexp;
28
+ url: typeof url;
29
+ };
30
+ export {};
31
+ //# sourceMappingURL=schemas.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@orpc/zod",
3
3
  "type": "module",
4
- "version": "0.0.0-next.aa57fb6",
4
+ "version": "0.0.0-next.ad0709a",
5
5
  "license": "MIT",
6
6
  "homepage": "https://orpc.unnoq.com",
7
7
  "repository": {
@@ -28,10 +28,13 @@
28
28
  "!**/*.tsbuildinfo",
29
29
  "dist"
30
30
  ],
31
+ "peerDependencies": {
32
+ "@orpc/openapi": "0.0.0-next.ad0709a"
33
+ },
31
34
  "dependencies": {
32
35
  "json-schema-typed": "^8.0.1",
33
36
  "wildcard-match": "^5.1.3",
34
- "zod": "^3.23.8"
37
+ "zod": "^3.24.1"
35
38
  },
36
39
  "scripts": {
37
40
  "build": "tsup --clean --sourcemap --entry.index=src/index.ts --format=esm --onSuccess='tsc -b --noCheck'",