zod 4.6.0 → 4.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/v4/classic/tests/discriminated-unions.test.ts +112 -6
- package/src/v4/classic/tests/prefault.test.ts +70 -0
- package/src/v4/classic/tests/recursive-types.test.ts +45 -0
- package/src/v4/core/compile.ts +9 -7
- package/src/v4/core/schemas.ts +45 -39
- package/src/v4/core/tests/locales/tg.test.ts +85 -0
- package/src/v4/core/versions.ts +1 -1
- package/src/v4/locales/index.ts +1 -0
- package/src/v4/locales/tg.ts +134 -0
- package/src/v4/mini/schemas.ts +1 -1
- package/src/v4/mini/tests/index.test.ts +22 -0
- package/src/v4/mini/tests/recursive-types.test.ts +16 -0
- package/v4/core/compile.cjs +8 -7
- package/v4/core/compile.js +8 -7
- package/v4/core/schemas.cjs +46 -37
- package/v4/core/schemas.d.cts +9 -5
- package/v4/core/schemas.d.ts +9 -5
- package/v4/core/schemas.js +46 -37
- package/v4/core/versions.cjs +1 -1
- package/v4/core/versions.js +1 -1
- package/v4/locales/index.cjs +3 -1
- package/v4/locales/index.d.cts +1 -0
- package/v4/locales/index.d.ts +1 -0
- package/v4/locales/index.js +1 -0
- package/v4/locales/tg.cjs +143 -0
- package/v4/locales/tg.d.cts +5 -0
- package/v4/locales/tg.d.ts +4 -0
- package/v4/locales/tg.js +116 -0
- package/v4/mini/schemas.d.cts +1 -1
- package/v4/mini/schemas.d.ts +1 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import type { $ZodStringFormats } from "../core/checks.js";
|
|
2
|
+
import type * as errors from "../core/errors.js";
|
|
3
|
+
import * as util from "../core/util.js";
|
|
4
|
+
|
|
5
|
+
const error: () => errors.$ZodErrorMap = () => {
|
|
6
|
+
// singular units after numerals in Tajik
|
|
7
|
+
const Sizable: Record<string, { unit: string; verb: string }> = {
|
|
8
|
+
string: { unit: "аломат", verb: "дошта бошад" },
|
|
9
|
+
file: { unit: "байт", verb: "дошта бошад" },
|
|
10
|
+
array: { unit: "унсур", verb: "дошта бошад" },
|
|
11
|
+
set: { unit: "унсур", verb: "дошта бошад" },
|
|
12
|
+
map: { unit: "сабт", verb: "дошта бошад" },
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function getSizing(origin: string): { unit: string; verb: string } | null {
|
|
16
|
+
return Sizable[origin] ?? null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const FormatDictionary: {
|
|
20
|
+
[k in $ZodStringFormats | (string & {})]?: string;
|
|
21
|
+
} = {
|
|
22
|
+
regex: "вуруд",
|
|
23
|
+
email: "суроғаи email",
|
|
24
|
+
url: "URL",
|
|
25
|
+
emoji: "эмоҷи",
|
|
26
|
+
uuid: "UUID",
|
|
27
|
+
uuidv4: "UUIDv4",
|
|
28
|
+
uuidv6: "UUIDv6",
|
|
29
|
+
nanoid: "nanoid",
|
|
30
|
+
guid: "GUID",
|
|
31
|
+
cuid: "cuid",
|
|
32
|
+
cuid2: "cuid2",
|
|
33
|
+
ulid: "ULID",
|
|
34
|
+
xid: "XID",
|
|
35
|
+
ksuid: "KSUID",
|
|
36
|
+
datetime: "санаву вақти ISO",
|
|
37
|
+
date: "санаи ISO",
|
|
38
|
+
time: "вақти ISO",
|
|
39
|
+
duration: "давомнокии ISO",
|
|
40
|
+
ipv4: "суроғаи IPv4",
|
|
41
|
+
ipv6: "суроғаи IPv6",
|
|
42
|
+
mac: "суроғаи MAC",
|
|
43
|
+
cidrv4: "маҳдудаи IPv4",
|
|
44
|
+
cidrv6: "маҳдудаи IPv6",
|
|
45
|
+
base64: "сатри дар формати base64",
|
|
46
|
+
base64url: "сатри дар формати base64url",
|
|
47
|
+
json_string: "сатри JSON",
|
|
48
|
+
e164: "рақами E.164",
|
|
49
|
+
credit_card: "рақами корти кредитӣ",
|
|
50
|
+
iban: "IBAN",
|
|
51
|
+
jwt: "JWT",
|
|
52
|
+
template_literal: "вуруд",
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const TypeDictionary: {
|
|
56
|
+
[k in errors.$ZodInvalidTypeExpected | (string & {})]?: string;
|
|
57
|
+
} = {
|
|
58
|
+
nan: "NaN",
|
|
59
|
+
number: "рақам",
|
|
60
|
+
string: "сатр",
|
|
61
|
+
array: "массив",
|
|
62
|
+
object: "объект",
|
|
63
|
+
date: "сана",
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return (issue) => {
|
|
67
|
+
switch (issue.code) {
|
|
68
|
+
case "invalid_type": {
|
|
69
|
+
const expected = TypeDictionary[issue.expected] ?? issue.expected;
|
|
70
|
+
const receivedType = util.parsedType(issue.input);
|
|
71
|
+
const received = TypeDictionary[receivedType] ?? receivedType;
|
|
72
|
+
return `Вуруди нодуруст: ${expected} интизор мерафт, ${received} гирифта шуд`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
case "invalid_value":
|
|
76
|
+
if (issue.values.length === 1)
|
|
77
|
+
return `Вуруди нодуруст: ${util.stringifyPrimitive(issue.values[0])} интизор мерафт`;
|
|
78
|
+
return `Интихоби нодуруст: яке аз ${util.joinValues(issue.values, "|")} интизор мерафт`;
|
|
79
|
+
|
|
80
|
+
case "too_big": {
|
|
81
|
+
const adj = issue.inclusive ? "<=" : "<";
|
|
82
|
+
const sizing = getSizing(issue.origin);
|
|
83
|
+
if (sizing)
|
|
84
|
+
return `Хеле калон: ${issue.origin ?? "қимат"} бояд ${adj}${issue.maximum.toString()} ${sizing.unit} ${sizing.verb}`;
|
|
85
|
+
return `Хеле калон: ${issue.origin ?? "қимат"} бояд ${adj}${issue.maximum.toString()} бошад`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
case "too_small": {
|
|
89
|
+
const adj = issue.inclusive ? ">=" : ">";
|
|
90
|
+
const sizing = getSizing(issue.origin);
|
|
91
|
+
if (sizing)
|
|
92
|
+
return `Хеле хурд: ${issue.origin} бояд ${adj}${issue.minimum.toString()} ${sizing.unit} ${sizing.verb}`;
|
|
93
|
+
return `Хеле хурд: ${issue.origin} бояд ${adj}${issue.minimum.toString()} бошад`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
case "invalid_format": {
|
|
97
|
+
const _issue = issue as errors.$ZodStringFormatIssues;
|
|
98
|
+
if (_issue.format === "starts_with") return `Сатри нодуруст: бояд бо "${_issue.prefix}" оғоз шавад`;
|
|
99
|
+
if (_issue.format === "ends_with") return `Сатри нодуруст: бояд бо "${_issue.suffix}" анҷом ёбад`;
|
|
100
|
+
if (_issue.format === "includes") return `Сатри нодуруст: бояд "${_issue.includes}"-ро дар бар гирад`;
|
|
101
|
+
if (_issue.format === "regex") return `Сатри нодуруст: бояд ба намунаи ${_issue.pattern} мувофиқат кунад`;
|
|
102
|
+
return `${FormatDictionary[_issue.format] ?? issue.format}-и нодуруст`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
case "not_multiple_of":
|
|
106
|
+
return `Рақами нодуруст: бояд ба ${issue.divisor} бе бақия тақсим шавад`;
|
|
107
|
+
|
|
108
|
+
case "unrecognized_keys":
|
|
109
|
+
return `Калид${issue.keys.length > 1 ? "ҳои" : "и"} номаълум: ${util.joinValues(issue.keys, ", ")}`;
|
|
110
|
+
|
|
111
|
+
case "invalid_key":
|
|
112
|
+
return `Калиди нодуруст дар ${issue.origin}`;
|
|
113
|
+
|
|
114
|
+
case "invalid_union":
|
|
115
|
+
if (issue.options && Array.isArray(issue.options) && issue.options.length > 0) {
|
|
116
|
+
const opts = issue.options.map((o) => `'${o}'`).join(" | ");
|
|
117
|
+
return `Қимати нодурусти дискриминатор: ${opts} интизор мерафт`;
|
|
118
|
+
}
|
|
119
|
+
return "Вуруди нодуруст";
|
|
120
|
+
|
|
121
|
+
case "invalid_element":
|
|
122
|
+
return `Қимати нодуруст дар ${issue.origin}`;
|
|
123
|
+
|
|
124
|
+
default:
|
|
125
|
+
return `Вуруди нодуруст`;
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export default function (): { localeError: errors.$ZodErrorMap } {
|
|
131
|
+
return {
|
|
132
|
+
localeError: error(),
|
|
133
|
+
};
|
|
134
|
+
}
|
package/src/v4/mini/schemas.ts
CHANGED
|
@@ -1597,7 +1597,7 @@ export const ZodMiniPrefault: core.$constructor<ZodMiniPrefault> = /*@__PURE__*/
|
|
|
1597
1597
|
// @__NO_SIDE_EFFECTS__
|
|
1598
1598
|
export function prefault<T extends SomeType>(
|
|
1599
1599
|
innerType: T,
|
|
1600
|
-
defaultValue:
|
|
1600
|
+
defaultValue: core.input<T> | (() => core.input<T>)
|
|
1601
1601
|
): ZodMiniPrefault<T> {
|
|
1602
1602
|
return new ZodMiniPrefault({
|
|
1603
1603
|
type: "prefault",
|
|
@@ -165,6 +165,28 @@ test("z.iso.duration", () => {
|
|
|
165
165
|
expect(z.safeParse(b, d2).success).toEqual(false);
|
|
166
166
|
});
|
|
167
167
|
|
|
168
|
+
test("z.prefault preserves undefined output", async () => {
|
|
169
|
+
const field = z.prefault(z.union([z.string(), z.undefined()]), () => undefined);
|
|
170
|
+
const schema = z.object({ a: field });
|
|
171
|
+
expectTypeOf<z.output<typeof field>>().toEqualTypeOf<string | undefined>();
|
|
172
|
+
expectTypeOf<z.output<typeof schema>>().toEqualTypeOf<{ a: string | undefined }>();
|
|
173
|
+
expect(z.parse(schema, {})).toStrictEqual({ a: undefined });
|
|
174
|
+
expect(z.parse(schema, { a: undefined })).toStrictEqual({ a: undefined });
|
|
175
|
+
expect(z.parse(schema, { a: "value" })).toStrictEqual({ a: "value" });
|
|
176
|
+
expect(z.safeParse(schema, { a: 123 }).success).toBe(false);
|
|
177
|
+
expect(await z.parseAsync(schema, {})).toStrictEqual({ a: undefined });
|
|
178
|
+
expect(z.parse(z.object({ a: z.prefault(z.optional(z.string()), undefined) }), {})).toStrictEqual({ a: undefined });
|
|
179
|
+
const transformed = z.prefault(
|
|
180
|
+
z.pipe(
|
|
181
|
+
z.string(),
|
|
182
|
+
z.transform(() => undefined)
|
|
183
|
+
),
|
|
184
|
+
"fallback"
|
|
185
|
+
);
|
|
186
|
+
expectTypeOf<z.output<typeof transformed>>().toEqualTypeOf<undefined>();
|
|
187
|
+
expect(z.parse(z.object({ a: transformed }), {})).toStrictEqual({ a: undefined });
|
|
188
|
+
});
|
|
189
|
+
|
|
168
190
|
test("z.undefined", () => {
|
|
169
191
|
const a = z.undefined();
|
|
170
192
|
expect(z.parse(a, undefined)).toEqual(undefined);
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { expect, expectTypeOf, test } from "vitest";
|
|
2
2
|
import { z } from "zod/mini";
|
|
3
3
|
|
|
4
|
+
test("recursive object schema type aliases", () => {
|
|
5
|
+
type ObjectField = z.ZodMiniObject<{ [k: string]: ObjectField }>;
|
|
6
|
+
type Field = z.ZodMiniString<string> | z.ZodMiniObject<{ [k: string]: Field }>;
|
|
7
|
+
type ObjectValue = { [k: string]: ObjectValue };
|
|
8
|
+
type Value = string | { [k: string]: Value };
|
|
9
|
+
expectTypeOf<z.input<ObjectField>>().toEqualTypeOf<ObjectValue>();
|
|
10
|
+
expectTypeOf<z.output<ObjectField>>().toEqualTypeOf<ObjectValue>();
|
|
11
|
+
expectTypeOf<keyof z.input<ObjectField>>().toEqualTypeOf<string>();
|
|
12
|
+
expectTypeOf<keyof z.output<ObjectField>>().toEqualTypeOf<string>();
|
|
13
|
+
expectTypeOf<z.input<Field>>().toEqualTypeOf<Value>();
|
|
14
|
+
expectTypeOf<z.output<Field>>().toEqualTypeOf<Value>();
|
|
15
|
+
const schema: Field = z.object({ nested: z.object({ name: z.string() }) });
|
|
16
|
+
expect(schema.parse({ nested: { name: "a", extra: true } })).toEqual({ nested: { name: "a" } });
|
|
17
|
+
expect(schema.safeParse({ nested: { name: 123 } }).success).toBe(false);
|
|
18
|
+
});
|
|
19
|
+
|
|
4
20
|
test("recursion with z.lazy", () => {
|
|
5
21
|
const data = {
|
|
6
22
|
name: "I",
|
package/v4/core/compile.cjs
CHANGED
|
@@ -1010,9 +1010,9 @@ function generateObjectCheck(doc, ctx, schema, accessor, buildsValue = true) {
|
|
|
1010
1010
|
}
|
|
1011
1011
|
}
|
|
1012
1012
|
// else: strip mode (no catchall) - unknown keys ignored, only include known keys
|
|
1013
|
-
//
|
|
1013
|
+
// defaulted required outputs keep their keys even when undefined
|
|
1014
1014
|
const outputVar = newVar(ctx);
|
|
1015
|
-
const hasConditionalKeys = allKeys.some((k) =>
|
|
1015
|
+
const hasConditionalKeys = allKeys.some((k) => mayOmitUndefined(propShape[k]) || dropsWhenAbsent(propShape[k]));
|
|
1016
1016
|
// Assert mode: every declared key is validated above, so the output literal and the unknown-key copy are pure waste. A `never` catchall already emitted its rejection loop; a schema catchall still has to validate the values it would otherwise have stored.
|
|
1017
1017
|
if (!buildsValue) {
|
|
1018
1018
|
if (unknownKeysMode === "schema") {
|
|
@@ -1042,7 +1042,7 @@ function generateObjectCheck(doc, ctx, schema, accessor, buildsValue = true) {
|
|
|
1042
1042
|
if (dropsWhenAbsent(propShape[k])) {
|
|
1043
1043
|
doc.write(`if (${kx} in ${accessor}) ${outputVar}[${kx}] = ${out};`);
|
|
1044
1044
|
}
|
|
1045
|
-
else if (
|
|
1045
|
+
else if (mayOmitUndefined(propShape[k])) {
|
|
1046
1046
|
doc.write(`if (${out} !== undefined || ${kx} in ${accessor}) ${outputVar}[${kx}] = ${out};`);
|
|
1047
1047
|
}
|
|
1048
1048
|
else {
|
|
@@ -1185,9 +1185,10 @@ function fastPathAcceptsAbsence(schema) {
|
|
|
1185
1185
|
function dropsWhenAbsent(schema) {
|
|
1186
1186
|
return schema._zod.optin === "optional" && schema._zod.optout === "optional";
|
|
1187
1187
|
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1188
|
+
function mayOmitUndefined(schema) {
|
|
1189
|
+
return (schema._zod.optin !== "defaulted" || schema._zod.optout === "optional") && mayOutputUndefined(schema);
|
|
1190
|
+
}
|
|
1191
|
+
// whether a schema's success-path output can be undefined
|
|
1191
1192
|
function mayOutputUndefined(schema) {
|
|
1192
1193
|
const def = schema._zod.def;
|
|
1193
1194
|
switch (def.type) {
|
|
@@ -1525,7 +1526,7 @@ function generateDiscriminatedUnionCheck(doc, ctx, def, accessor) {
|
|
|
1525
1526
|
if (!values || values.size === 0) {
|
|
1526
1527
|
throw new ZodCompileUnsupportedError("discriminated union option without static discriminator values");
|
|
1527
1528
|
}
|
|
1528
|
-
//
|
|
1529
|
+
// let the interpreter handle collisions instead of compiling first-match dispatch
|
|
1529
1530
|
for (const value of values) {
|
|
1530
1531
|
if (claimed.has(value)) {
|
|
1531
1532
|
throw new ZodCompileUnsupportedError(`duplicate discriminator value ${String(value)}`);
|
package/v4/core/compile.js
CHANGED
|
@@ -979,9 +979,9 @@ function generateObjectCheck(doc, ctx, schema, accessor, buildsValue = true) {
|
|
|
979
979
|
}
|
|
980
980
|
}
|
|
981
981
|
// else: strip mode (no catchall) - unknown keys ignored, only include known keys
|
|
982
|
-
//
|
|
982
|
+
// defaulted required outputs keep their keys even when undefined
|
|
983
983
|
const outputVar = newVar(ctx);
|
|
984
|
-
const hasConditionalKeys = allKeys.some((k) =>
|
|
984
|
+
const hasConditionalKeys = allKeys.some((k) => mayOmitUndefined(propShape[k]) || dropsWhenAbsent(propShape[k]));
|
|
985
985
|
// Assert mode: every declared key is validated above, so the output literal and the unknown-key copy are pure waste. A `never` catchall already emitted its rejection loop; a schema catchall still has to validate the values it would otherwise have stored.
|
|
986
986
|
if (!buildsValue) {
|
|
987
987
|
if (unknownKeysMode === "schema") {
|
|
@@ -1011,7 +1011,7 @@ function generateObjectCheck(doc, ctx, schema, accessor, buildsValue = true) {
|
|
|
1011
1011
|
if (dropsWhenAbsent(propShape[k])) {
|
|
1012
1012
|
doc.write(`if (${kx} in ${accessor}) ${outputVar}[${kx}] = ${out};`);
|
|
1013
1013
|
}
|
|
1014
|
-
else if (
|
|
1014
|
+
else if (mayOmitUndefined(propShape[k])) {
|
|
1015
1015
|
doc.write(`if (${out} !== undefined || ${kx} in ${accessor}) ${outputVar}[${kx}] = ${out};`);
|
|
1016
1016
|
}
|
|
1017
1017
|
else {
|
|
@@ -1154,9 +1154,10 @@ function fastPathAcceptsAbsence(schema) {
|
|
|
1154
1154
|
function dropsWhenAbsent(schema) {
|
|
1155
1155
|
return schema._zod.optin === "optional" && schema._zod.optout === "optional";
|
|
1156
1156
|
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1157
|
+
function mayOmitUndefined(schema) {
|
|
1158
|
+
return (schema._zod.optin !== "defaulted" || schema._zod.optout === "optional") && mayOutputUndefined(schema);
|
|
1159
|
+
}
|
|
1160
|
+
// whether a schema's success-path output can be undefined
|
|
1160
1161
|
function mayOutputUndefined(schema) {
|
|
1161
1162
|
const def = schema._zod.def;
|
|
1162
1163
|
switch (def.type) {
|
|
@@ -1494,7 +1495,7 @@ function generateDiscriminatedUnionCheck(doc, ctx, def, accessor) {
|
|
|
1494
1495
|
if (!values || values.size === 0) {
|
|
1495
1496
|
throw new ZodCompileUnsupportedError("discriminated union option without static discriminator values");
|
|
1496
1497
|
}
|
|
1497
|
-
//
|
|
1498
|
+
// let the interpreter handle collisions instead of compiling first-match dispatch
|
|
1498
1499
|
for (const value of values) {
|
|
1499
1500
|
if (claimed.has(value)) {
|
|
1500
1501
|
throw new ZodCompileUnsupportedError(`duplicate discriminator value ${String(value)}`);
|
package/v4/core/schemas.cjs
CHANGED
|
@@ -911,7 +911,7 @@ function handlePropertyResult(result, final, key, input, optin, optout) {
|
|
|
911
911
|
return;
|
|
912
912
|
}
|
|
913
913
|
if (result.value === undefined) {
|
|
914
|
-
if (isPresent) {
|
|
914
|
+
if (isPresent || (optin === "defaulted" && !isOptionalOut)) {
|
|
915
915
|
final.value[key] = undefined;
|
|
916
916
|
}
|
|
917
917
|
}
|
|
@@ -1166,16 +1166,17 @@ exports.$ZodObjectJIT = core.$constructor("$ZodObjectJIT", (inst, def) => {
|
|
|
1166
1166
|
doc.write(`
|
|
1167
1167
|
if (${id}.issues.length) {${prefixStr(id, k)}
|
|
1168
1168
|
}
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1169
|
+
`);
|
|
1170
|
+
if (optin === "defaulted") {
|
|
1171
|
+
doc.write(`newResult[${k}] = ${id}.value;`);
|
|
1172
|
+
}
|
|
1173
|
+
else {
|
|
1174
|
+
doc.write(`
|
|
1175
|
+
if (${id}.value !== undefined || ${isPresent}) {
|
|
1175
1176
|
newResult[${k}] = ${id}.value;
|
|
1176
1177
|
}
|
|
1177
|
-
|
|
1178
1178
|
`);
|
|
1179
|
+
}
|
|
1179
1180
|
}
|
|
1180
1181
|
}
|
|
1181
1182
|
doc.write(`payload.value = newResult;`);
|
|
@@ -1346,22 +1347,38 @@ exports.$ZodXor = core.$constructor("$ZodXor", (inst, def) => {
|
|
|
1346
1347
|
});
|
|
1347
1348
|
};
|
|
1348
1349
|
});
|
|
1349
|
-
/** Returns the option
|
|
1350
|
+
/** Returns the option whose discriminator claims `value`, or throws if ambiguous. */
|
|
1350
1351
|
function getDiscriminatedOption(union, value) {
|
|
1351
1352
|
const internals = union._zod;
|
|
1352
1353
|
let map = internals.bag.optionsMap;
|
|
1353
1354
|
if (!map) {
|
|
1354
|
-
map =
|
|
1355
|
-
const { options, discriminator } = internals.def;
|
|
1356
|
-
for (const option of options) {
|
|
1357
|
-
// First declaration wins, matching the order the parse path resolves a duplicate in.
|
|
1358
|
-
for (const v of option._zod.propValues?.[discriminator] ?? [])
|
|
1359
|
-
if (!map.has(v))
|
|
1360
|
-
map.set(v, option);
|
|
1361
|
-
}
|
|
1355
|
+
map = discriminatorMap(internals.def);
|
|
1362
1356
|
internals.bag.optionsMap = map;
|
|
1363
1357
|
}
|
|
1364
|
-
|
|
1358
|
+
const option = map.get(value);
|
|
1359
|
+
if (option === null)
|
|
1360
|
+
throw new Error(`Ambiguous discriminator value "${String(value)}"`);
|
|
1361
|
+
return option;
|
|
1362
|
+
}
|
|
1363
|
+
function discriminatorMap(def) {
|
|
1364
|
+
const map = new Map();
|
|
1365
|
+
for (const option of def.options) {
|
|
1366
|
+
const values = option._zod.propValues?.[def.discriminator];
|
|
1367
|
+
if (!values || values.size === 0)
|
|
1368
|
+
throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(option)}"`);
|
|
1369
|
+
for (const value of values) {
|
|
1370
|
+
if (map.has(value)) {
|
|
1371
|
+
if (value !== undefined)
|
|
1372
|
+
throw new Error(`Duplicate discriminator value "${String(value)}"`);
|
|
1373
|
+
// keep the collision marked so a later member cannot reclaim it
|
|
1374
|
+
map.set(value, null);
|
|
1375
|
+
}
|
|
1376
|
+
else {
|
|
1377
|
+
map.set(value, option);
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
return map;
|
|
1365
1382
|
}
|
|
1366
1383
|
exports.$ZodDiscriminatedUnion =
|
|
1367
1384
|
/*@__PURE__*/
|
|
@@ -1371,10 +1388,13 @@ core.$constructor("$ZodDiscriminatedUnion", (inst, def) => {
|
|
|
1371
1388
|
const _super = inst._zod.parse;
|
|
1372
1389
|
util.defineLazyInternal(inst, "propValues", (zod) => {
|
|
1373
1390
|
const propValues = {};
|
|
1391
|
+
let undefinedCount = 0;
|
|
1374
1392
|
for (const option of zod.def.options) {
|
|
1375
1393
|
const pv = option._zod.propValues;
|
|
1376
1394
|
if (!pv || Object.keys(pv).length === 0)
|
|
1377
1395
|
throw new Error(`Invalid discriminated union option at index "${zod.def.options.indexOf(option)}"`);
|
|
1396
|
+
if (pv[zod.def.discriminator]?.has(undefined))
|
|
1397
|
+
undefinedCount++;
|
|
1378
1398
|
for (const [k, v] of Object.entries(pv)) {
|
|
1379
1399
|
if (!Object.prototype.hasOwnProperty.call(propValues, k)) {
|
|
1380
1400
|
util.assignProp(propValues, k, new Set());
|
|
@@ -1384,6 +1404,8 @@ core.$constructor("$ZodDiscriminatedUnion", (inst, def) => {
|
|
|
1384
1404
|
}
|
|
1385
1405
|
}
|
|
1386
1406
|
}
|
|
1407
|
+
if (!zod.def.unionFallback && undefinedCount > 1)
|
|
1408
|
+
propValues[zod.def.discriminator]?.delete(undefined);
|
|
1387
1409
|
return propValues;
|
|
1388
1410
|
});
|
|
1389
1411
|
// Checked now rather than in the lookup map below, so an option that lacks the discriminator fails at the `discriminatedUnion` call instead of on the first object parsed. Options whose shape cannot be enumerated without resolving it — pipes and lazies — are left to the map.
|
|
@@ -1393,22 +1415,7 @@ core.$constructor("$ZodDiscriminatedUnion", (inst, def) => {
|
|
|
1393
1415
|
throw new Error(`Invalid discriminated union option at index "${i}"`);
|
|
1394
1416
|
}
|
|
1395
1417
|
});
|
|
1396
|
-
const disc = util.cached(() =>
|
|
1397
|
-
const opts = def.options;
|
|
1398
|
-
const map = new Map();
|
|
1399
|
-
for (const o of opts) {
|
|
1400
|
-
const values = o._zod.propValues?.[def.discriminator];
|
|
1401
|
-
if (!values || values.size === 0)
|
|
1402
|
-
throw new Error(`Invalid discriminated union option at index "${def.options.indexOf(o)}"`);
|
|
1403
|
-
for (const v of values) {
|
|
1404
|
-
if (map.has(v)) {
|
|
1405
|
-
throw new Error(`Duplicate discriminator value "${String(v)}"`);
|
|
1406
|
-
}
|
|
1407
|
-
map.set(v, o);
|
|
1408
|
-
}
|
|
1409
|
-
}
|
|
1410
|
-
return map;
|
|
1411
|
-
});
|
|
1418
|
+
const disc = util.cached(() => discriminatorMap(def));
|
|
1412
1419
|
inst._zod.parse = (payload, ctx) => {
|
|
1413
1420
|
const input = payload.value;
|
|
1414
1421
|
if (!util.isObject(input)) {
|
|
@@ -1420,8 +1427,10 @@ core.$constructor("$ZodDiscriminatedUnion", (inst, def) => {
|
|
|
1420
1427
|
});
|
|
1421
1428
|
return payload;
|
|
1422
1429
|
}
|
|
1423
|
-
const
|
|
1424
|
-
|
|
1430
|
+
const value = input?.[def.discriminator];
|
|
1431
|
+
const opt = disc.value.get(value);
|
|
1432
|
+
// forward metadata cannot choose an encoder for an absent tag
|
|
1433
|
+
if (opt && (value !== undefined || ctx.direction !== "backward")) {
|
|
1425
1434
|
return opt._zod.run(payload, ctx);
|
|
1426
1435
|
}
|
|
1427
1436
|
// Fall back to union matching when the fast discriminator path fails:
|
|
@@ -1436,7 +1445,7 @@ core.$constructor("$ZodDiscriminatedUnion", (inst, def) => {
|
|
|
1436
1445
|
errors: [],
|
|
1437
1446
|
note: "No matching discriminator",
|
|
1438
1447
|
discriminator: def.discriminator,
|
|
1439
|
-
options: Array.from(disc.value.keys()),
|
|
1448
|
+
options: Array.from(disc.value.keys()).filter((value) => disc.value.get(value) !== null),
|
|
1440
1449
|
input,
|
|
1441
1450
|
path: [def.discriminator],
|
|
1442
1451
|
inst,
|
package/v4/core/schemas.d.cts
CHANGED
|
@@ -631,12 +631,16 @@ type OptionalInSchema = {
|
|
|
631
631
|
optin: "optional" | "defaulted";
|
|
632
632
|
};
|
|
633
633
|
};
|
|
634
|
-
export type $InferObjectOutput<T extends $ZodLooseShape, Extra extends Record<string, unknown>> = string extends keyof T ? util.IsAny<T[keyof T]> extends true ? Record<string, unknown> :
|
|
634
|
+
export type $InferObjectOutput<T extends $ZodLooseShape, Extra extends Record<string, unknown>> = string extends keyof T ? util.IsAny<T[keyof T]> extends true ? Record<string, unknown> : {
|
|
635
|
+
[k in string]: core.output<T[keyof T]>;
|
|
636
|
+
} : keyof (T & Extra) extends never ? Record<string, never> : util.Prettify<{
|
|
635
637
|
-readonly [k in keyof T as T[k] extends OptionalOutSchema ? never : k]: T[k]["_zod"]["output"];
|
|
636
638
|
} & {
|
|
637
639
|
-readonly [k in keyof T as T[k] extends OptionalOutSchema ? k : never]?: T[k]["_zod"]["output"];
|
|
638
640
|
} & Extra>;
|
|
639
|
-
export type $InferObjectInput<T extends $ZodLooseShape, Extra extends Record<string, unknown>> = string extends keyof T ? util.IsAny<T[keyof T]> extends true ? Record<string, unknown> :
|
|
641
|
+
export type $InferObjectInput<T extends $ZodLooseShape, Extra extends Record<string, unknown>> = string extends keyof T ? util.IsAny<T[keyof T]> extends true ? Record<string, unknown> : {
|
|
642
|
+
[k in string]: core.input<T[keyof T]>;
|
|
643
|
+
} : keyof (T & Extra) extends never ? Record<string, never> : util.Prettify<{
|
|
640
644
|
-readonly [k in keyof T as T[k] extends OptionalInSchema ? never : k]: T[k]["_zod"]["input"];
|
|
641
645
|
} & {
|
|
642
646
|
-readonly [k in keyof T as T[k] extends OptionalInSchema ? k : never]?: T[k]["_zod"]["input"];
|
|
@@ -729,7 +733,7 @@ export interface $ZodDiscriminatedUnionInternals<Options extends readonly SomeTy
|
|
|
729
733
|
def: $ZodDiscriminatedUnionDef<Options, Disc>;
|
|
730
734
|
propValues: util.PropValues;
|
|
731
735
|
bag: util.LoosePartial<{
|
|
732
|
-
optionsMap: Map<util.Primitive, $ZodType>;
|
|
736
|
+
optionsMap: Map<util.Primitive, $ZodType | null>;
|
|
733
737
|
}>;
|
|
734
738
|
}
|
|
735
739
|
/** The discriminator values a member of `Options` can declare. An omittable discriminator contributes `undefined`, matching what `propValues` claims for it. */
|
|
@@ -748,7 +752,7 @@ export type $DiscriminatedOption<Options extends readonly SomeType[], Disc exten
|
|
|
748
752
|
};
|
|
749
753
|
} ? Disc extends keyof Out ? V extends Out[Disc] ? Options[I] : never : never : never;
|
|
750
754
|
}[number];
|
|
751
|
-
/** Returns the option
|
|
755
|
+
/** Returns the option whose discriminator claims `value`, or throws if ambiguous. */
|
|
752
756
|
export declare function getDiscriminatedOption<Options extends readonly SomeType[], Disc extends string, const V extends $DiscriminatorValue<Options, Disc>>(union: $ZodDiscriminatedUnion<Options, Disc>, value: V): $DiscriminatedOption<Options, Disc, V>;
|
|
753
757
|
export interface $ZodDiscriminatedUnion<Options extends readonly SomeType[] = readonly $ZodType[], Disc extends string = string> extends $ZodType {
|
|
754
758
|
_zod: $ZodDiscriminatedUnionInternals<Options, Disc>;
|
|
@@ -1006,7 +1010,7 @@ export interface $ZodPrefaultDef<T extends SomeType = $ZodType> extends $ZodType
|
|
|
1006
1010
|
/** The default value. May be a getter. */
|
|
1007
1011
|
defaultValue: core.input<T>;
|
|
1008
1012
|
}
|
|
1009
|
-
export interface $ZodPrefaultInternals<T extends SomeType = $ZodType> extends $ZodTypeInternals<
|
|
1013
|
+
export interface $ZodPrefaultInternals<T extends SomeType = $ZodType> extends $ZodTypeInternals<core.output<T>, core.input<T> | undefined> {
|
|
1010
1014
|
def: $ZodPrefaultDef<T>;
|
|
1011
1015
|
optin: "defaulted";
|
|
1012
1016
|
optout?: "optional" | undefined;
|
package/v4/core/schemas.d.ts
CHANGED
|
@@ -631,12 +631,16 @@ type OptionalInSchema = {
|
|
|
631
631
|
optin: "optional" | "defaulted";
|
|
632
632
|
};
|
|
633
633
|
};
|
|
634
|
-
export type $InferObjectOutput<T extends $ZodLooseShape, Extra extends Record<string, unknown>> = string extends keyof T ? util.IsAny<T[keyof T]> extends true ? Record<string, unknown> :
|
|
634
|
+
export type $InferObjectOutput<T extends $ZodLooseShape, Extra extends Record<string, unknown>> = string extends keyof T ? util.IsAny<T[keyof T]> extends true ? Record<string, unknown> : {
|
|
635
|
+
[k in string]: core.output<T[keyof T]>;
|
|
636
|
+
} : keyof (T & Extra) extends never ? Record<string, never> : util.Prettify<{
|
|
635
637
|
-readonly [k in keyof T as T[k] extends OptionalOutSchema ? never : k]: T[k]["_zod"]["output"];
|
|
636
638
|
} & {
|
|
637
639
|
-readonly [k in keyof T as T[k] extends OptionalOutSchema ? k : never]?: T[k]["_zod"]["output"];
|
|
638
640
|
} & Extra>;
|
|
639
|
-
export type $InferObjectInput<T extends $ZodLooseShape, Extra extends Record<string, unknown>> = string extends keyof T ? util.IsAny<T[keyof T]> extends true ? Record<string, unknown> :
|
|
641
|
+
export type $InferObjectInput<T extends $ZodLooseShape, Extra extends Record<string, unknown>> = string extends keyof T ? util.IsAny<T[keyof T]> extends true ? Record<string, unknown> : {
|
|
642
|
+
[k in string]: core.input<T[keyof T]>;
|
|
643
|
+
} : keyof (T & Extra) extends never ? Record<string, never> : util.Prettify<{
|
|
640
644
|
-readonly [k in keyof T as T[k] extends OptionalInSchema ? never : k]: T[k]["_zod"]["input"];
|
|
641
645
|
} & {
|
|
642
646
|
-readonly [k in keyof T as T[k] extends OptionalInSchema ? k : never]?: T[k]["_zod"]["input"];
|
|
@@ -729,7 +733,7 @@ export interface $ZodDiscriminatedUnionInternals<Options extends readonly SomeTy
|
|
|
729
733
|
def: $ZodDiscriminatedUnionDef<Options, Disc>;
|
|
730
734
|
propValues: util.PropValues;
|
|
731
735
|
bag: util.LoosePartial<{
|
|
732
|
-
optionsMap: Map<util.Primitive, $ZodType>;
|
|
736
|
+
optionsMap: Map<util.Primitive, $ZodType | null>;
|
|
733
737
|
}>;
|
|
734
738
|
}
|
|
735
739
|
/** The discriminator values a member of `Options` can declare. An omittable discriminator contributes `undefined`, matching what `propValues` claims for it. */
|
|
@@ -748,7 +752,7 @@ export type $DiscriminatedOption<Options extends readonly SomeType[], Disc exten
|
|
|
748
752
|
};
|
|
749
753
|
} ? Disc extends keyof Out ? V extends Out[Disc] ? Options[I] : never : never : never;
|
|
750
754
|
}[number];
|
|
751
|
-
/** Returns the option
|
|
755
|
+
/** Returns the option whose discriminator claims `value`, or throws if ambiguous. */
|
|
752
756
|
export declare function getDiscriminatedOption<Options extends readonly SomeType[], Disc extends string, const V extends $DiscriminatorValue<Options, Disc>>(union: $ZodDiscriminatedUnion<Options, Disc>, value: V): $DiscriminatedOption<Options, Disc, V>;
|
|
753
757
|
export interface $ZodDiscriminatedUnion<Options extends readonly SomeType[] = readonly $ZodType[], Disc extends string = string> extends $ZodType {
|
|
754
758
|
_zod: $ZodDiscriminatedUnionInternals<Options, Disc>;
|
|
@@ -1006,7 +1010,7 @@ export interface $ZodPrefaultDef<T extends SomeType = $ZodType> extends $ZodType
|
|
|
1006
1010
|
/** The default value. May be a getter. */
|
|
1007
1011
|
defaultValue: core.input<T>;
|
|
1008
1012
|
}
|
|
1009
|
-
export interface $ZodPrefaultInternals<T extends SomeType = $ZodType> extends $ZodTypeInternals<
|
|
1013
|
+
export interface $ZodPrefaultInternals<T extends SomeType = $ZodType> extends $ZodTypeInternals<core.output<T>, core.input<T> | undefined> {
|
|
1010
1014
|
def: $ZodPrefaultDef<T>;
|
|
1011
1015
|
optin: "defaulted";
|
|
1012
1016
|
optout?: "optional" | undefined;
|