zod 4.0.13 → 4.0.15

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.0.13",
3
+ "version": "4.0.15",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": "Colin McDonnell <zod@colinhacks.com>",
@@ -1149,7 +1149,7 @@ export function object<T extends core.$ZodLooseShape = Partial<Record<never, cor
1149
1149
  const def: core.$ZodObjectDef = {
1150
1150
  type: "object",
1151
1151
  get shape() {
1152
- util.assignProp(this, "shape", { ...shape });
1152
+ util.assignProp(this, "shape", shape ? util.objectClone(shape) : {});
1153
1153
  return this.shape;
1154
1154
  },
1155
1155
  ...util.normalizeParams(params),
@@ -1166,7 +1166,7 @@ export function strictObject<T extends core.$ZodLooseShape>(
1166
1166
  return new ZodObject({
1167
1167
  type: "object",
1168
1168
  get shape() {
1169
- util.assignProp(this, "shape", { ...shape });
1169
+ util.assignProp(this, "shape", util.objectClone(shape));
1170
1170
  return this.shape;
1171
1171
  },
1172
1172
  catchall: never(),
@@ -1183,7 +1183,7 @@ export function looseObject<T extends core.$ZodLooseShape>(
1183
1183
  return new ZodObject({
1184
1184
  type: "object",
1185
1185
  get shape() {
1186
- util.assignProp(this, "shape", { ...shape });
1186
+ util.assignProp(this, "shape", util.objectClone(shape));
1187
1187
  return this.shape;
1188
1188
  },
1189
1189
  catchall: unknown(),
@@ -366,6 +366,21 @@ test("object utilities with recursive types", () => {
366
366
  ]);
367
367
  });
368
368
 
369
+ test("tuple with recursive types", () => {
370
+ const TaskListNodeSchema = z.strictObject({
371
+ type: z.literal("taskList"),
372
+ get content() {
373
+ return z.array(z.tuple([TaskListNodeSchema, z.union([TaskListNodeSchema])])).min(1);
374
+ },
375
+ });
376
+ type TaskListNodeSchema = z.infer<typeof TaskListNodeSchema>;
377
+ type _TaskListNodeSchema = {
378
+ type: "taskList";
379
+ content: [_TaskListNodeSchema, _TaskListNodeSchema][];
380
+ };
381
+ expectTypeOf<TaskListNodeSchema>().toEqualTypeOf<_TaskListNodeSchema>();
382
+ });
383
+
369
384
  test("recursion compatibility", () => {
370
385
  // array
371
386
  const A = z.object({
@@ -431,6 +446,68 @@ test("recursion compatibility", () => {
431
446
  });
432
447
  });
433
448
 
449
+ test("recursive object with .check()", () => {
450
+ const Category = z
451
+ .object({
452
+ id: z.string(),
453
+ name: z.string(),
454
+ get subcategories() {
455
+ return z.array(Category).optional();
456
+ },
457
+ })
458
+ .check((ctx) => {
459
+ // Check for duplicate IDs among direct subcategories
460
+ if (ctx.value.subcategories) {
461
+ const siblingIds = new Set<string>();
462
+ ctx.value.subcategories.forEach((sub, index) => {
463
+ if (siblingIds.has(sub.id)) {
464
+ ctx.issues.push({
465
+ code: "custom",
466
+ message: `Duplicate sibling ID found: ${sub.id}`,
467
+ path: ["subcategories", index, "id"],
468
+ input: ctx.value,
469
+ });
470
+ }
471
+ siblingIds.add(sub.id);
472
+ });
473
+ }
474
+ });
475
+
476
+ // Valid - siblings have unique IDs
477
+ const validData = {
478
+ id: "electronics",
479
+ name: "Electronics",
480
+ subcategories: [
481
+ {
482
+ id: "computers",
483
+ name: "Computers",
484
+ subcategories: [
485
+ { id: "laptops", name: "Laptops" },
486
+ { id: "desktops", name: "Desktops" },
487
+ ],
488
+ },
489
+ {
490
+ id: "phones",
491
+ name: "Phones",
492
+ },
493
+ ],
494
+ };
495
+
496
+ // Invalid - duplicate sibling IDs
497
+ const invalidData = {
498
+ id: "electronics",
499
+ name: "Electronics",
500
+ subcategories: [
501
+ { id: "computers", name: "Computers" },
502
+ { id: "phones", name: "Phones" },
503
+ { id: "computers", name: "Computers Again" }, // Duplicate at index 2
504
+ ],
505
+ };
506
+
507
+ expect(() => Category.parse(validData)).not.toThrow();
508
+ expect(() => Category.parse(invalidData)).toThrow();
509
+ });
510
+
434
511
  // biome-ignore lint: sadf
435
512
  export type RecursiveA = z.ZodUnion<
436
513
  [
@@ -539,6 +539,19 @@ describe("toJSONSchema", () => {
539
539
  `);
540
540
  });
541
541
 
542
+ test("number constraints draft-4", () => {
543
+ expect(z.toJSONSchema(z.number().gt(5).lt(10), { target: "draft-4" })).toMatchInlineSnapshot(`
544
+ {
545
+ "$schema": "http://json-schema.org/draft-04/schema#",
546
+ "exclusiveMaximum": true,
547
+ "exclusiveMinimum": true,
548
+ "maximum": 10,
549
+ "minimum": 5,
550
+ "type": "number",
551
+ }
552
+ `);
553
+ });
554
+
542
555
  test("arrays", () => {
543
556
  expect(z.toJSONSchema(z.array(z.string()))).toMatchInlineSnapshot(`
544
557
  {
@@ -745,6 +758,19 @@ describe("toJSONSchema", () => {
745
758
  `);
746
759
  });
747
760
 
761
+ test("literal draft-4", () => {
762
+ const a = z.literal("hello");
763
+ expect(z.toJSONSchema(a, { target: "draft-4" })).toMatchInlineSnapshot(`
764
+ {
765
+ "$schema": "http://json-schema.org/draft-04/schema#",
766
+ "enum": [
767
+ "hello",
768
+ ],
769
+ "type": "string",
770
+ }
771
+ `);
772
+ });
773
+
748
774
  // pipe
749
775
  test("pipe", () => {
750
776
  const schema = z
@@ -314,8 +314,8 @@ export function _ksuid<T extends schemas.$ZodKSUID>(
314
314
  }
315
315
 
316
316
  // IPv4
317
- export type $ZodIPv4Params = StringFormatParams<schemas.$ZodIPv4, "pattern" | "when">;
318
- export type $ZodCheckIPv4Params = CheckStringFormatParams<schemas.$ZodIPv4, "pattern" | "when">;
317
+ export type $ZodIPv4Params = StringFormatParams<schemas.$ZodIPv4, "pattern" | "when" | "version">;
318
+ export type $ZodCheckIPv4Params = CheckStringFormatParams<schemas.$ZodIPv4, "pattern" | "when" | "version">;
319
319
  export function _ipv4<T extends schemas.$ZodIPv4>(
320
320
  Class: util.SchemaClass<T>,
321
321
  params?: string | $ZodIPv4Params | $ZodCheckIPv4Params
@@ -330,8 +330,8 @@ export function _ipv4<T extends schemas.$ZodIPv4>(
330
330
  }
331
331
 
332
332
  // IPv6
333
- export type $ZodIPv6Params = StringFormatParams<schemas.$ZodIPv6, "pattern" | "when">;
334
- export type $ZodCheckIPv6Params = CheckStringFormatParams<schemas.$ZodIPv6, "pattern" | "when">;
333
+ export type $ZodIPv6Params = StringFormatParams<schemas.$ZodIPv6, "pattern" | "when" | "version">;
334
+ export type $ZodCheckIPv6Params = CheckStringFormatParams<schemas.$ZodIPv6, "pattern" | "when" | "version">;
335
335
  export function _ipv6<T extends schemas.$ZodIPv6>(
336
336
  Class: util.SchemaClass<T>,
337
337
  params?: string | $ZodIPv6Params | $ZodCheckIPv6Params
@@ -84,8 +84,8 @@ export class $ZodAsyncError extends Error {
84
84
  // export type output<T extends schemas.$ZodType> = T["_zod"]["output"];
85
85
  // export type input<T extends schemas.$ZodType> = T["_zod"]["input"];
86
86
  // export type output<T extends schemas.$ZodType> = T["_zod"]["output"];
87
- export type input<T> = T extends { _zod: { input: any } } ? Required<T["_zod"]>["input"] : unknown;
88
- export type output<T> = T extends { _zod: { output: any } } ? Required<T["_zod"]>["output"] : unknown;
87
+ export type input<T> = T extends { _zod: { input: any } } ? T["_zod"]["input"] : unknown;
88
+ export type output<T> = T extends { _zod: { output: any } } ? T["_zod"]["output"] : unknown;
89
89
 
90
90
  // Mk2
91
91
  // export type input<T> = T extends { _zod: { "~input": any } }
@@ -45,7 +45,10 @@ export type Schema =
45
45
  export type _JSONSchema = boolean | JSONSchema;
46
46
  export type JSONSchema = {
47
47
  [k: string]: unknown;
48
- $schema?: "https://json-schema.org/draft/2020-12/schema" | "http://json-schema.org/draft-07/schema#";
48
+ $schema?:
49
+ | "https://json-schema.org/draft/2020-12/schema"
50
+ | "http://json-schema.org/draft-07/schema#"
51
+ | "http://json-schema.org/draft-04/schema#";
49
52
  $id?: string;
50
53
  $anchor?: string;
51
54
  $ref?: string;
@@ -75,9 +78,9 @@ export type JSONSchema = {
75
78
  not?: _JSONSchema;
76
79
  multipleOf?: number;
77
80
  maximum?: number;
78
- exclusiveMaximum?: number;
81
+ exclusiveMaximum?: number | boolean;
79
82
  minimum?: number;
80
- exclusiveMinimum?: number;
83
+ exclusiveMinimum?: number | boolean;
81
84
  maxLength?: number;
82
85
  minLength?: number;
83
86
  pattern?: string;
@@ -1701,6 +1701,8 @@ export interface $ZodObjectInternals<
1701
1701
  propValues: util.PropValues;
1702
1702
  output: $InferObjectOutput<Shape, Config["out"]>;
1703
1703
  input: $InferObjectInput<Shape, Config["in"]>;
1704
+ optin?: "optional" | undefined;
1705
+ optout?: "optional" | undefined;
1704
1706
  }
1705
1707
  export type $ZodLooseShape = Record<string, any>;
1706
1708
 
@@ -2282,9 +2284,12 @@ type TupleOutputTypeWithOptionals<T extends util.TupleItems> = T extends readonl
2282
2284
  export interface $ZodTupleInternals<
2283
2285
  T extends util.TupleItems = readonly $ZodType[],
2284
2286
  Rest extends SomeType | null = $ZodType | null,
2285
- > extends $ZodTypeInternals<$InferTupleOutputType<T, Rest>, $InferTupleInputType<T, Rest>> {
2287
+ > extends _$ZodTypeInternals {
2286
2288
  def: $ZodTupleDef<T, Rest>;
2287
2289
  isst: errors.$ZodIssueInvalidType | errors.$ZodIssueTooBig<unknown[]> | errors.$ZodIssueTooSmall<unknown[]>;
2290
+ // $ZodTypeInternals<$InferTupleOutputType<T, Rest>, $InferTupleInputType<T, Rest>>
2291
+ output: $InferTupleOutputType<T, Rest>;
2292
+ input: $InferTupleInputType<T, Rest>;
2288
2293
  }
2289
2294
 
2290
2295
  export interface $ZodTuple<
@@ -3746,11 +3751,18 @@ export interface $ZodLazy<T extends SomeType = $ZodType> extends $ZodType {
3746
3751
  export const $ZodLazy: core.$constructor<$ZodLazy> = /*@__PURE__*/ core.$constructor("$ZodLazy", (inst, def) => {
3747
3752
  $ZodType.init(inst, def);
3748
3753
 
3754
+ // let _innerType!: any;
3755
+ // util.defineLazy(def, "getter", () => {
3756
+ // if (!_innerType) {
3757
+ // _innerType = def.getter();
3758
+ // }
3759
+ // return () => _innerType;
3760
+ // });
3749
3761
  util.defineLazy(inst._zod, "innerType", () => def.getter() as $ZodType);
3750
3762
  util.defineLazy(inst._zod, "pattern", () => inst._zod.innerType._zod.pattern);
3751
3763
  util.defineLazy(inst._zod, "propValues", () => inst._zod.innerType._zod.propValues);
3752
- util.defineLazy(inst._zod, "optin", () => inst._zod.innerType._zod.optin);
3753
- util.defineLazy(inst._zod, "optout", () => inst._zod.innerType._zod.optout);
3764
+ util.defineLazy(inst._zod, "optin", () => inst._zod.innerType._zod.optin ?? undefined);
3765
+ util.defineLazy(inst._zod, "optout", () => inst._zod.innerType._zod.optout ?? undefined);
3754
3766
  inst._zod.parse = (payload, ctx) => {
3755
3767
  const inner = inst._zod.innerType;
3756
3768
  return inner._zod.run(payload, ctx);
@@ -10,8 +10,9 @@ interface JSONSchemaGeneratorParams {
10
10
  metadata?: $ZodRegistry<Record<string, any>>;
11
11
  /** The JSON Schema version to target.
12
12
  * - `"draft-2020-12"` — Default. JSON Schema Draft 2020-12
13
- * - `"draft-7"` — JSON Schema Draft 7 */
14
- target?: "draft-7" | "draft-2020-12";
13
+ * - `"draft-7"` — JSON Schema Draft 7
14
+ * - `"draft-4"` JSON Schema Draft 4 */
15
+ target?: "draft-4" | "draft-7" | "draft-2020-12";
15
16
  /** How to handle unrepresentable types.
16
17
  * - `"throw"` — Default. Unrepresentable types throw an error
17
18
  * - `"any"` — Unrepresentable types become `{}` */
@@ -71,7 +72,7 @@ interface Seen {
71
72
 
72
73
  export class JSONSchemaGenerator {
73
74
  metadataRegistry: $ZodRegistry<Record<string, any>>;
74
- target: "draft-7" | "draft-2020-12";
75
+ target: "draft-4" | "draft-7" | "draft-2020-12";
75
76
  unrepresentable: "throw" | "any";
76
77
  override: (ctx: {
77
78
  zodSchema: schemas.$ZodTypes;
@@ -163,7 +164,7 @@ export class JSONSchemaGenerator {
163
164
  else if (regexes.length > 1) {
164
165
  result.schema.allOf = [
165
166
  ...regexes.map((regex) => ({
166
- ...(this.target === "draft-7" ? ({ type: "string" } as const) : {}),
167
+ ...(this.target === "draft-7" || this.target === "draft-4" ? ({ type: "string" } as const) : {}),
167
168
  pattern: regex.source,
168
169
  })),
169
170
  ];
@@ -178,19 +179,33 @@ export class JSONSchemaGenerator {
178
179
  if (typeof format === "string" && format.includes("int")) json.type = "integer";
179
180
  else json.type = "number";
180
181
 
181
- if (typeof exclusiveMinimum === "number") json.exclusiveMinimum = exclusiveMinimum;
182
+ if (typeof exclusiveMinimum === "number") {
183
+ if (this.target === "draft-4") {
184
+ json.minimum = exclusiveMinimum;
185
+ json.exclusiveMinimum = true;
186
+ } else {
187
+ json.exclusiveMinimum = exclusiveMinimum;
188
+ }
189
+ }
182
190
  if (typeof minimum === "number") {
183
191
  json.minimum = minimum;
184
- if (typeof exclusiveMinimum === "number") {
192
+ if (typeof exclusiveMinimum === "number" && this.target !== "draft-4") {
185
193
  if (exclusiveMinimum >= minimum) delete json.minimum;
186
194
  else delete json.exclusiveMinimum;
187
195
  }
188
196
  }
189
197
 
190
- if (typeof exclusiveMaximum === "number") json.exclusiveMaximum = exclusiveMaximum;
198
+ if (typeof exclusiveMaximum === "number") {
199
+ if (this.target === "draft-4") {
200
+ json.maximum = exclusiveMaximum;
201
+ json.exclusiveMaximum = true;
202
+ } else {
203
+ json.exclusiveMaximum = exclusiveMaximum;
204
+ }
205
+ }
191
206
  if (typeof maximum === "number") {
192
207
  json.maximum = maximum;
193
- if (typeof exclusiveMaximum === "number") {
208
+ if (typeof exclusiveMaximum === "number" && this.target !== "draft-4") {
194
209
  if (exclusiveMaximum <= maximum) delete json.maximum;
195
210
  else delete json.exclusiveMaximum;
196
211
  }
@@ -379,7 +394,12 @@ export class JSONSchemaGenerator {
379
394
  case "record": {
380
395
  const json: JSONSchema.ObjectSchema = _json as any;
381
396
  json.type = "object";
382
- json.propertyNames = this.process(def.keyType, { ...params, path: [...params.path, "propertyNames"] });
397
+ if (this.target !== "draft-4") {
398
+ json.propertyNames = this.process(def.keyType, {
399
+ ...params,
400
+ path: [...params.path, "propertyNames"],
401
+ });
402
+ }
383
403
  json.additionalProperties = this.process(def.valueType, {
384
404
  ...params,
385
405
  path: [...params.path, "additionalProperties"],
@@ -432,7 +452,11 @@ export class JSONSchemaGenerator {
432
452
  } else if (vals.length === 1) {
433
453
  const val = vals[0]!;
434
454
  json.type = val === null ? ("null" as const) : (typeof val as any);
435
- json.const = val;
455
+ if (this.target === "draft-4") {
456
+ json.enum = [val];
457
+ } else {
458
+ json.const = val;
459
+ }
436
460
  } else {
437
461
  if (vals.every((v) => typeof v === "number")) json.type = "number";
438
462
  if (vals.every((v) => typeof v === "string")) json.type = "string";
@@ -749,7 +773,7 @@ export class JSONSchemaGenerator {
749
773
 
750
774
  // merge referenced schema into current
751
775
  const refSchema = this.seen.get(ref)!.schema;
752
- if (refSchema.$ref && params.target === "draft-7") {
776
+ if (refSchema.$ref && (params.target === "draft-7" || params.target === "draft-4")) {
753
777
  schema.allOf = schema.allOf ?? [];
754
778
  schema.allOf.push(refSchema);
755
779
  } else {
@@ -776,6 +800,8 @@ export class JSONSchemaGenerator {
776
800
  result.$schema = "https://json-schema.org/draft/2020-12/schema";
777
801
  } else if (this.target === "draft-7") {
778
802
  result.$schema = "http://json-schema.org/draft-07/schema#";
803
+ } else if (this.target === "draft-4") {
804
+ result.$schema = "http://json-schema.org/draft-04/schema#";
779
805
  } else {
780
806
  // @ts-ignore
781
807
  console.warn(`Invalid target: ${this.target}`);
@@ -257,16 +257,21 @@ export function floatSafeRemainder(val: number, step: number): number {
257
257
  return (valInt % stepInt) / 10 ** decCount;
258
258
  }
259
259
 
260
+ const EVALUATING = Symbol("evaluating");
261
+
260
262
  export function defineLazy<T, K extends keyof T>(object: T, key: K, getter: () => T[K]): void {
261
- const set = false;
263
+ let value: T[K] | typeof EVALUATING | undefined = undefined;
262
264
  Object.defineProperty(object, key, {
263
265
  get() {
264
- if (!set) {
265
- const value = getter();
266
- object[key] = value;
267
- return value;
266
+ if (value === EVALUATING) {
267
+ // Circular reference detected, return undefined to break the cycle
268
+ return undefined as T[K];
268
269
  }
269
- throw new Error("cached value already set");
270
+ if (value === undefined) {
271
+ value = EVALUATING;
272
+ value = getter();
273
+ }
274
+ return value;
270
275
  },
271
276
  set(v) {
272
277
  Object.defineProperty(object, key, {
@@ -279,6 +284,10 @@ export function defineLazy<T, K extends keyof T>(object: T, key: K, getter: () =
279
284
  });
280
285
  }
281
286
 
287
+ export function objectClone(obj: object) {
288
+ return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
289
+ }
290
+
282
291
  export function assignProp<T extends object, K extends PropertyKey>(
283
292
  target: T,
284
293
  prop: K,
@@ -1,5 +1,5 @@
1
1
  export const version = {
2
2
  major: 4,
3
3
  minor: 0,
4
- patch: 13 as number,
4
+ patch: 15 as number,
5
5
  } as const;
@@ -615,7 +615,7 @@ function object(shape, params) {
615
615
  const def = {
616
616
  type: "object",
617
617
  get shape() {
618
- index_js_1.util.assignProp(this, "shape", { ...shape });
618
+ index_js_1.util.assignProp(this, "shape", shape ? index_js_1.util.objectClone(shape) : {});
619
619
  return this.shape;
620
620
  },
621
621
  ...index_js_1.util.normalizeParams(params),
@@ -627,7 +627,7 @@ function strictObject(shape, params) {
627
627
  return new exports.ZodObject({
628
628
  type: "object",
629
629
  get shape() {
630
- index_js_1.util.assignProp(this, "shape", { ...shape });
630
+ index_js_1.util.assignProp(this, "shape", index_js_1.util.objectClone(shape));
631
631
  return this.shape;
632
632
  },
633
633
  catchall: never(),
@@ -639,7 +639,7 @@ function looseObject(shape, params) {
639
639
  return new exports.ZodObject({
640
640
  type: "object",
641
641
  get shape() {
642
- index_js_1.util.assignProp(this, "shape", { ...shape });
642
+ index_js_1.util.assignProp(this, "shape", index_js_1.util.objectClone(shape));
643
643
  return this.shape;
644
644
  },
645
645
  catchall: unknown(),
@@ -509,7 +509,7 @@ export function object(shape, params) {
509
509
  const def = {
510
510
  type: "object",
511
511
  get shape() {
512
- util.assignProp(this, "shape", { ...shape });
512
+ util.assignProp(this, "shape", shape ? util.objectClone(shape) : {});
513
513
  return this.shape;
514
514
  },
515
515
  ...util.normalizeParams(params),
@@ -521,7 +521,7 @@ export function strictObject(shape, params) {
521
521
  return new ZodObject({
522
522
  type: "object",
523
523
  get shape() {
524
- util.assignProp(this, "shape", { ...shape });
524
+ util.assignProp(this, "shape", util.objectClone(shape));
525
525
  return this.shape;
526
526
  },
527
527
  catchall: never(),
@@ -533,7 +533,7 @@ export function looseObject(shape, params) {
533
533
  return new ZodObject({
534
534
  type: "object",
535
535
  get shape() {
536
- util.assignProp(this, "shape", { ...shape });
536
+ util.assignProp(this, "shape", util.objectClone(shape));
537
537
  return this.shape;
538
538
  },
539
539
  catchall: unknown(),
package/v4/core/api.d.cts CHANGED
@@ -63,11 +63,11 @@ export declare function _xid<T extends schemas.$ZodXID>(Class: util.SchemaClass<
63
63
  export type $ZodKSUIDParams = StringFormatParams<schemas.$ZodKSUID, "when">;
64
64
  export type $ZodCheckKSUIDParams = CheckStringFormatParams<schemas.$ZodKSUID, "when">;
65
65
  export declare function _ksuid<T extends schemas.$ZodKSUID>(Class: util.SchemaClass<T>, params?: string | $ZodKSUIDParams | $ZodCheckKSUIDParams): T;
66
- export type $ZodIPv4Params = StringFormatParams<schemas.$ZodIPv4, "pattern" | "when">;
67
- export type $ZodCheckIPv4Params = CheckStringFormatParams<schemas.$ZodIPv4, "pattern" | "when">;
66
+ export type $ZodIPv4Params = StringFormatParams<schemas.$ZodIPv4, "pattern" | "when" | "version">;
67
+ export type $ZodCheckIPv4Params = CheckStringFormatParams<schemas.$ZodIPv4, "pattern" | "when" | "version">;
68
68
  export declare function _ipv4<T extends schemas.$ZodIPv4>(Class: util.SchemaClass<T>, params?: string | $ZodIPv4Params | $ZodCheckIPv4Params): T;
69
- export type $ZodIPv6Params = StringFormatParams<schemas.$ZodIPv6, "pattern" | "when">;
70
- export type $ZodCheckIPv6Params = CheckStringFormatParams<schemas.$ZodIPv6, "pattern" | "when">;
69
+ export type $ZodIPv6Params = StringFormatParams<schemas.$ZodIPv6, "pattern" | "when" | "version">;
70
+ export type $ZodCheckIPv6Params = CheckStringFormatParams<schemas.$ZodIPv6, "pattern" | "when" | "version">;
71
71
  export declare function _ipv6<T extends schemas.$ZodIPv6>(Class: util.SchemaClass<T>, params?: string | $ZodIPv6Params | $ZodCheckIPv6Params): T;
72
72
  export type $ZodCIDRv4Params = StringFormatParams<schemas.$ZodCIDRv4, "pattern" | "when">;
73
73
  export type $ZodCheckCIDRv4Params = CheckStringFormatParams<schemas.$ZodCIDRv4, "pattern" | "when">;
package/v4/core/api.d.ts CHANGED
@@ -63,11 +63,11 @@ export declare function _xid<T extends schemas.$ZodXID>(Class: util.SchemaClass<
63
63
  export type $ZodKSUIDParams = StringFormatParams<schemas.$ZodKSUID, "when">;
64
64
  export type $ZodCheckKSUIDParams = CheckStringFormatParams<schemas.$ZodKSUID, "when">;
65
65
  export declare function _ksuid<T extends schemas.$ZodKSUID>(Class: util.SchemaClass<T>, params?: string | $ZodKSUIDParams | $ZodCheckKSUIDParams): T;
66
- export type $ZodIPv4Params = StringFormatParams<schemas.$ZodIPv4, "pattern" | "when">;
67
- export type $ZodCheckIPv4Params = CheckStringFormatParams<schemas.$ZodIPv4, "pattern" | "when">;
66
+ export type $ZodIPv4Params = StringFormatParams<schemas.$ZodIPv4, "pattern" | "when" | "version">;
67
+ export type $ZodCheckIPv4Params = CheckStringFormatParams<schemas.$ZodIPv4, "pattern" | "when" | "version">;
68
68
  export declare function _ipv4<T extends schemas.$ZodIPv4>(Class: util.SchemaClass<T>, params?: string | $ZodIPv4Params | $ZodCheckIPv4Params): T;
69
- export type $ZodIPv6Params = StringFormatParams<schemas.$ZodIPv6, "pattern" | "when">;
70
- export type $ZodCheckIPv6Params = CheckStringFormatParams<schemas.$ZodIPv6, "pattern" | "when">;
69
+ export type $ZodIPv6Params = StringFormatParams<schemas.$ZodIPv6, "pattern" | "when" | "version">;
70
+ export type $ZodCheckIPv6Params = CheckStringFormatParams<schemas.$ZodIPv6, "pattern" | "when" | "version">;
71
71
  export declare function _ipv6<T extends schemas.$ZodIPv6>(Class: util.SchemaClass<T>, params?: string | $ZodIPv6Params | $ZodCheckIPv6Params): T;
72
72
  export type $ZodCIDRv4Params = StringFormatParams<schemas.$ZodCIDRv4, "pattern" | "when">;
73
73
  export type $ZodCheckCIDRv4Params = CheckStringFormatParams<schemas.$ZodCIDRv4, "pattern" | "when">;
@@ -30,12 +30,12 @@ export type input<T> = T extends {
30
30
  _zod: {
31
31
  input: any;
32
32
  };
33
- } ? Required<T["_zod"]>["input"] : unknown;
33
+ } ? T["_zod"]["input"] : unknown;
34
34
  export type output<T> = T extends {
35
35
  _zod: {
36
36
  output: any;
37
37
  };
38
- } ? Required<T["_zod"]>["output"] : unknown;
38
+ } ? T["_zod"]["output"] : unknown;
39
39
  export type { output as infer };
40
40
  export interface $ZodConfig {
41
41
  /** Custom error map. Overrides `config().localeError`. */
package/v4/core/core.d.ts CHANGED
@@ -30,12 +30,12 @@ export type input<T> = T extends {
30
30
  _zod: {
31
31
  input: any;
32
32
  };
33
- } ? Required<T["_zod"]>["input"] : unknown;
33
+ } ? T["_zod"]["input"] : unknown;
34
34
  export type output<T> = T extends {
35
35
  _zod: {
36
36
  output: any;
37
37
  };
38
- } ? Required<T["_zod"]>["output"] : unknown;
38
+ } ? T["_zod"]["output"] : unknown;
39
39
  export type { output as infer };
40
40
  export interface $ZodConfig {
41
41
  /** Custom error map. Overrides `config().localeError`. */
@@ -2,7 +2,7 @@ export type Schema = ObjectSchema | ArraySchema | StringSchema | NumberSchema |
2
2
  export type _JSONSchema = boolean | JSONSchema;
3
3
  export type JSONSchema = {
4
4
  [k: string]: unknown;
5
- $schema?: "https://json-schema.org/draft/2020-12/schema" | "http://json-schema.org/draft-07/schema#";
5
+ $schema?: "https://json-schema.org/draft/2020-12/schema" | "http://json-schema.org/draft-07/schema#" | "http://json-schema.org/draft-04/schema#";
6
6
  $id?: string;
7
7
  $anchor?: string;
8
8
  $ref?: string;
@@ -32,9 +32,9 @@ export type JSONSchema = {
32
32
  not?: _JSONSchema;
33
33
  multipleOf?: number;
34
34
  maximum?: number;
35
- exclusiveMaximum?: number;
35
+ exclusiveMaximum?: number | boolean;
36
36
  minimum?: number;
37
- exclusiveMinimum?: number;
37
+ exclusiveMinimum?: number | boolean;
38
38
  maxLength?: number;
39
39
  minLength?: number;
40
40
  pattern?: string;
@@ -2,7 +2,7 @@ export type Schema = ObjectSchema | ArraySchema | StringSchema | NumberSchema |
2
2
  export type _JSONSchema = boolean | JSONSchema;
3
3
  export type JSONSchema = {
4
4
  [k: string]: unknown;
5
- $schema?: "https://json-schema.org/draft/2020-12/schema" | "http://json-schema.org/draft-07/schema#";
5
+ $schema?: "https://json-schema.org/draft/2020-12/schema" | "http://json-schema.org/draft-07/schema#" | "http://json-schema.org/draft-04/schema#";
6
6
  $id?: string;
7
7
  $anchor?: string;
8
8
  $ref?: string;
@@ -32,9 +32,9 @@ export type JSONSchema = {
32
32
  not?: _JSONSchema;
33
33
  multipleOf?: number;
34
34
  maximum?: number;
35
- exclusiveMaximum?: number;
35
+ exclusiveMaximum?: number | boolean;
36
36
  minimum?: number;
37
- exclusiveMinimum?: number;
37
+ exclusiveMinimum?: number | boolean;
38
38
  maxLength?: number;
39
39
  minLength?: number;
40
40
  pattern?: string;
@@ -1684,11 +1684,18 @@ exports.$ZodPromise = core.$constructor("$ZodPromise", (inst, def) => {
1684
1684
  });
1685
1685
  exports.$ZodLazy = core.$constructor("$ZodLazy", (inst, def) => {
1686
1686
  exports.$ZodType.init(inst, def);
1687
+ // let _innerType!: any;
1688
+ // util.defineLazy(def, "getter", () => {
1689
+ // if (!_innerType) {
1690
+ // _innerType = def.getter();
1691
+ // }
1692
+ // return () => _innerType;
1693
+ // });
1687
1694
  util.defineLazy(inst._zod, "innerType", () => def.getter());
1688
1695
  util.defineLazy(inst._zod, "pattern", () => inst._zod.innerType._zod.pattern);
1689
1696
  util.defineLazy(inst._zod, "propValues", () => inst._zod.innerType._zod.propValues);
1690
- util.defineLazy(inst._zod, "optin", () => inst._zod.innerType._zod.optin);
1691
- util.defineLazy(inst._zod, "optout", () => inst._zod.innerType._zod.optout);
1697
+ util.defineLazy(inst._zod, "optin", () => inst._zod.innerType._zod.optin ?? undefined);
1698
+ util.defineLazy(inst._zod, "optout", () => inst._zod.innerType._zod.optout ?? undefined);
1692
1699
  inst._zod.parse = (payload, ctx) => {
1693
1700
  const inner = inst._zod.innerType;
1694
1701
  return inner._zod.run(payload, ctx);
@@ -587,6 +587,8 @@ out Shape extends Readonly<$ZodShape> = Readonly<$ZodShape>, out Config extends
587
587
  propValues: util.PropValues;
588
588
  output: $InferObjectOutput<Shape, Config["out"]>;
589
589
  input: $InferObjectInput<Shape, Config["in"]>;
590
+ optin?: "optional" | undefined;
591
+ optout?: "optional" | undefined;
590
592
  }
591
593
  export type $ZodLooseShape = Record<string, any>;
592
594
  export interface $ZodObject<
@@ -673,9 +675,11 @@ type TupleOutputTypeWithOptionals<T extends util.TupleItems> = T extends readonl
673
675
  ...infer Prefix extends SomeType[],
674
676
  infer Tail extends SomeType
675
677
  ] ? Tail["_zod"]["optout"] extends "optional" ? [...TupleOutputTypeWithOptionals<Prefix>, core.output<Tail>?] : TupleOutputTypeNoOptionals<T> : [];
676
- export interface $ZodTupleInternals<T extends util.TupleItems = readonly $ZodType[], Rest extends SomeType | null = $ZodType | null> extends $ZodTypeInternals<$InferTupleOutputType<T, Rest>, $InferTupleInputType<T, Rest>> {
678
+ export interface $ZodTupleInternals<T extends util.TupleItems = readonly $ZodType[], Rest extends SomeType | null = $ZodType | null> extends _$ZodTypeInternals {
677
679
  def: $ZodTupleDef<T, Rest>;
678
680
  isst: errors.$ZodIssueInvalidType | errors.$ZodIssueTooBig<unknown[]> | errors.$ZodIssueTooSmall<unknown[]>;
681
+ output: $InferTupleOutputType<T, Rest>;
682
+ input: $InferTupleInputType<T, Rest>;
679
683
  }
680
684
  export interface $ZodTuple<T extends util.TupleItems = readonly $ZodType[], Rest extends SomeType | null = $ZodType | null> extends $ZodType {
681
685
  _zod: $ZodTupleInternals<T, Rest>;
@@ -587,6 +587,8 @@ out Shape extends Readonly<$ZodShape> = Readonly<$ZodShape>, out Config extends
587
587
  propValues: util.PropValues;
588
588
  output: $InferObjectOutput<Shape, Config["out"]>;
589
589
  input: $InferObjectInput<Shape, Config["in"]>;
590
+ optin?: "optional" | undefined;
591
+ optout?: "optional" | undefined;
590
592
  }
591
593
  export type $ZodLooseShape = Record<string, any>;
592
594
  export interface $ZodObject<
@@ -673,9 +675,11 @@ type TupleOutputTypeWithOptionals<T extends util.TupleItems> = T extends readonl
673
675
  ...infer Prefix extends SomeType[],
674
676
  infer Tail extends SomeType
675
677
  ] ? Tail["_zod"]["optout"] extends "optional" ? [...TupleOutputTypeWithOptionals<Prefix>, core.output<Tail>?] : TupleOutputTypeNoOptionals<T> : [];
676
- export interface $ZodTupleInternals<T extends util.TupleItems = readonly $ZodType[], Rest extends SomeType | null = $ZodType | null> extends $ZodTypeInternals<$InferTupleOutputType<T, Rest>, $InferTupleInputType<T, Rest>> {
678
+ export interface $ZodTupleInternals<T extends util.TupleItems = readonly $ZodType[], Rest extends SomeType | null = $ZodType | null> extends _$ZodTypeInternals {
677
679
  def: $ZodTupleDef<T, Rest>;
678
680
  isst: errors.$ZodIssueInvalidType | errors.$ZodIssueTooBig<unknown[]> | errors.$ZodIssueTooSmall<unknown[]>;
681
+ output: $InferTupleOutputType<T, Rest>;
682
+ input: $InferTupleInputType<T, Rest>;
679
683
  }
680
684
  export interface $ZodTuple<T extends util.TupleItems = readonly $ZodType[], Rest extends SomeType | null = $ZodType | null> extends $ZodType {
681
685
  _zod: $ZodTupleInternals<T, Rest>;
@@ -1653,11 +1653,18 @@ export const $ZodPromise = /*@__PURE__*/ core.$constructor("$ZodPromise", (inst,
1653
1653
  });
1654
1654
  export const $ZodLazy = /*@__PURE__*/ core.$constructor("$ZodLazy", (inst, def) => {
1655
1655
  $ZodType.init(inst, def);
1656
+ // let _innerType!: any;
1657
+ // util.defineLazy(def, "getter", () => {
1658
+ // if (!_innerType) {
1659
+ // _innerType = def.getter();
1660
+ // }
1661
+ // return () => _innerType;
1662
+ // });
1656
1663
  util.defineLazy(inst._zod, "innerType", () => def.getter());
1657
1664
  util.defineLazy(inst._zod, "pattern", () => inst._zod.innerType._zod.pattern);
1658
1665
  util.defineLazy(inst._zod, "propValues", () => inst._zod.innerType._zod.propValues);
1659
- util.defineLazy(inst._zod, "optin", () => inst._zod.innerType._zod.optin);
1660
- util.defineLazy(inst._zod, "optout", () => inst._zod.innerType._zod.optout);
1666
+ util.defineLazy(inst._zod, "optin", () => inst._zod.innerType._zod.optin ?? undefined);
1667
+ util.defineLazy(inst._zod, "optout", () => inst._zod.innerType._zod.optout ?? undefined);
1661
1668
  inst._zod.parse = (payload, ctx) => {
1662
1669
  const inner = inst._zod.innerType;
1663
1670
  return inner._zod.run(payload, ctx);
@@ -83,7 +83,7 @@ class JSONSchemaGenerator {
83
83
  else if (regexes.length > 1) {
84
84
  result.schema.allOf = [
85
85
  ...regexes.map((regex) => ({
86
- ...(this.target === "draft-7" ? { type: "string" } : {}),
86
+ ...(this.target === "draft-7" || this.target === "draft-4" ? { type: "string" } : {}),
87
87
  pattern: regex.source,
88
88
  })),
89
89
  ];
@@ -98,22 +98,36 @@ class JSONSchemaGenerator {
98
98
  json.type = "integer";
99
99
  else
100
100
  json.type = "number";
101
- if (typeof exclusiveMinimum === "number")
102
- json.exclusiveMinimum = exclusiveMinimum;
101
+ if (typeof exclusiveMinimum === "number") {
102
+ if (this.target === "draft-4") {
103
+ json.minimum = exclusiveMinimum;
104
+ json.exclusiveMinimum = true;
105
+ }
106
+ else {
107
+ json.exclusiveMinimum = exclusiveMinimum;
108
+ }
109
+ }
103
110
  if (typeof minimum === "number") {
104
111
  json.minimum = minimum;
105
- if (typeof exclusiveMinimum === "number") {
112
+ if (typeof exclusiveMinimum === "number" && this.target !== "draft-4") {
106
113
  if (exclusiveMinimum >= minimum)
107
114
  delete json.minimum;
108
115
  else
109
116
  delete json.exclusiveMinimum;
110
117
  }
111
118
  }
112
- if (typeof exclusiveMaximum === "number")
113
- json.exclusiveMaximum = exclusiveMaximum;
119
+ if (typeof exclusiveMaximum === "number") {
120
+ if (this.target === "draft-4") {
121
+ json.maximum = exclusiveMaximum;
122
+ json.exclusiveMaximum = true;
123
+ }
124
+ else {
125
+ json.exclusiveMaximum = exclusiveMaximum;
126
+ }
127
+ }
114
128
  if (typeof maximum === "number") {
115
129
  json.maximum = maximum;
116
- if (typeof exclusiveMaximum === "number") {
130
+ if (typeof exclusiveMaximum === "number" && this.target !== "draft-4") {
117
131
  if (exclusiveMaximum <= maximum)
118
132
  delete json.maximum;
119
133
  else
@@ -294,7 +308,12 @@ class JSONSchemaGenerator {
294
308
  case "record": {
295
309
  const json = _json;
296
310
  json.type = "object";
297
- json.propertyNames = this.process(def.keyType, { ...params, path: [...params.path, "propertyNames"] });
311
+ if (this.target !== "draft-4") {
312
+ json.propertyNames = this.process(def.keyType, {
313
+ ...params,
314
+ path: [...params.path, "propertyNames"],
315
+ });
316
+ }
298
317
  json.additionalProperties = this.process(def.valueType, {
299
318
  ...params,
300
319
  path: [...params.path, "additionalProperties"],
@@ -354,7 +373,12 @@ class JSONSchemaGenerator {
354
373
  else if (vals.length === 1) {
355
374
  const val = vals[0];
356
375
  json.type = val === null ? "null" : typeof val;
357
- json.const = val;
376
+ if (this.target === "draft-4") {
377
+ json.enum = [val];
378
+ }
379
+ else {
380
+ json.const = val;
381
+ }
358
382
  }
359
383
  else {
360
384
  if (vals.every((v) => typeof v === "number"))
@@ -650,7 +674,7 @@ class JSONSchemaGenerator {
650
674
  flattenRef(ref, params);
651
675
  // merge referenced schema into current
652
676
  const refSchema = this.seen.get(ref).schema;
653
- if (refSchema.$ref && params.target === "draft-7") {
677
+ if (refSchema.$ref && (params.target === "draft-7" || params.target === "draft-4")) {
654
678
  schema.allOf = schema.allOf ?? [];
655
679
  schema.allOf.push(refSchema);
656
680
  }
@@ -677,6 +701,9 @@ class JSONSchemaGenerator {
677
701
  else if (this.target === "draft-7") {
678
702
  result.$schema = "http://json-schema.org/draft-07/schema#";
679
703
  }
704
+ else if (this.target === "draft-4") {
705
+ result.$schema = "http://json-schema.org/draft-04/schema#";
706
+ }
680
707
  else {
681
708
  // @ts-ignore
682
709
  console.warn(`Invalid target: ${this.target}`);
@@ -7,8 +7,9 @@ interface JSONSchemaGeneratorParams {
7
7
  metadata?: $ZodRegistry<Record<string, any>>;
8
8
  /** The JSON Schema version to target.
9
9
  * - `"draft-2020-12"` — Default. JSON Schema Draft 2020-12
10
- * - `"draft-7"` — JSON Schema Draft 7 */
11
- target?: "draft-7" | "draft-2020-12";
10
+ * - `"draft-7"` — JSON Schema Draft 7
11
+ * - `"draft-4"` JSON Schema Draft 4 */
12
+ target?: "draft-4" | "draft-7" | "draft-2020-12";
12
13
  /** How to handle unrepresentable types.
13
14
  * - `"throw"` — Default. Unrepresentable types throw an error
14
15
  * - `"any"` — Unrepresentable types become `{}` */
@@ -60,7 +61,7 @@ interface Seen {
60
61
  }
61
62
  export declare class JSONSchemaGenerator {
62
63
  metadataRegistry: $ZodRegistry<Record<string, any>>;
63
- target: "draft-7" | "draft-2020-12";
64
+ target: "draft-4" | "draft-7" | "draft-2020-12";
64
65
  unrepresentable: "throw" | "any";
65
66
  override: (ctx: {
66
67
  zodSchema: schemas.$ZodTypes;
@@ -7,8 +7,9 @@ interface JSONSchemaGeneratorParams {
7
7
  metadata?: $ZodRegistry<Record<string, any>>;
8
8
  /** The JSON Schema version to target.
9
9
  * - `"draft-2020-12"` — Default. JSON Schema Draft 2020-12
10
- * - `"draft-7"` — JSON Schema Draft 7 */
11
- target?: "draft-7" | "draft-2020-12";
10
+ * - `"draft-7"` — JSON Schema Draft 7
11
+ * - `"draft-4"` JSON Schema Draft 4 */
12
+ target?: "draft-4" | "draft-7" | "draft-2020-12";
12
13
  /** How to handle unrepresentable types.
13
14
  * - `"throw"` — Default. Unrepresentable types throw an error
14
15
  * - `"any"` — Unrepresentable types become `{}` */
@@ -60,7 +61,7 @@ interface Seen {
60
61
  }
61
62
  export declare class JSONSchemaGenerator {
62
63
  metadataRegistry: $ZodRegistry<Record<string, any>>;
63
- target: "draft-7" | "draft-2020-12";
64
+ target: "draft-4" | "draft-7" | "draft-2020-12";
64
65
  unrepresentable: "throw" | "any";
65
66
  override: (ctx: {
66
67
  zodSchema: schemas.$ZodTypes;
@@ -79,7 +79,7 @@ export class JSONSchemaGenerator {
79
79
  else if (regexes.length > 1) {
80
80
  result.schema.allOf = [
81
81
  ...regexes.map((regex) => ({
82
- ...(this.target === "draft-7" ? { type: "string" } : {}),
82
+ ...(this.target === "draft-7" || this.target === "draft-4" ? { type: "string" } : {}),
83
83
  pattern: regex.source,
84
84
  })),
85
85
  ];
@@ -94,22 +94,36 @@ export class JSONSchemaGenerator {
94
94
  json.type = "integer";
95
95
  else
96
96
  json.type = "number";
97
- if (typeof exclusiveMinimum === "number")
98
- json.exclusiveMinimum = exclusiveMinimum;
97
+ if (typeof exclusiveMinimum === "number") {
98
+ if (this.target === "draft-4") {
99
+ json.minimum = exclusiveMinimum;
100
+ json.exclusiveMinimum = true;
101
+ }
102
+ else {
103
+ json.exclusiveMinimum = exclusiveMinimum;
104
+ }
105
+ }
99
106
  if (typeof minimum === "number") {
100
107
  json.minimum = minimum;
101
- if (typeof exclusiveMinimum === "number") {
108
+ if (typeof exclusiveMinimum === "number" && this.target !== "draft-4") {
102
109
  if (exclusiveMinimum >= minimum)
103
110
  delete json.minimum;
104
111
  else
105
112
  delete json.exclusiveMinimum;
106
113
  }
107
114
  }
108
- if (typeof exclusiveMaximum === "number")
109
- json.exclusiveMaximum = exclusiveMaximum;
115
+ if (typeof exclusiveMaximum === "number") {
116
+ if (this.target === "draft-4") {
117
+ json.maximum = exclusiveMaximum;
118
+ json.exclusiveMaximum = true;
119
+ }
120
+ else {
121
+ json.exclusiveMaximum = exclusiveMaximum;
122
+ }
123
+ }
110
124
  if (typeof maximum === "number") {
111
125
  json.maximum = maximum;
112
- if (typeof exclusiveMaximum === "number") {
126
+ if (typeof exclusiveMaximum === "number" && this.target !== "draft-4") {
113
127
  if (exclusiveMaximum <= maximum)
114
128
  delete json.maximum;
115
129
  else
@@ -290,7 +304,12 @@ export class JSONSchemaGenerator {
290
304
  case "record": {
291
305
  const json = _json;
292
306
  json.type = "object";
293
- json.propertyNames = this.process(def.keyType, { ...params, path: [...params.path, "propertyNames"] });
307
+ if (this.target !== "draft-4") {
308
+ json.propertyNames = this.process(def.keyType, {
309
+ ...params,
310
+ path: [...params.path, "propertyNames"],
311
+ });
312
+ }
294
313
  json.additionalProperties = this.process(def.valueType, {
295
314
  ...params,
296
315
  path: [...params.path, "additionalProperties"],
@@ -350,7 +369,12 @@ export class JSONSchemaGenerator {
350
369
  else if (vals.length === 1) {
351
370
  const val = vals[0];
352
371
  json.type = val === null ? "null" : typeof val;
353
- json.const = val;
372
+ if (this.target === "draft-4") {
373
+ json.enum = [val];
374
+ }
375
+ else {
376
+ json.const = val;
377
+ }
354
378
  }
355
379
  else {
356
380
  if (vals.every((v) => typeof v === "number"))
@@ -646,7 +670,7 @@ export class JSONSchemaGenerator {
646
670
  flattenRef(ref, params);
647
671
  // merge referenced schema into current
648
672
  const refSchema = this.seen.get(ref).schema;
649
- if (refSchema.$ref && params.target === "draft-7") {
673
+ if (refSchema.$ref && (params.target === "draft-7" || params.target === "draft-4")) {
650
674
  schema.allOf = schema.allOf ?? [];
651
675
  schema.allOf.push(refSchema);
652
676
  }
@@ -673,6 +697,9 @@ export class JSONSchemaGenerator {
673
697
  else if (this.target === "draft-7") {
674
698
  result.$schema = "http://json-schema.org/draft-07/schema#";
675
699
  }
700
+ else if (this.target === "draft-4") {
701
+ result.$schema = "http://json-schema.org/draft-04/schema#";
702
+ }
676
703
  else {
677
704
  // @ts-ignore
678
705
  console.warn(`Invalid target: ${this.target}`);
package/v4/core/util.cjs CHANGED
@@ -14,6 +14,7 @@ exports.nullish = nullish;
14
14
  exports.cleanRegex = cleanRegex;
15
15
  exports.floatSafeRemainder = floatSafeRemainder;
16
16
  exports.defineLazy = defineLazy;
17
+ exports.objectClone = objectClone;
17
18
  exports.assignProp = assignProp;
18
19
  exports.mergeDefs = mergeDefs;
19
20
  exports.cloneDef = cloneDef;
@@ -107,16 +108,20 @@ function floatSafeRemainder(val, step) {
107
108
  const stepInt = Number.parseInt(step.toFixed(decCount).replace(".", ""));
108
109
  return (valInt % stepInt) / 10 ** decCount;
109
110
  }
111
+ const EVALUATING = Symbol("evaluating");
110
112
  function defineLazy(object, key, getter) {
111
- const set = false;
113
+ let value = undefined;
112
114
  Object.defineProperty(object, key, {
113
115
  get() {
114
- if (!set) {
115
- const value = getter();
116
- object[key] = value;
117
- return value;
116
+ if (value === EVALUATING) {
117
+ // Circular reference detected, return undefined to break the cycle
118
+ return undefined;
118
119
  }
119
- throw new Error("cached value already set");
120
+ if (value === undefined) {
121
+ value = EVALUATING;
122
+ value = getter();
123
+ }
124
+ return value;
120
125
  },
121
126
  set(v) {
122
127
  Object.defineProperty(object, key, {
@@ -128,6 +133,9 @@ function defineLazy(object, key, getter) {
128
133
  configurable: true,
129
134
  });
130
135
  }
136
+ function objectClone(obj) {
137
+ return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
138
+ }
131
139
  function assignProp(target, prop, value) {
132
140
  Object.defineProperty(target, prop, {
133
141
  value,
@@ -120,6 +120,7 @@ export declare function nullish(input: any): boolean;
120
120
  export declare function cleanRegex(source: string): string;
121
121
  export declare function floatSafeRemainder(val: number, step: number): number;
122
122
  export declare function defineLazy<T, K extends keyof T>(object: T, key: K, getter: () => T[K]): void;
123
+ export declare function objectClone(obj: object): any;
123
124
  export declare function assignProp<T extends object, K extends PropertyKey>(target: T, prop: K, value: K extends keyof T ? T[K] : any): void;
124
125
  export declare function mergeDefs(...defs: Record<string, any>[]): any;
125
126
  export declare function cloneDef(schema: schemas.$ZodType): any;
package/v4/core/util.d.ts CHANGED
@@ -120,6 +120,7 @@ export declare function nullish(input: any): boolean;
120
120
  export declare function cleanRegex(source: string): string;
121
121
  export declare function floatSafeRemainder(val: number, step: number): number;
122
122
  export declare function defineLazy<T, K extends keyof T>(object: T, key: K, getter: () => T[K]): void;
123
+ export declare function objectClone(obj: object): any;
123
124
  export declare function assignProp<T extends object, K extends PropertyKey>(target: T, prop: K, value: K extends keyof T ? T[K] : any): void;
124
125
  export declare function mergeDefs(...defs: Record<string, any>[]): any;
125
126
  export declare function cloneDef(schema: schemas.$ZodType): any;
package/v4/core/util.js CHANGED
@@ -61,16 +61,20 @@ export function floatSafeRemainder(val, step) {
61
61
  const stepInt = Number.parseInt(step.toFixed(decCount).replace(".", ""));
62
62
  return (valInt % stepInt) / 10 ** decCount;
63
63
  }
64
+ const EVALUATING = Symbol("evaluating");
64
65
  export function defineLazy(object, key, getter) {
65
- const set = false;
66
+ let value = undefined;
66
67
  Object.defineProperty(object, key, {
67
68
  get() {
68
- if (!set) {
69
- const value = getter();
70
- object[key] = value;
71
- return value;
69
+ if (value === EVALUATING) {
70
+ // Circular reference detected, return undefined to break the cycle
71
+ return undefined;
72
72
  }
73
- throw new Error("cached value already set");
73
+ if (value === undefined) {
74
+ value = EVALUATING;
75
+ value = getter();
76
+ }
77
+ return value;
74
78
  },
75
79
  set(v) {
76
80
  Object.defineProperty(object, key, {
@@ -82,6 +86,9 @@ export function defineLazy(object, key, getter) {
82
86
  configurable: true,
83
87
  });
84
88
  }
89
+ export function objectClone(obj) {
90
+ return Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
91
+ }
85
92
  export function assignProp(target, prop, value) {
86
93
  Object.defineProperty(target, prop, {
87
94
  value,
@@ -4,5 +4,5 @@ exports.version = void 0;
4
4
  exports.version = {
5
5
  major: 4,
6
6
  minor: 0,
7
- patch: 13,
7
+ patch: 15,
8
8
  };
@@ -1,5 +1,5 @@
1
1
  export const version = {
2
2
  major: 4,
3
3
  minor: 0,
4
- patch: 13,
4
+ patch: 15,
5
5
  };