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
|
@@ -260,6 +260,73 @@ test("mutual recursion with meta", () => {
|
|
|
260
260
|
expectTypeOf<B>().toEqualTypeOf<_B>();
|
|
261
261
|
});
|
|
262
262
|
|
|
263
|
+
test("object utilities with recursive types", () => {
|
|
264
|
+
const NodeBase = z.object({
|
|
265
|
+
id: z.string(),
|
|
266
|
+
name: z.string(),
|
|
267
|
+
get children() {
|
|
268
|
+
return z.array(Node).optional();
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
// Test extend
|
|
273
|
+
const NodeOne = NodeBase.extend({
|
|
274
|
+
name: z.literal("nodeOne"),
|
|
275
|
+
get children() {
|
|
276
|
+
return z.array(Node);
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
const NodeTwo = NodeBase.extend({
|
|
281
|
+
name: z.literal("nodeTwo"),
|
|
282
|
+
get children() {
|
|
283
|
+
return z.array(Node);
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Test pick
|
|
288
|
+
const PickedNode = NodeBase.pick({ id: true, name: true });
|
|
289
|
+
|
|
290
|
+
// Test omit
|
|
291
|
+
const OmittedNode = NodeBase.omit({ children: true });
|
|
292
|
+
|
|
293
|
+
// Test merge
|
|
294
|
+
const ExtraProps = {
|
|
295
|
+
metadata: z.string(),
|
|
296
|
+
get parent() {
|
|
297
|
+
return Node.optional();
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
const MergedNode = NodeBase.extend(ExtraProps);
|
|
301
|
+
|
|
302
|
+
// Test partial
|
|
303
|
+
const PartialNode = NodeBase.partial();
|
|
304
|
+
const PartialMaskedNode = NodeBase.partial({ name: true });
|
|
305
|
+
|
|
306
|
+
// Test required (assuming NodeBase has optional fields)
|
|
307
|
+
const OptionalNodeBase = z.object({
|
|
308
|
+
id: z.string().optional(),
|
|
309
|
+
name: z.string().optional(),
|
|
310
|
+
get children() {
|
|
311
|
+
return z.array(Node).optional();
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
const RequiredNode = OptionalNodeBase.required();
|
|
315
|
+
const RequiredMaskedNode = OptionalNodeBase.required({ id: true });
|
|
316
|
+
|
|
317
|
+
const Node = z.union([
|
|
318
|
+
NodeOne,
|
|
319
|
+
NodeTwo,
|
|
320
|
+
PickedNode,
|
|
321
|
+
OmittedNode,
|
|
322
|
+
MergedNode,
|
|
323
|
+
PartialNode,
|
|
324
|
+
PartialMaskedNode,
|
|
325
|
+
RequiredNode,
|
|
326
|
+
RequiredMaskedNode,
|
|
327
|
+
]);
|
|
328
|
+
});
|
|
329
|
+
|
|
263
330
|
test("recursion compatibility", () => {
|
|
264
331
|
// array
|
|
265
332
|
const A = z.object({
|
|
@@ -318,6 +318,83 @@ test("url validations", () => {
|
|
|
318
318
|
expect(() => url.parse("https://")).toThrow();
|
|
319
319
|
});
|
|
320
320
|
|
|
321
|
+
test("url preserves original input", () => {
|
|
322
|
+
const url = z.string().url();
|
|
323
|
+
|
|
324
|
+
// Test the specific case from the user report
|
|
325
|
+
const input = "https://example.com?key=NUXOmHqWNVTapJkJJHw8BfD155AuqhH_qju_5fNmQ4ZHV7u8";
|
|
326
|
+
const output = url.parse(input);
|
|
327
|
+
expect(output).toBe(input); // Should preserve the original input exactly
|
|
328
|
+
|
|
329
|
+
// Test other cases where URL constructor would normalize
|
|
330
|
+
expect(url.parse("https://example.com?foo=bar")).toBe("https://example.com?foo=bar");
|
|
331
|
+
expect(url.parse("http://example.com?test=123")).toBe("http://example.com?test=123");
|
|
332
|
+
expect(url.parse("https://sub.example.com?param=value&other=data")).toBe(
|
|
333
|
+
"https://sub.example.com?param=value&other=data"
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
// Test cases with trailing slashes are preserved
|
|
337
|
+
expect(url.parse("https://example.com/")).toBe("https://example.com/");
|
|
338
|
+
expect(url.parse("https://example.com/path/")).toBe("https://example.com/path/");
|
|
339
|
+
|
|
340
|
+
// Test cases with paths and query parameters
|
|
341
|
+
expect(url.parse("https://example.com/path?query=param")).toBe("https://example.com/path?query=param");
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
test("url trims whitespace", () => {
|
|
345
|
+
const url = z.string().url();
|
|
346
|
+
|
|
347
|
+
// Test trimming whitespace from URLs
|
|
348
|
+
expect(url.parse(" https://example.com ")).toBe("https://example.com");
|
|
349
|
+
expect(url.parse(" https://example.com/path?query=param ")).toBe("https://example.com/path?query=param");
|
|
350
|
+
expect(url.parse("\t\nhttps://example.com\t\n")).toBe("https://example.com");
|
|
351
|
+
expect(url.parse(" https://example.com?key=value ")).toBe("https://example.com?key=value");
|
|
352
|
+
|
|
353
|
+
// Test that URLs without extra whitespace are unchanged
|
|
354
|
+
expect(url.parse("https://example.com")).toBe("https://example.com");
|
|
355
|
+
expect(url.parse("https://example.com/path")).toBe("https://example.com/path");
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
test("url normalize flag", () => {
|
|
359
|
+
const normalizeUrl = z.url({ normalize: true });
|
|
360
|
+
const preserveUrl = z.url(); // normalize: false/undefined by default
|
|
361
|
+
|
|
362
|
+
// Test that normalize flag causes URL normalization
|
|
363
|
+
expect(normalizeUrl.parse("https://example.com?key=value")).toBe("https://example.com/?key=value");
|
|
364
|
+
expect(normalizeUrl.parse("http://example.com?test=123")).toBe("http://example.com/?test=123");
|
|
365
|
+
|
|
366
|
+
// Test with already normalized URLs
|
|
367
|
+
expect(normalizeUrl.parse("https://example.com/")).toBe("https://example.com/");
|
|
368
|
+
expect(normalizeUrl.parse("https://example.com/path?query=param")).toBe("https://example.com/path?query=param");
|
|
369
|
+
|
|
370
|
+
// Test complex URLs with normalization
|
|
371
|
+
expect(normalizeUrl.parse("https://example.com/../?key=value")).toBe("https://example.com/?key=value");
|
|
372
|
+
expect(normalizeUrl.parse("https://example.com/./path?key=value")).toBe("https://example.com/path?key=value");
|
|
373
|
+
|
|
374
|
+
// Compare with non-normalize behavior
|
|
375
|
+
expect(preserveUrl.parse("https://example.com?key=value")).toBe("https://example.com?key=value");
|
|
376
|
+
expect(preserveUrl.parse("http://example.com?test=123")).toBe("http://example.com?test=123");
|
|
377
|
+
|
|
378
|
+
// Test trimming with normalize
|
|
379
|
+
expect(normalizeUrl.parse(" https://example.com?key=value ")).toBe("https://example.com/?key=value");
|
|
380
|
+
expect(preserveUrl.parse(" https://example.com?key=value ")).toBe("https://example.com?key=value");
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
test("url normalize with hostname and protocol constraints", () => {
|
|
384
|
+
const constrainedNormalizeUrl = z.url({
|
|
385
|
+
normalize: true,
|
|
386
|
+
protocol: /^https$/,
|
|
387
|
+
hostname: /^example\.com$/,
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// Test that normalization works with constraints
|
|
391
|
+
expect(constrainedNormalizeUrl.parse("https://example.com?key=value")).toBe("https://example.com/?key=value");
|
|
392
|
+
|
|
393
|
+
// Test that constraints are still enforced
|
|
394
|
+
expect(() => constrainedNormalizeUrl.parse("http://example.com?key=value")).toThrow();
|
|
395
|
+
expect(() => constrainedNormalizeUrl.parse("https://other.com?key=value")).toThrow();
|
|
396
|
+
});
|
|
397
|
+
|
|
321
398
|
test("httpurl", () => {
|
|
322
399
|
const httpUrl = z.url({
|
|
323
400
|
protocol: /^https?$/,
|
|
@@ -464,8 +541,8 @@ test(`bad uuid`, () => {
|
|
|
464
541
|
"9491d710-3185-0e06-bea0-6a2f275345e0",
|
|
465
542
|
"9491d710-3185-5e06-0ea0-6a2f275345e0",
|
|
466
543
|
"d89e7b01-7598-ed11-9d7a-0022489382fd", // new sequential id
|
|
467
|
-
"b3ce60f8-e8b9-40f5-1150-172ede56ff74", // Variant 0 - RFC 4122: Reserved, NCS backward compatibility
|
|
468
|
-
"92e76bf9-28b3-4730-cd7f-cb6bc51f8c09", // Variant 2 - RFC 4122: Reserved, Microsoft Corporation backward compatibility
|
|
544
|
+
"b3ce60f8-e8b9-40f5-1150-172ede56ff74", // Variant 0 - RFC 9562/4122: Reserved, NCS backward compatibility
|
|
545
|
+
"92e76bf9-28b3-4730-cd7f-cb6bc51f8c09", // Variant 2 - RFC 9562/4122: Reserved, Microsoft Corporation backward compatibility
|
|
469
546
|
"invalid uuid",
|
|
470
547
|
"9491d710-3185-4e06-bea0-6a2f275345e0X",
|
|
471
548
|
"ffffffff-ffff-ffff-ffff-ffffffffffff",
|
|
@@ -481,8 +558,8 @@ test("good guid", () => {
|
|
|
481
558
|
for (const goodGuid of [
|
|
482
559
|
"9491d710-3185-4e06-bea0-6a2f275345e0",
|
|
483
560
|
"d89e7b01-7598-ed11-9d7a-0022489382fd", // new sequential id
|
|
484
|
-
"b3ce60f8-e8b9-40f5-1150-172ede56ff74", // Variant 0 - RFC 4122: Reserved, NCS backward compatibility
|
|
485
|
-
"92e76bf9-28b3-4730-cd7f-cb6bc51f8c09", // Variant 2 - RFC 4122: Reserved, Microsoft Corporation backward compatibility
|
|
561
|
+
"b3ce60f8-e8b9-40f5-1150-172ede56ff74", // Variant 0 - RFC 9562/4122: Reserved, NCS backward compatibility
|
|
562
|
+
"92e76bf9-28b3-4730-cd7f-cb6bc51f8c09", // Variant 2 - RFC 9562/4122: Reserved, Microsoft Corporation backward compatibility
|
|
486
563
|
"00000000-0000-0000-0000-000000000000",
|
|
487
564
|
"ffffffff-ffff-ffff-ffff-ffffffffffff",
|
|
488
565
|
]) {
|
|
@@ -6,6 +6,7 @@ const hello = z.templateLiteral(["hello"]);
|
|
|
6
6
|
const world = z.templateLiteral(["", z.literal("world")]);
|
|
7
7
|
const one = z.templateLiteral([1]);
|
|
8
8
|
const two = z.templateLiteral(["", z.literal(2)]);
|
|
9
|
+
const onePointOne = z.templateLiteral([z.literal(1.1)]);
|
|
9
10
|
const truee = z.templateLiteral([true]);
|
|
10
11
|
const anotherTrue = z.templateLiteral(["", z.literal(true)]);
|
|
11
12
|
const falsee = z.templateLiteral([false]);
|
|
@@ -289,6 +290,7 @@ test("template literal parsing - success - basic cases", () => {
|
|
|
289
290
|
world.parse("world");
|
|
290
291
|
one.parse("1");
|
|
291
292
|
two.parse("2");
|
|
293
|
+
onePointOne.parse("1.1");
|
|
292
294
|
truee.parse("true");
|
|
293
295
|
anotherTrue.parse("true");
|
|
294
296
|
falsee.parse("false");
|
|
@@ -381,6 +383,7 @@ test("template literal parsing - failure - basic cases", () => {
|
|
|
381
383
|
expect(() => one.parse("2")).toThrow();
|
|
382
384
|
expect(() => one.parse("12")).toThrow();
|
|
383
385
|
expect(() => one.parse("21")).toThrow();
|
|
386
|
+
expect(() => onePointOne.parse("1s1")).toThrow();
|
|
384
387
|
expect(() => two.parse("1")).toThrow();
|
|
385
388
|
expect(() => two.parse("21")).toThrow();
|
|
386
389
|
expect(() => two.parse("12")).toThrow();
|
|
@@ -248,3 +248,113 @@ test("async short circuit on dirty", async () => {
|
|
|
248
248
|
]]
|
|
249
249
|
`);
|
|
250
250
|
});
|
|
251
|
+
|
|
252
|
+
test("do not continue by default", () => {
|
|
253
|
+
const A = z
|
|
254
|
+
.string()
|
|
255
|
+
.transform((val, ctx) => {
|
|
256
|
+
ctx.addIssue({
|
|
257
|
+
code: "custom",
|
|
258
|
+
message: `custom error`,
|
|
259
|
+
});
|
|
260
|
+
ctx.addIssue({
|
|
261
|
+
code: "custom",
|
|
262
|
+
message: `custom error`,
|
|
263
|
+
});
|
|
264
|
+
return val;
|
|
265
|
+
})
|
|
266
|
+
.pipe(z.number() as any);
|
|
267
|
+
expect(A.safeParse("asdf")).toMatchInlineSnapshot(`
|
|
268
|
+
{
|
|
269
|
+
"error": [ZodError: [
|
|
270
|
+
{
|
|
271
|
+
"code": "custom",
|
|
272
|
+
"message": "custom error",
|
|
273
|
+
"path": []
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"code": "custom",
|
|
277
|
+
"message": "custom error",
|
|
278
|
+
"path": []
|
|
279
|
+
}
|
|
280
|
+
]],
|
|
281
|
+
"success": false,
|
|
282
|
+
}
|
|
283
|
+
`);
|
|
284
|
+
|
|
285
|
+
const B = z
|
|
286
|
+
.string()
|
|
287
|
+
.transform((val, ctx) => {
|
|
288
|
+
ctx.issues.push({
|
|
289
|
+
code: "custom",
|
|
290
|
+
message: `custom error`,
|
|
291
|
+
input: val,
|
|
292
|
+
});
|
|
293
|
+
ctx.issues.push({
|
|
294
|
+
code: "custom",
|
|
295
|
+
message: `custom error`,
|
|
296
|
+
input: val,
|
|
297
|
+
});
|
|
298
|
+
return val;
|
|
299
|
+
})
|
|
300
|
+
.pipe(z.number() as any);
|
|
301
|
+
expect(B.safeParse("asdf")).toMatchInlineSnapshot(`
|
|
302
|
+
{
|
|
303
|
+
"error": [ZodError: [
|
|
304
|
+
{
|
|
305
|
+
"code": "custom",
|
|
306
|
+
"message": "custom error",
|
|
307
|
+
"path": []
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
"code": "custom",
|
|
311
|
+
"message": "custom error",
|
|
312
|
+
"path": []
|
|
313
|
+
}
|
|
314
|
+
]],
|
|
315
|
+
"success": false,
|
|
316
|
+
}
|
|
317
|
+
`);
|
|
318
|
+
|
|
319
|
+
const C = z
|
|
320
|
+
.string()
|
|
321
|
+
.transform((val, ctx) => {
|
|
322
|
+
ctx.issues.push({
|
|
323
|
+
code: "custom",
|
|
324
|
+
message: `custom error`,
|
|
325
|
+
input: val,
|
|
326
|
+
continue: true,
|
|
327
|
+
});
|
|
328
|
+
ctx.issues.push({
|
|
329
|
+
code: "custom",
|
|
330
|
+
message: `custom error`,
|
|
331
|
+
input: val,
|
|
332
|
+
continue: true,
|
|
333
|
+
});
|
|
334
|
+
return val;
|
|
335
|
+
})
|
|
336
|
+
.pipe(z.number() as any);
|
|
337
|
+
expect(C.safeParse("asdf")).toMatchInlineSnapshot(`
|
|
338
|
+
{
|
|
339
|
+
"error": [ZodError: [
|
|
340
|
+
{
|
|
341
|
+
"code": "custom",
|
|
342
|
+
"message": "custom error",
|
|
343
|
+
"path": []
|
|
344
|
+
},
|
|
345
|
+
{
|
|
346
|
+
"code": "custom",
|
|
347
|
+
"message": "custom error",
|
|
348
|
+
"path": []
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
"expected": "number",
|
|
352
|
+
"code": "invalid_type",
|
|
353
|
+
"path": [],
|
|
354
|
+
"message": "Invalid input: expected number, received string"
|
|
355
|
+
}
|
|
356
|
+
]],
|
|
357
|
+
"success": false,
|
|
358
|
+
}
|
|
359
|
+
`);
|
|
360
|
+
});
|
|
@@ -27,7 +27,7 @@ test("return valid over invalid", () => {
|
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
test("return errors from both union arms", () => {
|
|
30
|
-
const result = z.union([z.number(), z.
|
|
30
|
+
const result = z.union([z.number(), z.boolean()]).safeParse("a");
|
|
31
31
|
expect(result.success).toEqual(false);
|
|
32
32
|
if (!result.success) {
|
|
33
33
|
expect(result.error.issues).toMatchInlineSnapshot(`
|
|
@@ -45,8 +45,9 @@ test("return errors from both union arms", () => {
|
|
|
45
45
|
],
|
|
46
46
|
[
|
|
47
47
|
{
|
|
48
|
-
"code": "
|
|
49
|
-
"
|
|
48
|
+
"code": "invalid_type",
|
|
49
|
+
"expected": "boolean",
|
|
50
|
+
"message": "Invalid input: expected boolean, received string",
|
|
50
51
|
"path": [],
|
|
51
52
|
},
|
|
52
53
|
],
|
|
@@ -92,3 +93,44 @@ test("union values", () => {
|
|
|
92
93
|
}
|
|
93
94
|
`);
|
|
94
95
|
});
|
|
96
|
+
|
|
97
|
+
test("non-aborted errors", () => {
|
|
98
|
+
const zItemTest = z.union([
|
|
99
|
+
z.object({
|
|
100
|
+
date: z.number(),
|
|
101
|
+
startDate: z.optional(z.null()),
|
|
102
|
+
endDate: z.optional(z.null()),
|
|
103
|
+
}),
|
|
104
|
+
z
|
|
105
|
+
.object({
|
|
106
|
+
date: z.optional(z.null()),
|
|
107
|
+
startDate: z.number(),
|
|
108
|
+
endDate: z.number(),
|
|
109
|
+
})
|
|
110
|
+
.refine((data) => data.startDate !== data.endDate, {
|
|
111
|
+
error: "startDate and endDate must be different",
|
|
112
|
+
path: ["endDate"],
|
|
113
|
+
}),
|
|
114
|
+
]);
|
|
115
|
+
|
|
116
|
+
const res = zItemTest.safeParse({
|
|
117
|
+
date: null,
|
|
118
|
+
startDate: 1,
|
|
119
|
+
endDate: 1,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
expect(res).toMatchInlineSnapshot(`
|
|
123
|
+
{
|
|
124
|
+
"error": [ZodError: [
|
|
125
|
+
{
|
|
126
|
+
"code": "custom",
|
|
127
|
+
"path": [
|
|
128
|
+
"endDate"
|
|
129
|
+
],
|
|
130
|
+
"message": "startDate and endDate must be different"
|
|
131
|
+
}
|
|
132
|
+
]],
|
|
133
|
+
"success": false,
|
|
134
|
+
}
|
|
135
|
+
`);
|
|
136
|
+
});
|
package/src/v4/core/checks.ts
CHANGED
|
@@ -1128,12 +1128,12 @@ export interface $ZodCheckMimeTypeDef extends $ZodCheckDef {
|
|
|
1128
1128
|
mime: util.MimeTypes[];
|
|
1129
1129
|
}
|
|
1130
1130
|
|
|
1131
|
-
export interface $ZodCheckMimeTypeInternals<T extends File = File> extends $ZodCheckInternals<T> {
|
|
1131
|
+
export interface $ZodCheckMimeTypeInternals<T extends schemas.File = schemas.File> extends $ZodCheckInternals<T> {
|
|
1132
1132
|
def: $ZodCheckMimeTypeDef;
|
|
1133
1133
|
issc: errors.$ZodIssueInvalidValue;
|
|
1134
1134
|
}
|
|
1135
1135
|
|
|
1136
|
-
export interface $ZodCheckMimeType<T extends File = File> extends $ZodCheck<T> {
|
|
1136
|
+
export interface $ZodCheckMimeType<T extends schemas.File = schemas.File> extends $ZodCheck<T> {
|
|
1137
1137
|
_zod: $ZodCheckMimeTypeInternals<T>;
|
|
1138
1138
|
}
|
|
1139
1139
|
|
package/src/v4/core/errors.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { $ZodCheck, $ZodStringFormats } from "./checks.js";
|
|
2
2
|
import { $constructor } from "./core.js";
|
|
3
3
|
import type { $ZodType } from "./schemas.js";
|
|
4
|
+
import type { StandardSchemaV1 } from "./standard-schema.js";
|
|
4
5
|
import * as util from "./util.js";
|
|
5
6
|
|
|
6
7
|
///////////////////////////
|
|
@@ -162,7 +163,7 @@ type RawIssue<T extends $ZodIssueBase> = util.Flatten<
|
|
|
162
163
|
readonly input?: unknown;
|
|
163
164
|
/** The schema or check that originated this issue. */
|
|
164
165
|
readonly inst?: $ZodType | $ZodCheck;
|
|
165
|
-
/**
|
|
166
|
+
/** If `true`, Zod will continue executing validation despite this issue. */
|
|
166
167
|
readonly continue?: boolean | undefined;
|
|
167
168
|
} & Record<string, any>
|
|
168
169
|
>;
|
|
@@ -196,13 +197,8 @@ const initializer = (inst: $ZodError, def: $ZodIssue[]): void => {
|
|
|
196
197
|
value: def,
|
|
197
198
|
enumerable: false,
|
|
198
199
|
});
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
return JSON.stringify(def, util.jsonStringifyReplacer, 2);
|
|
202
|
-
},
|
|
203
|
-
enumerable: true,
|
|
204
|
-
// configurable: false,
|
|
205
|
-
});
|
|
200
|
+
inst.message = JSON.stringify(def, util.jsonStringifyReplacer, 2);
|
|
201
|
+
|
|
206
202
|
Object.defineProperty(inst, "toString", {
|
|
207
203
|
value: () => inst.message,
|
|
208
204
|
enumerable: false,
|
|
@@ -391,8 +387,9 @@ export function treeifyError<T>(error: $ZodError, _mapper?: any) {
|
|
|
391
387
|
* ✖ Invalid input: expected number
|
|
392
388
|
* ```
|
|
393
389
|
*/
|
|
394
|
-
export function toDotPath(
|
|
390
|
+
export function toDotPath(_path: readonly (string | number | symbol | StandardSchemaV1.PathSegment)[]): string {
|
|
395
391
|
const segs: string[] = [];
|
|
392
|
+
const path: PropertyKey[] = _path.map((seg: any) => (typeof seg === "object" ? seg.key : seg));
|
|
396
393
|
for (const seg of path) {
|
|
397
394
|
if (typeof seg === "number") segs.push(`[${seg}]`);
|
|
398
395
|
else if (typeof seg === "symbol") segs.push(`[${JSON.stringify(String(seg))}]`);
|
|
@@ -406,14 +403,10 @@ export function toDotPath(path: (string | number | symbol)[]): string {
|
|
|
406
403
|
return segs.join("");
|
|
407
404
|
}
|
|
408
405
|
|
|
409
|
-
|
|
410
|
-
issues: $ZodIssueBase[];
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
export function prettifyError(error: BaseError): string {
|
|
406
|
+
export function prettifyError(error: StandardSchemaV1.FailureResult): string {
|
|
414
407
|
const lines: string[] = [];
|
|
415
408
|
// sort by path length
|
|
416
|
-
const issues = [...error.issues].sort((a, b) => a.path.length - b.path.length);
|
|
409
|
+
const issues = [...error.issues].sort((a, b) => (a.path ?? []).length - (b.path ?? []).length);
|
|
417
410
|
|
|
418
411
|
// Process each issue
|
|
419
412
|
for (const issue of issues) {
|
package/src/v4/core/regexes.ts
CHANGED
|
@@ -16,7 +16,7 @@ export const extendedDuration: RegExp =
|
|
|
16
16
|
/** A regex for any UUID-like identifier: 8-4-4-4-12 hex pattern */
|
|
17
17
|
export const guid: RegExp = /^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/;
|
|
18
18
|
|
|
19
|
-
/** Returns a regex for validating an RFC 4122 UUID.
|
|
19
|
+
/** Returns a regex for validating an RFC 9562/4122 UUID.
|
|
20
20
|
*
|
|
21
21
|
* @param version Optionally specify a version 1-8. If no version is specified, all versions are supported. */
|
|
22
22
|
export const uuid = (version?: number | undefined): RegExp => {
|
|
@@ -23,7 +23,7 @@ export type $replace<Meta, S extends $ZodType> = Meta extends $output
|
|
|
23
23
|
? { [K in keyof Meta]: $replace<Meta[K], S> }
|
|
24
24
|
: Meta;
|
|
25
25
|
|
|
26
|
-
type MetadataType =
|
|
26
|
+
type MetadataType = object | undefined;
|
|
27
27
|
export class $ZodRegistry<Meta extends MetadataType = MetadataType, Schema extends $ZodType = $ZodType> {
|
|
28
28
|
_meta!: Meta;
|
|
29
29
|
_schema!: Schema;
|
|
@@ -68,7 +68,8 @@ export class $ZodRegistry<Meta extends MetadataType = MetadataType, Schema exten
|
|
|
68
68
|
if (p) {
|
|
69
69
|
const pm: any = { ...(this.get(p) ?? {}) };
|
|
70
70
|
delete pm.id; // do not inherit id
|
|
71
|
-
|
|
71
|
+
const f = { ...pm, ...this._map.get(schema) } as any;
|
|
72
|
+
return Object.keys(f).length ? f : undefined;
|
|
72
73
|
}
|
|
73
74
|
return this._map.get(schema) as any;
|
|
74
75
|
}
|