zod 3.26.0-canary.20250707T201657 → 3.26.0-canary.20250708T225111
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/schemas.ts +4 -7
- package/src/v4/classic/tests/error-utils.test.ts +27 -2
- package/src/v4/classic/tests/recursive-types.test.ts +30 -0
- package/src/v4/classic/tests/refine.test.ts +109 -0
- package/src/v4/classic/tests/registries.test.ts +9 -0
- package/src/v4/classic/tests/to-json-schema.test.ts +42 -3
- package/src/v4/core/api.ts +2 -0
- package/src/v4/core/checks.ts +8 -10
- package/src/v4/core/errors.ts +13 -7
- package/src/v4/core/registries.ts +7 -1
- package/src/v4/core/schemas.ts +4 -4
- package/src/v4/core/to-json-schema.ts +44 -23
- package/v4/classic/schemas.cjs +4 -4
- package/v4/classic/schemas.d.cts +2 -2
- package/v4/classic/schemas.d.ts +2 -2
- package/v4/classic/schemas.js +4 -4
- package/v4/core/checks.cjs +18 -12
- package/v4/core/checks.d.cts +2 -1
- package/v4/core/checks.d.ts +2 -1
- package/v4/core/checks.js +18 -12
- package/v4/core/errors.cjs +4 -0
- package/v4/core/errors.d.cts +3 -1
- package/v4/core/errors.d.ts +3 -1
- package/v4/core/errors.js +4 -0
- package/v4/core/registries.cjs +6 -1
- package/v4/core/registries.d.cts +2 -1
- package/v4/core/registries.d.ts +2 -1
- package/v4/core/registries.js +6 -1
- package/v4/core/schemas.cjs +2 -2
- package/v4/core/schemas.js +2 -2
- package/v4/core/to-json-schema.cjs +41 -22
- package/v4/core/to-json-schema.d.cts +1 -1
- package/v4/core/to-json-schema.d.ts +1 -1
- package/v4/core/to-json-schema.js +41 -22
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zod",
|
|
3
|
-
"version": "3.26.0-canary.
|
|
3
|
+
"version": "3.26.0-canary.20250708T225111",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Colin McDonnell <zod@colinhacks.com>",
|
|
6
6
|
"description": "TypeScript-first schema declaration and validation library with static type inference",
|
|
@@ -1937,10 +1937,10 @@ export const ZodCustom: core.$constructor<ZodCustom> = /*@__PURE__*/ core.$const
|
|
|
1937
1937
|
});
|
|
1938
1938
|
|
|
1939
1939
|
// custom checks
|
|
1940
|
-
export function check<O = unknown>(fn: core.CheckFn<O
|
|
1940
|
+
export function check<O = unknown>(fn: core.CheckFn<O>): core.$ZodCheck<O> {
|
|
1941
1941
|
const ch = new core.$ZodCheck({
|
|
1942
1942
|
check: "custom",
|
|
1943
|
-
...util.normalizeParams(params),
|
|
1943
|
+
// ...util.normalizeParams(params),
|
|
1944
1944
|
});
|
|
1945
1945
|
|
|
1946
1946
|
ch._zod.check = fn;
|
|
@@ -1962,10 +1962,7 @@ export function refine<T>(
|
|
|
1962
1962
|
}
|
|
1963
1963
|
|
|
1964
1964
|
// superRefine
|
|
1965
|
-
export function superRefine<T>(
|
|
1966
|
-
fn: (arg: T, payload: RefinementCtx<T>) => void | Promise<void>,
|
|
1967
|
-
params?: string | core.$ZodCustomParams
|
|
1968
|
-
): core.$ZodCheck<T> {
|
|
1965
|
+
export function superRefine<T>(fn: (arg: T, payload: RefinementCtx<T>) => void | Promise<void>): core.$ZodCheck<T> {
|
|
1969
1966
|
const ch = check<T>((payload) => {
|
|
1970
1967
|
(payload as RefinementCtx).addIssue = (issue) => {
|
|
1971
1968
|
if (typeof issue === "string") {
|
|
@@ -1983,7 +1980,7 @@ export function superRefine<T>(
|
|
|
1983
1980
|
};
|
|
1984
1981
|
|
|
1985
1982
|
return fn(payload.value, payload as RefinementCtx<T>);
|
|
1986
|
-
}
|
|
1983
|
+
});
|
|
1987
1984
|
return ch;
|
|
1988
1985
|
}
|
|
1989
1986
|
|
|
@@ -321,7 +321,7 @@ test("all errors", () => {
|
|
|
321
321
|
});
|
|
322
322
|
|
|
323
323
|
const schema = z.strictObject({
|
|
324
|
-
username: z.string(),
|
|
324
|
+
username: z.string().brand<"username">(),
|
|
325
325
|
favoriteNumbers: z.array(z.number()),
|
|
326
326
|
nesting: z.object({
|
|
327
327
|
a: z.string(),
|
|
@@ -336,8 +336,33 @@ const result = schema.safeParse({
|
|
|
336
336
|
extra: 1234,
|
|
337
337
|
});
|
|
338
338
|
|
|
339
|
+
const tree = z.treeifyError(result.error!);
|
|
340
|
+
|
|
341
|
+
expectTypeOf(tree).toEqualTypeOf<{
|
|
342
|
+
errors: string[];
|
|
343
|
+
properties?: {
|
|
344
|
+
username?: {
|
|
345
|
+
errors: string[];
|
|
346
|
+
};
|
|
347
|
+
favoriteNumbers?: {
|
|
348
|
+
errors: string[];
|
|
349
|
+
items?: {
|
|
350
|
+
errors: string[];
|
|
351
|
+
}[];
|
|
352
|
+
};
|
|
353
|
+
nesting?: {
|
|
354
|
+
errors: string[];
|
|
355
|
+
properties?: {
|
|
356
|
+
a?: {
|
|
357
|
+
errors: string[];
|
|
358
|
+
};
|
|
359
|
+
};
|
|
360
|
+
};
|
|
361
|
+
};
|
|
362
|
+
}>();
|
|
363
|
+
|
|
339
364
|
test("z.treeifyError", () => {
|
|
340
|
-
expect(
|
|
365
|
+
expect(tree).toMatchInlineSnapshot(`
|
|
341
366
|
{
|
|
342
367
|
"errors": [
|
|
343
368
|
"Unrecognized key: "extra"",
|
|
@@ -324,3 +324,33 @@ test("recursion compatibility", () => {
|
|
|
324
324
|
},
|
|
325
325
|
});
|
|
326
326
|
});
|
|
327
|
+
|
|
328
|
+
// biome-ignore lint: sadf
|
|
329
|
+
export type RecursiveA = z.ZodUnion<
|
|
330
|
+
[
|
|
331
|
+
z.ZodObject<{
|
|
332
|
+
a: z.ZodDefault<RecursiveA>;
|
|
333
|
+
b: z.ZodPrefault<RecursiveA>;
|
|
334
|
+
c: z.ZodNonOptional<RecursiveA>;
|
|
335
|
+
d: z.ZodOptional<RecursiveA>;
|
|
336
|
+
e: z.ZodNullable<RecursiveA>;
|
|
337
|
+
g: z.ZodReadonly<RecursiveA>;
|
|
338
|
+
h: z.ZodPipe<RecursiveA, z.ZodString>;
|
|
339
|
+
i: z.ZodArray<RecursiveA>;
|
|
340
|
+
j: z.ZodSet<RecursiveA>;
|
|
341
|
+
k: z.ZodMap<RecursiveA, RecursiveA>;
|
|
342
|
+
l: z.ZodRecord<z.ZodString, RecursiveA>;
|
|
343
|
+
m: z.ZodUnion<[RecursiveA, RecursiveA]>;
|
|
344
|
+
n: z.ZodIntersection<RecursiveA, RecursiveA>;
|
|
345
|
+
o: z.ZodLazy<RecursiveA>;
|
|
346
|
+
p: z.ZodPromise<RecursiveA>;
|
|
347
|
+
q: z.ZodCatch<RecursiveA>;
|
|
348
|
+
r: z.ZodSuccess<RecursiveA>;
|
|
349
|
+
s: z.ZodTransform<RecursiveA, string>;
|
|
350
|
+
t: z.ZodTuple<[RecursiveA, RecursiveA]>;
|
|
351
|
+
u: z.ZodObject<{
|
|
352
|
+
a: RecursiveA;
|
|
353
|
+
}>;
|
|
354
|
+
}>,
|
|
355
|
+
]
|
|
356
|
+
>;
|
|
@@ -421,3 +421,112 @@ describe("type refinement", () => {
|
|
|
421
421
|
});
|
|
422
422
|
});
|
|
423
423
|
*/
|
|
424
|
+
|
|
425
|
+
test("when", () => {
|
|
426
|
+
const schema = z
|
|
427
|
+
.strictObject({
|
|
428
|
+
password: z.string().min(8),
|
|
429
|
+
confirmPassword: z.string(),
|
|
430
|
+
other: z.string(),
|
|
431
|
+
})
|
|
432
|
+
.refine(
|
|
433
|
+
(data) => {
|
|
434
|
+
console.log("running check...");
|
|
435
|
+
console.log(data);
|
|
436
|
+
console.log(data.password);
|
|
437
|
+
return data.password === data.confirmPassword;
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
message: "Passwords do not match",
|
|
441
|
+
path: ["confirmPassword"],
|
|
442
|
+
when(payload) {
|
|
443
|
+
if (payload.value === undefined) return false;
|
|
444
|
+
if (payload.value === null) return false;
|
|
445
|
+
// no issues with confirmPassword or password
|
|
446
|
+
return payload.issues.every((iss) => iss.path?.[0] !== "confirmPassword" && iss.path?.[0] !== "password");
|
|
447
|
+
},
|
|
448
|
+
}
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
expect(schema.safeParse(undefined)).toMatchInlineSnapshot(`
|
|
452
|
+
{
|
|
453
|
+
"error": [ZodError: [
|
|
454
|
+
{
|
|
455
|
+
"expected": "object",
|
|
456
|
+
"code": "invalid_type",
|
|
457
|
+
"path": [],
|
|
458
|
+
"message": "Invalid input: expected object, received undefined"
|
|
459
|
+
}
|
|
460
|
+
]],
|
|
461
|
+
"success": false,
|
|
462
|
+
}
|
|
463
|
+
`);
|
|
464
|
+
expect(schema.safeParse(null)).toMatchInlineSnapshot(`
|
|
465
|
+
{
|
|
466
|
+
"error": [ZodError: [
|
|
467
|
+
{
|
|
468
|
+
"expected": "object",
|
|
469
|
+
"code": "invalid_type",
|
|
470
|
+
"path": [],
|
|
471
|
+
"message": "Invalid input: expected object, received null"
|
|
472
|
+
}
|
|
473
|
+
]],
|
|
474
|
+
"success": false,
|
|
475
|
+
}
|
|
476
|
+
`);
|
|
477
|
+
expect(
|
|
478
|
+
schema.safeParse({
|
|
479
|
+
password: "asdf",
|
|
480
|
+
confirmPassword: "asdfg",
|
|
481
|
+
other: "qwer",
|
|
482
|
+
})
|
|
483
|
+
).toMatchInlineSnapshot(`
|
|
484
|
+
{
|
|
485
|
+
"error": [ZodError: [
|
|
486
|
+
{
|
|
487
|
+
"origin": "string",
|
|
488
|
+
"code": "too_small",
|
|
489
|
+
"minimum": 8,
|
|
490
|
+
"inclusive": true,
|
|
491
|
+
"path": [
|
|
492
|
+
"password"
|
|
493
|
+
],
|
|
494
|
+
"message": "Too small: expected string to have >=8 characters"
|
|
495
|
+
}
|
|
496
|
+
]],
|
|
497
|
+
"success": false,
|
|
498
|
+
}
|
|
499
|
+
`);
|
|
500
|
+
|
|
501
|
+
expect(
|
|
502
|
+
schema.safeParse({
|
|
503
|
+
password: "asdf",
|
|
504
|
+
confirmPassword: "asdfg",
|
|
505
|
+
other: 1234,
|
|
506
|
+
})
|
|
507
|
+
).toMatchInlineSnapshot(`
|
|
508
|
+
{
|
|
509
|
+
"error": [ZodError: [
|
|
510
|
+
{
|
|
511
|
+
"origin": "string",
|
|
512
|
+
"code": "too_small",
|
|
513
|
+
"minimum": 8,
|
|
514
|
+
"inclusive": true,
|
|
515
|
+
"path": [
|
|
516
|
+
"password"
|
|
517
|
+
],
|
|
518
|
+
"message": "Too small: expected string to have >=8 characters"
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
"expected": "string",
|
|
522
|
+
"code": "invalid_type",
|
|
523
|
+
"path": [
|
|
524
|
+
"other"
|
|
525
|
+
],
|
|
526
|
+
"message": "Invalid input: expected string, received number"
|
|
527
|
+
}
|
|
528
|
+
]],
|
|
529
|
+
"success": false,
|
|
530
|
+
}
|
|
531
|
+
`);
|
|
532
|
+
});
|
|
@@ -193,3 +193,12 @@ test("function meta with replacement", () => {
|
|
|
193
193
|
|
|
194
194
|
expect(myReg.get(mySchema)!.defaulter("hello", true)).toEqual(5);
|
|
195
195
|
});
|
|
196
|
+
|
|
197
|
+
test("test .clear()", () => {
|
|
198
|
+
const reg = z.registry();
|
|
199
|
+
const a = z.string();
|
|
200
|
+
reg.add(a);
|
|
201
|
+
expect(reg.has(a)).toEqual(true);
|
|
202
|
+
reg.clear();
|
|
203
|
+
expect(reg.has(a)).toEqual(false);
|
|
204
|
+
});
|
|
@@ -1746,16 +1746,17 @@ test("basic registry", () => {
|
|
|
1746
1746
|
myRegistry.add(User, { id: "User" });
|
|
1747
1747
|
myRegistry.add(Post, { id: "Post" });
|
|
1748
1748
|
|
|
1749
|
-
const result = z.z.toJSONSchema(myRegistry);
|
|
1749
|
+
const result = z.z.toJSONSchema(myRegistry, { uri: (id) => `https://example.com/${id}.json` });
|
|
1750
1750
|
expect(result).toMatchInlineSnapshot(`
|
|
1751
1751
|
{
|
|
1752
1752
|
"schemas": {
|
|
1753
1753
|
"Post": {
|
|
1754
|
+
"$id": "https://example.com/Post.json",
|
|
1754
1755
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
1755
1756
|
"additionalProperties": false,
|
|
1756
1757
|
"properties": {
|
|
1757
1758
|
"author": {
|
|
1758
|
-
"$ref": "User",
|
|
1759
|
+
"$ref": "https://example.com/User.json",
|
|
1759
1760
|
},
|
|
1760
1761
|
"content": {
|
|
1761
1762
|
"type": "string",
|
|
@@ -1772,6 +1773,7 @@ test("basic registry", () => {
|
|
|
1772
1773
|
"type": "object",
|
|
1773
1774
|
},
|
|
1774
1775
|
"User": {
|
|
1776
|
+
"$id": "https://example.com/User.json",
|
|
1775
1777
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
1776
1778
|
"additionalProperties": false,
|
|
1777
1779
|
"properties": {
|
|
@@ -1780,7 +1782,7 @@ test("basic registry", () => {
|
|
|
1780
1782
|
},
|
|
1781
1783
|
"posts": {
|
|
1782
1784
|
"items": {
|
|
1783
|
-
"$ref": "Post",
|
|
1785
|
+
"$ref": "https://example.com/Post.json",
|
|
1784
1786
|
},
|
|
1785
1787
|
"type": "array",
|
|
1786
1788
|
},
|
|
@@ -2273,3 +2275,40 @@ test("custom toJSONSchema", () => {
|
|
|
2273
2275
|
}
|
|
2274
2276
|
`);
|
|
2275
2277
|
});
|
|
2278
|
+
|
|
2279
|
+
test("cycle detection - root", () => {
|
|
2280
|
+
const schema = z.object({
|
|
2281
|
+
name: z.string(),
|
|
2282
|
+
get subcategories() {
|
|
2283
|
+
return z.array(schema);
|
|
2284
|
+
},
|
|
2285
|
+
});
|
|
2286
|
+
|
|
2287
|
+
expect(() => z.toJSONSchema(schema, { cycles: "throw" })).toThrowErrorMatchingInlineSnapshot(`
|
|
2288
|
+
[Error: Cycle detected: #/properties/subcategories/items/<root>
|
|
2289
|
+
|
|
2290
|
+
Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.]
|
|
2291
|
+
`);
|
|
2292
|
+
});
|
|
2293
|
+
|
|
2294
|
+
test("cycle detection - mutual recursion", () => {
|
|
2295
|
+
const A = z.object({
|
|
2296
|
+
name: z.string(),
|
|
2297
|
+
get subcategories() {
|
|
2298
|
+
return z.array(B);
|
|
2299
|
+
},
|
|
2300
|
+
});
|
|
2301
|
+
|
|
2302
|
+
const B = z.object({
|
|
2303
|
+
name: z.string(),
|
|
2304
|
+
get subcategories() {
|
|
2305
|
+
return z.array(A);
|
|
2306
|
+
},
|
|
2307
|
+
});
|
|
2308
|
+
|
|
2309
|
+
expect(() => z.toJSONSchema(A, { cycles: "throw" })).toThrowErrorMatchingInlineSnapshot(`
|
|
2310
|
+
[Error: Cycle detected: #/properties/subcategories/items/properties/subcategories/items/<root>
|
|
2311
|
+
|
|
2312
|
+
Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.]
|
|
2313
|
+
`);
|
|
2314
|
+
});
|
package/src/v4/core/api.ts
CHANGED
|
@@ -779,6 +779,8 @@ export function _nan<T extends schemas.$ZodNaN>(Class: util.SchemaClass<T>, para
|
|
|
779
779
|
});
|
|
780
780
|
}
|
|
781
781
|
|
|
782
|
+
// export type $ZodCheckParams = CheckParams<checks.$ZodCheck, "abort">;
|
|
783
|
+
|
|
782
784
|
export type $ZodCheckLessThanParams = CheckParams<checks.$ZodCheckLessThan, "inclusive" | "value">;
|
|
783
785
|
export function _lt(
|
|
784
786
|
value: util.Numeric,
|
package/src/v4/core/checks.ts
CHANGED
|
@@ -13,18 +13,16 @@ export interface $ZodCheckDef {
|
|
|
13
13
|
error?: errors.$ZodErrorMap<never> | undefined;
|
|
14
14
|
/** If true, no later checks will be executed if this check fails. Default `false`. */
|
|
15
15
|
abort?: boolean | undefined;
|
|
16
|
+
/** If provided, this check will only be executed if the function returns `true`. Defaults to `payload => z.util.isAborted(payload)`. */
|
|
17
|
+
when?: ((payload: schemas.ParsePayload) => boolean) | undefined;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
export interface $ZodCheckInternals<T> {
|
|
19
21
|
def: $ZodCheckDef;
|
|
20
22
|
/** The set of issues this check might throw. */
|
|
21
23
|
issc?: errors.$ZodIssueBase;
|
|
22
|
-
// "_check"(input: $ZodResult<T>): util.MaybeAsync<void>;
|
|
23
24
|
check(payload: schemas.ParsePayload<T>): util.MaybeAsync<void>;
|
|
24
|
-
// _parseB(payload: ParsePayload<any>, ctx: ParseContext): util.MaybeAsync<ParsePayload>;
|
|
25
25
|
onattach: ((schema: schemas.$ZodType) => void)[];
|
|
26
|
-
// "_async": boolean;
|
|
27
|
-
when?: ((payload: schemas.ParsePayload) => boolean) | undefined;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
export interface $ZodCheck<in T = never> {
|
|
@@ -452,7 +450,7 @@ export const $ZodCheckMaxSize: core.$constructor<$ZodCheckMaxSize> = /*@__PURE__
|
|
|
452
450
|
(inst, def) => {
|
|
453
451
|
$ZodCheck.init(inst, def);
|
|
454
452
|
|
|
455
|
-
inst._zod.when
|
|
453
|
+
inst._zod.def.when ??= (payload) => {
|
|
456
454
|
const val = payload.value;
|
|
457
455
|
return !util.nullish(val) && (val as any).size !== undefined;
|
|
458
456
|
};
|
|
@@ -501,7 +499,7 @@ export const $ZodCheckMinSize: core.$constructor<$ZodCheckMinSize> = /*@__PURE__
|
|
|
501
499
|
(inst, def) => {
|
|
502
500
|
$ZodCheck.init(inst, def);
|
|
503
501
|
|
|
504
|
-
inst._zod.when
|
|
502
|
+
inst._zod.def.when ??= (payload) => {
|
|
505
503
|
const val = payload.value;
|
|
506
504
|
return !util.nullish(val) && (val as any).size !== undefined;
|
|
507
505
|
};
|
|
@@ -550,7 +548,7 @@ export const $ZodCheckSizeEquals: core.$constructor<$ZodCheckSizeEquals> = /*@__
|
|
|
550
548
|
(inst, def) => {
|
|
551
549
|
$ZodCheck.init(inst, def);
|
|
552
550
|
|
|
553
|
-
inst._zod.when
|
|
551
|
+
inst._zod.def.when ??= (payload) => {
|
|
554
552
|
const val = payload.value;
|
|
555
553
|
return !util.nullish(val) && (val as any).size !== undefined;
|
|
556
554
|
};
|
|
@@ -604,7 +602,7 @@ export const $ZodCheckMaxLength: core.$constructor<$ZodCheckMaxLength> = /*@__PU
|
|
|
604
602
|
(inst, def) => {
|
|
605
603
|
$ZodCheck.init(inst, def);
|
|
606
604
|
|
|
607
|
-
inst._zod.when
|
|
605
|
+
inst._zod.def.when ??= (payload) => {
|
|
608
606
|
const val = payload.value;
|
|
609
607
|
return !util.nullish(val) && (val as any).length !== undefined;
|
|
610
608
|
};
|
|
@@ -655,7 +653,7 @@ export const $ZodCheckMinLength: core.$constructor<$ZodCheckMinLength> = /*@__PU
|
|
|
655
653
|
(inst, def) => {
|
|
656
654
|
$ZodCheck.init(inst, def);
|
|
657
655
|
|
|
658
|
-
inst._zod.when
|
|
656
|
+
inst._zod.def.when ??= (payload) => {
|
|
659
657
|
const val = payload.value;
|
|
660
658
|
return !util.nullish(val) && (val as any).length !== undefined;
|
|
661
659
|
};
|
|
@@ -707,7 +705,7 @@ export const $ZodCheckLengthEquals: core.$constructor<$ZodCheckLengthEquals> = /
|
|
|
707
705
|
(inst, def) => {
|
|
708
706
|
$ZodCheck.init(inst, def);
|
|
709
707
|
|
|
710
|
-
inst._zod.when
|
|
708
|
+
inst._zod.def.when ??= (payload) => {
|
|
711
709
|
const val = payload.value;
|
|
712
710
|
return !util.nullish(val) && (val as any).length !== undefined;
|
|
713
711
|
};
|
package/src/v4/core/errors.ts
CHANGED
|
@@ -203,6 +203,10 @@ const initializer = (inst: $ZodError, def: $ZodIssue[]): void => {
|
|
|
203
203
|
enumerable: true,
|
|
204
204
|
// configurable: false,
|
|
205
205
|
});
|
|
206
|
+
Object.defineProperty(inst, "toString", {
|
|
207
|
+
value: () => inst.message,
|
|
208
|
+
enumerable: false,
|
|
209
|
+
});
|
|
206
210
|
};
|
|
207
211
|
|
|
208
212
|
export const $ZodError: $constructor<$ZodError> = $constructor("$ZodError", initializer);
|
|
@@ -291,13 +295,15 @@ export function formatError<T>(error: $ZodError, _mapper?: any) {
|
|
|
291
295
|
return fieldErrors;
|
|
292
296
|
}
|
|
293
297
|
|
|
294
|
-
export type $ZodErrorTree<T, U = string> = T extends
|
|
295
|
-
? { errors: U[]
|
|
296
|
-
: T extends any[]
|
|
297
|
-
? { errors: U[]; items?:
|
|
298
|
-
: T extends
|
|
299
|
-
? { errors: U[];
|
|
300
|
-
:
|
|
298
|
+
export type $ZodErrorTree<T, U = string> = T extends util.Primitive
|
|
299
|
+
? { errors: U[] }
|
|
300
|
+
: T extends [any, ...any[]]
|
|
301
|
+
? { errors: U[]; items?: { [K in keyof T]?: $ZodErrorTree<T[K], U> } }
|
|
302
|
+
: T extends any[]
|
|
303
|
+
? { errors: U[]; items?: Array<$ZodErrorTree<T[number], U>> }
|
|
304
|
+
: T extends object
|
|
305
|
+
? { errors: U[]; properties?: { [K in keyof T]?: $ZodErrorTree<T[K], U> } }
|
|
306
|
+
: { errors: U[] };
|
|
301
307
|
|
|
302
308
|
export function treeifyError<T>(error: $ZodError<T>): $ZodErrorTree<T>;
|
|
303
309
|
export function treeifyError<T, U>(error: $ZodError<T>, mapper?: (issue: $ZodIssue) => U): $ZodErrorTree<T, U>;
|
|
@@ -27,7 +27,7 @@ type MetadataType = Record<string, unknown> | undefined;
|
|
|
27
27
|
export class $ZodRegistry<Meta extends MetadataType = MetadataType, Schema extends $ZodType = $ZodType> {
|
|
28
28
|
_meta!: Meta;
|
|
29
29
|
_schema!: Schema;
|
|
30
|
-
_map:
|
|
30
|
+
_map: Map<Schema, $replace<Meta, Schema>> = new Map();
|
|
31
31
|
_idmap: Map<string, Schema> = new Map();
|
|
32
32
|
|
|
33
33
|
add<S extends Schema>(
|
|
@@ -45,6 +45,12 @@ export class $ZodRegistry<Meta extends MetadataType = MetadataType, Schema exten
|
|
|
45
45
|
return this as any;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
clear(): this {
|
|
49
|
+
this._map = new Map();
|
|
50
|
+
this._idmap = new Map();
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
|
|
48
54
|
remove(schema: Schema): this {
|
|
49
55
|
const meta: any = this._map.get(schema);
|
|
50
56
|
if (meta && typeof meta === "object" && "id" in meta) {
|
package/src/v4/core/schemas.ts
CHANGED
|
@@ -204,18 +204,18 @@ export const $ZodType: core.$constructor<$ZodType> = /*@__PURE__*/ core.$constru
|
|
|
204
204
|
ctx?: ParseContextInternal | undefined
|
|
205
205
|
): util.MaybeAsync<ParsePayload> => {
|
|
206
206
|
let isAborted = util.aborted(payload);
|
|
207
|
+
|
|
207
208
|
let asyncResult!: Promise<unknown> | undefined;
|
|
208
209
|
for (const ch of checks) {
|
|
209
|
-
if (ch._zod.when) {
|
|
210
|
-
const shouldRun = ch._zod.when(payload);
|
|
211
|
-
|
|
210
|
+
if (ch._zod.def.when) {
|
|
211
|
+
const shouldRun = ch._zod.def.when(payload);
|
|
212
212
|
if (!shouldRun) continue;
|
|
213
213
|
} else if (isAborted) {
|
|
214
214
|
continue;
|
|
215
215
|
}
|
|
216
|
-
|
|
217
216
|
const currLen = payload.issues.length;
|
|
218
217
|
const _ = ch._zod.check(payload as any) as any as ParsePayload;
|
|
218
|
+
|
|
219
219
|
if (_ instanceof Promise && ctx?.async === false) {
|
|
220
220
|
throw new core.$ZodAsyncError();
|
|
221
221
|
}
|
|
@@ -47,7 +47,7 @@ interface EmitParams {
|
|
|
47
47
|
| {
|
|
48
48
|
/** */
|
|
49
49
|
registry: $ZodRegistry<{ id?: string | undefined }>;
|
|
50
|
-
uri
|
|
50
|
+
uri?: ((id: string) => string) | undefined;
|
|
51
51
|
defs: Record<string, JSONSchema.BaseSchema>;
|
|
52
52
|
}
|
|
53
53
|
| undefined;
|
|
@@ -614,6 +614,8 @@ export class JSONSchemaGenerator {
|
|
|
614
614
|
// initialize result with root schema fields
|
|
615
615
|
// Object.assign(result, seen.cached);
|
|
616
616
|
|
|
617
|
+
// returns a ref to the schema
|
|
618
|
+
// defId will be empty if the ref points to an external schema (or #)
|
|
617
619
|
const makeURI = (entry: [schemas.$ZodType<unknown, unknown>, Seen]): { ref: string; defId?: string } => {
|
|
618
620
|
// comparing the seen objects because sometimes
|
|
619
621
|
// multiple schemas map to the same seen object.
|
|
@@ -625,12 +627,15 @@ export class JSONSchemaGenerator {
|
|
|
625
627
|
const externalId = params.external.registry.get(entry[0])?.id; // ?? "__shared";// `__schema${this.counter++}`;
|
|
626
628
|
|
|
627
629
|
// check if schema is in the external registry
|
|
628
|
-
|
|
630
|
+
const uriGenerator = params.external.uri ?? ((id) => id);
|
|
631
|
+
if (externalId) {
|
|
632
|
+
return { ref: uriGenerator(externalId) };
|
|
633
|
+
}
|
|
629
634
|
|
|
630
635
|
// otherwise, add to __shared
|
|
631
636
|
const id: string = entry[1].defId ?? (entry[1].schema.id as string) ?? `schema${this.counter++}`;
|
|
632
|
-
entry[1].defId = id;
|
|
633
|
-
return { defId: id, ref: `${
|
|
637
|
+
entry[1].defId = id; // set defId so it will be reused if needed
|
|
638
|
+
return { defId: id, ref: `${uriGenerator("__shared")}#/${defsSegment}/${id}` };
|
|
634
639
|
}
|
|
635
640
|
|
|
636
641
|
if (entry[1] === root) {
|
|
@@ -647,6 +652,7 @@ export class JSONSchemaGenerator {
|
|
|
647
652
|
// stored cached version in `def` property
|
|
648
653
|
// remove all properties, set $ref
|
|
649
654
|
const extractToDef = (entry: [schemas.$ZodType<unknown, unknown>, Seen]): void => {
|
|
655
|
+
// if the schema is already a reference, do not extract it
|
|
650
656
|
if (entry[1].schema.$ref) {
|
|
651
657
|
return;
|
|
652
658
|
}
|
|
@@ -664,15 +670,29 @@ export class JSONSchemaGenerator {
|
|
|
664
670
|
schema.$ref = ref;
|
|
665
671
|
};
|
|
666
672
|
|
|
673
|
+
// throw on cycles
|
|
674
|
+
|
|
675
|
+
// break cycles
|
|
676
|
+
if (params.cycles === "throw") {
|
|
677
|
+
for (const entry of this.seen.entries()) {
|
|
678
|
+
const seen = entry[1];
|
|
679
|
+
if (seen.cycle) {
|
|
680
|
+
throw new Error(
|
|
681
|
+
"Cycle detected: " +
|
|
682
|
+
`#/${seen.cycle?.join("/")}/<root>` +
|
|
683
|
+
'\n\nSet the `cycles` parameter to `"ref"` to resolve cyclical schemas with defs.'
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
667
689
|
// extract schemas into $defs
|
|
668
690
|
for (const entry of this.seen.entries()) {
|
|
669
691
|
const seen = entry[1];
|
|
670
692
|
|
|
671
693
|
// convert root schema to # $ref
|
|
672
|
-
// also prevents root schema from being extracted
|
|
673
694
|
if (schema === entry[0]) {
|
|
674
|
-
//
|
|
675
|
-
extractToDef(entry);
|
|
695
|
+
extractToDef(entry); // this has special handling for the root schema
|
|
676
696
|
continue;
|
|
677
697
|
}
|
|
678
698
|
|
|
@@ -689,21 +709,13 @@ export class JSONSchemaGenerator {
|
|
|
689
709
|
const id = this.metadataRegistry.get(entry[0])?.id;
|
|
690
710
|
if (id) {
|
|
691
711
|
extractToDef(entry);
|
|
692
|
-
|
|
693
712
|
continue;
|
|
694
713
|
}
|
|
695
714
|
|
|
696
715
|
// break cycles
|
|
697
716
|
if (seen.cycle) {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
"Cycle detected: " +
|
|
701
|
-
`#/${seen.cycle?.join("/")}/<root>` +
|
|
702
|
-
'\n\nSet the `cycles` parameter to `"ref"` to resolve cyclical schemas with defs.'
|
|
703
|
-
);
|
|
704
|
-
} else if (params.cycles === "ref") {
|
|
705
|
-
extractToDef(entry);
|
|
706
|
-
}
|
|
717
|
+
// any
|
|
718
|
+
extractToDef(entry);
|
|
707
719
|
continue;
|
|
708
720
|
}
|
|
709
721
|
|
|
@@ -768,6 +780,12 @@ export class JSONSchemaGenerator {
|
|
|
768
780
|
console.warn(`Invalid target: ${this.target}`);
|
|
769
781
|
}
|
|
770
782
|
|
|
783
|
+
if (params.external?.uri) {
|
|
784
|
+
const id = params.external.registry.get(schema)?.id;
|
|
785
|
+
if (!id) throw new Error("Schema is missing an `id` property");
|
|
786
|
+
result.$id = params.external.uri(id);
|
|
787
|
+
}
|
|
788
|
+
|
|
771
789
|
Object.assign(result, root.def);
|
|
772
790
|
|
|
773
791
|
// build defs object
|
|
@@ -780,11 +798,14 @@ export class JSONSchemaGenerator {
|
|
|
780
798
|
}
|
|
781
799
|
|
|
782
800
|
// set definitions in result
|
|
783
|
-
if (
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
801
|
+
if (params.external) {
|
|
802
|
+
} else {
|
|
803
|
+
if (Object.keys(defs).length > 0) {
|
|
804
|
+
if (this.target === "draft-2020-12") {
|
|
805
|
+
result.$defs = defs;
|
|
806
|
+
} else {
|
|
807
|
+
result.definitions = defs;
|
|
808
|
+
}
|
|
788
809
|
}
|
|
789
810
|
}
|
|
790
811
|
|
|
@@ -824,7 +845,7 @@ export function toJSONSchema(
|
|
|
824
845
|
const schemas: Record<string, JSONSchema.BaseSchema> = {};
|
|
825
846
|
const external = {
|
|
826
847
|
registry: input,
|
|
827
|
-
uri: (_params as RegistryToJSONSchemaParams)?.uri
|
|
848
|
+
uri: (_params as RegistryToJSONSchemaParams)?.uri,
|
|
828
849
|
defs,
|
|
829
850
|
};
|
|
830
851
|
for (const entry of input._idmap.entries()) {
|
package/v4/classic/schemas.cjs
CHANGED
|
@@ -1038,10 +1038,10 @@ exports.ZodCustom = core.$constructor("ZodCustom", (inst, def) => {
|
|
|
1038
1038
|
exports.ZodType.init(inst, def);
|
|
1039
1039
|
});
|
|
1040
1040
|
// custom checks
|
|
1041
|
-
function check(fn
|
|
1041
|
+
function check(fn) {
|
|
1042
1042
|
const ch = new core.$ZodCheck({
|
|
1043
1043
|
check: "custom",
|
|
1044
|
-
...
|
|
1044
|
+
// ...util.normalizeParams(params),
|
|
1045
1045
|
});
|
|
1046
1046
|
ch._zod.check = fn;
|
|
1047
1047
|
return ch;
|
|
@@ -1053,7 +1053,7 @@ function refine(fn, _params = {}) {
|
|
|
1053
1053
|
return core._refine(exports.ZodCustom, fn, _params);
|
|
1054
1054
|
}
|
|
1055
1055
|
// superRefine
|
|
1056
|
-
function superRefine(fn
|
|
1056
|
+
function superRefine(fn) {
|
|
1057
1057
|
const ch = check((payload) => {
|
|
1058
1058
|
payload.addIssue = (issue) => {
|
|
1059
1059
|
if (typeof issue === "string") {
|
|
@@ -1072,7 +1072,7 @@ function superRefine(fn, params) {
|
|
|
1072
1072
|
}
|
|
1073
1073
|
};
|
|
1074
1074
|
return fn(payload.value, payload);
|
|
1075
|
-
}
|
|
1075
|
+
});
|
|
1076
1076
|
return ch;
|
|
1077
1077
|
}
|
|
1078
1078
|
function _instanceof(cls, params = {
|
package/v4/classic/schemas.d.cts
CHANGED
|
@@ -602,10 +602,10 @@ export declare function promise<T extends core.SomeType>(innerType: T): ZodPromi
|
|
|
602
602
|
export interface ZodCustom<O = unknown, I = unknown> extends _ZodType<core.$ZodCustomInternals<O, I>>, core.$ZodCustom<O, I> {
|
|
603
603
|
}
|
|
604
604
|
export declare const ZodCustom: core.$constructor<ZodCustom>;
|
|
605
|
-
export declare function check<O = unknown>(fn: core.CheckFn<O
|
|
605
|
+
export declare function check<O = unknown>(fn: core.CheckFn<O>): core.$ZodCheck<O>;
|
|
606
606
|
export declare function custom<O>(fn?: (data: unknown) => unknown, _params?: string | core.$ZodCustomParams | undefined): ZodCustom<O, O>;
|
|
607
607
|
export declare function refine<T>(fn: (arg: NoInfer<T>) => util.MaybeAsync<unknown>, _params?: string | core.$ZodCustomParams): core.$ZodCheck<T>;
|
|
608
|
-
export declare function superRefine<T>(fn: (arg: T, payload: RefinementCtx<T>) => void | Promise<void
|
|
608
|
+
export declare function superRefine<T>(fn: (arg: T, payload: RefinementCtx<T>) => void | Promise<void>): core.$ZodCheck<T>;
|
|
609
609
|
type ZodInstanceOfParams = core.Params<ZodCustom, core.$ZodIssueCustom, "type" | "check" | "checks" | "fn" | "abort" | "error" | "params" | "path">;
|
|
610
610
|
declare function _instanceof<T extends typeof util.Class>(cls: T, params?: ZodInstanceOfParams): ZodCustom<InstanceType<T>, InstanceType<T>>;
|
|
611
611
|
export { _instanceof as instanceof };
|