zod 4.1.1 → 4.1.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zod",
3
- "version": "4.1.1",
3
+ "version": "4.1.2",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": "Colin McDonnell <zod@colinhacks.com>",
@@ -27,6 +27,7 @@ export {
27
27
  flattenError,
28
28
  toJSONSchema,
29
29
  TimePrecision,
30
+ util,
30
31
  NEVER,
31
32
  } from "../core/index.js";
32
33
 
@@ -2,7 +2,7 @@ import { expect, test } from "vitest";
2
2
  import * as z from "zod/v4";
3
3
 
4
4
  // ============================================================================
5
- // Number/BigInt Codecs
5
+ // stringToNumber
6
6
  // ============================================================================
7
7
 
8
8
  const stringToNumber = () =>
@@ -11,128 +11,6 @@ const stringToNumber = () =>
11
11
  encode: (num) => num.toString(),
12
12
  });
13
13
 
14
- const stringToInt = () =>
15
- z.codec(z.string(), z.int(), {
16
- decode: (str) => Number.parseInt(str, 10),
17
- encode: (num) => num.toString(),
18
- });
19
-
20
- const stringToBigInt = () =>
21
- z.codec(z.string(), z.bigint(), {
22
- decode: (str) => BigInt(str),
23
- encode: (bigint) => bigint.toString(),
24
- });
25
-
26
- const numberToBigInt = () =>
27
- z.codec(z.int(), z.bigint(), {
28
- decode: (num) => BigInt(num),
29
- encode: (bigint) => Number(bigint),
30
- });
31
-
32
- // ============================================================================
33
- // Date/Duration Codecs
34
- // ============================================================================
35
-
36
- const isoDatetimeToDate = () =>
37
- z.codec(z.iso.datetime(), z.date(), {
38
- decode: (isoString) => new Date(isoString),
39
- encode: (date) => date.toISOString(),
40
- });
41
-
42
- const epochSecondsToDate = () =>
43
- z.codec(z.int().min(0), z.date(), {
44
- decode: (seconds) => new Date(seconds * 1000),
45
- encode: (date) => Math.floor(date.getTime() / 1000),
46
- });
47
-
48
- const epochMillisToDate = () =>
49
- z.codec(z.int().min(0), z.date(), {
50
- decode: (millis) => new Date(millis),
51
- encode: (date) => date.getTime(),
52
- });
53
-
54
- // ============================================================================
55
- // JSON Codec
56
- // ============================================================================
57
-
58
- const json = <T extends z.ZodTypeAny>(schema: T) =>
59
- z.codec(z.string(), schema, {
60
- decode: (jsonString) => JSON.parse(jsonString),
61
- encode: (value) => JSON.stringify(value),
62
- });
63
-
64
- // ============================================================================
65
- // Text/Bytes Codecs
66
- // ============================================================================
67
-
68
- const utf8ToBytes = () =>
69
- z.codec(z.string(), z.instanceof(Uint8Array), {
70
- decode: (str) => new TextEncoder().encode(str),
71
- encode: (bytes) => new TextDecoder().decode(bytes),
72
- });
73
-
74
- const bytesToUtf8 = () =>
75
- z.codec(z.instanceof(Uint8Array), z.string(), {
76
- decode: (bytes) => new TextDecoder().decode(bytes),
77
- encode: (str) => new TextEncoder().encode(str),
78
- });
79
-
80
- // ============================================================================
81
- // Binary-to-text Codecs
82
- // ============================================================================
83
-
84
- // Using utility functions from z.core.util
85
-
86
- const base64 = () =>
87
- z.codec(z.base64(), z.instanceof(Uint8Array), {
88
- decode: (base64String) => z.core.util.base64ToUint8Array(base64String),
89
- encode: (bytes) => z.core.util.uint8ArrayToBase64(bytes),
90
- });
91
-
92
- const base64urlToBytes = () =>
93
- z.codec(z.base64url(), z.instanceof(Uint8Array), {
94
- decode: (base64urlString) => z.core.util.base64urlToUint8Array(base64urlString),
95
- encode: (bytes) => z.core.util.uint8ArrayToBase64url(bytes),
96
- });
97
-
98
- const hexToBytes = () =>
99
- z.codec(z.hex(), z.instanceof(Uint8Array), {
100
- decode: (hexString) => z.core.util.hexToUint8Array(hexString),
101
- encode: (bytes) => z.core.util.uint8ArrayToHex(bytes),
102
- });
103
-
104
- // ============================================================================
105
- // URL Codecs
106
- // ============================================================================
107
-
108
- const stringToURL = () =>
109
- z.codec(z.url(), z.instanceof(URL), {
110
- decode: (urlString) => new URL(urlString),
111
- encode: (url) => url.href,
112
- });
113
-
114
- const stringToHttpURL = () =>
115
- z.codec(z.httpUrl(), z.instanceof(URL), {
116
- decode: (urlString) => new URL(urlString),
117
- encode: (url) => url.href,
118
- });
119
-
120
- const uriComponent = () =>
121
- z.codec(z.string(), z.string(), {
122
- decode: (encodedString) => decodeURIComponent(encodedString),
123
- encode: (decodedString) => encodeURIComponent(decodedString),
124
- });
125
-
126
- // ============================================================================
127
- // Boolean Codec
128
- // ============================================================================
129
-
130
- const stringToBoolean = (options?: { truthy?: string[]; falsy?: string[] }) => z.stringbool(options);
131
-
132
- // ============================================================================
133
- // Tests
134
- // ============================================================================
135
-
136
14
  test("stringToNumber codec", () => {
137
15
  const codec = stringToNumber();
138
16
 
@@ -152,6 +30,16 @@ test("stringToNumber codec", () => {
152
30
  expect(roundTrip).toBe("3.14159");
153
31
  });
154
32
 
33
+ // ============================================================================
34
+ // stringToInt
35
+ // ============================================================================
36
+
37
+ const stringToInt = () =>
38
+ z.codec(z.string(), z.int(), {
39
+ decode: (str) => Number.parseInt(str, 10),
40
+ encode: (num) => num.toString(),
41
+ });
42
+
155
43
  test("stringToInt codec", () => {
156
44
  const codec = stringToInt();
157
45
 
@@ -171,6 +59,16 @@ test("stringToInt codec", () => {
171
59
  expect(roundTrip).toBe("999");
172
60
  });
173
61
 
62
+ // ============================================================================
63
+ // stringToBigInt
64
+ // ============================================================================
65
+
66
+ const stringToBigInt = () =>
67
+ z.codec(z.string(), z.bigint(), {
68
+ decode: (str) => BigInt(str),
69
+ encode: (bigint) => bigint.toString(),
70
+ });
71
+
174
72
  test("stringToBigInt codec", () => {
175
73
  const codec = stringToBigInt();
176
74
 
@@ -190,6 +88,16 @@ test("stringToBigInt codec", () => {
190
88
  expect(roundTrip).toBe("987654321098765432109876543210");
191
89
  });
192
90
 
91
+ // ============================================================================
92
+ // numberToBigInt
93
+ // ============================================================================
94
+
95
+ const numberToBigInt = () =>
96
+ z.codec(z.int(), z.bigint(), {
97
+ decode: (num) => BigInt(num),
98
+ encode: (bigint) => Number(bigint),
99
+ });
100
+
193
101
  test("numberToBigInt codec", () => {
194
102
  const codec = numberToBigInt();
195
103
 
@@ -209,6 +117,16 @@ test("numberToBigInt codec", () => {
209
117
  expect(roundTrip).toBe(999);
210
118
  });
211
119
 
120
+ // ============================================================================
121
+ // isoDatetimeToDate
122
+ // ============================================================================
123
+
124
+ const isoDatetimeToDate = () =>
125
+ z.codec(z.iso.datetime(), z.date(), {
126
+ decode: (isoString) => new Date(isoString),
127
+ encode: (date) => date.toISOString(),
128
+ });
129
+
212
130
  test("isoDatetimeToDate codec", () => {
213
131
  const codec = isoDatetimeToDate();
214
132
 
@@ -227,6 +145,16 @@ test("isoDatetimeToDate codec", () => {
227
145
  expect(roundTrip).toBe("2024-12-25T15:45:30.123Z");
228
146
  });
229
147
 
148
+ // ============================================================================
149
+ // epochSecondsToDate
150
+ // ============================================================================
151
+
152
+ const epochSecondsToDate = () =>
153
+ z.codec(z.int().min(0), z.date(), {
154
+ decode: (seconds) => new Date(seconds * 1000),
155
+ encode: (date) => Math.floor(date.getTime() / 1000),
156
+ });
157
+
230
158
  test("epochSecondsToDate codec", () => {
231
159
  const codec = epochSecondsToDate();
232
160
 
@@ -245,6 +173,16 @@ test("epochSecondsToDate codec", () => {
245
173
  expect(roundTrip).toBe(1640995200);
246
174
  });
247
175
 
176
+ // ============================================================================
177
+ // epochMillisToDate
178
+ // ============================================================================
179
+
180
+ const epochMillisToDate = () =>
181
+ z.codec(z.int().min(0), z.date(), {
182
+ decode: (millis) => new Date(millis),
183
+ encode: (date) => date.getTime(),
184
+ });
185
+
248
186
  test("epochMillisToDate codec", () => {
249
187
  const codec = epochMillisToDate();
250
188
 
@@ -263,8 +201,30 @@ test("epochMillisToDate codec", () => {
263
201
  expect(roundTrip).toBe(1640995200123);
264
202
  });
265
203
 
204
+ // ============================================================================
205
+ // json
206
+ // ============================================================================
207
+
208
+ const jsonCodec = <T extends z.core.$ZodType>(schema: T) =>
209
+ z.codec(z.string(), schema, {
210
+ decode: (jsonString, ctx) => {
211
+ try {
212
+ return JSON.parse(jsonString);
213
+ } catch (err: any) {
214
+ ctx.issues.push({
215
+ code: "invalid_format",
216
+ format: "json",
217
+ input: jsonString,
218
+ message: err.message,
219
+ });
220
+ return z.NEVER;
221
+ }
222
+ },
223
+ encode: (value) => JSON.stringify(value),
224
+ });
225
+
266
226
  test("json codec", () => {
267
- const codec = json(z.object({ name: z.string(), age: z.number() }));
227
+ const codec = jsonCodec(z.object({ name: z.string(), age: z.number() }));
268
228
 
269
229
  // Test decode
270
230
  const decoded = z.decode(codec, '{"name":"Alice","age":30}');
@@ -281,6 +241,16 @@ test("json codec", () => {
281
241
  expect(JSON.parse(roundTrip)).toEqual(JSON.parse(original));
282
242
  });
283
243
 
244
+ // ============================================================================
245
+ // utf8ToBytes
246
+ // ============================================================================
247
+
248
+ const utf8ToBytes = () =>
249
+ z.codec(z.string(), z.instanceof(Uint8Array), {
250
+ decode: (str) => new TextEncoder().encode(str),
251
+ encode: (bytes) => new TextDecoder().decode(bytes),
252
+ });
253
+
284
254
  test("utf8ToBytes codec", () => {
285
255
  const codec = utf8ToBytes();
286
256
 
@@ -299,6 +269,16 @@ test("utf8ToBytes codec", () => {
299
269
  expect(roundTrip).toBe(original);
300
270
  });
301
271
 
272
+ // ============================================================================
273
+ // bytesToUtf8
274
+ // ============================================================================
275
+
276
+ const bytesToUtf8 = () =>
277
+ z.codec(z.instanceof(Uint8Array), z.string(), {
278
+ decode: (bytes) => new TextDecoder().decode(bytes),
279
+ encode: (str) => new TextEncoder().encode(str),
280
+ });
281
+
302
282
  test("bytesToUtf8 codec", () => {
303
283
  const codec = bytesToUtf8();
304
284
 
@@ -318,6 +298,16 @@ test("bytesToUtf8 codec", () => {
318
298
  expect(roundTrip).toEqual(original);
319
299
  });
320
300
 
301
+ // ============================================================================
302
+ // base64
303
+ // ============================================================================
304
+
305
+ const base64 = () =>
306
+ z.codec(z.base64(), z.instanceof(Uint8Array), {
307
+ decode: (base64String) => z.util.base64ToUint8Array(base64String),
308
+ encode: (bytes) => z.util.uint8ArrayToBase64(bytes),
309
+ });
310
+
321
311
  test("base64 codec", () => {
322
312
  const codec = base64();
323
313
 
@@ -336,6 +326,16 @@ test("base64 codec", () => {
336
326
  expect(roundTrip).toBe(original);
337
327
  });
338
328
 
329
+ // ============================================================================
330
+ // base64urlToBytes
331
+ // ============================================================================
332
+
333
+ const base64urlToBytes = () =>
334
+ z.codec(z.base64url(), z.instanceof(Uint8Array), {
335
+ decode: (base64urlString) => z.util.base64urlToUint8Array(base64urlString),
336
+ encode: (bytes) => z.util.uint8ArrayToBase64url(bytes),
337
+ });
338
+
339
339
  test("base64urlToBytes codec", () => {
340
340
  const codec = base64urlToBytes();
341
341
 
@@ -354,6 +354,16 @@ test("base64urlToBytes codec", () => {
354
354
  expect(roundTrip).toBe(original);
355
355
  });
356
356
 
357
+ // ============================================================================
358
+ // hexToBytes
359
+ // ============================================================================
360
+
361
+ const hexToBytes = () =>
362
+ z.codec(z.hex(), z.instanceof(Uint8Array), {
363
+ decode: (hexString) => z.util.hexToUint8Array(hexString),
364
+ encode: (bytes) => z.util.uint8ArrayToHex(bytes),
365
+ });
366
+
357
367
  test("hexToBytes codec", () => {
358
368
  const codec = hexToBytes();
359
369
 
@@ -376,6 +386,16 @@ test("hexToBytes codec", () => {
376
386
  expect(roundTrip).toBe("deadbeef");
377
387
  });
378
388
 
389
+ // ============================================================================
390
+ // stringToURL
391
+ // ============================================================================
392
+
393
+ const stringToURL = () =>
394
+ z.codec(z.url(), z.instanceof(URL), {
395
+ decode: (urlString) => new URL(urlString),
396
+ encode: (url) => url.href,
397
+ });
398
+
379
399
  test("stringToURL codec", () => {
380
400
  const codec = stringToURL();
381
401
 
@@ -396,6 +416,16 @@ test("stringToURL codec", () => {
396
416
  expect(roundTrip).toBe(original);
397
417
  });
398
418
 
419
+ // ============================================================================
420
+ // stringToHttpURL
421
+ // ============================================================================
422
+
423
+ const stringToHttpURL = () =>
424
+ z.codec(z.httpUrl(), z.instanceof(URL), {
425
+ decode: (urlString) => new URL(urlString),
426
+ encode: (url) => url.href,
427
+ });
428
+
399
429
  test("stringToHttpURL codec", () => {
400
430
  const codec = stringToHttpURL();
401
431
 
@@ -419,6 +449,16 @@ test("stringToHttpURL codec", () => {
419
449
  expect(roundTrip).toBe(original);
420
450
  });
421
451
 
452
+ // ============================================================================
453
+ // uriComponent
454
+ // ============================================================================
455
+
456
+ const uriComponent = () =>
457
+ z.codec(z.string(), z.string(), {
458
+ decode: (encodedString) => decodeURIComponent(encodedString),
459
+ encode: (decodedString) => encodeURIComponent(decodedString),
460
+ });
461
+
422
462
  test("uriComponent codec", () => {
423
463
  const codec = uriComponent();
424
464
 
@@ -442,6 +482,12 @@ test("uriComponent codec", () => {
442
482
  expect(decodedComplex).toBe(complex);
443
483
  });
444
484
 
485
+ // ============================================================================
486
+ // stringToBoolean
487
+ // ============================================================================
488
+
489
+ const stringToBoolean = (options?: { truthy?: string[]; falsy?: string[] }) => z.stringbool(options);
490
+
445
491
  test("stringToBoolean codec", () => {
446
492
  const codec = stringToBoolean();
447
493
 
@@ -469,6 +515,10 @@ test("stringToBoolean codec", () => {
469
515
  expect(z.encode(customCodec, false)).toBe("no");
470
516
  });
471
517
 
518
+ // ============================================================================
519
+ // Error Handling Tests
520
+ // ============================================================================
521
+
472
522
  // Test error cases - these test input validation, not transform errors
473
523
  test("codec input validation", () => {
474
524
  // Test invalid base64 format
@@ -495,25 +545,10 @@ test("codec input validation", () => {
495
545
  // Test transform errors - these test errors added by transform functions
496
546
  test("codec transform error handling", () => {
497
547
  // JSON codec that can fail during transform
498
- const jsonCodec = z.codec(z.string(), z.json(), {
499
- decode: (jsonString, ctx) => {
500
- try {
501
- return JSON.parse(jsonString);
502
- } catch (err: any) {
503
- ctx.issues.push({
504
- code: "invalid_format",
505
- format: "json",
506
- input: jsonString,
507
- message: err.message,
508
- });
509
- return z.NEVER;
510
- }
511
- },
512
- encode: (value) => JSON.stringify(value),
513
- });
548
+ const anyJSON = jsonCodec(z.json());
514
549
 
515
550
  // Test successful JSON parsing
516
- const validResult = z.safeDecode(jsonCodec, '{"valid": "json"}');
551
+ const validResult = z.safeDecode(anyJSON, '{"valid": "json"}');
517
552
  expect(validResult.success).toBe(true);
518
553
  if (validResult.success) {
519
554
  expect(validResult.data).toEqual({ valid: "json" });
@@ -521,7 +556,7 @@ test("codec transform error handling", () => {
521
556
 
522
557
  // Test invalid JSON that should create a single "invalid_format" issue
523
558
  // Verifies that the transform error aborts before reaching the output schema
524
- const invalidResult = z.safeDecode(jsonCodec, '{"invalid":,}');
559
+ const invalidResult = z.safeDecode(anyJSON, '{"invalid":,}');
525
560
  expect(invalidResult.success).toBe(false);
526
561
  if (!invalidResult.success) {
527
562
  expect(invalidResult.error.issues).toMatchInlineSnapshot(`
@@ -653,6 +653,24 @@ describe("toJSONSchema", () => {
653
653
  });
654
654
 
655
655
  test("tuple", () => {
656
+ const schema = z.tuple([z.string(), z.number()]);
657
+ expect(z.toJSONSchema(schema)).toMatchInlineSnapshot(`
658
+ {
659
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
660
+ "prefixItems": [
661
+ {
662
+ "type": "string",
663
+ },
664
+ {
665
+ "type": "number",
666
+ },
667
+ ],
668
+ "type": "array",
669
+ }
670
+ `);
671
+ });
672
+
673
+ test("tuple with rest", () => {
656
674
  const schema = z.tuple([z.string(), z.number()]).rest(z.boolean());
657
675
  expect(z.toJSONSchema(schema)).toMatchInlineSnapshot(`
658
676
  {
@@ -673,6 +691,46 @@ describe("toJSONSchema", () => {
673
691
  `);
674
692
  });
675
693
 
694
+ test("tuple openapi", () => {
695
+ const schema = z.tuple([z.string(), z.number()]);
696
+ expect(z.toJSONSchema(schema, { target: "openapi-3.0" })).toMatchInlineSnapshot(`
697
+ {
698
+ "items": [
699
+ {
700
+ "type": "string",
701
+ },
702
+ {
703
+ "type": "number",
704
+ },
705
+ ],
706
+ "maxItems": 2,
707
+ "minItems": 2,
708
+ "type": "array",
709
+ }
710
+ `);
711
+ });
712
+
713
+ test("tuple with rest openapi", () => {
714
+ const schema = z.tuple([z.string(), z.number()]).rest(z.boolean());
715
+ expect(z.toJSONSchema(schema, { target: "openapi-3.0" })).toMatchInlineSnapshot(`
716
+ {
717
+ "items": [
718
+ {
719
+ "type": "string",
720
+ },
721
+ {
722
+ "type": "number",
723
+ },
724
+ {
725
+ "type": "boolean",
726
+ },
727
+ ],
728
+ "minItems": 2,
729
+ "type": "array",
730
+ }
731
+ `);
732
+ });
733
+
676
734
  test("promise", () => {
677
735
  const schema = z.promise(z.string());
678
736
  expect(z.toJSONSchema(schema)).toMatchInlineSnapshot(`
@@ -371,32 +371,34 @@ export class JSONSchemaGenerator {
371
371
  const prefixItems = def.items.map((x, i) =>
372
372
  this.process(x, { ...params, path: [...params.path, "prefixItems", i] })
373
373
  );
374
+ const rest = def.rest
375
+ ? this.process(def.rest, {
376
+ ...params,
377
+ path: [...params.path, "items"],
378
+ })
379
+ : null;
380
+
374
381
  if (this.target === "draft-2020-12") {
375
382
  json.prefixItems = prefixItems;
383
+ if (rest) {
384
+ json.items = rest;
385
+ }
386
+ } else if (this.target === "openapi-3.0") {
387
+ json.items = [...prefixItems];
388
+ if (rest) {
389
+ json.items.push(rest);
390
+ }
391
+ json.minItems = prefixItems.length;
392
+ if (!rest) {
393
+ json.maxItems = prefixItems.length;
394
+ }
376
395
  } else {
377
396
  json.items = prefixItems;
378
- }
379
-
380
- if (def.rest) {
381
- const rest = this.process(def.rest, {
382
- ...params,
383
- path: [...params.path, "items"],
384
- });
385
- if (this.target === "draft-2020-12") {
386
- json.items = rest;
387
- } else {
397
+ if (rest) {
388
398
  json.additionalItems = rest;
389
399
  }
390
400
  }
391
401
 
392
- // additionalItems
393
- if (def.rest) {
394
- json.items = this.process(def.rest, {
395
- ...params,
396
- path: [...params.path, "items"],
397
- });
398
- }
399
-
400
402
  // length
401
403
  const { minimum, maximum } = schema._zod.bag as {
402
404
  minimum?: number;
@@ -1,5 +1,5 @@
1
1
  export const version = {
2
2
  major: 4,
3
3
  minor: 1,
4
- patch: 1 as number,
4
+ patch: 2 as number,
5
5
  } as const;
@@ -19,6 +19,7 @@ export {
19
19
  flattenError,
20
20
  toJSONSchema,
21
21
  TimePrecision,
22
+ util,
22
23
  NEVER,
23
24
  } from "../core/index.js";
24
25
 
@@ -29,7 +29,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
29
29
  return (mod && mod.__esModule) ? mod : { "default": mod };
30
30
  };
31
31
  Object.defineProperty(exports, "__esModule", { value: true });
32
- exports.coerce = exports.iso = exports.ZodISODuration = exports.ZodISOTime = exports.ZodISODate = exports.ZodISODateTime = exports.locales = exports.NEVER = exports.TimePrecision = exports.toJSONSchema = exports.flattenError = exports.formatError = exports.prettifyError = exports.treeifyError = exports.regexes = exports.clone = exports.$brand = exports.$input = exports.$output = exports.config = exports.registry = exports.globalRegistry = exports.core = void 0;
32
+ exports.coerce = exports.iso = exports.ZodISODuration = exports.ZodISOTime = exports.ZodISODate = exports.ZodISODateTime = exports.locales = exports.NEVER = exports.util = exports.TimePrecision = exports.toJSONSchema = exports.flattenError = exports.formatError = exports.prettifyError = exports.treeifyError = exports.regexes = exports.clone = exports.$brand = exports.$input = exports.$output = exports.config = exports.registry = exports.globalRegistry = exports.core = void 0;
33
33
  exports.core = __importStar(require("../core/index.cjs"));
34
34
  __exportStar(require("./schemas.cjs"), exports);
35
35
  __exportStar(require("./checks.cjs"), exports);
@@ -55,6 +55,7 @@ Object.defineProperty(exports, "formatError", { enumerable: true, get: function
55
55
  Object.defineProperty(exports, "flattenError", { enumerable: true, get: function () { return index_js_2.flattenError; } });
56
56
  Object.defineProperty(exports, "toJSONSchema", { enumerable: true, get: function () { return index_js_2.toJSONSchema; } });
57
57
  Object.defineProperty(exports, "TimePrecision", { enumerable: true, get: function () { return index_js_2.TimePrecision; } });
58
+ Object.defineProperty(exports, "util", { enumerable: true, get: function () { return index_js_2.util; } });
58
59
  Object.defineProperty(exports, "NEVER", { enumerable: true, get: function () { return index_js_2.NEVER; } });
59
60
  exports.locales = __importStar(require("../locales/index.cjs"));
60
61
  // iso
@@ -5,7 +5,7 @@ export * from "./errors.cjs";
5
5
  export * from "./parse.cjs";
6
6
  export * from "./compat.cjs";
7
7
  export type { infer, output, input } from "../core/index.cjs";
8
- export { globalRegistry, type GlobalMeta, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, toJSONSchema, TimePrecision, NEVER, } from "../core/index.cjs";
8
+ export { globalRegistry, type GlobalMeta, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, toJSONSchema, TimePrecision, util, NEVER, } from "../core/index.cjs";
9
9
  export * as locales from "../locales/index.cjs";
10
10
  export { ZodISODateTime, ZodISODate, ZodISOTime, ZodISODuration } from "./iso.cjs";
11
11
  export * as iso from "./iso.cjs";
@@ -5,7 +5,7 @@ export * from "./errors.js";
5
5
  export * from "./parse.js";
6
6
  export * from "./compat.js";
7
7
  export type { infer, output, input } from "../core/index.js";
8
- export { globalRegistry, type GlobalMeta, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, toJSONSchema, TimePrecision, NEVER, } from "../core/index.js";
8
+ export { globalRegistry, type GlobalMeta, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, toJSONSchema, TimePrecision, util, NEVER, } from "../core/index.js";
9
9
  export * as locales from "../locales/index.js";
10
10
  export { ZodISODateTime, ZodISODate, ZodISOTime, ZodISODuration } from "./iso.js";
11
11
  export * as iso from "./iso.js";
@@ -8,7 +8,7 @@ export * from "./compat.js";
8
8
  import { config } from "../core/index.js";
9
9
  import en from "../locales/en.js";
10
10
  config(en());
11
- export { globalRegistry, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, toJSONSchema, TimePrecision, NEVER, } from "../core/index.js";
11
+ export { globalRegistry, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, toJSONSchema, TimePrecision, util, NEVER, } from "../core/index.js";
12
12
  export * as locales from "../locales/index.js";
13
13
  // iso
14
14
  // must be exported from top-level
@@ -289,31 +289,34 @@ class JSONSchemaGenerator {
289
289
  const json = _json;
290
290
  json.type = "array";
291
291
  const prefixItems = def.items.map((x, i) => this.process(x, { ...params, path: [...params.path, "prefixItems", i] }));
292
+ const rest = def.rest
293
+ ? this.process(def.rest, {
294
+ ...params,
295
+ path: [...params.path, "items"],
296
+ })
297
+ : null;
292
298
  if (this.target === "draft-2020-12") {
293
299
  json.prefixItems = prefixItems;
300
+ if (rest) {
301
+ json.items = rest;
302
+ }
303
+ }
304
+ else if (this.target === "openapi-3.0") {
305
+ json.items = [...prefixItems];
306
+ if (rest) {
307
+ json.items.push(rest);
308
+ }
309
+ json.minItems = prefixItems.length;
310
+ if (!rest) {
311
+ json.maxItems = prefixItems.length;
312
+ }
294
313
  }
295
314
  else {
296
315
  json.items = prefixItems;
297
- }
298
- if (def.rest) {
299
- const rest = this.process(def.rest, {
300
- ...params,
301
- path: [...params.path, "items"],
302
- });
303
- if (this.target === "draft-2020-12") {
304
- json.items = rest;
305
- }
306
- else {
316
+ if (rest) {
307
317
  json.additionalItems = rest;
308
318
  }
309
319
  }
310
- // additionalItems
311
- if (def.rest) {
312
- json.items = this.process(def.rest, {
313
- ...params,
314
- path: [...params.path, "items"],
315
- });
316
- }
317
320
  // length
318
321
  const { minimum, maximum } = schema._zod.bag;
319
322
  if (typeof minimum === "number")
@@ -285,31 +285,34 @@ export class JSONSchemaGenerator {
285
285
  const json = _json;
286
286
  json.type = "array";
287
287
  const prefixItems = def.items.map((x, i) => this.process(x, { ...params, path: [...params.path, "prefixItems", i] }));
288
+ const rest = def.rest
289
+ ? this.process(def.rest, {
290
+ ...params,
291
+ path: [...params.path, "items"],
292
+ })
293
+ : null;
288
294
  if (this.target === "draft-2020-12") {
289
295
  json.prefixItems = prefixItems;
296
+ if (rest) {
297
+ json.items = rest;
298
+ }
299
+ }
300
+ else if (this.target === "openapi-3.0") {
301
+ json.items = [...prefixItems];
302
+ if (rest) {
303
+ json.items.push(rest);
304
+ }
305
+ json.minItems = prefixItems.length;
306
+ if (!rest) {
307
+ json.maxItems = prefixItems.length;
308
+ }
290
309
  }
291
310
  else {
292
311
  json.items = prefixItems;
293
- }
294
- if (def.rest) {
295
- const rest = this.process(def.rest, {
296
- ...params,
297
- path: [...params.path, "items"],
298
- });
299
- if (this.target === "draft-2020-12") {
300
- json.items = rest;
301
- }
302
- else {
312
+ if (rest) {
303
313
  json.additionalItems = rest;
304
314
  }
305
315
  }
306
- // additionalItems
307
- if (def.rest) {
308
- json.items = this.process(def.rest, {
309
- ...params,
310
- path: [...params.path, "items"],
311
- });
312
- }
313
316
  // length
314
317
  const { minimum, maximum } = schema._zod.bag;
315
318
  if (typeof minimum === "number")
@@ -4,5 +4,5 @@ exports.version = void 0;
4
4
  exports.version = {
5
5
  major: 4,
6
6
  minor: 1,
7
- patch: 1,
7
+ patch: 2,
8
8
  };
@@ -1,5 +1,5 @@
1
1
  export const version = {
2
2
  major: 4,
3
3
  minor: 1,
4
- patch: 1,
4
+ patch: 2,
5
5
  };
@@ -26,7 +26,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
26
26
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.coerce = exports.ZodMiniISODuration = exports.ZodMiniISOTime = exports.ZodMiniISODate = exports.ZodMiniISODateTime = exports.iso = exports.locales = exports.NEVER = exports.TimePrecision = exports.toJSONSchema = exports.flattenError = exports.formatError = exports.prettifyError = exports.treeifyError = exports.regexes = exports.clone = exports.$brand = exports.$input = exports.$output = exports.config = exports.registry = exports.globalRegistry = exports.core = void 0;
29
+ exports.coerce = exports.ZodMiniISODuration = exports.ZodMiniISOTime = exports.ZodMiniISODate = exports.ZodMiniISODateTime = exports.iso = exports.locales = exports.NEVER = exports.util = exports.TimePrecision = exports.toJSONSchema = exports.flattenError = exports.formatError = exports.prettifyError = exports.treeifyError = exports.regexes = exports.clone = exports.$brand = exports.$input = exports.$output = exports.config = exports.registry = exports.globalRegistry = exports.core = void 0;
30
30
  exports.core = __importStar(require("../core/index.cjs"));
31
31
  __exportStar(require("./parse.cjs"), exports);
32
32
  __exportStar(require("./schemas.cjs"), exports);
@@ -46,6 +46,7 @@ Object.defineProperty(exports, "formatError", { enumerable: true, get: function
46
46
  Object.defineProperty(exports, "flattenError", { enumerable: true, get: function () { return index_js_1.flattenError; } });
47
47
  Object.defineProperty(exports, "toJSONSchema", { enumerable: true, get: function () { return index_js_1.toJSONSchema; } });
48
48
  Object.defineProperty(exports, "TimePrecision", { enumerable: true, get: function () { return index_js_1.TimePrecision; } });
49
+ Object.defineProperty(exports, "util", { enumerable: true, get: function () { return index_js_1.util; } });
49
50
  Object.defineProperty(exports, "NEVER", { enumerable: true, get: function () { return index_js_1.NEVER; } });
50
51
  exports.locales = __importStar(require("../locales/index.cjs"));
51
52
  /** A special constant with type `never` */
@@ -3,7 +3,7 @@ export * from "./parse.cjs";
3
3
  export * from "./schemas.cjs";
4
4
  export * from "./checks.cjs";
5
5
  export type { infer, output, input } from "../core/index.cjs";
6
- export { globalRegistry, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, toJSONSchema, TimePrecision, NEVER, } from "../core/index.cjs";
6
+ export { globalRegistry, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, toJSONSchema, TimePrecision, util, NEVER, } from "../core/index.cjs";
7
7
  export * as locales from "../locales/index.cjs";
8
8
  /** A special constant with type `never` */
9
9
  export * as iso from "./iso.cjs";
@@ -3,7 +3,7 @@ export * from "./parse.js";
3
3
  export * from "./schemas.js";
4
4
  export * from "./checks.js";
5
5
  export type { infer, output, input } from "../core/index.js";
6
- export { globalRegistry, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, toJSONSchema, TimePrecision, NEVER, } from "../core/index.js";
6
+ export { globalRegistry, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, toJSONSchema, TimePrecision, util, NEVER, } from "../core/index.js";
7
7
  export * as locales from "../locales/index.js";
8
8
  /** A special constant with type `never` */
9
9
  export * as iso from "./iso.js";
@@ -2,7 +2,7 @@ export * as core from "../core/index.js";
2
2
  export * from "./parse.js";
3
3
  export * from "./schemas.js";
4
4
  export * from "./checks.js";
5
- export { globalRegistry, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, toJSONSchema, TimePrecision, NEVER, } from "../core/index.js";
5
+ export { globalRegistry, registry, config, $output, $input, $brand, clone, regexes, treeifyError, prettifyError, formatError, flattenError, toJSONSchema, TimePrecision, util, NEVER, } from "../core/index.js";
6
6
  export * as locales from "../locales/index.js";
7
7
  /** A special constant with type `never` */
8
8
  // export const NEVER = {} as never;