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 +1 -1
- package/src/v4/classic/schemas.ts +3 -3
- package/src/v4/classic/tests/recursive-types.test.ts +77 -0
- package/src/v4/classic/tests/to-json-schema.test.ts +26 -0
- package/src/v4/core/api.ts +4 -4
- package/src/v4/core/core.ts +2 -2
- package/src/v4/core/json-schema.ts +6 -3
- package/src/v4/core/schemas.ts +15 -3
- package/src/v4/core/to-json-schema.ts +37 -11
- package/src/v4/core/util.ts +15 -6
- package/src/v4/core/versions.ts +1 -1
- package/v4/classic/schemas.cjs +3 -3
- package/v4/classic/schemas.js +3 -3
- package/v4/core/api.d.cts +4 -4
- package/v4/core/api.d.ts +4 -4
- package/v4/core/core.d.cts +2 -2
- package/v4/core/core.d.ts +2 -2
- package/v4/core/json-schema.d.cts +3 -3
- package/v4/core/json-schema.d.ts +3 -3
- package/v4/core/schemas.cjs +9 -2
- package/v4/core/schemas.d.cts +5 -1
- package/v4/core/schemas.d.ts +5 -1
- package/v4/core/schemas.js +9 -2
- package/v4/core/to-json-schema.cjs +37 -10
- package/v4/core/to-json-schema.d.cts +4 -3
- package/v4/core/to-json-schema.d.ts +4 -3
- package/v4/core/to-json-schema.js +37 -10
- package/v4/core/util.cjs +14 -6
- package/v4/core/util.d.cts +1 -0
- package/v4/core/util.d.ts +1 -0
- package/v4/core/util.js +13 -6
- package/v4/core/versions.cjs +1 -1
- package/v4/core/versions.js +1 -1
package/package.json
CHANGED
|
@@ -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",
|
|
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",
|
|
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",
|
|
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
|
package/src/v4/core/api.ts
CHANGED
|
@@ -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
|
package/src/v4/core/core.ts
CHANGED
|
@@ -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 } } ?
|
|
88
|
-
export type output<T> = T extends { _zod: { output: any } } ?
|
|
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?:
|
|
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;
|
package/src/v4/core/schemas.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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")
|
|
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")
|
|
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
|
-
|
|
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
|
-
|
|
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}`);
|
package/src/v4/core/util.ts
CHANGED
|
@@ -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
|
-
|
|
263
|
+
let value: T[K] | typeof EVALUATING | undefined = undefined;
|
|
262
264
|
Object.defineProperty(object, key, {
|
|
263
265
|
get() {
|
|
264
|
-
if (
|
|
265
|
-
|
|
266
|
-
|
|
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
|
-
|
|
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,
|
package/src/v4/core/versions.ts
CHANGED
package/v4/classic/schemas.cjs
CHANGED
|
@@ -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",
|
|
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",
|
|
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",
|
|
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(),
|
package/v4/classic/schemas.js
CHANGED
|
@@ -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",
|
|
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",
|
|
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",
|
|
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">;
|
package/v4/core/core.d.cts
CHANGED
|
@@ -30,12 +30,12 @@ export type input<T> = T extends {
|
|
|
30
30
|
_zod: {
|
|
31
31
|
input: any;
|
|
32
32
|
};
|
|
33
|
-
} ?
|
|
33
|
+
} ? T["_zod"]["input"] : unknown;
|
|
34
34
|
export type output<T> = T extends {
|
|
35
35
|
_zod: {
|
|
36
36
|
output: any;
|
|
37
37
|
};
|
|
38
|
-
} ?
|
|
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
|
-
} ?
|
|
33
|
+
} ? T["_zod"]["input"] : unknown;
|
|
34
34
|
export type output<T> = T extends {
|
|
35
35
|
_zod: {
|
|
36
36
|
output: any;
|
|
37
37
|
};
|
|
38
|
-
} ?
|
|
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;
|
package/v4/core/json-schema.d.ts
CHANGED
|
@@ -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;
|
package/v4/core/schemas.cjs
CHANGED
|
@@ -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);
|
package/v4/core/schemas.d.cts
CHANGED
|
@@ -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
|
|
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>;
|
package/v4/core/schemas.d.ts
CHANGED
|
@@ -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
|
|
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>;
|
package/v4/core/schemas.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
113
|
+
let value = undefined;
|
|
112
114
|
Object.defineProperty(object, key, {
|
|
113
115
|
get() {
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return value;
|
|
116
|
+
if (value === EVALUATING) {
|
|
117
|
+
// Circular reference detected, return undefined to break the cycle
|
|
118
|
+
return undefined;
|
|
118
119
|
}
|
|
119
|
-
|
|
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,
|
package/v4/core/util.d.cts
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.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
|
-
|
|
66
|
+
let value = undefined;
|
|
66
67
|
Object.defineProperty(object, key, {
|
|
67
68
|
get() {
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return value;
|
|
69
|
+
if (value === EVALUATING) {
|
|
70
|
+
// Circular reference detected, return undefined to break the cycle
|
|
71
|
+
return undefined;
|
|
72
72
|
}
|
|
73
|
-
|
|
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,
|
package/v4/core/versions.cjs
CHANGED
package/v4/core/versions.js
CHANGED