zod 4.0.4 → 4.0.6
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/v3/tests/string.test.ts +2 -2
- package/src/v3/types.ts +3 -1
- package/src/v4/classic/compat.ts +2 -39
- package/src/v4/classic/errors.ts +9 -2
- package/src/v4/classic/schemas.ts +11 -9
- package/src/v4/classic/tests/catch.test.ts +4 -5
- package/src/v4/classic/tests/discriminated-unions.test.ts +41 -0
- package/src/v4/classic/tests/error-utils.test.ts +43 -0
- package/src/v4/classic/tests/literal.test.ts +25 -0
- package/src/v4/classic/tests/partial.test.ts +193 -0
- package/src/v4/classic/tests/pickomit.test.ts +5 -5
- package/src/v4/classic/tests/preprocess.test.ts +4 -15
- package/src/v4/classic/tests/record.test.ts +15 -1
- package/src/v4/classic/tests/recursive-types.test.ts +67 -0
- package/src/v4/classic/tests/string.test.ts +81 -4
- package/src/v4/classic/tests/template-literal.test.ts +3 -0
- package/src/v4/classic/tests/to-json-schema.test.ts +1 -0
- package/src/v4/classic/tests/transform.test.ts +110 -0
- package/src/v4/classic/tests/union.test.ts +45 -3
- package/src/v4/core/checks.ts +2 -2
- package/src/v4/core/errors.ts +8 -15
- package/src/v4/core/regexes.ts +1 -1
- package/src/v4/core/registries.ts +3 -2
- package/src/v4/core/schemas.ts +93 -99
- package/src/v4/core/to-json-schema.ts +1 -0
- package/src/v4/core/util.ts +175 -115
- package/src/v4/core/versions.ts +1 -1
- package/src/v4/locales/bg.ts +136 -0
- package/src/v4/locales/da.ts +141 -0
- package/src/v4/locales/index.ts +2 -0
- package/src/v4/locales/is.ts +127 -0
- package/src/v4/mini/schemas.ts +3 -1
- package/v3/types.cjs +2 -0
- package/v3/types.d.cts +4 -1
- package/v3/types.d.ts +4 -1
- package/v3/types.js +2 -0
- package/v4/classic/compat.cjs +1 -37
- package/v4/classic/compat.d.cts +1 -37
- package/v4/classic/compat.d.ts +1 -37
- package/v4/classic/compat.js +1 -37
- package/v4/classic/errors.cjs +9 -2
- package/v4/classic/errors.js +9 -2
- package/v4/classic/schemas.cjs +5 -3
- package/v4/classic/schemas.d.cts +3 -3
- package/v4/classic/schemas.d.ts +3 -3
- package/v4/classic/schemas.js +5 -3
- package/v4/core/checks.d.cts +2 -2
- package/v4/core/checks.d.ts +2 -2
- package/v4/core/errors.cjs +4 -9
- package/v4/core/errors.d.cts +4 -6
- package/v4/core/errors.d.ts +4 -6
- package/v4/core/errors.js +4 -9
- package/v4/core/regexes.cjs +1 -1
- package/v4/core/regexes.d.cts +1 -1
- package/v4/core/regexes.d.ts +1 -1
- package/v4/core/regexes.js +1 -1
- package/v4/core/registries.cjs +2 -1
- package/v4/core/registries.d.cts +1 -1
- package/v4/core/registries.d.ts +1 -1
- package/v4/core/registries.js +2 -1
- package/v4/core/schemas.cjs +49 -88
- package/v4/core/schemas.d.cts +10 -4
- package/v4/core/schemas.d.ts +10 -4
- package/v4/core/schemas.js +49 -88
- package/v4/core/to-json-schema.cjs +1 -0
- package/v4/core/to-json-schema.js +1 -0
- package/v4/core/util.cjs +163 -112
- package/v4/core/util.d.cts +1 -0
- package/v4/core/util.d.ts +1 -0
- package/v4/core/util.js +162 -112
- package/v4/core/versions.cjs +1 -1
- package/v4/core/versions.js +1 -1
- package/v4/locales/bg.cjs +156 -0
- package/v4/locales/bg.d.cts +5 -0
- package/v4/locales/bg.d.ts +5 -0
- package/v4/locales/bg.js +128 -0
- package/v4/locales/da.cjs +157 -0
- package/v4/locales/da.d.cts +4 -0
- package/v4/locales/da.d.ts +4 -0
- package/v4/locales/da.js +131 -0
- package/v4/locales/index.cjs +5 -1
- package/v4/locales/index.d.cts +2 -0
- package/v4/locales/index.d.ts +2 -0
- package/v4/locales/index.js +2 -0
- package/v4/locales/is.cjs +145 -0
- package/v4/locales/is.d.cts +5 -0
- package/v4/locales/is.d.ts +5 -0
- package/v4/locales/is.js +117 -0
- package/v4/mini/schemas.cjs +3 -1
- package/v4/mini/schemas.js +3 -1
package/package.json
CHANGED
|
@@ -342,8 +342,8 @@ test("uuid", () => {
|
|
|
342
342
|
uuid.parse("9491d710-3185-4e06-bea0-6a2f275345e0");
|
|
343
343
|
uuid.parse("d89e7b01-7598-ed11-9d7a-0022489382fd"); // new sequential id
|
|
344
344
|
uuid.parse("00000000-0000-0000-0000-000000000000");
|
|
345
|
-
uuid.parse("b3ce60f8-e8b9-40f5-1150-172ede56ff74"); // Variant 0 - RFC 4122: Reserved, NCS backward compatibility
|
|
346
|
-
uuid.parse("92e76bf9-28b3-4730-cd7f-cb6bc51f8c09"); // Variant 2 - RFC 4122: Reserved, Microsoft Corporation backward compatibility
|
|
345
|
+
uuid.parse("b3ce60f8-e8b9-40f5-1150-172ede56ff74"); // Variant 0 - RFC 9562/4122: Reserved, NCS backward compatibility
|
|
346
|
+
uuid.parse("92e76bf9-28b3-4730-cd7f-cb6bc51f8c09"); // Variant 2 - RFC 9562/4122: Reserved, Microsoft Corporation backward compatibility
|
|
347
347
|
const result = uuid.safeParse("9491d710-3185-4e06-bea0-6a2f275345e0X");
|
|
348
348
|
expect(result.success).toEqual(false);
|
|
349
349
|
if (!result.success) {
|
package/src/v3/types.ts
CHANGED
|
@@ -705,6 +705,7 @@ function isValidJWT(jwt: string, alg?: string): boolean {
|
|
|
705
705
|
.replace(/-/g, "+")
|
|
706
706
|
.replace(/_/g, "/")
|
|
707
707
|
.padEnd(header.length + ((4 - (header.length % 4)) % 4), "=");
|
|
708
|
+
// @ts-ignore
|
|
708
709
|
const decoded = JSON.parse(atob(base64));
|
|
709
710
|
if (typeof decoded !== "object" || decoded === null) return false;
|
|
710
711
|
if ("typ" in decoded && decoded?.typ !== "JWT") return false;
|
|
@@ -875,6 +876,7 @@ export class ZodString extends ZodType<string, ZodStringDef, string> {
|
|
|
875
876
|
}
|
|
876
877
|
} else if (check.kind === "url") {
|
|
877
878
|
try {
|
|
879
|
+
// @ts-ignore
|
|
878
880
|
new URL(input.data);
|
|
879
881
|
} catch {
|
|
880
882
|
ctx = this._getOrReturnCtx(input, ctx);
|
|
@@ -2454,7 +2456,7 @@ export class ZodObject<
|
|
|
2454
2456
|
Output = objectOutputType<T, Catchall, UnknownKeys>,
|
|
2455
2457
|
Input = objectInputType<T, Catchall, UnknownKeys>,
|
|
2456
2458
|
> extends ZodType<Output, ZodObjectDef<T, UnknownKeys, Catchall>, Input> {
|
|
2457
|
-
|
|
2459
|
+
_cached: { shape: T; keys: string[] } | null = null;
|
|
2458
2460
|
|
|
2459
2461
|
_getCached(): { shape: T; keys: string[] } {
|
|
2460
2462
|
if (this._cached !== null) return this._cached;
|
package/src/v4/classic/compat.ts
CHANGED
|
@@ -66,42 +66,5 @@ export type {
|
|
|
66
66
|
/** Included for Zod 3 compatibility */
|
|
67
67
|
export type ZodRawShape = core.$ZodShape;
|
|
68
68
|
|
|
69
|
-
/** @deprecated Do not use.
|
|
70
|
-
export enum ZodFirstPartyTypeKind {
|
|
71
|
-
ZodString = "ZodString",
|
|
72
|
-
ZodNumber = "ZodNumber",
|
|
73
|
-
ZodNaN = "ZodNaN",
|
|
74
|
-
ZodBigInt = "ZodBigInt",
|
|
75
|
-
ZodBoolean = "ZodBoolean",
|
|
76
|
-
ZodDate = "ZodDate",
|
|
77
|
-
ZodSymbol = "ZodSymbol",
|
|
78
|
-
ZodUndefined = "ZodUndefined",
|
|
79
|
-
ZodNull = "ZodNull",
|
|
80
|
-
ZodAny = "ZodAny",
|
|
81
|
-
ZodUnknown = "ZodUnknown",
|
|
82
|
-
ZodNever = "ZodNever",
|
|
83
|
-
ZodVoid = "ZodVoid",
|
|
84
|
-
ZodArray = "ZodArray",
|
|
85
|
-
ZodObject = "ZodObject",
|
|
86
|
-
ZodUnion = "ZodUnion",
|
|
87
|
-
ZodDiscriminatedUnion = "ZodDiscriminatedUnion",
|
|
88
|
-
ZodIntersection = "ZodIntersection",
|
|
89
|
-
ZodTuple = "ZodTuple",
|
|
90
|
-
ZodRecord = "ZodRecord",
|
|
91
|
-
ZodMap = "ZodMap",
|
|
92
|
-
ZodSet = "ZodSet",
|
|
93
|
-
ZodFunction = "ZodFunction",
|
|
94
|
-
ZodLazy = "ZodLazy",
|
|
95
|
-
ZodLiteral = "ZodLiteral",
|
|
96
|
-
ZodEnum = "ZodEnum",
|
|
97
|
-
ZodEffects = "ZodEffects",
|
|
98
|
-
ZodNativeEnum = "ZodNativeEnum",
|
|
99
|
-
ZodOptional = "ZodOptional",
|
|
100
|
-
ZodNullable = "ZodNullable",
|
|
101
|
-
ZodDefault = "ZodDefault",
|
|
102
|
-
ZodCatch = "ZodCatch",
|
|
103
|
-
ZodPromise = "ZodPromise",
|
|
104
|
-
ZodBranded = "ZodBranded",
|
|
105
|
-
ZodPipeline = "ZodPipeline",
|
|
106
|
-
ZodReadonly = "ZodReadonly",
|
|
107
|
-
}
|
|
69
|
+
/** @deprecated Do not use. Stub definition, only included for zod-to-json-schema compatibility. */
|
|
70
|
+
export enum ZodFirstPartyTypeKind {}
|
package/src/v4/classic/errors.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as core from "../core/index.js";
|
|
2
2
|
import { $ZodError } from "../core/index.js";
|
|
3
|
+
import * as util from "../core/util.js";
|
|
3
4
|
|
|
4
5
|
/** @deprecated Use `z.core.$ZodIssue` from `@zod/core` instead, especially if you are building a library on top of Zod. */
|
|
5
6
|
export type ZodIssue = core.$ZodIssue;
|
|
@@ -34,11 +35,17 @@ const initializer = (inst: ZodError, issues: core.$ZodIssue[]) => {
|
|
|
34
35
|
// enumerable: false,
|
|
35
36
|
},
|
|
36
37
|
addIssue: {
|
|
37
|
-
value: (issue: any) =>
|
|
38
|
+
value: (issue: any) => {
|
|
39
|
+
inst.issues.push(issue);
|
|
40
|
+
inst.message = JSON.stringify(inst.issues, util.jsonStringifyReplacer, 2);
|
|
41
|
+
},
|
|
38
42
|
// enumerable: false,
|
|
39
43
|
},
|
|
40
44
|
addIssues: {
|
|
41
|
-
value: (issues: any) =>
|
|
45
|
+
value: (issues: any) => {
|
|
46
|
+
inst.issues.push(...issues);
|
|
47
|
+
inst.message = JSON.stringify(inst.issues, util.jsonStringifyReplacer, 2);
|
|
48
|
+
},
|
|
42
49
|
// enumerable: false,
|
|
43
50
|
},
|
|
44
51
|
isEmpty: {
|
|
@@ -61,8 +61,6 @@ export interface ZodType<
|
|
|
61
61
|
|
|
62
62
|
// refinements
|
|
63
63
|
refine(check: (arg: core.output<this>) => unknown | Promise<unknown>, params?: string | core.$ZodCustomParams): this;
|
|
64
|
-
/** @deprecated Use [`.check()`](https://zod.dev/api?id=check) instead.
|
|
65
|
-
*/
|
|
66
64
|
superRefine(
|
|
67
65
|
refinement: (arg: core.output<this>, ctx: RefinementCtx<core.output<this>>) => void | Promise<void>
|
|
68
66
|
): this;
|
|
@@ -1070,9 +1068,7 @@ export interface ZodObject<
|
|
|
1070
1068
|
/** This is the default behavior. This method call is likely unnecessary. */
|
|
1071
1069
|
strip(): ZodObject<Shape, core.$strip>;
|
|
1072
1070
|
|
|
1073
|
-
extend<U extends core.$ZodLooseShape
|
|
1074
|
-
shape: U
|
|
1075
|
-
): ZodObject<util.Extend<Shape, U>, Config>;
|
|
1071
|
+
extend<U extends core.$ZodLooseShape>(shape: U): ZodObject<util.Extend<Shape, U>, Config>;
|
|
1076
1072
|
|
|
1077
1073
|
/**
|
|
1078
1074
|
* @deprecated Use [`A.extend(B.shape)`](https://zod.dev/api?id=extend) instead.
|
|
@@ -1132,7 +1128,6 @@ export const ZodObject: core.$constructor<ZodObject> = /*@__PURE__*/ core.$const
|
|
|
1132
1128
|
inst.keyof = () => _enum(Object.keys(inst._zod.def.shape)) as any;
|
|
1133
1129
|
inst.catchall = (catchall) => inst.clone({ ...inst._zod.def, catchall: catchall as any as core.$ZodType }) as any;
|
|
1134
1130
|
inst.passthrough = () => inst.clone({ ...inst._zod.def, catchall: unknown() });
|
|
1135
|
-
// inst.nonstrict = () => inst.clone({ ...inst._zod.def, catchall: api.unknown() });
|
|
1136
1131
|
inst.loose = () => inst.clone({ ...inst._zod.def, catchall: unknown() });
|
|
1137
1132
|
inst.strict = () => inst.clone({ ...inst._zod.def, catchall: never() });
|
|
1138
1133
|
inst.strip = () => inst.clone({ ...inst._zod.def, catchall: undefined });
|
|
@@ -1224,6 +1219,7 @@ export interface ZodDiscriminatedUnion<Options extends readonly core.SomeType[]
|
|
|
1224
1219
|
extends ZodUnion<Options>,
|
|
1225
1220
|
core.$ZodDiscriminatedUnion<Options> {
|
|
1226
1221
|
_zod: core.$ZodDiscriminatedUnionInternals<Options>;
|
|
1222
|
+
def: core.$ZodDiscriminatedUnionDef<Options>;
|
|
1227
1223
|
}
|
|
1228
1224
|
export const ZodDiscriminatedUnion: core.$constructor<ZodDiscriminatedUnion> = /*@__PURE__*/ core.$constructor(
|
|
1229
1225
|
"ZodDiscriminatedUnion",
|
|
@@ -1351,9 +1347,11 @@ export function partialRecord<Key extends core.$ZodRecordKey, Value extends core
|
|
|
1351
1347
|
valueType: Value,
|
|
1352
1348
|
params?: string | core.$ZodRecordParams
|
|
1353
1349
|
): ZodRecord<Key & core.$partial, Value> {
|
|
1350
|
+
const k = core.clone(keyType);
|
|
1351
|
+
k._zod.values = undefined;
|
|
1354
1352
|
return new ZodRecord({
|
|
1355
1353
|
type: "record",
|
|
1356
|
-
keyType:
|
|
1354
|
+
keyType: k,
|
|
1357
1355
|
valueType: valueType as any,
|
|
1358
1356
|
...util.normalizeParams(params),
|
|
1359
1357
|
}) as any;
|
|
@@ -1585,7 +1583,7 @@ export const ZodTransform: core.$constructor<ZodTransform> = /*@__PURE__*/ core.
|
|
|
1585
1583
|
_issue.code ??= "custom";
|
|
1586
1584
|
_issue.input ??= payload.value;
|
|
1587
1585
|
_issue.inst ??= inst;
|
|
1588
|
-
_issue.continue ??= true;
|
|
1586
|
+
// _issue.continue ??= true;
|
|
1589
1587
|
payload.issues.push(util.issue(_issue));
|
|
1590
1588
|
}
|
|
1591
1589
|
};
|
|
@@ -1839,12 +1837,16 @@ export function pipe(in_: core.SomeType, out: core.SomeType) {
|
|
|
1839
1837
|
// ZodReadonly
|
|
1840
1838
|
export interface ZodReadonly<T extends core.SomeType = core.$ZodType>
|
|
1841
1839
|
extends _ZodType<core.$ZodReadonlyInternals<T>>,
|
|
1842
|
-
core.$ZodReadonly<T> {
|
|
1840
|
+
core.$ZodReadonly<T> {
|
|
1841
|
+
unwrap(): T;
|
|
1842
|
+
}
|
|
1843
1843
|
export const ZodReadonly: core.$constructor<ZodReadonly> = /*@__PURE__*/ core.$constructor(
|
|
1844
1844
|
"ZodReadonly",
|
|
1845
1845
|
(inst, def) => {
|
|
1846
1846
|
core.$ZodReadonly.init(inst, def);
|
|
1847
1847
|
ZodType.init(inst, def);
|
|
1848
|
+
|
|
1849
|
+
inst.unwrap = () => inst._zod.def.innerType;
|
|
1848
1850
|
}
|
|
1849
1851
|
);
|
|
1850
1852
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { expect, expectTypeOf, test } from "vitest";
|
|
2
2
|
import { z } from "zod/v4";
|
|
3
|
-
import type { util } from "zod/v4/core";
|
|
4
3
|
|
|
5
4
|
test("basic catch", () => {
|
|
6
5
|
expect(z.string().catch("default").parse(undefined)).toBe("default");
|
|
@@ -45,7 +44,7 @@ test("catch with transform", () => {
|
|
|
45
44
|
expect(stringWithDefault.unwrap().out).toBeInstanceOf(z.ZodTransform);
|
|
46
45
|
|
|
47
46
|
type inp = z.input<typeof stringWithDefault>;
|
|
48
|
-
expectTypeOf<inp>().toEqualTypeOf<string
|
|
47
|
+
expectTypeOf<inp>().toEqualTypeOf<string>();
|
|
49
48
|
type out = z.output<typeof stringWithDefault>;
|
|
50
49
|
expectTypeOf<out>().toEqualTypeOf<string>();
|
|
51
50
|
});
|
|
@@ -59,7 +58,7 @@ test("catch on existing optional", () => {
|
|
|
59
58
|
expect(stringWithDefault.unwrap().unwrap()).toBeInstanceOf(z.ZodString);
|
|
60
59
|
|
|
61
60
|
type inp = z.input<typeof stringWithDefault>;
|
|
62
|
-
expectTypeOf<inp>().toEqualTypeOf<string | undefined
|
|
61
|
+
expectTypeOf<inp>().toEqualTypeOf<string | undefined>();
|
|
63
62
|
type out = z.output<typeof stringWithDefault>;
|
|
64
63
|
expectTypeOf<out>().toEqualTypeOf<string | undefined>();
|
|
65
64
|
});
|
|
@@ -68,7 +67,7 @@ test("optional on catch", () => {
|
|
|
68
67
|
const stringWithDefault = z.string().catch("asdf").optional();
|
|
69
68
|
|
|
70
69
|
type inp = z.input<typeof stringWithDefault>;
|
|
71
|
-
expectTypeOf<inp>().toEqualTypeOf<string |
|
|
70
|
+
expectTypeOf<inp>().toEqualTypeOf<string | undefined>();
|
|
72
71
|
type out = z.output<typeof stringWithDefault>;
|
|
73
72
|
expectTypeOf<out>().toEqualTypeOf<string | undefined>();
|
|
74
73
|
});
|
|
@@ -102,7 +101,7 @@ test("nested", () => {
|
|
|
102
101
|
inner: "asdf",
|
|
103
102
|
});
|
|
104
103
|
type input = z.input<typeof outer>;
|
|
105
|
-
expectTypeOf<input>().toEqualTypeOf<{ inner: string
|
|
104
|
+
expectTypeOf<input>().toEqualTypeOf<{ inner: string }>();
|
|
106
105
|
type out = z.output<typeof outer>;
|
|
107
106
|
|
|
108
107
|
expectTypeOf<out>().toEqualTypeOf<{ inner: string }>();
|
|
@@ -617,3 +617,44 @@ test("readonly literal discriminator", () => {
|
|
|
617
617
|
discUnion.parse({ type: "c", a: "hello" });
|
|
618
618
|
}).toThrow();
|
|
619
619
|
});
|
|
620
|
+
|
|
621
|
+
test("pipes", () => {
|
|
622
|
+
const schema = z
|
|
623
|
+
.object({
|
|
624
|
+
type: z.literal("foo"),
|
|
625
|
+
})
|
|
626
|
+
.transform((s) => ({ ...s, v: 2 }));
|
|
627
|
+
|
|
628
|
+
expect(schema._zod.propValues).toMatchInlineSnapshot(`
|
|
629
|
+
{
|
|
630
|
+
"type": Set {
|
|
631
|
+
"foo",
|
|
632
|
+
},
|
|
633
|
+
}
|
|
634
|
+
`);
|
|
635
|
+
|
|
636
|
+
const schema2 = z.object({
|
|
637
|
+
type: z.literal("bar"),
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
const combinedSchema = z.discriminatedUnion("type", [schema, schema2], {
|
|
641
|
+
unionFallback: false,
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
combinedSchema.parse({
|
|
645
|
+
type: "foo",
|
|
646
|
+
v: 2,
|
|
647
|
+
});
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
test("def", () => {
|
|
651
|
+
const schema = z.discriminatedUnion(
|
|
652
|
+
"type",
|
|
653
|
+
[z.object({ type: z.literal("play") }), z.object({ type: z.literal("pause") })],
|
|
654
|
+
{ unionFallback: true }
|
|
655
|
+
);
|
|
656
|
+
|
|
657
|
+
expect(schema.def).toBeDefined();
|
|
658
|
+
expect(schema.def.discriminator).toEqual("type");
|
|
659
|
+
expect(schema.def.unionFallback).toEqual(true);
|
|
660
|
+
});
|
|
@@ -550,3 +550,46 @@ test("disc union treeify/format", () => {
|
|
|
550
550
|
}
|
|
551
551
|
`);
|
|
552
552
|
});
|
|
553
|
+
|
|
554
|
+
test("update message after adding issues", () => {
|
|
555
|
+
const e = new z.ZodError([]);
|
|
556
|
+
e.addIssue({
|
|
557
|
+
code: "custom",
|
|
558
|
+
message: "message",
|
|
559
|
+
input: "asdf",
|
|
560
|
+
path: [],
|
|
561
|
+
});
|
|
562
|
+
expect(e.message).toMatchInlineSnapshot(`
|
|
563
|
+
"[
|
|
564
|
+
{
|
|
565
|
+
"code": "custom",
|
|
566
|
+
"message": "message",
|
|
567
|
+
"input": "asdf",
|
|
568
|
+
"path": []
|
|
569
|
+
}
|
|
570
|
+
]"
|
|
571
|
+
`);
|
|
572
|
+
|
|
573
|
+
e.addIssue({
|
|
574
|
+
code: "custom",
|
|
575
|
+
message: "message",
|
|
576
|
+
input: "asdf",
|
|
577
|
+
path: [],
|
|
578
|
+
});
|
|
579
|
+
expect(e.message).toMatchInlineSnapshot(`
|
|
580
|
+
"[
|
|
581
|
+
{
|
|
582
|
+
"code": "custom",
|
|
583
|
+
"message": "message",
|
|
584
|
+
"input": "asdf",
|
|
585
|
+
"path": []
|
|
586
|
+
},
|
|
587
|
+
{
|
|
588
|
+
"code": "custom",
|
|
589
|
+
"message": "message",
|
|
590
|
+
"input": "asdf",
|
|
591
|
+
"path": []
|
|
592
|
+
}
|
|
593
|
+
]"
|
|
594
|
+
`);
|
|
595
|
+
});
|
|
@@ -90,3 +90,28 @@ test("readonly", () => {
|
|
|
90
90
|
const a = ["asdf"] as const;
|
|
91
91
|
z.literal(a);
|
|
92
92
|
});
|
|
93
|
+
|
|
94
|
+
test("literal pattern", () => {
|
|
95
|
+
expect(z.literal(1.1)._zod.pattern).toMatchInlineSnapshot(`/\\^\\(1\\\\\\.1\\)\\$/`);
|
|
96
|
+
|
|
97
|
+
expect(z.templateLiteral([z.literal(1.1)]).safeParse("1.1")).toMatchInlineSnapshot(`
|
|
98
|
+
{
|
|
99
|
+
"data": "1.1",
|
|
100
|
+
"success": true,
|
|
101
|
+
}
|
|
102
|
+
`);
|
|
103
|
+
expect(z.templateLiteral([z.literal(1.1)]).safeParse("1n1")).toMatchInlineSnapshot(`
|
|
104
|
+
{
|
|
105
|
+
"error": [ZodError: [
|
|
106
|
+
{
|
|
107
|
+
"code": "invalid_format",
|
|
108
|
+
"format": "template_literal",
|
|
109
|
+
"pattern": "^(1\\\\.1)$",
|
|
110
|
+
"path": [],
|
|
111
|
+
"message": "Invalid input"
|
|
112
|
+
}
|
|
113
|
+
]],
|
|
114
|
+
"success": false,
|
|
115
|
+
}
|
|
116
|
+
`);
|
|
117
|
+
});
|
|
@@ -145,3 +145,196 @@ test("partial with mask -- ignore falsy values", async () => {
|
|
|
145
145
|
masked.parse({ country: "US" });
|
|
146
146
|
await masked.parseAsync({ country: "US" });
|
|
147
147
|
});
|
|
148
|
+
|
|
149
|
+
test("catch/prefault/default", () => {
|
|
150
|
+
const mySchema = z.object({
|
|
151
|
+
a: z.string().catch("catch value").optional(),
|
|
152
|
+
b: z.string().default("default value").optional(),
|
|
153
|
+
c: z.string().prefault("prefault value").optional(),
|
|
154
|
+
d: z.string().catch("catch value"),
|
|
155
|
+
e: z.string().default("default value"),
|
|
156
|
+
f: z.string().prefault("prefault value"),
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
expect(mySchema.parse({})).toMatchInlineSnapshot(`
|
|
160
|
+
{
|
|
161
|
+
"b": "default value",
|
|
162
|
+
"c": "prefault value",
|
|
163
|
+
"d": "catch value",
|
|
164
|
+
"e": "default value",
|
|
165
|
+
"f": "prefault value",
|
|
166
|
+
}
|
|
167
|
+
`);
|
|
168
|
+
|
|
169
|
+
expect(mySchema.parse({}, { jitless: true })).toMatchInlineSnapshot(`
|
|
170
|
+
{
|
|
171
|
+
"b": "default value",
|
|
172
|
+
"c": "prefault value",
|
|
173
|
+
"d": "catch value",
|
|
174
|
+
"e": "default value",
|
|
175
|
+
"f": "prefault value",
|
|
176
|
+
}
|
|
177
|
+
`);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test("handleOptionalObjectResult branches", () => {
|
|
181
|
+
const mySchema = z.object({
|
|
182
|
+
// Branch: input[key] === undefined, key not in input, caught error
|
|
183
|
+
caughtMissing: z.string().catch("caught").optional(),
|
|
184
|
+
// Branch: input[key] === undefined, key in input, caught error
|
|
185
|
+
caughtUndefined: z.string().catch("caught").optional(),
|
|
186
|
+
// Branch: input[key] === undefined, key not in input, validation issues
|
|
187
|
+
issueMissing: z.string().min(5).optional(),
|
|
188
|
+
// Branch: input[key] === undefined, key in input, validation issues
|
|
189
|
+
issueUndefined: z.string().min(5).optional(),
|
|
190
|
+
// Branch: input[key] === undefined, validation returns undefined
|
|
191
|
+
validUndefined: z.string().optional(),
|
|
192
|
+
// Branch: input[key] === undefined, non-undefined result (default/transform)
|
|
193
|
+
defaultValue: z.string().default("default").optional(),
|
|
194
|
+
// Branch: input[key] defined, caught error
|
|
195
|
+
caughtDefined: z.string().catch("caught").optional(),
|
|
196
|
+
// Branch: input[key] defined, validation issues
|
|
197
|
+
issueDefined: z.string().min(5).optional(),
|
|
198
|
+
// Branch: input[key] defined, validation returns undefined
|
|
199
|
+
validDefinedUndefined: z
|
|
200
|
+
.string()
|
|
201
|
+
.transform(() => undefined)
|
|
202
|
+
.optional(),
|
|
203
|
+
// Branch: input[key] defined, non-undefined value
|
|
204
|
+
validDefined: z.string().optional(),
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Test input[key] === undefined cases
|
|
208
|
+
const result1 = mySchema.parse(
|
|
209
|
+
{
|
|
210
|
+
// caughtMissing: not present (key not in input)
|
|
211
|
+
caughtUndefined: undefined, // key in input
|
|
212
|
+
// issueMissing: not present (key not in input)
|
|
213
|
+
issueUndefined: undefined, // key in input
|
|
214
|
+
validUndefined: undefined,
|
|
215
|
+
// defaultValue: not present, will get default
|
|
216
|
+
},
|
|
217
|
+
{ jitless: true }
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
expect(result1).toEqual({
|
|
221
|
+
caughtUndefined: undefined,
|
|
222
|
+
issueUndefined: undefined,
|
|
223
|
+
validUndefined: undefined,
|
|
224
|
+
defaultValue: "default",
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// Test input[key] defined cases (successful)
|
|
228
|
+
const result2 = mySchema.parse(
|
|
229
|
+
{
|
|
230
|
+
caughtDefined: 123, // invalid type, should catch
|
|
231
|
+
validDefinedUndefined: "test", // transforms to undefined
|
|
232
|
+
validDefined: "valid", // valid value
|
|
233
|
+
},
|
|
234
|
+
{ jitless: true }
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
expect(result2).toEqual({
|
|
238
|
+
caughtDefined: "caught",
|
|
239
|
+
validDefinedUndefined: undefined,
|
|
240
|
+
validDefined: "valid",
|
|
241
|
+
defaultValue: "default",
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// Test validation issues are properly reported (input[key] defined, validation fails)
|
|
245
|
+
expect(() =>
|
|
246
|
+
mySchema.parse(
|
|
247
|
+
{
|
|
248
|
+
issueDefined: "abc", // too short
|
|
249
|
+
},
|
|
250
|
+
{ jitless: true }
|
|
251
|
+
)
|
|
252
|
+
).toThrow();
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
test("fastpass vs non-fastpass consistency", () => {
|
|
256
|
+
const mySchema = z.object({
|
|
257
|
+
caughtMissing: z.string().catch("caught").optional(),
|
|
258
|
+
caughtUndefined: z.string().catch("caught").optional(),
|
|
259
|
+
issueMissing: z.string().min(5).optional(),
|
|
260
|
+
issueUndefined: z.string().min(5).optional(),
|
|
261
|
+
validUndefined: z.string().optional(),
|
|
262
|
+
defaultValue: z.string().default("default").optional(),
|
|
263
|
+
caughtDefined: z.string().catch("caught").optional(),
|
|
264
|
+
validDefinedUndefined: z
|
|
265
|
+
.string()
|
|
266
|
+
.transform(() => undefined)
|
|
267
|
+
.optional(),
|
|
268
|
+
validDefined: z.string().optional(),
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const input = {
|
|
272
|
+
caughtUndefined: undefined,
|
|
273
|
+
issueUndefined: undefined,
|
|
274
|
+
validUndefined: undefined,
|
|
275
|
+
caughtDefined: 123,
|
|
276
|
+
validDefinedUndefined: "test",
|
|
277
|
+
validDefined: "valid",
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// Test both paths produce identical results
|
|
281
|
+
const jitlessResult = mySchema.parse(input, { jitless: true });
|
|
282
|
+
const fastpassResult = mySchema.parse(input);
|
|
283
|
+
|
|
284
|
+
expect(jitlessResult).toEqual(fastpassResult);
|
|
285
|
+
expect(jitlessResult).toEqual({
|
|
286
|
+
caughtUndefined: undefined,
|
|
287
|
+
issueUndefined: undefined,
|
|
288
|
+
validUndefined: undefined,
|
|
289
|
+
defaultValue: "default",
|
|
290
|
+
caughtDefined: "caught",
|
|
291
|
+
validDefinedUndefined: undefined,
|
|
292
|
+
validDefined: "valid",
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
test("optional with check", () => {
|
|
297
|
+
const baseSchema = z
|
|
298
|
+
.string()
|
|
299
|
+
.optional()
|
|
300
|
+
.check(({ value, ...ctx }) => {
|
|
301
|
+
ctx.issues.push({
|
|
302
|
+
code: "custom",
|
|
303
|
+
input: value,
|
|
304
|
+
message: "message",
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
// this correctly fails
|
|
309
|
+
expect(baseSchema.safeParse(undefined)).toMatchInlineSnapshot(`
|
|
310
|
+
{
|
|
311
|
+
"error": [ZodError: [
|
|
312
|
+
{
|
|
313
|
+
"code": "custom",
|
|
314
|
+
"message": "message",
|
|
315
|
+
"path": []
|
|
316
|
+
}
|
|
317
|
+
]],
|
|
318
|
+
"success": false,
|
|
319
|
+
}
|
|
320
|
+
`);
|
|
321
|
+
|
|
322
|
+
const schemaObject = z.object({
|
|
323
|
+
date: baseSchema,
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
expect(schemaObject.safeParse({ date: undefined })).toMatchInlineSnapshot(`
|
|
327
|
+
{
|
|
328
|
+
"error": [ZodError: [
|
|
329
|
+
{
|
|
330
|
+
"code": "custom",
|
|
331
|
+
"message": "message",
|
|
332
|
+
"path": [
|
|
333
|
+
"date"
|
|
334
|
+
]
|
|
335
|
+
}
|
|
336
|
+
]],
|
|
337
|
+
"success": false,
|
|
338
|
+
}
|
|
339
|
+
`);
|
|
340
|
+
});
|
|
@@ -114,14 +114,14 @@ test("pick/omit/required/partial - do not allow unknown keys", () => {
|
|
|
114
114
|
age: z.number(),
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
-
expect(() => schema.pick({ name: true, asdf: true })).toThrow();
|
|
117
|
+
expect(() => schema.pick({ name: true, asdf: true }).safeParse({})).toThrow();
|
|
118
118
|
|
|
119
119
|
// @ts-expect-error
|
|
120
|
-
expect(() => schema.pick({ $unknown: true })).toThrow();
|
|
120
|
+
expect(() => schema.pick({ $unknown: true }).safeParse({})).toThrow();
|
|
121
121
|
// @ts-expect-error
|
|
122
|
-
expect(() => schema.omit({ $unknown: true })).toThrow();
|
|
122
|
+
expect(() => schema.omit({ $unknown: true }).safeParse({})).toThrow();
|
|
123
123
|
// @ts-expect-error
|
|
124
|
-
expect(() => schema.required({ $unknown: true })).toThrow();
|
|
124
|
+
expect(() => schema.required({ $unknown: true }).safeParse({})).toThrow();
|
|
125
125
|
// @ts-expect-error
|
|
126
|
-
expect(() => schema.partial({ $unknown: true })).toThrow();
|
|
126
|
+
expect(() => schema.partial({ $unknown: true }).safeParse({})).toThrow();
|
|
127
127
|
});
|
|
@@ -73,17 +73,18 @@ test("preprocess ctx.addIssue with parse", () => {
|
|
|
73
73
|
`);
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
-
test("preprocess ctx.addIssue
|
|
76
|
+
test("preprocess ctx.addIssue fatal by default", () => {
|
|
77
77
|
const schema = z.preprocess((data, ctx) => {
|
|
78
78
|
ctx.addIssue({
|
|
79
79
|
code: "custom",
|
|
80
80
|
message: `custom error`,
|
|
81
81
|
});
|
|
82
|
+
|
|
82
83
|
return data;
|
|
83
84
|
}, z.string());
|
|
84
85
|
const result = schema.safeParse(1234);
|
|
85
86
|
|
|
86
|
-
expect(result.error!.issues).toHaveLength(
|
|
87
|
+
expect(result.error!.issues).toHaveLength(1);
|
|
87
88
|
expect(result).toMatchInlineSnapshot(`
|
|
88
89
|
{
|
|
89
90
|
"error": [ZodError: [
|
|
@@ -91,12 +92,6 @@ test("preprocess ctx.addIssue non-fatal by default", () => {
|
|
|
91
92
|
"code": "custom",
|
|
92
93
|
"message": "custom error",
|
|
93
94
|
"path": []
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
"expected": "string",
|
|
97
|
-
"code": "invalid_type",
|
|
98
|
-
"path": [],
|
|
99
|
-
"message": "Invalid input: expected string, received number"
|
|
100
95
|
}
|
|
101
96
|
]],
|
|
102
97
|
"success": false,
|
|
@@ -175,7 +170,7 @@ test("z.NEVER in preprocess", () => {
|
|
|
175
170
|
expectTypeOf<foo>().toEqualTypeOf<number>();
|
|
176
171
|
const result = foo.safeParse(undefined);
|
|
177
172
|
|
|
178
|
-
expect(result.error!.issues).toHaveLength(
|
|
173
|
+
expect(result.error!.issues).toHaveLength(1);
|
|
179
174
|
expect(result).toMatchInlineSnapshot(`
|
|
180
175
|
{
|
|
181
176
|
"error": [ZodError: [
|
|
@@ -183,12 +178,6 @@ test("z.NEVER in preprocess", () => {
|
|
|
183
178
|
"code": "custom",
|
|
184
179
|
"message": "bad",
|
|
185
180
|
"path": []
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
"expected": "number",
|
|
189
|
-
"code": "invalid_type",
|
|
190
|
-
"path": [],
|
|
191
|
-
"message": "Invalid input: expected number, received object"
|
|
192
181
|
}
|
|
193
182
|
]],
|
|
194
183
|
"success": false,
|
|
@@ -336,7 +336,21 @@ test("partial record", () => {
|
|
|
336
336
|
type schema = z.infer<typeof schema>;
|
|
337
337
|
expectTypeOf<schema>().toEqualTypeOf<Partial<Record<string, string>>>();
|
|
338
338
|
|
|
339
|
-
const Keys = z.enum(["id", "name", "email"])
|
|
339
|
+
const Keys = z.enum(["id", "name", "email"]); //.or(z.never());
|
|
340
340
|
const Person = z.partialRecord(Keys, z.string());
|
|
341
341
|
expectTypeOf<z.infer<typeof Person>>().toEqualTypeOf<Partial<Record<"id" | "name" | "email", string>>>();
|
|
342
|
+
|
|
343
|
+
Person.parse({
|
|
344
|
+
id: "123",
|
|
345
|
+
// name: "John",
|
|
346
|
+
// email: "john@example.com",
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
Person.parse({
|
|
350
|
+
// id: "123",
|
|
351
|
+
// name: "John",
|
|
352
|
+
email: "john@example.com",
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
expect(Person.def.keyType._zod.def.type).toEqual("enum");
|
|
342
356
|
});
|