@wecode-ai/weibo-openclaw-plugin 2.2.3 → 2.2.5
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/node_modules/tar/dist/commonjs/index.min.js +3 -3
- package/node_modules/tar/dist/commonjs/index.min.js.map +3 -3
- package/node_modules/tar/dist/commonjs/pack.d.ts +4 -1
- package/node_modules/tar/dist/commonjs/pack.d.ts.map +1 -1
- package/node_modules/tar/dist/commonjs/pack.js +41 -7
- package/node_modules/tar/dist/commonjs/pack.js.map +1 -1
- package/node_modules/tar/dist/esm/index.min.js +3 -3
- package/node_modules/tar/dist/esm/index.min.js.map +3 -3
- package/node_modules/tar/dist/esm/pack.d.ts +4 -1
- package/node_modules/tar/dist/esm/pack.d.ts.map +1 -1
- package/node_modules/tar/dist/esm/pack.js +41 -7
- package/node_modules/tar/dist/esm/pack.js.map +1 -1
- package/node_modules/tar/package.json +4 -4
- package/node_modules/zod/README.md +1 -18
- package/node_modules/zod/locales/package.json +2 -1
- package/node_modules/zod/mini/package.json +2 -1
- package/node_modules/zod/package.json +1 -1
- package/node_modules/zod/src/v3/tests/all-errors.test.ts +3 -3
- package/node_modules/zod/src/v3/tests/object.test.ts +5 -5
- package/node_modules/zod/src/v3/tests/partials.test.ts +3 -3
- package/node_modules/zod/src/v4/classic/errors.ts +2 -2
- package/node_modules/zod/src/v4/classic/external.ts +1 -0
- package/node_modules/zod/src/v4/classic/from-json-schema.ts +39 -23
- package/node_modules/zod/src/v4/classic/parse.ts +6 -6
- package/node_modules/zod/src/v4/classic/schemas.ts +414 -151
- package/node_modules/zod/src/v4/classic/tests/assignability.test.ts +6 -0
- package/node_modules/zod/src/v4/classic/tests/catch.test.ts +50 -0
- package/node_modules/zod/src/v4/classic/tests/codec.test.ts +142 -1
- package/node_modules/zod/src/v4/classic/tests/continuability.test.ts +1 -1
- package/node_modules/zod/src/v4/classic/tests/datetime.test.ts +1 -1
- package/node_modules/zod/src/v4/classic/tests/default.test.ts +44 -0
- package/node_modules/zod/src/v4/classic/tests/detached-methods.test.ts +197 -0
- package/node_modules/zod/src/v4/classic/tests/discriminated-unions.test.ts +34 -1
- package/node_modules/zod/src/v4/classic/tests/error-utils.test.ts +214 -2
- package/node_modules/zod/src/v4/classic/tests/from-json-schema.test.ts +161 -0
- package/node_modules/zod/src/v4/classic/tests/function.test.ts +6 -6
- package/node_modules/zod/src/v4/classic/tests/global-config.test.ts +39 -0
- package/node_modules/zod/src/v4/classic/tests/index.test.ts +2 -2
- package/node_modules/zod/src/v4/classic/tests/jitless-allows-eval.test.ts +46 -0
- package/node_modules/zod/src/v4/classic/tests/locales_ka.test.ts +29 -0
- package/node_modules/zod/src/v4/classic/tests/locales_ro.test.ts +24 -0
- package/node_modules/zod/src/v4/classic/tests/number.test.ts +55 -0
- package/node_modules/zod/src/v4/classic/tests/object.test.ts +83 -6
- package/node_modules/zod/src/v4/classic/tests/optional.test.ts +114 -4
- package/node_modules/zod/src/v4/classic/tests/partial.test.ts +24 -1
- package/node_modules/zod/src/v4/classic/tests/prefault.test.ts +1 -1
- package/node_modules/zod/src/v4/classic/tests/preprocess-types.test.ts +26 -0
- package/node_modules/zod/src/v4/classic/tests/preprocess.test.ts +69 -0
- package/node_modules/zod/src/v4/classic/tests/record.test.ts +85 -0
- package/node_modules/zod/src/v4/classic/tests/recursive-types.test.ts +49 -0
- package/node_modules/zod/src/v4/classic/tests/refine.test.ts +63 -0
- package/node_modules/zod/src/v4/classic/tests/string.test.ts +50 -1
- package/node_modules/zod/src/v4/classic/tests/template-literal.test.ts +4 -4
- package/node_modules/zod/src/v4/classic/tests/to-json-schema.test.ts +150 -15
- package/node_modules/zod/src/v4/classic/tests/transform.test.ts +17 -0
- package/node_modules/zod/src/v4/classic/tests/tuple.test.ts +315 -2
- package/node_modules/zod/src/v4/classic/tests/union.test.ts +54 -0
- package/node_modules/zod/src/v4/core/api.ts +31 -6
- package/node_modules/zod/src/v4/core/checks.ts +1 -1
- package/node_modules/zod/src/v4/core/core.ts +17 -2
- package/node_modules/zod/src/v4/core/errors.ts +31 -24
- package/node_modules/zod/src/v4/core/json-schema-processors.ts +17 -18
- package/node_modules/zod/src/v4/core/parse.ts +7 -7
- package/node_modules/zod/src/v4/core/regexes.ts +8 -1
- package/node_modules/zod/src/v4/core/schemas.ts +263 -71
- package/node_modules/zod/src/v4/core/tests/locales/el.test.ts +215 -0
- package/node_modules/zod/src/v4/core/tests/locales/fr.test.ts +72 -0
- package/node_modules/zod/src/v4/core/tests/locales/hr.test.ts +163 -0
- package/node_modules/zod/src/v4/core/tests/locales/uz.test.ts +22 -0
- package/node_modules/zod/src/v4/core/tests/record-constructor.test.ts +58 -0
- package/node_modules/zod/src/v4/core/to-json-schema.ts +10 -1
- package/node_modules/zod/src/v4/core/util.ts +52 -35
- package/node_modules/zod/src/v4/core/versions.ts +2 -2
- package/node_modules/zod/src/v4/locales/el.ts +121 -0
- package/node_modules/zod/src/v4/locales/en.ts +4 -0
- package/node_modules/zod/src/v4/locales/fr.ts +24 -8
- package/node_modules/zod/src/v4/locales/hr.ts +131 -0
- package/node_modules/zod/src/v4/locales/index.ts +3 -0
- package/node_modules/zod/src/v4/locales/it.ts +1 -1
- package/node_modules/zod/src/v4/locales/ka.ts +8 -8
- package/node_modules/zod/src/v4/locales/ro.ts +129 -0
- package/node_modules/zod/src/v4/locales/uz.ts +1 -0
- package/node_modules/zod/src/v4/mini/external.ts +1 -0
- package/node_modules/zod/src/v4/mini/schemas.ts +56 -25
- package/node_modules/zod/src/v4/mini/tests/codec.test.ts +19 -0
- package/node_modules/zod/src/v4/mini/tests/index.test.ts +32 -2
- package/node_modules/zod/src/v4/mini/tests/object.test.ts +9 -9
- package/node_modules/zod/src/v4/mini/tests/recursive-types.test.ts +51 -1
- package/node_modules/zod/src/v4/mini/tests/string.test.ts +5 -0
- package/node_modules/zod/v3/package.json +2 -1
- package/node_modules/zod/v4/classic/errors.js +2 -2
- package/node_modules/zod/v4/classic/external.d.cts +1 -0
- package/node_modules/zod/v4/classic/external.d.ts +1 -0
- package/node_modules/zod/v4/classic/from-json-schema.cjs +31 -16
- package/node_modules/zod/v4/classic/from-json-schema.js +31 -16
- package/node_modules/zod/v4/classic/package.json +2 -1
- package/node_modules/zod/v4/classic/schemas.cjs +358 -119
- package/node_modules/zod/v4/classic/schemas.d.cts +42 -14
- package/node_modules/zod/v4/classic/schemas.d.ts +42 -14
- package/node_modules/zod/v4/classic/schemas.js +356 -118
- package/node_modules/zod/v4/core/api.cjs +7 -2
- package/node_modules/zod/v4/core/api.d.cts +26 -5
- package/node_modules/zod/v4/core/api.d.ts +26 -5
- package/node_modules/zod/v4/core/api.js +7 -2
- package/node_modules/zod/v4/core/checks.d.cts +1 -1
- package/node_modules/zod/v4/core/checks.d.ts +1 -1
- package/node_modules/zod/v4/core/core.cjs +3 -1
- package/node_modules/zod/v4/core/core.js +4 -2
- package/node_modules/zod/v4/core/errors.cjs +26 -23
- package/node_modules/zod/v4/core/errors.d.cts +1 -0
- package/node_modules/zod/v4/core/errors.d.ts +1 -0
- package/node_modules/zod/v4/core/errors.js +26 -23
- package/node_modules/zod/v4/core/json-schema-processors.cjs +16 -20
- package/node_modules/zod/v4/core/json-schema-processors.js +16 -20
- package/node_modules/zod/v4/core/package.json +2 -1
- package/node_modules/zod/v4/core/parse.cjs +7 -7
- package/node_modules/zod/v4/core/parse.js +7 -7
- package/node_modules/zod/v4/core/regexes.cjs +9 -3
- package/node_modules/zod/v4/core/regexes.d.cts +6 -0
- package/node_modules/zod/v4/core/regexes.d.ts +6 -0
- package/node_modules/zod/v4/core/regexes.js +7 -1
- package/node_modules/zod/v4/core/schemas.cjs +211 -65
- package/node_modules/zod/v4/core/schemas.d.cts +39 -1
- package/node_modules/zod/v4/core/schemas.d.ts +39 -1
- package/node_modules/zod/v4/core/schemas.js +210 -64
- package/node_modules/zod/v4/core/to-json-schema.cjs +12 -1
- package/node_modules/zod/v4/core/to-json-schema.js +12 -1
- package/node_modules/zod/v4/core/util.cjs +54 -30
- package/node_modules/zod/v4/core/util.d.cts +1 -0
- package/node_modules/zod/v4/core/util.d.ts +1 -0
- package/node_modules/zod/v4/core/util.js +55 -32
- package/node_modules/zod/v4/core/versions.cjs +2 -2
- package/node_modules/zod/v4/core/versions.d.cts +1 -1
- package/node_modules/zod/v4/core/versions.d.ts +1 -1
- package/node_modules/zod/v4/core/versions.js +2 -2
- package/node_modules/zod/v4/locales/el.cjs +136 -0
- package/node_modules/zod/v4/locales/el.d.cts +5 -0
- package/node_modules/zod/v4/locales/el.d.ts +4 -0
- package/node_modules/zod/v4/locales/el.js +109 -0
- package/node_modules/zod/v4/locales/en.cjs +4 -0
- package/node_modules/zod/v4/locales/en.js +4 -0
- package/node_modules/zod/v4/locales/fr.cjs +24 -7
- package/node_modules/zod/v4/locales/fr.js +24 -7
- package/node_modules/zod/v4/locales/hr.cjs +149 -0
- package/node_modules/zod/v4/locales/hr.d.cts +5 -0
- package/node_modules/zod/v4/locales/hr.d.ts +4 -0
- package/node_modules/zod/v4/locales/hr.js +122 -0
- package/node_modules/zod/v4/locales/index.cjs +8 -1
- package/node_modules/zod/v4/locales/index.d.cts +3 -0
- package/node_modules/zod/v4/locales/index.d.ts +3 -0
- package/node_modules/zod/v4/locales/index.js +3 -0
- package/node_modules/zod/v4/locales/it.cjs +1 -1
- package/node_modules/zod/v4/locales/it.js +1 -1
- package/node_modules/zod/v4/locales/ka.cjs +8 -8
- package/node_modules/zod/v4/locales/ka.js +8 -8
- package/node_modules/zod/v4/locales/package.json +2 -1
- package/node_modules/zod/v4/locales/ro.cjs +146 -0
- package/node_modules/zod/v4/locales/ro.d.cts +5 -0
- package/node_modules/zod/v4/locales/ro.d.ts +4 -0
- package/node_modules/zod/v4/locales/ro.js +119 -0
- package/node_modules/zod/v4/locales/uz.cjs +1 -0
- package/node_modules/zod/v4/locales/uz.js +1 -0
- package/node_modules/zod/v4/mini/external.d.cts +1 -0
- package/node_modules/zod/v4/mini/external.d.ts +1 -0
- package/node_modules/zod/v4/mini/package.json +2 -1
- package/node_modules/zod/v4/mini/schemas.cjs +41 -4
- package/node_modules/zod/v4/mini/schemas.d.cts +28 -10
- package/node_modules/zod/v4/mini/schemas.d.ts +28 -10
- package/node_modules/zod/v4/mini/schemas.js +40 -4
- package/node_modules/zod/v4/package.json +2 -1
- package/node_modules/zod/v4-mini/package.json +2 -1
- package/package.json +2 -1
- package/skills/manifest.json +3 -2
- package/skills/weibo-creator/SKILL.md +296 -0
- package/skills/weibo-creator/references/creator-v-upgrade.md +27 -0
- package/skills/weibo-creator/scripts/weibo-creator.js +212 -0
- package/skills/weibo-cron/SKILL.md +1 -1
- package/skills/weibo-cron/references/HEARTBEAT-PROCESS.md +1 -1
- package/skills/weibo-crowd/SKILL.md +1 -1
- package/skills/weibo-crowd/references/SILICON-TEAHOUSE-RULES.md +3 -2
- package/src/accounts.js +1 -1
- package/src/accounts.js.map +1 -1
- package/src/channel.js +1 -1
- package/src/channel.js.map +1 -1
- package/src/outbound.d.ts.map +1 -1
- package/src/outbound.js +82 -4
- package/src/outbound.js.map +1 -1
- package/src/send.d.ts +23 -0
- package/src/send.d.ts.map +1 -1
- package/src/send.js +54 -2
- package/src/send.js.map +1 -1
- package/src/token.d.ts +8 -0
- package/src/token.d.ts.map +1 -1
- package/src/token.js +16 -1
- package/src/token.js.map +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { expect, expectTypeOf, test } from "vitest";
|
|
1
|
+
import { describe, expect, expectTypeOf, test } from "vitest";
|
|
2
2
|
import * as z from "zod/v4";
|
|
3
3
|
import * as core from "zod/v4/core";
|
|
4
4
|
|
|
@@ -232,8 +232,7 @@ test("inferred merged object type with optional properties", async () => {
|
|
|
232
232
|
.object({ a: z.string(), b: z.string().optional() })
|
|
233
233
|
.merge(z.object({ a: z.string().optional(), b: z.string() }));
|
|
234
234
|
type Merged = z.infer<typeof Merged>;
|
|
235
|
-
expectTypeOf<Merged>().toEqualTypeOf<{ a?: string; b: string }>();
|
|
236
|
-
expectTypeOf<Merged>().toEqualTypeOf<{ a?: string; b: string }>();
|
|
235
|
+
expectTypeOf<Merged>().toEqualTypeOf<{ a?: string | undefined; b: string }>();
|
|
237
236
|
});
|
|
238
237
|
|
|
239
238
|
test("inferred unioned object type with optional properties", async () => {
|
|
@@ -242,7 +241,9 @@ test("inferred unioned object type with optional properties", async () => {
|
|
|
242
241
|
z.object({ a: z.string().optional(), b: z.string() }),
|
|
243
242
|
]);
|
|
244
243
|
type Unioned = z.infer<typeof Unioned>;
|
|
245
|
-
expectTypeOf<Unioned>().toEqualTypeOf<
|
|
244
|
+
expectTypeOf<Unioned>().toEqualTypeOf<
|
|
245
|
+
{ a: string; b?: string | undefined } | { a?: string | undefined; b: string }
|
|
246
|
+
>();
|
|
246
247
|
});
|
|
247
248
|
|
|
248
249
|
test("inferred enum type", async () => {
|
|
@@ -279,13 +280,13 @@ test("z.keyof returns enum", () => {
|
|
|
279
280
|
test("inferred partial object type with optional properties", async () => {
|
|
280
281
|
const Partial = z.object({ a: z.string(), b: z.string().optional() }).partial();
|
|
281
282
|
type Partial = z.infer<typeof Partial>;
|
|
282
|
-
expectTypeOf<Partial>().toEqualTypeOf<{ a?: string; b?: string }>();
|
|
283
|
+
expectTypeOf<Partial>().toEqualTypeOf<{ a?: string | undefined; b?: string | undefined }>();
|
|
283
284
|
});
|
|
284
285
|
|
|
285
286
|
test("inferred picked object type with optional properties", async () => {
|
|
286
287
|
const Picked = z.object({ a: z.string(), b: z.string().optional() }).pick({ b: true });
|
|
287
288
|
type Picked = z.infer<typeof Picked>;
|
|
288
|
-
expectTypeOf<Picked>().toEqualTypeOf<{ b?: string }>();
|
|
289
|
+
expectTypeOf<Picked>().toEqualTypeOf<{ b?: string | undefined }>();
|
|
289
290
|
});
|
|
290
291
|
|
|
291
292
|
test("inferred type for unknown/any keys", () => {
|
|
@@ -405,6 +406,36 @@ test("unknownkeys merging", () => {
|
|
|
405
406
|
expect(c._zod.def.catchall).toBeInstanceOf(core.$ZodNever);
|
|
406
407
|
});
|
|
407
408
|
|
|
409
|
+
test("merge() throws when receiver has refinements", () => {
|
|
410
|
+
const a = z
|
|
411
|
+
.object({
|
|
412
|
+
password: z.string(),
|
|
413
|
+
confirmPassword: z.string(),
|
|
414
|
+
})
|
|
415
|
+
.refine((data) => data.password === data.confirmPassword);
|
|
416
|
+
|
|
417
|
+
const b = z.object({ email: z.string() });
|
|
418
|
+
|
|
419
|
+
expect(() => a.merge(b)).toThrow(".merge() cannot be used on object schemas containing refinements");
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
test("merge() throws when receiver has superRefine", () => {
|
|
423
|
+
const a = z.object({ x: z.string() }).superRefine(() => {});
|
|
424
|
+
const b = z.object({ y: z.number() });
|
|
425
|
+
|
|
426
|
+
expect(() => a.merge(b)).toThrow(".merge() cannot be used on object schemas containing refinements");
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
test("merge() preserves refinements on the second schema", () => {
|
|
430
|
+
const a = z.object({ name: z.string() });
|
|
431
|
+
const b = z.object({ age: z.number() }).refine((data) => data.age >= 18, { message: "Must be 18+" });
|
|
432
|
+
|
|
433
|
+
const merged = a.merge(b);
|
|
434
|
+
|
|
435
|
+
expect(merged.parse({ name: "n", age: 21 })).toEqual({ name: "n", age: 21 });
|
|
436
|
+
expect(() => merged.parse({ name: "n", age: 12 })).toThrow("Must be 18+");
|
|
437
|
+
});
|
|
438
|
+
|
|
408
439
|
const personToExtend = z.object({
|
|
409
440
|
firstName: z.string(),
|
|
410
441
|
lastName: z.string(),
|
|
@@ -638,3 +669,49 @@ test("safeExtend() on object with refinements should not throw", () => {
|
|
|
638
669
|
|
|
639
670
|
expect(() => schema.safeExtend({ b: z.string() })).not.toThrow();
|
|
640
671
|
});
|
|
672
|
+
|
|
673
|
+
// __proto__ in input must not replace the prototype of the parsed object via
|
|
674
|
+
// the assignment setter on the result {}.
|
|
675
|
+
// https://github.com/colinhacks/zod/security/advisories/GHSA-r34p-xfmx-58wv
|
|
676
|
+
// https://github.com/colinhacks/zod/security/advisories/GHSA-84jv-fqfx-wxhr
|
|
677
|
+
describe("__proto__ in object catchall paths", () => {
|
|
678
|
+
const protoInput = () => JSON.parse('{"__proto__":{"isAdmin":true},"name":"alice"}');
|
|
679
|
+
|
|
680
|
+
test("looseObject drops __proto__ and preserves Object.prototype", () => {
|
|
681
|
+
const schema = z.looseObject({ name: z.string() });
|
|
682
|
+
const parsed = schema.parse(protoInput());
|
|
683
|
+
expect(Object.keys(parsed)).toEqual(["name"]);
|
|
684
|
+
expect((parsed as any).isAdmin).toBeUndefined();
|
|
685
|
+
expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype);
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
test("passthrough drops __proto__", () => {
|
|
689
|
+
const schema = z.object({ name: z.string() }).passthrough();
|
|
690
|
+
const parsed = schema.parse(protoInput());
|
|
691
|
+
expect((parsed as any).isAdmin).toBeUndefined();
|
|
692
|
+
expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype);
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
test("catchall(unknown) drops __proto__", () => {
|
|
696
|
+
const schema = z.object({ name: z.string() }).catchall(z.unknown());
|
|
697
|
+
const parsed = schema.parse(protoInput());
|
|
698
|
+
expect((parsed as any).isAdmin).toBeUndefined();
|
|
699
|
+
expect(Object.getPrototypeOf(parsed)).toBe(Object.prototype);
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
test("safeParseAsync + jitless drops __proto__", async () => {
|
|
703
|
+
const schema = z.looseObject({ name: z.string() });
|
|
704
|
+
const result = await schema.safeParseAsync(protoInput(), { jitless: true } as any);
|
|
705
|
+
expect(result.success).toBe(true);
|
|
706
|
+
if (result.success) {
|
|
707
|
+
expect((result.data as any).isAdmin).toBeUndefined();
|
|
708
|
+
expect(Object.getPrototypeOf(result.data)).toBe(Object.prototype);
|
|
709
|
+
}
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
test("strict does not surface __proto__ as unrecognized", () => {
|
|
713
|
+
const schema = z.object({ name: z.string() }).strict();
|
|
714
|
+
const result = schema.safeParse(protoInput());
|
|
715
|
+
expect(result.success).toBe(true);
|
|
716
|
+
});
|
|
717
|
+
});
|
|
@@ -40,15 +40,15 @@ test("optionality", () => {
|
|
|
40
40
|
|
|
41
41
|
// z.undefined should NOT be optional
|
|
42
42
|
const f = z.undefined();
|
|
43
|
-
expect(f._zod.optin).toEqual(
|
|
44
|
-
expect(f._zod.optout).toEqual(
|
|
43
|
+
expect(f._zod.optin).toEqual(undefined);
|
|
44
|
+
expect(f._zod.optout).toEqual(undefined);
|
|
45
45
|
expectTypeOf<typeof f._zod.optin>().toEqualTypeOf<"optional" | undefined>();
|
|
46
46
|
expectTypeOf<typeof f._zod.optout>().toEqualTypeOf<"optional" | undefined>();
|
|
47
47
|
|
|
48
48
|
// z.union should be optional if any of the types are optional
|
|
49
49
|
const g = z.union([z.string(), z.undefined()]);
|
|
50
|
-
expect(g._zod.optin).toEqual(
|
|
51
|
-
expect(g._zod.optout).toEqual(
|
|
50
|
+
expect(g._zod.optin).toEqual(undefined);
|
|
51
|
+
expect(g._zod.optout).toEqual(undefined);
|
|
52
52
|
expectTypeOf<typeof g._zod.optin>().toEqualTypeOf<"optional" | undefined>();
|
|
53
53
|
expectTypeOf<typeof g._zod.optout>().toEqualTypeOf<"optional" | undefined>();
|
|
54
54
|
|
|
@@ -135,6 +135,52 @@ test("optional prop with pipe", () => {
|
|
|
135
135
|
schema.parse({}, { jitless: true });
|
|
136
136
|
});
|
|
137
137
|
|
|
138
|
+
test("object absent keys require optin optional", () => {
|
|
139
|
+
const valueUndefined = z.object({
|
|
140
|
+
value: z.undefined(),
|
|
141
|
+
union: z.union([z.string(), z.undefined()]),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
expect(valueUndefined.safeParse({}).error!.issues).toMatchInlineSnapshot(`
|
|
145
|
+
[
|
|
146
|
+
{
|
|
147
|
+
"code": "invalid_type",
|
|
148
|
+
"expected": "nonoptional",
|
|
149
|
+
"message": "Invalid input: expected nonoptional, received undefined",
|
|
150
|
+
"path": [
|
|
151
|
+
"value",
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"code": "invalid_type",
|
|
156
|
+
"expected": "nonoptional",
|
|
157
|
+
"message": "Invalid input: expected nonoptional, received undefined",
|
|
158
|
+
"path": [
|
|
159
|
+
"union",
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
]
|
|
163
|
+
`);
|
|
164
|
+
expect(valueUndefined.safeParse({}, { jitless: true }).success).toEqual(false);
|
|
165
|
+
expect(valueUndefined.parse({ value: undefined, union: undefined })).toEqual({
|
|
166
|
+
value: undefined,
|
|
167
|
+
union: undefined,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const optionalOutOnly = z.object({
|
|
171
|
+
value: z
|
|
172
|
+
.string()
|
|
173
|
+
.transform((val) => (Math.random() ? val : undefined))
|
|
174
|
+
.pipe(z.string().optional()),
|
|
175
|
+
});
|
|
176
|
+
expect(optionalOutOnly.safeParse({}).success).toEqual(false);
|
|
177
|
+
expect(optionalOutOnly.safeParse({}, { jitless: true }).success).toEqual(false);
|
|
178
|
+
|
|
179
|
+
const defaulted = z.object({ value: z.string().default("fallback") });
|
|
180
|
+
expect(defaulted.parse({})).toEqual({ value: "fallback" });
|
|
181
|
+
expect(defaulted.parse({}, { jitless: true })).toEqual({ value: "fallback" });
|
|
182
|
+
});
|
|
183
|
+
|
|
138
184
|
// exactOptional tests
|
|
139
185
|
test(".exactOptional()", () => {
|
|
140
186
|
const schema = z.string().exactOptional();
|
|
@@ -221,3 +267,67 @@ test("exactOptional vs optional comparison", () => {
|
|
|
221
267
|
// exactOptional() rejects explicit undefined
|
|
222
268
|
expect(exactOptionalSchema.safeParse({ a: undefined }).success).toEqual(false);
|
|
223
269
|
});
|
|
270
|
+
|
|
271
|
+
// Defensive inference coverage: every schema that propagates `optout` participates
|
|
272
|
+
// in object-key optionality inference. If anyone ever changes the set of values that
|
|
273
|
+
// `optout` can take (or how OptionalOutSchema matches them), these assertions must
|
|
274
|
+
// continue to hold or downstream `z.infer<typeof obj>` types silently flip required keys.
|
|
275
|
+
test("object key optionality through optout propagation", () => {
|
|
276
|
+
const direct = z.object({ k: z.string().optional() });
|
|
277
|
+
expectTypeOf<z.infer<typeof direct>>().toEqualTypeOf<{ k?: string | undefined }>();
|
|
278
|
+
|
|
279
|
+
const exact = z.object({ k: z.string().exactOptional() });
|
|
280
|
+
expectTypeOf<z.infer<typeof exact>>().toEqualTypeOf<{ k?: string }>();
|
|
281
|
+
|
|
282
|
+
// nullable() preserves the inner type's optout
|
|
283
|
+
const nullableOpt = z.object({ k: z.string().optional().nullable() });
|
|
284
|
+
expectTypeOf<z.infer<typeof nullableOpt>>().toEqualTypeOf<{ k?: string | null | undefined }>();
|
|
285
|
+
|
|
286
|
+
// optional() wrapping nullable() — still optional out
|
|
287
|
+
const optNullable = z.object({ k: z.string().nullable().optional() });
|
|
288
|
+
expectTypeOf<z.infer<typeof optNullable>>().toEqualTypeOf<{ k?: string | null | undefined }>();
|
|
289
|
+
|
|
290
|
+
// union containing an optional member must mark the key as optional
|
|
291
|
+
const unionWithOpt = z.object({ k: z.union([z.string(), z.string().optional()]) });
|
|
292
|
+
expectTypeOf<z.infer<typeof unionWithOpt>>().toEqualTypeOf<{ k?: string | undefined }>();
|
|
293
|
+
|
|
294
|
+
// pipe ending in optional()
|
|
295
|
+
const pipedToOpt = z.object({
|
|
296
|
+
k: z
|
|
297
|
+
.string()
|
|
298
|
+
.transform((v) => (Math.random() ? v : undefined))
|
|
299
|
+
.pipe(z.string().optional()),
|
|
300
|
+
});
|
|
301
|
+
expectTypeOf<z.output<typeof pipedToOpt>>().toEqualTypeOf<{ k?: string | undefined }>();
|
|
302
|
+
|
|
303
|
+
// mixed shape pinning required vs optional keys end-to-end
|
|
304
|
+
const mixed = z.object({
|
|
305
|
+
req: z.string(),
|
|
306
|
+
opt: z.string().optional(),
|
|
307
|
+
exact: z.string().exactOptional(),
|
|
308
|
+
def: z.string().default("x"),
|
|
309
|
+
nullableOpt: z.string().optional().nullable(),
|
|
310
|
+
});
|
|
311
|
+
expectTypeOf<z.output<typeof mixed>>().toEqualTypeOf<{
|
|
312
|
+
req: string;
|
|
313
|
+
opt?: string | undefined;
|
|
314
|
+
exact?: string;
|
|
315
|
+
def: string;
|
|
316
|
+
nullableOpt?: string | null | undefined;
|
|
317
|
+
}>();
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// Defensive: tuple optional-tail inference also reads optout. The PR that introduced
|
|
321
|
+
// `"includeUndefined"` had to update TupleOutputTypeWithOptionals; pin the result so
|
|
322
|
+
// any future flag change has to keep this contract.
|
|
323
|
+
test("tuple tail optionality through optout propagation", () => {
|
|
324
|
+
const trailingOptional = z.tuple([z.string(), z.number().optional()]);
|
|
325
|
+
expectTypeOf<z.output<typeof trailingOptional>>().toEqualTypeOf<[string, (number | undefined)?]>();
|
|
326
|
+
|
|
327
|
+
const trailingExact = z.tuple([z.string(), z.number().exactOptional()]);
|
|
328
|
+
expectTypeOf<z.output<typeof trailingExact>>().toEqualTypeOf<[string, number?]>();
|
|
329
|
+
|
|
330
|
+
// Interior optional must NOT make the tail optional
|
|
331
|
+
const interiorOptional = z.tuple([z.string(), z.number().optional(), z.string()]);
|
|
332
|
+
expectTypeOf<z.output<typeof interiorOptional>>().toEqualTypeOf<[string, number | undefined, string]>();
|
|
333
|
+
});
|
|
@@ -156,6 +156,10 @@ test("catch/prefault/default", () => {
|
|
|
156
156
|
f: z.string().prefault("prefault value"),
|
|
157
157
|
});
|
|
158
158
|
|
|
159
|
+
// Catch (d) and default/prefault (b, c, e, f) handle absent keys gracefully.
|
|
160
|
+
// `a: catch().optional()` short-circuits to undefined when the original
|
|
161
|
+
// input was undefined, so the property is omitted from the output. All
|
|
162
|
+
// other catch/default/prefault keys produce their fallback values.
|
|
159
163
|
expect(mySchema.parse({})).toMatchInlineSnapshot(`
|
|
160
164
|
{
|
|
161
165
|
"b": "default value",
|
|
@@ -165,7 +169,6 @@ test("catch/prefault/default", () => {
|
|
|
165
169
|
"f": "prefault value",
|
|
166
170
|
}
|
|
167
171
|
`);
|
|
168
|
-
|
|
169
172
|
expect(mySchema.parse({}, { jitless: true })).toMatchInlineSnapshot(`
|
|
170
173
|
{
|
|
171
174
|
"b": "default value",
|
|
@@ -175,6 +178,26 @@ test("catch/prefault/default", () => {
|
|
|
175
178
|
"f": "prefault value",
|
|
176
179
|
}
|
|
177
180
|
`);
|
|
181
|
+
|
|
182
|
+
expect(mySchema.parse({ d: undefined })).toMatchInlineSnapshot(`
|
|
183
|
+
{
|
|
184
|
+
"b": "default value",
|
|
185
|
+
"c": "prefault value",
|
|
186
|
+
"d": "catch value",
|
|
187
|
+
"e": "default value",
|
|
188
|
+
"f": "prefault value",
|
|
189
|
+
}
|
|
190
|
+
`);
|
|
191
|
+
|
|
192
|
+
expect(mySchema.parse({ d: undefined }, { jitless: true })).toMatchInlineSnapshot(`
|
|
193
|
+
{
|
|
194
|
+
"b": "default value",
|
|
195
|
+
"c": "prefault value",
|
|
196
|
+
"d": "catch value",
|
|
197
|
+
"e": "default value",
|
|
198
|
+
"f": "prefault value",
|
|
199
|
+
}
|
|
200
|
+
`);
|
|
178
201
|
});
|
|
179
202
|
|
|
180
203
|
test("handleOptionalObjectResult branches", () => {
|
|
@@ -41,7 +41,7 @@ test("object schema with prefault should return shallow clone", () => {
|
|
|
41
41
|
.object({
|
|
42
42
|
a: z.string(),
|
|
43
43
|
})
|
|
44
|
-
.
|
|
44
|
+
.prefault({ a: "x" });
|
|
45
45
|
const result1 = schema.parse(undefined);
|
|
46
46
|
const result2 = schema.parse(undefined);
|
|
47
47
|
expect(result1).not.toBe(result2);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { expectTypeOf, test } from "vitest";
|
|
2
|
+
import * as z from "zod/v4";
|
|
3
|
+
|
|
4
|
+
test("ZodPreprocess<B> assignable to ZodPipe<$ZodTransform, B>", () => {
|
|
5
|
+
const pre = z.preprocess((v) => v, z.string().optional());
|
|
6
|
+
const _asPipe: z.ZodPipe<z.core.$ZodTransform, z.ZodOptional<z.ZodString>> = pre;
|
|
7
|
+
const _asCorePipe: z.core.$ZodPipe<z.core.$ZodTransform, z.ZodOptional<z.ZodString>> = pre;
|
|
8
|
+
expectTypeOf(_asPipe).toMatchTypeOf<z.ZodPipe>();
|
|
9
|
+
expectTypeOf(_asCorePipe).toMatchTypeOf<z.core.$ZodPipe>();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("ZodPreprocess optin/optout defer to B", () => {
|
|
13
|
+
const optionalInside = z.preprocess((v) => v, z.string().optional());
|
|
14
|
+
expectTypeOf<(typeof optionalInside)["_zod"]["optin"]>().toEqualTypeOf<"optional">();
|
|
15
|
+
expectTypeOf<(typeof optionalInside)["_zod"]["optout"]>().toEqualTypeOf<"optional">();
|
|
16
|
+
|
|
17
|
+
const required = z.preprocess((v) => v, z.string());
|
|
18
|
+
expectTypeOf<(typeof required)["_zod"]["optin"]>().toEqualTypeOf<"optional" | undefined>();
|
|
19
|
+
expectTypeOf<(typeof required)["_zod"]["optout"]>().toEqualTypeOf<"optional" | undefined>();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("ZodPreprocess input/output inference", () => {
|
|
23
|
+
const pre = z.preprocess((v) => v, z.number().optional());
|
|
24
|
+
expectTypeOf<z.output<typeof pre>>().toEqualTypeOf<number | undefined>();
|
|
25
|
+
expectTypeOf<z.input<typeof pre>>().toEqualTypeOf<unknown>();
|
|
26
|
+
});
|
|
@@ -280,3 +280,72 @@ test("perform transform with non-fatal issues", () => {
|
|
|
280
280
|
]]
|
|
281
281
|
`);
|
|
282
282
|
});
|
|
283
|
+
|
|
284
|
+
test("preprocess accepts absent object keys (4.3 parity)", () => {
|
|
285
|
+
const schema = z.object({ a: z.preprocess((v) => v ?? "X", z.string()) });
|
|
286
|
+
expect(schema.parse({})).toEqual({ a: "X" });
|
|
287
|
+
expect(schema.parse({ a: "hi" })).toEqual({ a: "hi" });
|
|
288
|
+
expect(schema.parse({ a: undefined })).toEqual({ a: "X" });
|
|
289
|
+
|
|
290
|
+
// Outer optional clobbers preprocess output on undefined input
|
|
291
|
+
expect(
|
|
292
|
+
z
|
|
293
|
+
.preprocess((v) => v ?? "X", z.string())
|
|
294
|
+
.optional()
|
|
295
|
+
.parse(undefined)
|
|
296
|
+
).toBeUndefined();
|
|
297
|
+
expect(
|
|
298
|
+
z
|
|
299
|
+
.preprocess((v) => v ?? "X", z.string())
|
|
300
|
+
.optional()
|
|
301
|
+
.parse("hi")
|
|
302
|
+
).toBe("hi");
|
|
303
|
+
expect(z.object({ a: z.preprocess((v) => v ?? "X", z.string()).optional() }).parse({})).toEqual({});
|
|
304
|
+
|
|
305
|
+
// Top-level direct call unchanged
|
|
306
|
+
expect(z.preprocess((v) => v ?? "X", z.string()).parse(undefined)).toBe("X");
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
// https://github.com/colinhacks/zod/issues/5917
|
|
310
|
+
test("optional propagates through preprocess inside object", () => {
|
|
311
|
+
const outer = z.object({ x: z.preprocess((v) => v, z.number()).optional() });
|
|
312
|
+
const inner = z.object({ x: z.preprocess((v) => v, z.number().optional()) });
|
|
313
|
+
|
|
314
|
+
expect(outer.safeParse({}).success).toBe(true);
|
|
315
|
+
expect(inner.safeParse({}).success).toBe(true);
|
|
316
|
+
|
|
317
|
+
expect(outer.safeParse({ x: 1 })).toEqual({ success: true, data: { x: 1 } });
|
|
318
|
+
expect(inner.safeParse({ x: 1 })).toEqual({ success: true, data: { x: 1 } });
|
|
319
|
+
|
|
320
|
+
expect(inner._zod.def.shape.x._zod.optin).toBe("optional");
|
|
321
|
+
expect(inner._zod.def.shape.x._zod.optout).toBe("optional");
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
test("preprocess is a structural subtype of ZodPipe", () => {
|
|
325
|
+
const schema = z.preprocess((v) => v, z.string());
|
|
326
|
+
expect(schema).toBeInstanceOf(z.ZodPipe);
|
|
327
|
+
expect(schema).toBeInstanceOf(z.ZodPreprocess);
|
|
328
|
+
expect(schema._zod.def.type).toBe("pipe");
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
test("preprocess does not propagate values/propValues from inner schema", () => {
|
|
332
|
+
const inner = z.preprocess((v) => v, z.literal("test"));
|
|
333
|
+
expect(inner._zod.values).toBeUndefined();
|
|
334
|
+
expect(inner._zod.propValues).toBeUndefined();
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
test("preprocess as discriminator throws at construction (no propValues to inherit)", () => {
|
|
338
|
+
const schema = z.discriminatedUnion("kind", [
|
|
339
|
+
z.object({ kind: z.preprocess((v: any) => String(v).toUpperCase(), z.literal("A")), a: z.string() }),
|
|
340
|
+
z.object({ kind: z.preprocess((v: any) => String(v).toUpperCase(), z.literal("B")), b: z.number() }),
|
|
341
|
+
]);
|
|
342
|
+
expect(() => schema.parse({ kind: "a", a: "x" })).toThrow(/Invalid discriminated union option/);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
test("preprocess as record key does not restrict accepted keys", () => {
|
|
346
|
+
const schema = z.record(
|
|
347
|
+
z.preprocess((v: any) => String(v).toLowerCase(), z.enum(["a", "b"])),
|
|
348
|
+
z.string()
|
|
349
|
+
);
|
|
350
|
+
expect(schema.safeParse({ A: "x", B: "y" })).toEqual({ success: true, data: { a: "x", b: "y" } });
|
|
351
|
+
});
|
|
@@ -272,6 +272,67 @@ test("union exhaustiveness", () => {
|
|
|
272
272
|
`);
|
|
273
273
|
});
|
|
274
274
|
|
|
275
|
+
test("applies transforms on the key schema (#5296)", () => {
|
|
276
|
+
const single = z.record(
|
|
277
|
+
z.literal("a").transform(() => "b" as const),
|
|
278
|
+
z.string()
|
|
279
|
+
);
|
|
280
|
+
expect(single.parse({ a: "John" })).toEqual({ b: "John" });
|
|
281
|
+
|
|
282
|
+
const multi = z.record(
|
|
283
|
+
z.literal(["a", "b"]).transform((k) => k.toUpperCase()),
|
|
284
|
+
z.number()
|
|
285
|
+
);
|
|
286
|
+
expect(multi.parse({ a: 1, b: 2 })).toEqual({ A: 1, B: 2 });
|
|
287
|
+
|
|
288
|
+
// required-key semantics still hold when the keyType has a known value set
|
|
289
|
+
expect(multi.safeParse({ a: 1 }).success).toBe(false);
|
|
290
|
+
|
|
291
|
+
const en = z.record(
|
|
292
|
+
z.enum(["a", "b"]).transform((k) => k.toUpperCase()),
|
|
293
|
+
z.number()
|
|
294
|
+
);
|
|
295
|
+
expect(en.parse({ a: 1, b: 2 })).toEqual({ A: 1, B: 2 });
|
|
296
|
+
|
|
297
|
+
// matches partialRecord, which already applied transforms
|
|
298
|
+
const part = z.partialRecord(
|
|
299
|
+
z.literal("a").transform(() => "b" as const),
|
|
300
|
+
z.string()
|
|
301
|
+
);
|
|
302
|
+
expect(part.parse({ a: "John" })).toEqual({ b: "John" });
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
test("surfaces key schema refinement failures as invalid_key", () => {
|
|
306
|
+
// refine rejects "b" but it's still in the literal's value set
|
|
307
|
+
const schema = z.record(
|
|
308
|
+
z.literal(["a", "b"]).refine((k) => k === "a", { message: "only 'a' is allowed" }),
|
|
309
|
+
z.string()
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
expect(schema.safeParse({ a: "ok", b: "nope" })).toMatchInlineSnapshot(`
|
|
313
|
+
{
|
|
314
|
+
"error": [ZodError: [
|
|
315
|
+
{
|
|
316
|
+
"code": "invalid_key",
|
|
317
|
+
"origin": "record",
|
|
318
|
+
"issues": [
|
|
319
|
+
{
|
|
320
|
+
"code": "custom",
|
|
321
|
+
"path": [],
|
|
322
|
+
"message": "only 'a' is allowed"
|
|
323
|
+
}
|
|
324
|
+
],
|
|
325
|
+
"path": [
|
|
326
|
+
"b"
|
|
327
|
+
],
|
|
328
|
+
"message": "Invalid key in record"
|
|
329
|
+
}
|
|
330
|
+
]],
|
|
331
|
+
"success": false,
|
|
332
|
+
}
|
|
333
|
+
`);
|
|
334
|
+
});
|
|
335
|
+
|
|
275
336
|
test("string record parse - pass", () => {
|
|
276
337
|
const schema = z.record(z.string(), z.boolean());
|
|
277
338
|
schema.parse({
|
|
@@ -630,3 +691,27 @@ test("numeric string keys", () => {
|
|
|
630
691
|
);
|
|
631
692
|
expect(transformedSchema.parse({ 5: "five", 10: "ten" })).toEqual({ 10: "five", 20: "ten" });
|
|
632
693
|
});
|
|
694
|
+
|
|
695
|
+
test("v3-compat single-arg form: z.record(valueType)", () => {
|
|
696
|
+
// single arg should default keyType to z.string() and use the arg as valueType
|
|
697
|
+
const schema = (z.record as any)(z.number());
|
|
698
|
+
expect(schema.keyType._zod.def.type).toEqual("string");
|
|
699
|
+
expect(schema.valueType._zod.def.type).toEqual("number");
|
|
700
|
+
|
|
701
|
+
expect(schema.parse({ a: 1, b: 2 })).toEqual({ a: 1, b: 2 });
|
|
702
|
+
expect(schema.safeParse({ a: "x" }).success).toBe(false);
|
|
703
|
+
|
|
704
|
+
// params still flow through in the single-arg form
|
|
705
|
+
const withMessage = (z.record as any)(z.number(), "must be a number record");
|
|
706
|
+
expect(withMessage.keyType._zod.def.type).toEqual("string");
|
|
707
|
+
expect(withMessage.valueType._zod.def.type).toEqual("number");
|
|
708
|
+
|
|
709
|
+
// toJSONSchema should produce a well-formed schema (regression: previously produced
|
|
710
|
+
// additionalProperties from undefined valueType, crashing process())
|
|
711
|
+
const json = z.toJSONSchema(schema);
|
|
712
|
+
expect(json).toMatchObject({
|
|
713
|
+
type: "object",
|
|
714
|
+
propertyNames: { type: "string" },
|
|
715
|
+
additionalProperties: { type: "number" },
|
|
716
|
+
});
|
|
717
|
+
});
|
|
@@ -135,6 +135,11 @@ test("pick and omit with getter", () => {
|
|
|
135
135
|
}
|
|
136
136
|
expectTypeOf<Category>().toEqualTypeOf<_Category>();
|
|
137
137
|
|
|
138
|
+
// Shape should not surface `readonly` modifiers from getter-defined keys.
|
|
139
|
+
// object/strictObject/looseObject all pass shape through util.Writeable<T>.
|
|
140
|
+
type Shape = (typeof Category)["shape"];
|
|
141
|
+
expectTypeOf<Shape>().toEqualTypeOf<{ name: z.ZodString; subcategories: z.ZodArray<typeof Category> }>();
|
|
142
|
+
|
|
138
143
|
const PickedCategory = Category.pick({ name: true });
|
|
139
144
|
const OmittedCategory = Category.omit({ subcategories: true });
|
|
140
145
|
|
|
@@ -148,6 +153,50 @@ test("pick and omit with getter", () => {
|
|
|
148
153
|
expect(() => OmittedCategory.parse({ name: "test", subcategories: [] })).toThrow();
|
|
149
154
|
});
|
|
150
155
|
|
|
156
|
+
test("shape stays writeable through extend/safeExtend/partial/required", () => {
|
|
157
|
+
const Base = z.object({ name: z.string() });
|
|
158
|
+
|
|
159
|
+
const Extended = Base.extend({
|
|
160
|
+
get sub() {
|
|
161
|
+
return z.array(Extended);
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
type ExtendedShape = (typeof Extended)["shape"];
|
|
165
|
+
expectTypeOf<ExtendedShape>().toEqualTypeOf<{
|
|
166
|
+
name: z.ZodString;
|
|
167
|
+
sub: z.ZodArray<typeof Extended>;
|
|
168
|
+
}>();
|
|
169
|
+
|
|
170
|
+
const SafeExt = Base.safeExtend({ extra: z.string() } as const);
|
|
171
|
+
type SafeExtShape = (typeof SafeExt)["shape"];
|
|
172
|
+
expectTypeOf<SafeExtShape>().toEqualTypeOf<{
|
|
173
|
+
name: z.ZodString;
|
|
174
|
+
extra: z.ZodString;
|
|
175
|
+
}>();
|
|
176
|
+
|
|
177
|
+
const FromConst = Base.extend({ a: z.string(), b: z.number() } as const);
|
|
178
|
+
type FromConstShape = (typeof FromConst)["shape"];
|
|
179
|
+
expectTypeOf<FromConstShape>().toEqualTypeOf<{
|
|
180
|
+
name: z.ZodString;
|
|
181
|
+
a: z.ZodString;
|
|
182
|
+
b: z.ZodNumber;
|
|
183
|
+
}>();
|
|
184
|
+
|
|
185
|
+
const PartialExtended = Extended.partial();
|
|
186
|
+
type PartialShape = (typeof PartialExtended)["shape"];
|
|
187
|
+
expectTypeOf<PartialShape>().toEqualTypeOf<{
|
|
188
|
+
name: z.ZodOptional<z.ZodString>;
|
|
189
|
+
sub: z.ZodOptional<z.ZodArray<typeof Extended>>;
|
|
190
|
+
}>();
|
|
191
|
+
|
|
192
|
+
const RequiredExtended = Extended.required();
|
|
193
|
+
type RequiredShape = (typeof RequiredExtended)["shape"];
|
|
194
|
+
expectTypeOf<RequiredShape>().toEqualTypeOf<{
|
|
195
|
+
name: z.ZodNonOptional<z.ZodString>;
|
|
196
|
+
sub: z.ZodNonOptional<z.ZodArray<typeof Extended>>;
|
|
197
|
+
}>();
|
|
198
|
+
});
|
|
199
|
+
|
|
151
200
|
test("deferred self-recursion", () => {
|
|
152
201
|
const Feature = z.object({
|
|
153
202
|
title: z.string(),
|
|
@@ -414,6 +414,69 @@ describe("chained refinements", () => {
|
|
|
414
414
|
};
|
|
415
415
|
expect(objectSchema.parse(validData)).toEqual(validData);
|
|
416
416
|
});
|
|
417
|
+
|
|
418
|
+
test("should run superRefine validation even when base schema validation fails when 'when' is defined and returns true", () => {
|
|
419
|
+
const baseSchema = z.object({
|
|
420
|
+
foo: z.number(),
|
|
421
|
+
bar: z.number(),
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
const schema = baseSchema.superRefine(
|
|
425
|
+
(data, ctx) => {
|
|
426
|
+
if (data.foo > 10) {
|
|
427
|
+
ctx.addIssue({
|
|
428
|
+
code: "custom",
|
|
429
|
+
message: "foo must be less than 10",
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
when: ({ value }) => baseSchema.pick({ foo: true }).safeParse(value).success,
|
|
435
|
+
}
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
const result = schema.safeParse({
|
|
439
|
+
foo: 11,
|
|
440
|
+
});
|
|
441
|
+
expect(result.success).toEqual(false);
|
|
442
|
+
|
|
443
|
+
if (!result.success) {
|
|
444
|
+
expect(result.error.issues.length).toEqual(2);
|
|
445
|
+
expect(result.error.issues[0].message).toEqual("Invalid input: expected number, received undefined");
|
|
446
|
+
expect(result.error.issues[1].message).toEqual("foo must be less than 10");
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
test("should not run superRefine validation when 'when' is defined and returns false", () => {
|
|
451
|
+
const baseSchema = z.object({
|
|
452
|
+
foo: z.number(),
|
|
453
|
+
bar: z.number(),
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
const schema = baseSchema.superRefine(
|
|
457
|
+
(data, ctx) => {
|
|
458
|
+
if (data.foo > 10) {
|
|
459
|
+
ctx.addIssue({
|
|
460
|
+
code: "custom",
|
|
461
|
+
message: "foo must be less than 10",
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
when: ({ value }) => baseSchema.safeParse(value).success,
|
|
467
|
+
}
|
|
468
|
+
);
|
|
469
|
+
|
|
470
|
+
const result = schema.safeParse({
|
|
471
|
+
foo: 11,
|
|
472
|
+
});
|
|
473
|
+
expect(result.success).toEqual(false);
|
|
474
|
+
|
|
475
|
+
if (!result.success) {
|
|
476
|
+
expect(result.error.issues.length).toEqual(1);
|
|
477
|
+
expect(result.error.issues[0].message).toEqual("Invalid input: expected number, received undefined");
|
|
478
|
+
}
|
|
479
|
+
});
|
|
417
480
|
});
|
|
418
481
|
|
|
419
482
|
describe("type refinement with type guards", () => {
|