zod 4.1.12 → 4.1.13
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/checks.ts +1 -0
- package/src/v4/classic/schemas.ts +20 -0
- package/src/v4/classic/tests/continuability.test.ts +22 -0
- package/src/v4/classic/tests/describe-meta-checks.test.ts +27 -0
- package/src/v4/classic/tests/index.test.ts +55 -1
- package/src/v4/classic/tests/promise.test.ts +1 -1
- package/src/v4/classic/tests/readonly.test.ts +1 -1
- package/src/v4/classic/tests/record.test.ts +141 -9
- package/src/v4/classic/tests/registries.test.ts +5 -1
- package/src/v4/classic/tests/string.test.ts +72 -0
- package/src/v4/classic/tests/template-literal.test.ts +8 -0
- package/src/v4/classic/tests/to-json-schema.test.ts +97 -0
- package/src/v4/classic/tests/tuple.test.ts +18 -0
- package/src/v4/classic/tests/url.test.ts +13 -0
- package/src/v4/core/api.ts +45 -0
- package/src/v4/core/core.ts +22 -9
- package/src/v4/core/regexes.ts +6 -1
- package/src/v4/core/registries.ts +12 -1
- package/src/v4/core/schemas.ts +50 -33
- package/src/v4/core/tests/extend.test.ts +42 -1
- package/src/v4/core/tests/locales/he.test.ts +379 -0
- package/src/v4/core/tests/locales/nl.test.ts +46 -0
- package/src/v4/core/tests/record-constructor.test.ts +67 -0
- package/src/v4/core/tests/recursive-tuples.test.ts +45 -0
- package/src/v4/core/to-json-schema.ts +55 -91
- package/src/v4/core/util.ts +11 -0
- package/src/v4/core/versions.ts +1 -1
- package/src/v4/locales/en.ts +1 -0
- package/src/v4/locales/he.ts +202 -71
- package/src/v4/locales/nl.ts +10 -10
- package/src/v4/mini/iso.ts +4 -4
- package/src/v4/mini/schemas.ts +17 -0
- package/src/v4/mini/tests/functions.test.ts +0 -38
- package/src/v4/mini/tests/index.test.ts +24 -1
- package/src/v4/mini/tests/string.test.ts +32 -0
- package/v3/ZodError.d.cts +1 -1
- package/v3/ZodError.d.ts +1 -1
- package/v4/classic/checks.cjs +2 -1
- package/v4/classic/checks.d.cts +1 -1
- package/v4/classic/checks.d.ts +1 -1
- package/v4/classic/checks.js +1 -1
- package/v4/classic/schemas.cjs +15 -2
- package/v4/classic/schemas.d.cts +8 -0
- package/v4/classic/schemas.d.ts +8 -0
- package/v4/classic/schemas.js +12 -0
- package/v4/core/api.cjs +40 -0
- package/v4/core/api.d.cts +7 -0
- package/v4/core/api.d.ts +7 -0
- package/v4/core/api.js +36 -0
- package/v4/core/core.cjs +20 -11
- package/v4/core/core.js +20 -11
- package/v4/core/regexes.cjs +31 -2
- package/v4/core/regexes.d.cts +1 -0
- package/v4/core/regexes.d.ts +1 -0
- package/v4/core/regexes.js +5 -0
- package/v4/core/registries.cjs +3 -1
- package/v4/core/registries.js +3 -1
- package/v4/core/schemas.cjs +32 -33
- package/v4/core/schemas.d.cts +12 -2
- package/v4/core/schemas.d.ts +12 -2
- package/v4/core/schemas.js +30 -31
- package/v4/core/to-json-schema.cjs +55 -92
- package/v4/core/to-json-schema.js +55 -92
- package/v4/core/util.cjs +11 -0
- package/v4/core/util.d.cts +1 -0
- package/v4/core/util.d.ts +1 -0
- package/v4/core/util.js +10 -0
- package/v4/core/versions.cjs +1 -1
- package/v4/core/versions.js +1 -1
- package/v4/locales/en.cjs +1 -0
- package/v4/locales/en.js +1 -0
- package/v4/locales/he.cjs +177 -66
- package/v4/locales/he.js +177 -66
- package/v4/locales/nl.cjs +8 -8
- package/v4/locales/nl.js +8 -8
- package/v4/mini/iso.cjs +4 -4
- package/v4/mini/iso.js +4 -4
- package/v4/mini/schemas.cjs +13 -2
- package/v4/mini/schemas.d.cts +6 -0
- package/v4/mini/schemas.d.ts +6 -0
- package/v4/mini/schemas.js +10 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, test } from "vitest";
|
|
2
|
+
import { z } from "../../../../index.js";
|
|
3
|
+
import he from "../../../locales/he.js";
|
|
4
|
+
|
|
5
|
+
describe("Hebrew localization", () => {
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
z.config(he());
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
describe("too_small errors with definite article and gendered verbs", () => {
|
|
11
|
+
test("string type (feminine - צריכה)", () => {
|
|
12
|
+
const schema = z.string().min(3);
|
|
13
|
+
const result = schema.safeParse("ab");
|
|
14
|
+
expect(result.success).toBe(false);
|
|
15
|
+
if (!result.success) {
|
|
16
|
+
expect(result.error.issues[0].message).toBe("קצר מדי: המחרוזת צריכה להכיל 3 תווים או יותר");
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("number type (masculine - צריך)", () => {
|
|
21
|
+
const schema = z.number().min(10);
|
|
22
|
+
const result = schema.safeParse(5);
|
|
23
|
+
expect(result.success).toBe(false);
|
|
24
|
+
if (!result.success) {
|
|
25
|
+
expect(result.error.issues[0].message).toBe("קטן מדי: המספר צריך להיות גדול או שווה ל-10");
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("array type (masculine - צריך)", () => {
|
|
30
|
+
const schema = z.array(z.string()).min(1);
|
|
31
|
+
const result = schema.safeParse([]);
|
|
32
|
+
expect(result.success).toBe(false);
|
|
33
|
+
if (!result.success) {
|
|
34
|
+
expect(result.error.issues[0].message).toBe("קטן מדי: המערך צריך להכיל לפחות פריט אחד");
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("set type (feminine - צריכה)", () => {
|
|
39
|
+
const schema = z.set(z.string()).min(2);
|
|
40
|
+
const result = schema.safeParse(new Set(["a"]));
|
|
41
|
+
expect(result.success).toBe(false);
|
|
42
|
+
if (!result.success) {
|
|
43
|
+
expect(result.error.issues[0].message).toBe("קטן מדי: הקבוצה (Set) צריכה להכיל 2 פריטים או יותר");
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe("too_big errors with definite article and gendered verbs", () => {
|
|
49
|
+
test("string type (feminine - צריכה)", () => {
|
|
50
|
+
const schema = z.string().max(3);
|
|
51
|
+
const result = schema.safeParse("abcde");
|
|
52
|
+
expect(result.success).toBe(false);
|
|
53
|
+
if (!result.success) {
|
|
54
|
+
expect(result.error.issues[0].message).toBe("ארוך מדי: המחרוזת צריכה להכיל 3 תווים או פחות");
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("number type (masculine - צריך)", () => {
|
|
59
|
+
const schema = z.number().max(365);
|
|
60
|
+
const result = schema.safeParse(400);
|
|
61
|
+
expect(result.success).toBe(false);
|
|
62
|
+
if (!result.success) {
|
|
63
|
+
expect(result.error.issues[0].message).toBe("גדול מדי: המספר צריך להיות קטן או שווה ל-365");
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("array max", () => {
|
|
68
|
+
const schema = z.array(z.string()).max(2);
|
|
69
|
+
const result = schema.safeParse(["a", "b", "c"]);
|
|
70
|
+
expect(result.success).toBe(false);
|
|
71
|
+
if (!result.success) {
|
|
72
|
+
expect(result.error.issues[0].message).toBe("גדול מדי: המערך צריך להכיל 2 פריטים או פחות");
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe("invalid_type errors with definite article and gendered verbs", () => {
|
|
78
|
+
test("string expected (feminine), number received", () => {
|
|
79
|
+
const schema = z.string();
|
|
80
|
+
const result = schema.safeParse(123);
|
|
81
|
+
expect(result.success).toBe(false);
|
|
82
|
+
if (!result.success) {
|
|
83
|
+
expect(result.error.issues[0].message).toBe("קלט לא תקין: צריך להיות מחרוזת, התקבל מספר");
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("number expected (masculine), string received", () => {
|
|
88
|
+
const schema = z.number();
|
|
89
|
+
const result = schema.safeParse("abc");
|
|
90
|
+
expect(result.success).toBe(false);
|
|
91
|
+
if (!result.success) {
|
|
92
|
+
expect(result.error.issues[0].message).toBe("קלט לא תקין: צריך להיות מספר, התקבל מחרוזת");
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("boolean expected (masculine), null received", () => {
|
|
97
|
+
const schema = z.boolean();
|
|
98
|
+
const result = schema.safeParse(null);
|
|
99
|
+
expect(result.success).toBe(false);
|
|
100
|
+
if (!result.success) {
|
|
101
|
+
expect(result.error.issues[0].message).toBe("קלט לא תקין: צריך להיות ערך בוליאני, התקבל ערך ריק (null)");
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("array expected (masculine), object received", () => {
|
|
106
|
+
const schema = z.array(z.string());
|
|
107
|
+
const result = schema.safeParse({});
|
|
108
|
+
expect(result.success).toBe(false);
|
|
109
|
+
if (!result.success) {
|
|
110
|
+
expect(result.error.issues[0].message).toBe("קלט לא תקין: צריך להיות מערך, התקבל אובייקט");
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("object expected (masculine), array received", () => {
|
|
115
|
+
const schema = z.object({ a: z.string() });
|
|
116
|
+
const result = schema.safeParse([]);
|
|
117
|
+
expect(result.success).toBe(false);
|
|
118
|
+
if (!result.success) {
|
|
119
|
+
expect(result.error.issues[0].message).toBe("קלט לא תקין: צריך להיות אובייקט, התקבל מערך");
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("function expected (feminine), string received", () => {
|
|
124
|
+
const schema = z.function();
|
|
125
|
+
const result = schema.safeParse("not a function");
|
|
126
|
+
expect(result.success).toBe(false);
|
|
127
|
+
if (!result.success) {
|
|
128
|
+
expect(result.error.issues[0].message).toBe("קלט לא תקין: צריך להיות פונקציה, התקבל מחרוזת");
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe("gendered verbs consistency", () => {
|
|
134
|
+
test("feminine types use צריכה", () => {
|
|
135
|
+
const feminineTypes = [
|
|
136
|
+
{ schema: z.string().min(5), input: "abc" },
|
|
137
|
+
{ schema: z.set(z.string()).min(2), input: new Set(["a"]) },
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
for (const { schema, input } of feminineTypes) {
|
|
141
|
+
const result = schema.safeParse(input);
|
|
142
|
+
expect(result.success).toBe(false);
|
|
143
|
+
if (!result.success) {
|
|
144
|
+
expect(result.error.issues[0].message).toContain("צריכה");
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test("masculine types use צריך", () => {
|
|
150
|
+
const masculineTypes = [
|
|
151
|
+
{ schema: z.number().min(10), input: 5 },
|
|
152
|
+
{ schema: z.array(z.string()).min(2), input: ["a"] },
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
for (const { schema, input } of masculineTypes) {
|
|
156
|
+
const result = schema.safeParse(input);
|
|
157
|
+
expect(result.success).toBe(false);
|
|
158
|
+
if (!result.success) {
|
|
159
|
+
expect(result.error.issues[0].message).toContain("צריך");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe("invalid_value with enum", () => {
|
|
166
|
+
test("single value", () => {
|
|
167
|
+
const schema = z.enum(["a"]);
|
|
168
|
+
const result = schema.safeParse("b");
|
|
169
|
+
expect(result.success).toBe(false);
|
|
170
|
+
if (!result.success) {
|
|
171
|
+
expect(result.error.issues[0].message).toBe('ערך לא תקין: הערך חייב להיות "a"');
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test("two values", () => {
|
|
176
|
+
const schema = z.enum(["a", "b"]);
|
|
177
|
+
const result = schema.safeParse("c");
|
|
178
|
+
expect(result.success).toBe(false);
|
|
179
|
+
if (!result.success) {
|
|
180
|
+
expect(result.error.issues[0].message).toBe('ערך לא תקין: האפשרויות המתאימות הן "a" או "b"');
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("multiple values", () => {
|
|
185
|
+
const schema = z.enum(["a", "b", "c"]);
|
|
186
|
+
const result = schema.safeParse("d");
|
|
187
|
+
expect(result.success).toBe(false);
|
|
188
|
+
if (!result.success) {
|
|
189
|
+
expect(result.error.issues[0].message).toBe('ערך לא תקין: האפשרויות המתאימות הן "a", "b" או "c"');
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe("other error types", () => {
|
|
195
|
+
test("not_multiple_of", () => {
|
|
196
|
+
const schema = z.number().multipleOf(3);
|
|
197
|
+
const result = schema.safeParse(10);
|
|
198
|
+
expect(result.success).toBe(false);
|
|
199
|
+
if (!result.success) {
|
|
200
|
+
expect(result.error.issues[0].message).toBe("מספר לא תקין: חייב להיות מכפלה של 3");
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test("unrecognized_keys - single key", () => {
|
|
205
|
+
const schema = z.object({ a: z.string() }).strict();
|
|
206
|
+
const result = schema.safeParse({ a: "test", b: "extra" });
|
|
207
|
+
expect(result.success).toBe(false);
|
|
208
|
+
if (!result.success) {
|
|
209
|
+
expect(result.error.issues[0].message).toBe('מפתח לא מזוהה: "b"');
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
test("unrecognized_keys - multiple keys", () => {
|
|
214
|
+
const schema = z.object({ a: z.string() }).strict();
|
|
215
|
+
const result = schema.safeParse({ a: "test", b: "extra", c: "more" });
|
|
216
|
+
expect(result.success).toBe(false);
|
|
217
|
+
if (!result.success) {
|
|
218
|
+
expect(result.error.issues[0].message).toBe('מפתחות לא מזוהים: "b", "c"');
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
test("invalid_union", () => {
|
|
223
|
+
const schema = z.union([z.string(), z.number()]);
|
|
224
|
+
const result = schema.safeParse(true);
|
|
225
|
+
expect(result.success).toBe(false);
|
|
226
|
+
if (!result.success) {
|
|
227
|
+
expect(result.error.issues[0].message).toBe("קלט לא תקין");
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
test("invalid_key in object", () => {
|
|
232
|
+
const schema = z.record(z.number(), z.string());
|
|
233
|
+
const result = schema.safeParse({ notANumber: "value" });
|
|
234
|
+
expect(result.success).toBe(false);
|
|
235
|
+
if (!result.success) {
|
|
236
|
+
expect(result.error.issues[0].message).toBe("שדה לא תקין באובייקט");
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
describe("invalid_format with string checks", () => {
|
|
242
|
+
test("startsWith", () => {
|
|
243
|
+
const schema = z.string().startsWith("hello");
|
|
244
|
+
const result = schema.safeParse("world");
|
|
245
|
+
expect(result.success).toBe(false);
|
|
246
|
+
if (!result.success) {
|
|
247
|
+
expect(result.error.issues[0].message).toBe('המחרוזת חייבת להתחיל ב "hello"');
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test("endsWith", () => {
|
|
252
|
+
const schema = z.string().endsWith("world");
|
|
253
|
+
const result = schema.safeParse("hello");
|
|
254
|
+
expect(result.success).toBe(false);
|
|
255
|
+
if (!result.success) {
|
|
256
|
+
expect(result.error.issues[0].message).toBe('המחרוזת חייבת להסתיים ב "world"');
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test("includes", () => {
|
|
261
|
+
const schema = z.string().includes("test");
|
|
262
|
+
const result = schema.safeParse("hello world");
|
|
263
|
+
expect(result.success).toBe(false);
|
|
264
|
+
if (!result.success) {
|
|
265
|
+
expect(result.error.issues[0].message).toBe('המחרוזת חייבת לכלול "test"');
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
test("regex", () => {
|
|
270
|
+
const schema = z.string().regex(/^[a-z]+$/);
|
|
271
|
+
const result = schema.safeParse("ABC123");
|
|
272
|
+
expect(result.success).toBe(false);
|
|
273
|
+
if (!result.success) {
|
|
274
|
+
expect(result.error.issues[0].message).toBe("המחרוזת חייבת להתאים לתבנית /^[a-z]+$/");
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
describe("invalid_format with common formats", () => {
|
|
280
|
+
test("email", () => {
|
|
281
|
+
const schema = z.string().email();
|
|
282
|
+
const result = schema.safeParse("not-an-email");
|
|
283
|
+
expect(result.success).toBe(false);
|
|
284
|
+
if (!result.success) {
|
|
285
|
+
expect(result.error.issues[0].message).toBe("כתובת אימייל לא תקינה");
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test("url", () => {
|
|
290
|
+
const schema = z.string().url();
|
|
291
|
+
const result = schema.safeParse("not-a-url");
|
|
292
|
+
expect(result.success).toBe(false);
|
|
293
|
+
if (!result.success) {
|
|
294
|
+
expect(result.error.issues[0].message).toBe("כתובת רשת לא תקינה");
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
test("uuid", () => {
|
|
299
|
+
const schema = z.string().uuid();
|
|
300
|
+
const result = schema.safeParse("not-a-uuid");
|
|
301
|
+
expect(result.success).toBe(false);
|
|
302
|
+
if (!result.success) {
|
|
303
|
+
expect(result.error.issues[0].message).toBe("UUID לא תקין");
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
describe("tuple validation", () => {
|
|
309
|
+
test("invalid element type in tuple shows full error message", () => {
|
|
310
|
+
const schema = z.tuple([z.string(), z.number()]);
|
|
311
|
+
const result = schema.safeParse(["abc", "not a number"]);
|
|
312
|
+
expect(result.success).toBe(false);
|
|
313
|
+
if (!result.success) {
|
|
314
|
+
expect(result.error.issues[0].message).toBe("קלט לא תקין: צריך להיות מספר, התקבל מחרוזת");
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
describe("inclusive vs exclusive bounds", () => {
|
|
320
|
+
test("inclusive minimum (>=)", () => {
|
|
321
|
+
const schema = z.number().min(10);
|
|
322
|
+
const result = schema.safeParse(5);
|
|
323
|
+
expect(result.success).toBe(false);
|
|
324
|
+
if (!result.success) {
|
|
325
|
+
expect(result.error.issues[0].message).toBe("קטן מדי: המספר צריך להיות גדול או שווה ל-10");
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
test("exclusive minimum (>)", () => {
|
|
330
|
+
const schema = z.number().gt(10);
|
|
331
|
+
const result = schema.safeParse(10);
|
|
332
|
+
expect(result.success).toBe(false);
|
|
333
|
+
if (!result.success) {
|
|
334
|
+
expect(result.error.issues[0].message).toBe("קטן מדי: המספר צריך להיות גדול מ-10");
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
test("inclusive maximum (<=)", () => {
|
|
339
|
+
const schema = z.number().max(10);
|
|
340
|
+
const result = schema.safeParse(15);
|
|
341
|
+
expect(result.success).toBe(false);
|
|
342
|
+
if (!result.success) {
|
|
343
|
+
expect(result.error.issues[0].message).toBe("גדול מדי: המספר צריך להיות קטן או שווה ל-10");
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
test("exclusive maximum (<)", () => {
|
|
348
|
+
const schema = z.number().lt(10);
|
|
349
|
+
const result = schema.safeParse(10);
|
|
350
|
+
expect(result.success).toBe(false);
|
|
351
|
+
if (!result.success) {
|
|
352
|
+
expect(result.error.issues[0].message).toBe("גדול מדי: המספר צריך להיות קטן מ-10");
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
describe("all type names with definite article", () => {
|
|
358
|
+
test("verifies all type translations are correct", () => {
|
|
359
|
+
const types = [
|
|
360
|
+
{ schema: z.string(), expected: "מחרוזת", input: 123 },
|
|
361
|
+
{ schema: z.number(), expected: "מספר", input: "abc" },
|
|
362
|
+
{ schema: z.boolean(), expected: "ערך בוליאני", input: "abc" },
|
|
363
|
+
{ schema: z.bigint(), expected: "BigInt", input: "abc" },
|
|
364
|
+
{ schema: z.date(), expected: "תאריך", input: "abc" },
|
|
365
|
+
{ schema: z.array(z.any()), expected: "מערך", input: "abc" },
|
|
366
|
+
{ schema: z.object({}), expected: "אובייקט", input: "abc" },
|
|
367
|
+
{ schema: z.function(), expected: "פונקציה", input: "abc" },
|
|
368
|
+
];
|
|
369
|
+
|
|
370
|
+
for (const { schema, expected, input } of types) {
|
|
371
|
+
const result = schema.safeParse(input);
|
|
372
|
+
expect(result.success).toBe(false);
|
|
373
|
+
if (!result.success) {
|
|
374
|
+
expect(result.error.issues[0].message).toContain(expected);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { expect, test } from "vitest";
|
|
2
|
+
import nl from "../../../locales/nl.js";
|
|
3
|
+
|
|
4
|
+
test("Dutch locale error messages", () => {
|
|
5
|
+
const { localeError } = nl();
|
|
6
|
+
|
|
7
|
+
// Test invalid_type
|
|
8
|
+
expect(
|
|
9
|
+
localeError({
|
|
10
|
+
code: "invalid_type",
|
|
11
|
+
expected: "string",
|
|
12
|
+
input: 123,
|
|
13
|
+
})
|
|
14
|
+
).toBe("Ongeldige invoer: verwacht string, ontving getal");
|
|
15
|
+
|
|
16
|
+
// Test too_big with sizing
|
|
17
|
+
expect(
|
|
18
|
+
localeError({
|
|
19
|
+
code: "too_big",
|
|
20
|
+
origin: "string",
|
|
21
|
+
maximum: 10,
|
|
22
|
+
inclusive: true,
|
|
23
|
+
input: "test string that is too long",
|
|
24
|
+
})
|
|
25
|
+
).toBe("Te groot: verwacht dat string te hebben <=10 tekens");
|
|
26
|
+
|
|
27
|
+
// Test too_small with sizing
|
|
28
|
+
expect(
|
|
29
|
+
localeError({
|
|
30
|
+
code: "too_small",
|
|
31
|
+
origin: "array",
|
|
32
|
+
minimum: 5,
|
|
33
|
+
inclusive: false,
|
|
34
|
+
input: [1, 2],
|
|
35
|
+
})
|
|
36
|
+
).toBe("Te klein: verwacht dat array te hebben >5 elementen");
|
|
37
|
+
|
|
38
|
+
// Test invalid_format
|
|
39
|
+
expect(
|
|
40
|
+
localeError({
|
|
41
|
+
code: "invalid_format",
|
|
42
|
+
format: "email",
|
|
43
|
+
input: "invalid-email",
|
|
44
|
+
})
|
|
45
|
+
).toBe("Ongeldig: emailadres");
|
|
46
|
+
});
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { expect, test } from "vitest";
|
|
2
|
+
import * as z from "zod/v4";
|
|
3
|
+
|
|
4
|
+
test("record should parse objects with non-function constructor field", () => {
|
|
5
|
+
const schema = z.record(z.string(), z.any());
|
|
6
|
+
|
|
7
|
+
expect(() => schema.parse({ constructor: "string", key: "value" })).not.toThrow();
|
|
8
|
+
|
|
9
|
+
const result1 = schema.parse({ constructor: "string", key: "value" });
|
|
10
|
+
expect(result1).toEqual({ constructor: "string", key: "value" });
|
|
11
|
+
|
|
12
|
+
expect(() => schema.parse({ constructor: 123, key: "value" })).not.toThrow();
|
|
13
|
+
|
|
14
|
+
const result2 = schema.parse({ constructor: 123, key: "value" });
|
|
15
|
+
expect(result2).toEqual({ constructor: 123, key: "value" });
|
|
16
|
+
|
|
17
|
+
expect(() => schema.parse({ constructor: null, key: "value" })).not.toThrow();
|
|
18
|
+
|
|
19
|
+
const result3 = schema.parse({ constructor: null, key: "value" });
|
|
20
|
+
expect(result3).toEqual({ constructor: null, key: "value" });
|
|
21
|
+
|
|
22
|
+
expect(() => schema.parse({ constructor: {}, key: "value" })).not.toThrow();
|
|
23
|
+
|
|
24
|
+
const result4 = schema.parse({ constructor: {}, key: "value" });
|
|
25
|
+
expect(result4).toEqual({ constructor: {}, key: "value" });
|
|
26
|
+
|
|
27
|
+
expect(() => schema.parse({ constructor: [], key: "value" })).not.toThrow();
|
|
28
|
+
|
|
29
|
+
const result5 = schema.parse({ constructor: [], key: "value" });
|
|
30
|
+
expect(result5).toEqual({ constructor: [], key: "value" });
|
|
31
|
+
|
|
32
|
+
expect(() => schema.parse({ constructor: true, key: "value" })).not.toThrow();
|
|
33
|
+
|
|
34
|
+
const result6 = schema.parse({ constructor: true, key: "value" });
|
|
35
|
+
expect(result6).toEqual({ constructor: true, key: "value" });
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("record should still work with normal objects", () => {
|
|
39
|
+
const schema = z.record(z.string(), z.string());
|
|
40
|
+
|
|
41
|
+
expect(() => schema.parse({ normalKey: "value" })).not.toThrow();
|
|
42
|
+
|
|
43
|
+
const result1 = schema.parse({ normalKey: "value" });
|
|
44
|
+
expect(result1).toEqual({ normalKey: "value" });
|
|
45
|
+
|
|
46
|
+
expect(() => schema.parse({ key1: "value1", key2: "value2" })).not.toThrow();
|
|
47
|
+
|
|
48
|
+
const result2 = schema.parse({ key1: "value1", key2: "value2" });
|
|
49
|
+
expect(result2).toEqual({ key1: "value1", key2: "value2" });
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("record should validate values according to schema even with constructor field", () => {
|
|
53
|
+
const stringSchema = z.record(z.string(), z.string());
|
|
54
|
+
|
|
55
|
+
expect(() => stringSchema.parse({ constructor: "string", key: "value" })).not.toThrow();
|
|
56
|
+
|
|
57
|
+
expect(() => stringSchema.parse({ constructor: 123, key: "value" })).toThrow();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("record should work with different key types and constructor field", () => {
|
|
61
|
+
const enumSchema = z.record(z.enum(["constructor", "key"]), z.string());
|
|
62
|
+
|
|
63
|
+
expect(() => enumSchema.parse({ constructor: "value1", key: "value2" })).not.toThrow();
|
|
64
|
+
|
|
65
|
+
const result = enumSchema.parse({ constructor: "value1", key: "value2" });
|
|
66
|
+
expect(result).toEqual({ constructor: "value1", key: "value2" });
|
|
67
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import * as z from "zod/v4";
|
|
3
|
+
|
|
4
|
+
describe("Recursive Tuples Regression #5089", () => {
|
|
5
|
+
it("creates recursive tuple without crash", () => {
|
|
6
|
+
expect(() => {
|
|
7
|
+
const y = z.lazy((): any => z.tuple([y, y]).or(z.string()));
|
|
8
|
+
}).not.toThrow();
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("parses recursive tuple data correctly", () => {
|
|
12
|
+
const y = z.lazy((): any => z.tuple([y, y]).or(z.string()));
|
|
13
|
+
|
|
14
|
+
// Base case
|
|
15
|
+
expect(y.parse("hello")).toBe("hello");
|
|
16
|
+
|
|
17
|
+
// Recursive cases
|
|
18
|
+
expect(() => y.parse(["a", "b"])).not.toThrow();
|
|
19
|
+
expect(() => y.parse(["a", ["b", "c"]])).not.toThrow();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("matches #5089 expected behavior", () => {
|
|
23
|
+
// Exact code from the issue
|
|
24
|
+
expect(() => {
|
|
25
|
+
const y = z.lazy((): any => z.tuple([y, y]).or(z.string()));
|
|
26
|
+
y.parse(["a", ["b", "c"]]);
|
|
27
|
+
}).not.toThrow();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("handles workaround pattern", () => {
|
|
31
|
+
// Alternative pattern from issue discussion
|
|
32
|
+
expect(() => {
|
|
33
|
+
const y = z.lazy((): any => z.string().or(z.lazy(() => z.tuple([y, y]))));
|
|
34
|
+
y.parse(["a", ["b", "c"]]);
|
|
35
|
+
}).not.toThrow();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("recursive arrays still work (comparison)", () => {
|
|
39
|
+
const y = z.lazy((): any => z.array(y).or(z.string()));
|
|
40
|
+
|
|
41
|
+
expect(y.parse("hello")).toBe("hello");
|
|
42
|
+
expect(y.parse(["hello", "world"])).toEqual(["hello", "world"]);
|
|
43
|
+
expect(y.parse(["a", ["b", "c"]])).toEqual(["a", ["b", "c"]]);
|
|
44
|
+
});
|
|
45
|
+
});
|