zod 3.26.0-canary.20250703T215303 → 3.26.0-canary.20250708T090717
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/index.cjs +2 -2
- package/index.d.cts +2 -2
- package/index.d.ts +2 -2
- package/index.js +2 -2
- package/package.json +1 -1
- package/src/index.ts +2 -2
- package/src/v4/classic/schemas.ts +8 -9
- package/src/v4/classic/tests/brand.test.ts +1 -3
- package/src/v4/classic/tests/discriminated-unions.test.ts +27 -0
- package/src/v4/classic/tests/index.test.ts +1 -1
- package/src/v4/classic/tests/object.test.ts +11 -1
- package/src/v4/classic/tests/record.test.ts +11 -1
- package/src/v4/classic/tests/recursive-types.test.ts +33 -2
- package/src/v4/classic/tests/refine.test.ts +109 -0
- package/src/v4/classic/tests/registries.test.ts +9 -0
- package/src/v4/classic/tests/to-json-schema.test.ts +78 -17
- package/src/v4/core/api.ts +2 -0
- package/src/v4/core/checks.ts +8 -10
- package/src/v4/core/errors.ts +4 -0
- package/src/v4/core/registries.ts +11 -1
- package/src/v4/core/schemas.ts +80 -34
- package/src/v4/core/to-json-schema.ts +67 -30
- package/src/v4/mini/schemas.ts +2 -2
- package/src/v4/mini/tests/string.test.ts +6 -0
- package/v4/classic/schemas.cjs +4 -4
- package/v4/classic/schemas.d.cts +4 -3
- package/v4/classic/schemas.d.ts +4 -3
- package/v4/classic/schemas.js +4 -4
- package/v4/core/checks.cjs +18 -12
- package/v4/core/checks.d.cts +2 -1
- package/v4/core/checks.d.ts +2 -1
- package/v4/core/checks.js +18 -12
- package/v4/core/errors.cjs +4 -0
- package/v4/core/errors.js +4 -0
- package/v4/core/registries.cjs +10 -1
- package/v4/core/registries.d.cts +2 -1
- package/v4/core/registries.d.ts +2 -1
- package/v4/core/registries.js +10 -1
- package/v4/core/schemas.cjs +15 -6
- package/v4/core/schemas.d.cts +31 -9
- package/v4/core/schemas.d.ts +31 -9
- package/v4/core/schemas.js +15 -6
- package/v4/core/to-json-schema.cjs +51 -26
- package/v4/core/to-json-schema.d.cts +6 -2
- package/v4/core/to-json-schema.d.ts +6 -2
- package/v4/core/to-json-schema.js +51 -26
- package/v4/mini/schemas.d.cts +1 -1
- package/v4/mini/schemas.d.ts +1 -1
package/index.cjs
CHANGED
|
@@ -27,7 +27,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.z = void 0;
|
|
30
|
-
const z = __importStar(require("./v3/
|
|
30
|
+
const z = __importStar(require("./v3/external.cjs"));
|
|
31
31
|
exports.z = z;
|
|
32
|
-
__exportStar(require("./v3/
|
|
32
|
+
__exportStar(require("./v3/external.cjs"), exports);
|
|
33
33
|
exports.default = z;
|
package/index.d.cts
CHANGED
package/index.d.ts
CHANGED
package/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zod",
|
|
3
|
-
"version": "3.26.0-canary.
|
|
3
|
+
"version": "3.26.0-canary.20250708T090717",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Colin McDonnell <zod@colinhacks.com>",
|
|
6
6
|
"description": "TypeScript-first schema declaration and validation library with static type inference",
|
package/src/index.ts
CHANGED
|
@@ -365,6 +365,8 @@ export const ZodString: core.$constructor<ZodString> = /*@__PURE__*/ core.$const
|
|
|
365
365
|
inst.duration = (params) => inst.check(iso.duration(params as any));
|
|
366
366
|
});
|
|
367
367
|
|
|
368
|
+
export function string(params?: string | core.$ZodStringParams): ZodString;
|
|
369
|
+
export function string<T extends string>(params?: string | core.$ZodStringParams): core.$ZodType<T, T>;
|
|
368
370
|
export function string(params?: string | core.$ZodStringParams): ZodString {
|
|
369
371
|
return core._string(ZodString, params) as any;
|
|
370
372
|
}
|
|
@@ -1357,11 +1359,11 @@ export function partialRecord<Key extends core.$ZodRecordKey, Value extends core
|
|
|
1357
1359
|
keyType: Key,
|
|
1358
1360
|
valueType: Value,
|
|
1359
1361
|
params?: string | core.$ZodRecordParams
|
|
1360
|
-
): ZodRecord<
|
|
1362
|
+
): ZodRecord<Key & core.$partial, Value> {
|
|
1361
1363
|
return new ZodRecord({
|
|
1362
1364
|
type: "record",
|
|
1363
1365
|
keyType: union([keyType, never()]),
|
|
1364
|
-
valueType: valueType as any
|
|
1366
|
+
valueType: valueType as any,
|
|
1365
1367
|
...util.normalizeParams(params),
|
|
1366
1368
|
}) as any;
|
|
1367
1369
|
}
|
|
@@ -1935,10 +1937,10 @@ export const ZodCustom: core.$constructor<ZodCustom> = /*@__PURE__*/ core.$const
|
|
|
1935
1937
|
});
|
|
1936
1938
|
|
|
1937
1939
|
// custom checks
|
|
1938
|
-
export function check<O = unknown>(fn: core.CheckFn<O
|
|
1940
|
+
export function check<O = unknown>(fn: core.CheckFn<O>): core.$ZodCheck<O> {
|
|
1939
1941
|
const ch = new core.$ZodCheck({
|
|
1940
1942
|
check: "custom",
|
|
1941
|
-
...util.normalizeParams(params),
|
|
1943
|
+
// ...util.normalizeParams(params),
|
|
1942
1944
|
});
|
|
1943
1945
|
|
|
1944
1946
|
ch._zod.check = fn;
|
|
@@ -1960,10 +1962,7 @@ export function refine<T>(
|
|
|
1960
1962
|
}
|
|
1961
1963
|
|
|
1962
1964
|
// superRefine
|
|
1963
|
-
export function superRefine<T>(
|
|
1964
|
-
fn: (arg: T, payload: RefinementCtx<T>) => void | Promise<void>,
|
|
1965
|
-
params?: string | core.$ZodCustomParams
|
|
1966
|
-
): core.$ZodCheck<T> {
|
|
1965
|
+
export function superRefine<T>(fn: (arg: T, payload: RefinementCtx<T>) => void | Promise<void>): core.$ZodCheck<T> {
|
|
1967
1966
|
const ch = check<T>((payload) => {
|
|
1968
1967
|
(payload as RefinementCtx).addIssue = (issue) => {
|
|
1969
1968
|
if (typeof issue === "string") {
|
|
@@ -1981,7 +1980,7 @@ export function superRefine<T>(
|
|
|
1981
1980
|
};
|
|
1982
1981
|
|
|
1983
1982
|
return fn(payload.value, payload as RefinementCtx<T>);
|
|
1984
|
-
}
|
|
1983
|
+
});
|
|
1985
1984
|
return ch;
|
|
1986
1985
|
}
|
|
1987
1986
|
|
|
@@ -59,7 +59,5 @@ test("$branded", () => {
|
|
|
59
59
|
test("branded record", () => {
|
|
60
60
|
const recordWithBrandedNumberKeys = z.record(z.string().brand("SomeBrand"), z.number());
|
|
61
61
|
type recordWithBrandedNumberKeys = z.infer<typeof recordWithBrandedNumberKeys>;
|
|
62
|
-
expectTypeOf<recordWithBrandedNumberKeys>().toEqualTypeOf<
|
|
63
|
-
Record<string & z.core.$brand<"SomeBrand">, number | undefined>
|
|
64
|
-
>();
|
|
62
|
+
expectTypeOf<recordWithBrandedNumberKeys>().toEqualTypeOf<Record<string & z.core.$brand<"SomeBrand">, number>>();
|
|
65
63
|
});
|
|
@@ -24,6 +24,9 @@ test("_values", () => {
|
|
|
24
24
|
|
|
25
25
|
const post = z.literal("test").transform((_) => Math.random());
|
|
26
26
|
expect(post._zod.values).toEqual(new Set(["test"]));
|
|
27
|
+
|
|
28
|
+
// Test that readonly literals pass through their values property
|
|
29
|
+
expect(z.literal("test").readonly()._zod.values).toEqual(new Set(["test"]));
|
|
27
30
|
});
|
|
28
31
|
|
|
29
32
|
test("valid parse - object", () => {
|
|
@@ -590,3 +593,27 @@ test("nested discriminated unions", () => {
|
|
|
590
593
|
}
|
|
591
594
|
`);
|
|
592
595
|
});
|
|
596
|
+
|
|
597
|
+
test("readonly literal discriminator", () => {
|
|
598
|
+
const discUnion = z.discriminatedUnion("type", [
|
|
599
|
+
z.object({ type: z.literal("a").readonly(), a: z.string() }),
|
|
600
|
+
z.object({ type: z.literal("b"), b: z.number() }),
|
|
601
|
+
]);
|
|
602
|
+
|
|
603
|
+
// Test that both discriminator values are correctly included in propValues
|
|
604
|
+
const propValues = discUnion._zod.propValues;
|
|
605
|
+
expect(propValues?.type?.has("a")).toBe(true);
|
|
606
|
+
expect(propValues?.type?.has("b")).toBe(true);
|
|
607
|
+
|
|
608
|
+
// Test that the discriminated union works correctly
|
|
609
|
+
const result1 = discUnion.parse({ type: "a", a: "hello" });
|
|
610
|
+
expect(result1).toEqual({ type: "a", a: "hello" });
|
|
611
|
+
|
|
612
|
+
const result2 = discUnion.parse({ type: "b", b: 42 });
|
|
613
|
+
expect(result2).toEqual({ type: "b", b: 42 });
|
|
614
|
+
|
|
615
|
+
// Test that invalid discriminator values are rejected
|
|
616
|
+
expect(() => {
|
|
617
|
+
discUnion.parse({ type: "c", a: "hello" });
|
|
618
|
+
}).toThrow();
|
|
619
|
+
});
|
|
@@ -301,7 +301,7 @@ test("z.record", () => {
|
|
|
301
301
|
// partial enum
|
|
302
302
|
const d = z.record(z.enum(["a", "b"]).or(z.never()), z.string());
|
|
303
303
|
type d = z.output<typeof d>;
|
|
304
|
-
expectTypeOf<d>().toEqualTypeOf<
|
|
304
|
+
expectTypeOf<d>().toEqualTypeOf<Record<"a" | "b", string>>();
|
|
305
305
|
});
|
|
306
306
|
|
|
307
307
|
test("z.map", () => {
|
|
@@ -217,6 +217,16 @@ test("test inferred merged type", async () => {
|
|
|
217
217
|
expectTypeOf<asdf>().toEqualTypeOf<{ a: number }>();
|
|
218
218
|
});
|
|
219
219
|
|
|
220
|
+
test("inferred type with Record shape", () => {
|
|
221
|
+
type A = z.ZodObject<Record<string, z.ZodType<string, number>>>;
|
|
222
|
+
expectTypeOf<z.infer<A>>().toEqualTypeOf<Record<string, string>>();
|
|
223
|
+
expectTypeOf<z.input<A>>().toEqualTypeOf<Record<string, number>>();
|
|
224
|
+
|
|
225
|
+
type B = z.ZodObject;
|
|
226
|
+
expectTypeOf<z.infer<B>>().toEqualTypeOf<Record<string, unknown>>();
|
|
227
|
+
expectTypeOf<z.input<B>>().toEqualTypeOf<Record<string, unknown>>();
|
|
228
|
+
});
|
|
229
|
+
|
|
220
230
|
test("inferred merged object type with optional properties", async () => {
|
|
221
231
|
const Merged = z
|
|
222
232
|
.object({ a: z.string(), b: z.string().optional() })
|
|
@@ -549,5 +559,5 @@ test("index signature in shape", () => {
|
|
|
549
559
|
const schema = makeZodObj("foo");
|
|
550
560
|
type schema = z.infer<typeof schema>;
|
|
551
561
|
|
|
552
|
-
expectTypeOf<schema>().toEqualTypeOf<Record<string,
|
|
562
|
+
expectTypeOf<schema>().toEqualTypeOf<Record<string, string>>();
|
|
553
563
|
});
|
|
@@ -17,7 +17,7 @@ test("type inference", () => {
|
|
|
17
17
|
expectTypeOf<booleanRecord>().toEqualTypeOf<Record<string, boolean>>();
|
|
18
18
|
expectTypeOf<recordWithEnumKeys>().toEqualTypeOf<Record<"Tuna" | "Salmon", string>>();
|
|
19
19
|
expectTypeOf<recordWithLiteralKey>().toEqualTypeOf<Record<"Tuna" | "Salmon", string>>();
|
|
20
|
-
expectTypeOf<recordWithLiteralUnionKeys>().toEqualTypeOf<
|
|
20
|
+
expectTypeOf<recordWithLiteralUnionKeys>().toEqualTypeOf<Record<"Tuna" | "Salmon", string>>();
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
test("enum exhaustiveness", () => {
|
|
@@ -330,3 +330,13 @@ test("async parsing", async () => {
|
|
|
330
330
|
]]
|
|
331
331
|
`);
|
|
332
332
|
});
|
|
333
|
+
|
|
334
|
+
test("partial record", () => {
|
|
335
|
+
const schema = z.partialRecord(z.string(), z.string());
|
|
336
|
+
type schema = z.infer<typeof schema>;
|
|
337
|
+
expectTypeOf<schema>().toEqualTypeOf<Partial<Record<string, string>>>();
|
|
338
|
+
|
|
339
|
+
const Keys = z.enum(["id", "name", "email"]).or(z.never());
|
|
340
|
+
const Person = z.partialRecord(Keys, z.string());
|
|
341
|
+
expectTypeOf<z.infer<typeof Person>>().toEqualTypeOf<Partial<Record<"id" | "name" | "email", string>>>();
|
|
342
|
+
});
|
|
@@ -160,9 +160,10 @@ test("deferred self-recursion", () => {
|
|
|
160
160
|
const Output = z.object({
|
|
161
161
|
id: z.int(), //.nonnegative(),
|
|
162
162
|
name: z.string(),
|
|
163
|
-
features: z.
|
|
163
|
+
get features(): z.ZodArray<typeof Feature> {
|
|
164
|
+
return Feature.array();
|
|
165
|
+
},
|
|
164
166
|
});
|
|
165
|
-
|
|
166
167
|
type Output = z.output<typeof Output>;
|
|
167
168
|
|
|
168
169
|
type _Feature = {
|
|
@@ -323,3 +324,33 @@ test("recursion compatibility", () => {
|
|
|
323
324
|
},
|
|
324
325
|
});
|
|
325
326
|
});
|
|
327
|
+
|
|
328
|
+
// biome-ignore lint: sadf
|
|
329
|
+
export type RecursiveA = z.ZodUnion<
|
|
330
|
+
[
|
|
331
|
+
z.ZodObject<{
|
|
332
|
+
a: z.ZodDefault<RecursiveA>;
|
|
333
|
+
b: z.ZodPrefault<RecursiveA>;
|
|
334
|
+
c: z.ZodNonOptional<RecursiveA>;
|
|
335
|
+
d: z.ZodOptional<RecursiveA>;
|
|
336
|
+
e: z.ZodNullable<RecursiveA>;
|
|
337
|
+
g: z.ZodReadonly<RecursiveA>;
|
|
338
|
+
h: z.ZodPipe<RecursiveA, z.ZodString>;
|
|
339
|
+
i: z.ZodArray<RecursiveA>;
|
|
340
|
+
j: z.ZodSet<RecursiveA>;
|
|
341
|
+
k: z.ZodMap<RecursiveA, RecursiveA>;
|
|
342
|
+
l: z.ZodRecord<z.ZodString, RecursiveA>;
|
|
343
|
+
m: z.ZodUnion<[RecursiveA, RecursiveA]>;
|
|
344
|
+
n: z.ZodIntersection<RecursiveA, RecursiveA>;
|
|
345
|
+
o: z.ZodLazy<RecursiveA>;
|
|
346
|
+
p: z.ZodPromise<RecursiveA>;
|
|
347
|
+
q: z.ZodCatch<RecursiveA>;
|
|
348
|
+
r: z.ZodSuccess<RecursiveA>;
|
|
349
|
+
s: z.ZodTransform<RecursiveA, string>;
|
|
350
|
+
t: z.ZodTuple<[RecursiveA, RecursiveA]>;
|
|
351
|
+
u: z.ZodObject<{
|
|
352
|
+
a: RecursiveA;
|
|
353
|
+
}>;
|
|
354
|
+
}>,
|
|
355
|
+
]
|
|
356
|
+
>;
|
|
@@ -421,3 +421,112 @@ describe("type refinement", () => {
|
|
|
421
421
|
});
|
|
422
422
|
});
|
|
423
423
|
*/
|
|
424
|
+
|
|
425
|
+
test("when", () => {
|
|
426
|
+
const schema = z
|
|
427
|
+
.strictObject({
|
|
428
|
+
password: z.string().min(8),
|
|
429
|
+
confirmPassword: z.string(),
|
|
430
|
+
other: z.string(),
|
|
431
|
+
})
|
|
432
|
+
.refine(
|
|
433
|
+
(data) => {
|
|
434
|
+
console.log("running check...");
|
|
435
|
+
console.log(data);
|
|
436
|
+
console.log(data.password);
|
|
437
|
+
return data.password === data.confirmPassword;
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
message: "Passwords do not match",
|
|
441
|
+
path: ["confirmPassword"],
|
|
442
|
+
when(payload) {
|
|
443
|
+
if (payload.value === undefined) return false;
|
|
444
|
+
if (payload.value === null) return false;
|
|
445
|
+
// no issues with confirmPassword or password
|
|
446
|
+
return payload.issues.every((iss) => iss.path?.[0] !== "confirmPassword" && iss.path?.[0] !== "password");
|
|
447
|
+
},
|
|
448
|
+
}
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
expect(schema.safeParse(undefined)).toMatchInlineSnapshot(`
|
|
452
|
+
{
|
|
453
|
+
"error": [ZodError: [
|
|
454
|
+
{
|
|
455
|
+
"expected": "object",
|
|
456
|
+
"code": "invalid_type",
|
|
457
|
+
"path": [],
|
|
458
|
+
"message": "Invalid input: expected object, received undefined"
|
|
459
|
+
}
|
|
460
|
+
]],
|
|
461
|
+
"success": false,
|
|
462
|
+
}
|
|
463
|
+
`);
|
|
464
|
+
expect(schema.safeParse(null)).toMatchInlineSnapshot(`
|
|
465
|
+
{
|
|
466
|
+
"error": [ZodError: [
|
|
467
|
+
{
|
|
468
|
+
"expected": "object",
|
|
469
|
+
"code": "invalid_type",
|
|
470
|
+
"path": [],
|
|
471
|
+
"message": "Invalid input: expected object, received null"
|
|
472
|
+
}
|
|
473
|
+
]],
|
|
474
|
+
"success": false,
|
|
475
|
+
}
|
|
476
|
+
`);
|
|
477
|
+
expect(
|
|
478
|
+
schema.safeParse({
|
|
479
|
+
password: "asdf",
|
|
480
|
+
confirmPassword: "asdfg",
|
|
481
|
+
other: "qwer",
|
|
482
|
+
})
|
|
483
|
+
).toMatchInlineSnapshot(`
|
|
484
|
+
{
|
|
485
|
+
"error": [ZodError: [
|
|
486
|
+
{
|
|
487
|
+
"origin": "string",
|
|
488
|
+
"code": "too_small",
|
|
489
|
+
"minimum": 8,
|
|
490
|
+
"inclusive": true,
|
|
491
|
+
"path": [
|
|
492
|
+
"password"
|
|
493
|
+
],
|
|
494
|
+
"message": "Too small: expected string to have >=8 characters"
|
|
495
|
+
}
|
|
496
|
+
]],
|
|
497
|
+
"success": false,
|
|
498
|
+
}
|
|
499
|
+
`);
|
|
500
|
+
|
|
501
|
+
expect(
|
|
502
|
+
schema.safeParse({
|
|
503
|
+
password: "asdf",
|
|
504
|
+
confirmPassword: "asdfg",
|
|
505
|
+
other: 1234,
|
|
506
|
+
})
|
|
507
|
+
).toMatchInlineSnapshot(`
|
|
508
|
+
{
|
|
509
|
+
"error": [ZodError: [
|
|
510
|
+
{
|
|
511
|
+
"origin": "string",
|
|
512
|
+
"code": "too_small",
|
|
513
|
+
"minimum": 8,
|
|
514
|
+
"inclusive": true,
|
|
515
|
+
"path": [
|
|
516
|
+
"password"
|
|
517
|
+
],
|
|
518
|
+
"message": "Too small: expected string to have >=8 characters"
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
"expected": "string",
|
|
522
|
+
"code": "invalid_type",
|
|
523
|
+
"path": [
|
|
524
|
+
"other"
|
|
525
|
+
],
|
|
526
|
+
"message": "Invalid input: expected string, received number"
|
|
527
|
+
}
|
|
528
|
+
]],
|
|
529
|
+
"success": false,
|
|
530
|
+
}
|
|
531
|
+
`);
|
|
532
|
+
});
|
|
@@ -193,3 +193,12 @@ test("function meta with replacement", () => {
|
|
|
193
193
|
|
|
194
194
|
expect(myReg.get(mySchema)!.defaulter("hello", true)).toEqual(5);
|
|
195
195
|
});
|
|
196
|
+
|
|
197
|
+
test("test .clear()", () => {
|
|
198
|
+
const reg = z.registry();
|
|
199
|
+
const a = z.string();
|
|
200
|
+
reg.add(a);
|
|
201
|
+
expect(reg.has(a)).toEqual(true);
|
|
202
|
+
reg.clear();
|
|
203
|
+
expect(reg.has(a)).toEqual(false);
|
|
204
|
+
});
|
|
@@ -28,10 +28,9 @@ describe("toJSONSchema", () => {
|
|
|
28
28
|
"type": "null",
|
|
29
29
|
}
|
|
30
30
|
`);
|
|
31
|
-
expect(z.toJSONSchema(z.undefined())).toMatchInlineSnapshot(`
|
|
31
|
+
expect(z.toJSONSchema(z.undefined(), { unrepresentable: "any" })).toMatchInlineSnapshot(`
|
|
32
32
|
{
|
|
33
33
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
34
|
-
"not": {},
|
|
35
34
|
}
|
|
36
35
|
`);
|
|
37
36
|
expect(z.toJSONSchema(z.any())).toMatchInlineSnapshot(`
|
|
@@ -232,6 +231,7 @@ describe("toJSONSchema", () => {
|
|
|
232
231
|
expect(() => z.toJSONSchema(z.int64())).toThrow("BigInt cannot be represented in JSON Schema");
|
|
233
232
|
expect(() => z.toJSONSchema(z.symbol())).toThrow("Symbols cannot be represented in JSON Schema");
|
|
234
233
|
expect(() => z.toJSONSchema(z.void())).toThrow("Void cannot be represented in JSON Schema");
|
|
234
|
+
expect(() => z.toJSONSchema(z.undefined())).toThrow("Undefined cannot be represented in JSON Schema");
|
|
235
235
|
expect(() => z.toJSONSchema(z.date())).toThrow("Date cannot be represented in JSON Schema");
|
|
236
236
|
expect(() => z.toJSONSchema(z.map(z.string(), z.number()))).toThrow("Map cannot be represented in JSON Schema");
|
|
237
237
|
expect(() => z.toJSONSchema(z.set(z.string()))).toThrow("Set cannot be represented in JSON Schema");
|
|
@@ -1259,6 +1259,35 @@ test("override execution order", () => {
|
|
|
1259
1259
|
`);
|
|
1260
1260
|
});
|
|
1261
1261
|
|
|
1262
|
+
test("override with path", () => {
|
|
1263
|
+
const userSchema = z.object({
|
|
1264
|
+
name: z.string(),
|
|
1265
|
+
age: z.number(),
|
|
1266
|
+
});
|
|
1267
|
+
|
|
1268
|
+
const capturedPaths: (string | number)[][] = [];
|
|
1269
|
+
|
|
1270
|
+
z.toJSONSchema(userSchema, {
|
|
1271
|
+
override(ctx) {
|
|
1272
|
+
capturedPaths.push(ctx.path);
|
|
1273
|
+
},
|
|
1274
|
+
});
|
|
1275
|
+
|
|
1276
|
+
expect(capturedPaths).toMatchInlineSnapshot(`
|
|
1277
|
+
[
|
|
1278
|
+
[
|
|
1279
|
+
"properties",
|
|
1280
|
+
"age",
|
|
1281
|
+
],
|
|
1282
|
+
[
|
|
1283
|
+
"properties",
|
|
1284
|
+
"name",
|
|
1285
|
+
],
|
|
1286
|
+
[],
|
|
1287
|
+
]
|
|
1288
|
+
`);
|
|
1289
|
+
});
|
|
1290
|
+
|
|
1262
1291
|
test("pipe", () => {
|
|
1263
1292
|
const mySchema = z
|
|
1264
1293
|
.string()
|
|
@@ -1717,16 +1746,17 @@ test("basic registry", () => {
|
|
|
1717
1746
|
myRegistry.add(User, { id: "User" });
|
|
1718
1747
|
myRegistry.add(Post, { id: "Post" });
|
|
1719
1748
|
|
|
1720
|
-
const result = z.z.toJSONSchema(myRegistry);
|
|
1749
|
+
const result = z.z.toJSONSchema(myRegistry, { uri: (id) => `https://example.com/${id}.json` });
|
|
1721
1750
|
expect(result).toMatchInlineSnapshot(`
|
|
1722
1751
|
{
|
|
1723
1752
|
"schemas": {
|
|
1724
1753
|
"Post": {
|
|
1754
|
+
"$id": "https://example.com/Post.json",
|
|
1725
1755
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
1726
1756
|
"additionalProperties": false,
|
|
1727
1757
|
"properties": {
|
|
1728
1758
|
"author": {
|
|
1729
|
-
"$ref": "User",
|
|
1759
|
+
"$ref": "https://example.com/User.json",
|
|
1730
1760
|
},
|
|
1731
1761
|
"content": {
|
|
1732
1762
|
"type": "string",
|
|
@@ -1743,6 +1773,7 @@ test("basic registry", () => {
|
|
|
1743
1773
|
"type": "object",
|
|
1744
1774
|
},
|
|
1745
1775
|
"User": {
|
|
1776
|
+
"$id": "https://example.com/User.json",
|
|
1746
1777
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
1747
1778
|
"additionalProperties": false,
|
|
1748
1779
|
"properties": {
|
|
@@ -1751,7 +1782,7 @@ test("basic registry", () => {
|
|
|
1751
1782
|
},
|
|
1752
1783
|
"posts": {
|
|
1753
1784
|
"items": {
|
|
1754
|
-
"$ref": "Post",
|
|
1785
|
+
"$ref": "https://example.com/Post.json",
|
|
1755
1786
|
},
|
|
1756
1787
|
"type": "array",
|
|
1757
1788
|
},
|
|
@@ -1858,9 +1889,8 @@ test("input type", () => {
|
|
|
1858
1889
|
e: z.string().prefault("hello"),
|
|
1859
1890
|
f: z.string().catch("hello"),
|
|
1860
1891
|
g: z.never(),
|
|
1861
|
-
h: z.
|
|
1862
|
-
i: z.union([z.string(), z.
|
|
1863
|
-
j: z.union([z.string(), z.string().optional()]),
|
|
1892
|
+
h: z.union([z.string(), z.number().default(2)]),
|
|
1893
|
+
i: z.union([z.string(), z.string().optional()]),
|
|
1864
1894
|
});
|
|
1865
1895
|
expect(z.toJSONSchema(schema, { io: "input" })).toMatchInlineSnapshot(`
|
|
1866
1896
|
{
|
|
@@ -1898,9 +1928,6 @@ test("input type", () => {
|
|
|
1898
1928
|
"not": {},
|
|
1899
1929
|
},
|
|
1900
1930
|
"h": {
|
|
1901
|
-
"not": {},
|
|
1902
|
-
},
|
|
1903
|
-
"i": {
|
|
1904
1931
|
"anyOf": [
|
|
1905
1932
|
{
|
|
1906
1933
|
"type": "string",
|
|
@@ -1911,7 +1938,7 @@ test("input type", () => {
|
|
|
1911
1938
|
},
|
|
1912
1939
|
],
|
|
1913
1940
|
},
|
|
1914
|
-
"
|
|
1941
|
+
"i": {
|
|
1915
1942
|
"anyOf": [
|
|
1916
1943
|
{
|
|
1917
1944
|
"type": "string",
|
|
@@ -1966,9 +1993,6 @@ test("input type", () => {
|
|
|
1966
1993
|
"not": {},
|
|
1967
1994
|
},
|
|
1968
1995
|
"h": {
|
|
1969
|
-
"not": {},
|
|
1970
|
-
},
|
|
1971
|
-
"i": {
|
|
1972
1996
|
"anyOf": [
|
|
1973
1997
|
{
|
|
1974
1998
|
"type": "string",
|
|
@@ -1979,7 +2003,7 @@ test("input type", () => {
|
|
|
1979
2003
|
},
|
|
1980
2004
|
],
|
|
1981
2005
|
},
|
|
1982
|
-
"
|
|
2006
|
+
"i": {
|
|
1983
2007
|
"anyOf": [
|
|
1984
2008
|
{
|
|
1985
2009
|
"type": "string",
|
|
@@ -1997,7 +2021,7 @@ test("input type", () => {
|
|
|
1997
2021
|
"e",
|
|
1998
2022
|
"f",
|
|
1999
2023
|
"g",
|
|
2000
|
-
"
|
|
2024
|
+
"h",
|
|
2001
2025
|
],
|
|
2002
2026
|
"type": "object",
|
|
2003
2027
|
}
|
|
@@ -2251,3 +2275,40 @@ test("custom toJSONSchema", () => {
|
|
|
2251
2275
|
}
|
|
2252
2276
|
`);
|
|
2253
2277
|
});
|
|
2278
|
+
|
|
2279
|
+
test("cycle detection - root", () => {
|
|
2280
|
+
const schema = z.object({
|
|
2281
|
+
name: z.string(),
|
|
2282
|
+
get subcategories() {
|
|
2283
|
+
return z.array(schema);
|
|
2284
|
+
},
|
|
2285
|
+
});
|
|
2286
|
+
|
|
2287
|
+
expect(() => z.toJSONSchema(schema, { cycles: "throw" })).toThrowErrorMatchingInlineSnapshot(`
|
|
2288
|
+
[Error: Cycle detected: #/properties/subcategories/items/<root>
|
|
2289
|
+
|
|
2290
|
+
Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.]
|
|
2291
|
+
`);
|
|
2292
|
+
});
|
|
2293
|
+
|
|
2294
|
+
test("cycle detection - mutual recursion", () => {
|
|
2295
|
+
const A = z.object({
|
|
2296
|
+
name: z.string(),
|
|
2297
|
+
get subcategories() {
|
|
2298
|
+
return z.array(B);
|
|
2299
|
+
},
|
|
2300
|
+
});
|
|
2301
|
+
|
|
2302
|
+
const B = z.object({
|
|
2303
|
+
name: z.string(),
|
|
2304
|
+
get subcategories() {
|
|
2305
|
+
return z.array(A);
|
|
2306
|
+
},
|
|
2307
|
+
});
|
|
2308
|
+
|
|
2309
|
+
expect(() => z.toJSONSchema(A, { cycles: "throw" })).toThrowErrorMatchingInlineSnapshot(`
|
|
2310
|
+
[Error: Cycle detected: #/properties/subcategories/items/properties/subcategories/items/<root>
|
|
2311
|
+
|
|
2312
|
+
Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.]
|
|
2313
|
+
`);
|
|
2314
|
+
});
|
package/src/v4/core/api.ts
CHANGED
|
@@ -779,6 +779,8 @@ export function _nan<T extends schemas.$ZodNaN>(Class: util.SchemaClass<T>, para
|
|
|
779
779
|
});
|
|
780
780
|
}
|
|
781
781
|
|
|
782
|
+
// export type $ZodCheckParams = CheckParams<checks.$ZodCheck, "abort">;
|
|
783
|
+
|
|
782
784
|
export type $ZodCheckLessThanParams = CheckParams<checks.$ZodCheckLessThan, "inclusive" | "value">;
|
|
783
785
|
export function _lt(
|
|
784
786
|
value: util.Numeric,
|
package/src/v4/core/checks.ts
CHANGED
|
@@ -13,18 +13,16 @@ export interface $ZodCheckDef {
|
|
|
13
13
|
error?: errors.$ZodErrorMap<never> | undefined;
|
|
14
14
|
/** If true, no later checks will be executed if this check fails. Default `false`. */
|
|
15
15
|
abort?: boolean | undefined;
|
|
16
|
+
/** If provided, this check will only be executed if the function returns `true`. Defaults to `payload => z.util.isAborted(payload)`. */
|
|
17
|
+
when?: ((payload: schemas.ParsePayload) => boolean) | undefined;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export interface $ZodCheckInternals<T> {
|
|
19
21
|
def: $ZodCheckDef;
|
|
20
22
|
/** The set of issues this check might throw. */
|
|
21
23
|
issc?: errors.$ZodIssueBase;
|
|
22
|
-
// "_check"(input: $ZodResult<T>): util.MaybeAsync<void>;
|
|
23
24
|
check(payload: schemas.ParsePayload<T>): util.MaybeAsync<void>;
|
|
24
|
-
// _parseB(payload: ParsePayload<any>, ctx: ParseContext): util.MaybeAsync<ParsePayload>;
|
|
25
25
|
onattach: ((schema: schemas.$ZodType) => void)[];
|
|
26
|
-
// "_async": boolean;
|
|
27
|
-
when?: ((payload: schemas.ParsePayload) => boolean) | undefined;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
export interface $ZodCheck<in T = never> {
|
|
@@ -452,7 +450,7 @@ export const $ZodCheckMaxSize: core.$constructor<$ZodCheckMaxSize> = /*@__PURE__
|
|
|
452
450
|
(inst, def) => {
|
|
453
451
|
$ZodCheck.init(inst, def);
|
|
454
452
|
|
|
455
|
-
inst._zod.when
|
|
453
|
+
inst._zod.def.when ??= (payload) => {
|
|
456
454
|
const val = payload.value;
|
|
457
455
|
return !util.nullish(val) && (val as any).size !== undefined;
|
|
458
456
|
};
|
|
@@ -501,7 +499,7 @@ export const $ZodCheckMinSize: core.$constructor<$ZodCheckMinSize> = /*@__PURE__
|
|
|
501
499
|
(inst, def) => {
|
|
502
500
|
$ZodCheck.init(inst, def);
|
|
503
501
|
|
|
504
|
-
inst._zod.when
|
|
502
|
+
inst._zod.def.when ??= (payload) => {
|
|
505
503
|
const val = payload.value;
|
|
506
504
|
return !util.nullish(val) && (val as any).size !== undefined;
|
|
507
505
|
};
|
|
@@ -550,7 +548,7 @@ export const $ZodCheckSizeEquals: core.$constructor<$ZodCheckSizeEquals> = /*@__
|
|
|
550
548
|
(inst, def) => {
|
|
551
549
|
$ZodCheck.init(inst, def);
|
|
552
550
|
|
|
553
|
-
inst._zod.when
|
|
551
|
+
inst._zod.def.when ??= (payload) => {
|
|
554
552
|
const val = payload.value;
|
|
555
553
|
return !util.nullish(val) && (val as any).size !== undefined;
|
|
556
554
|
};
|
|
@@ -604,7 +602,7 @@ export const $ZodCheckMaxLength: core.$constructor<$ZodCheckMaxLength> = /*@__PU
|
|
|
604
602
|
(inst, def) => {
|
|
605
603
|
$ZodCheck.init(inst, def);
|
|
606
604
|
|
|
607
|
-
inst._zod.when
|
|
605
|
+
inst._zod.def.when ??= (payload) => {
|
|
608
606
|
const val = payload.value;
|
|
609
607
|
return !util.nullish(val) && (val as any).length !== undefined;
|
|
610
608
|
};
|
|
@@ -655,7 +653,7 @@ export const $ZodCheckMinLength: core.$constructor<$ZodCheckMinLength> = /*@__PU
|
|
|
655
653
|
(inst, def) => {
|
|
656
654
|
$ZodCheck.init(inst, def);
|
|
657
655
|
|
|
658
|
-
inst._zod.when
|
|
656
|
+
inst._zod.def.when ??= (payload) => {
|
|
659
657
|
const val = payload.value;
|
|
660
658
|
return !util.nullish(val) && (val as any).length !== undefined;
|
|
661
659
|
};
|
|
@@ -707,7 +705,7 @@ export const $ZodCheckLengthEquals: core.$constructor<$ZodCheckLengthEquals> = /
|
|
|
707
705
|
(inst, def) => {
|
|
708
706
|
$ZodCheck.init(inst, def);
|
|
709
707
|
|
|
710
|
-
inst._zod.when
|
|
708
|
+
inst._zod.def.when ??= (payload) => {
|
|
711
709
|
const val = payload.value;
|
|
712
710
|
return !util.nullish(val) && (val as any).length !== undefined;
|
|
713
711
|
};
|
package/src/v4/core/errors.ts
CHANGED
|
@@ -203,6 +203,10 @@ const initializer = (inst: $ZodError, def: $ZodIssue[]): void => {
|
|
|
203
203
|
enumerable: true,
|
|
204
204
|
// configurable: false,
|
|
205
205
|
});
|
|
206
|
+
Object.defineProperty(inst, "toString", {
|
|
207
|
+
value: () => inst.message,
|
|
208
|
+
enumerable: false,
|
|
209
|
+
});
|
|
206
210
|
};
|
|
207
211
|
|
|
208
212
|
export const $ZodError: $constructor<$ZodError> = $constructor("$ZodError", initializer);
|