zod 3.26.0-canary.20250703T013930 → 3.26.0-canary.20250703T214020

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.
Files changed (278) hide show
  1. package/package.json +20 -20
  2. package/src/index.ts +4 -0
  3. package/src/v3/ZodError.ts +330 -0
  4. package/src/v3/benchmarks/datetime.ts +58 -0
  5. package/src/v3/benchmarks/discriminatedUnion.ts +80 -0
  6. package/src/v3/benchmarks/index.ts +59 -0
  7. package/src/v3/benchmarks/ipv4.ts +57 -0
  8. package/src/v3/benchmarks/object.ts +69 -0
  9. package/src/v3/benchmarks/primitives.ts +162 -0
  10. package/src/v3/benchmarks/realworld.ts +63 -0
  11. package/src/v3/benchmarks/string.ts +55 -0
  12. package/src/v3/benchmarks/union.ts +80 -0
  13. package/src/v3/errors.ts +13 -0
  14. package/src/v3/external.ts +6 -0
  15. package/src/v3/helpers/enumUtil.ts +17 -0
  16. package/src/v3/helpers/errorUtil.ts +8 -0
  17. package/src/v3/helpers/parseUtil.ts +176 -0
  18. package/src/v3/helpers/partialUtil.ts +34 -0
  19. package/src/v3/helpers/typeAliases.ts +2 -0
  20. package/src/v3/helpers/util.ts +224 -0
  21. package/src/v3/index.ts +4 -0
  22. package/src/v3/locales/en.ts +124 -0
  23. package/src/v3/standard-schema.ts +113 -0
  24. package/src/v3/tests/Mocker.ts +54 -0
  25. package/src/v3/tests/all-errors.test.ts +157 -0
  26. package/src/v3/tests/anyunknown.test.ts +28 -0
  27. package/src/v3/tests/array.test.ts +71 -0
  28. package/src/v3/tests/async-parsing.test.ts +388 -0
  29. package/src/v3/tests/async-refinements.test.ts +46 -0
  30. package/src/v3/tests/base.test.ts +29 -0
  31. package/src/v3/tests/bigint.test.ts +55 -0
  32. package/src/v3/tests/branded.test.ts +53 -0
  33. package/src/v3/tests/catch.test.ts +220 -0
  34. package/src/v3/tests/coerce.test.ts +133 -0
  35. package/src/v3/tests/complex.test.ts +56 -0
  36. package/src/v3/tests/custom.test.ts +31 -0
  37. package/src/v3/tests/date.test.ts +32 -0
  38. package/src/v3/tests/deepmasking.test.ts +186 -0
  39. package/src/v3/tests/default.test.ts +112 -0
  40. package/src/v3/tests/description.test.ts +33 -0
  41. package/src/v3/tests/discriminated-unions.test.ts +315 -0
  42. package/src/v3/tests/enum.test.ts +80 -0
  43. package/src/v3/tests/error.test.ts +551 -0
  44. package/src/v3/tests/firstparty.test.ts +87 -0
  45. package/src/v3/tests/firstpartyschematypes.test.ts +21 -0
  46. package/src/v3/tests/function.test.ts +257 -0
  47. package/src/v3/tests/generics.test.ts +48 -0
  48. package/src/v3/tests/instanceof.test.ts +37 -0
  49. package/src/v3/tests/intersection.test.ts +110 -0
  50. package/src/v3/tests/language-server.source.ts +76 -0
  51. package/src/v3/tests/language-server.test.ts +207 -0
  52. package/src/v3/tests/literal.test.ts +36 -0
  53. package/src/v3/tests/map.test.ts +110 -0
  54. package/src/v3/tests/masking.test.ts +4 -0
  55. package/src/v3/tests/mocker.test.ts +19 -0
  56. package/src/v3/tests/nan.test.ts +21 -0
  57. package/src/v3/tests/nativeEnum.test.ts +87 -0
  58. package/src/v3/tests/nullable.test.ts +42 -0
  59. package/src/v3/tests/number.test.ts +176 -0
  60. package/src/v3/tests/object-augmentation.test.ts +29 -0
  61. package/src/v3/tests/object-in-es5-env.test.ts +29 -0
  62. package/src/v3/tests/object.test.ts +434 -0
  63. package/src/v3/tests/optional.test.ts +42 -0
  64. package/src/v3/tests/parseUtil.test.ts +23 -0
  65. package/src/v3/tests/parser.test.ts +41 -0
  66. package/src/v3/tests/partials.test.ts +243 -0
  67. package/src/v3/tests/pickomit.test.ts +111 -0
  68. package/src/v3/tests/pipeline.test.ts +29 -0
  69. package/src/v3/tests/preprocess.test.ts +186 -0
  70. package/src/v3/tests/primitive.test.ts +440 -0
  71. package/src/v3/tests/promise.test.ts +90 -0
  72. package/src/v3/tests/readonly.test.ts +194 -0
  73. package/src/v3/tests/record.test.ts +171 -0
  74. package/src/v3/tests/recursive.test.ts +197 -0
  75. package/src/v3/tests/refine.test.ts +313 -0
  76. package/src/v3/tests/safeparse.test.ts +27 -0
  77. package/src/v3/tests/set.test.ts +142 -0
  78. package/src/v3/tests/standard-schema.test.ts +83 -0
  79. package/src/v3/tests/string.test.ts +916 -0
  80. package/src/v3/tests/transformer.test.ts +233 -0
  81. package/src/v3/tests/tuple.test.ts +90 -0
  82. package/src/v3/tests/unions.test.ts +57 -0
  83. package/src/v3/tests/validations.test.ts +133 -0
  84. package/src/v3/tests/void.test.ts +15 -0
  85. package/src/v3/types.ts +5136 -0
  86. package/src/v4/classic/checks.ts +30 -0
  87. package/src/v4/classic/coerce.ts +27 -0
  88. package/src/v4/classic/compat.ts +66 -0
  89. package/src/v4/classic/errors.ts +75 -0
  90. package/src/v4/classic/external.ts +50 -0
  91. package/src/v4/classic/index.ts +5 -0
  92. package/src/v4/classic/iso.ts +90 -0
  93. package/src/v4/classic/parse.ts +33 -0
  94. package/src/v4/classic/schemas.ts +2055 -0
  95. package/src/v4/classic/tests/anyunknown.test.ts +26 -0
  96. package/src/v4/classic/tests/array.test.ts +264 -0
  97. package/src/v4/classic/tests/assignability.test.ts +210 -0
  98. package/src/v4/classic/tests/async-parsing.test.ts +381 -0
  99. package/src/v4/classic/tests/async-refinements.test.ts +68 -0
  100. package/src/v4/classic/tests/base.test.ts +7 -0
  101. package/src/v4/classic/tests/bigint.test.ts +54 -0
  102. package/src/v4/classic/tests/brand.test.ts +65 -0
  103. package/src/v4/classic/tests/catch.test.ts +252 -0
  104. package/src/v4/classic/tests/coalesce.test.ts +20 -0
  105. package/src/v4/classic/tests/coerce.test.ts +160 -0
  106. package/src/v4/classic/tests/continuability.test.ts +352 -0
  107. package/src/v4/classic/tests/custom.test.ts +40 -0
  108. package/src/v4/classic/tests/date.test.ts +31 -0
  109. package/src/v4/classic/tests/datetime.test.ts +296 -0
  110. package/src/v4/classic/tests/default.test.ts +313 -0
  111. package/src/v4/classic/tests/description.test.ts +32 -0
  112. package/src/v4/classic/tests/discriminated-unions.test.ts +592 -0
  113. package/src/v4/classic/tests/enum.test.ts +285 -0
  114. package/src/v4/classic/tests/error-utils.test.ts +527 -0
  115. package/src/v4/classic/tests/error.test.ts +711 -0
  116. package/src/v4/classic/tests/file.test.ts +91 -0
  117. package/src/v4/classic/tests/firstparty.test.ts +175 -0
  118. package/src/v4/classic/tests/function.test.ts +268 -0
  119. package/src/v4/classic/tests/generics.test.ts +72 -0
  120. package/src/v4/classic/tests/index.test.ts +829 -0
  121. package/src/v4/classic/tests/instanceof.test.ts +34 -0
  122. package/src/v4/classic/tests/intersection.test.ts +171 -0
  123. package/src/v4/classic/tests/json.test.ts +108 -0
  124. package/src/v4/classic/tests/lazy.test.ts +227 -0
  125. package/src/v4/classic/tests/literal.test.ts +92 -0
  126. package/src/v4/classic/tests/map.test.ts +196 -0
  127. package/src/v4/classic/tests/nan.test.ts +21 -0
  128. package/src/v4/classic/tests/nested-refine.test.ts +168 -0
  129. package/src/v4/classic/tests/nonoptional.test.ts +86 -0
  130. package/src/v4/classic/tests/nullable.test.ts +22 -0
  131. package/src/v4/classic/tests/number.test.ts +247 -0
  132. package/src/v4/classic/tests/object.test.ts +553 -0
  133. package/src/v4/classic/tests/optional.test.ts +103 -0
  134. package/src/v4/classic/tests/partial.test.ts +147 -0
  135. package/src/v4/classic/tests/pickomit.test.ts +127 -0
  136. package/src/v4/classic/tests/pipe.test.ts +81 -0
  137. package/src/v4/classic/tests/prefault.test.ts +37 -0
  138. package/src/v4/classic/tests/preprocess.test.ts +298 -0
  139. package/src/v4/classic/tests/primitive.test.ts +175 -0
  140. package/src/v4/classic/tests/promise.test.ts +81 -0
  141. package/src/v4/classic/tests/prototypes.test.ts +23 -0
  142. package/src/v4/classic/tests/readonly.test.ts +252 -0
  143. package/src/v4/classic/tests/record.test.ts +332 -0
  144. package/src/v4/classic/tests/recursive-types.test.ts +325 -0
  145. package/src/v4/classic/tests/refine.test.ts +423 -0
  146. package/src/v4/classic/tests/registries.test.ts +195 -0
  147. package/src/v4/classic/tests/set.test.ts +179 -0
  148. package/src/v4/classic/tests/standard-schema.test.ts +57 -0
  149. package/src/v4/classic/tests/string-formats.test.ts +109 -0
  150. package/src/v4/classic/tests/string.test.ts +881 -0
  151. package/src/v4/classic/tests/stringbool.test.ts +66 -0
  152. package/src/v4/classic/tests/template-literal.test.ts +758 -0
  153. package/src/v4/classic/tests/to-json-schema.test.ts +2182 -0
  154. package/src/v4/classic/tests/transform.test.ts +250 -0
  155. package/src/v4/classic/tests/tuple.test.ts +163 -0
  156. package/src/v4/classic/tests/union.test.ts +94 -0
  157. package/src/v4/classic/tests/validations.test.ts +283 -0
  158. package/src/v4/classic/tests/void.test.ts +12 -0
  159. package/src/v4/core/api.ts +1592 -0
  160. package/src/v4/core/checks.ts +1285 -0
  161. package/src/v4/core/config.ts +15 -0
  162. package/src/v4/core/core.ts +134 -0
  163. package/src/v4/core/doc.ts +44 -0
  164. package/src/v4/core/errors.ts +420 -0
  165. package/src/v4/core/function.ts +176 -0
  166. package/src/v4/core/index.ts +15 -0
  167. package/src/v4/core/json-schema.ts +143 -0
  168. package/src/v4/core/parse.ts +94 -0
  169. package/src/v4/core/regexes.ts +135 -0
  170. package/src/v4/core/registries.ts +86 -0
  171. package/src/v4/core/schemas.ts +3781 -0
  172. package/src/v4/core/standard-schema.ts +64 -0
  173. package/src/v4/core/tests/index.test.ts +46 -0
  174. package/src/v4/core/tests/locales/be.test.ts +124 -0
  175. package/src/v4/core/tests/locales/en.test.ts +22 -0
  176. package/src/v4/core/tests/locales/ru.test.ts +128 -0
  177. package/src/v4/core/tests/locales/tr.test.ts +69 -0
  178. package/src/v4/core/to-json-schema.ts +944 -0
  179. package/src/v4/core/util.ts +775 -0
  180. package/src/v4/core/versions.ts +5 -0
  181. package/src/v4/core/zsf.ts +323 -0
  182. package/src/v4/index.ts +4 -0
  183. package/src/v4/locales/ar.ts +125 -0
  184. package/src/v4/locales/az.ts +121 -0
  185. package/src/v4/locales/be.ts +184 -0
  186. package/src/v4/locales/ca.ts +127 -0
  187. package/src/v4/locales/cs.ts +142 -0
  188. package/src/v4/locales/de.ts +124 -0
  189. package/src/v4/locales/en.ts +127 -0
  190. package/src/v4/locales/eo.ts +125 -0
  191. package/src/v4/locales/es.ts +125 -0
  192. package/src/v4/locales/fa.ts +134 -0
  193. package/src/v4/locales/fi.ts +131 -0
  194. package/src/v4/locales/fr-CA.ts +126 -0
  195. package/src/v4/locales/fr.ts +124 -0
  196. package/src/v4/locales/he.ts +125 -0
  197. package/src/v4/locales/hu.ts +126 -0
  198. package/src/v4/locales/id.ts +125 -0
  199. package/src/v4/locales/index.ts +39 -0
  200. package/src/v4/locales/it.ts +125 -0
  201. package/src/v4/locales/ja.ts +122 -0
  202. package/src/v4/locales/kh.ts +126 -0
  203. package/src/v4/locales/ko.ts +131 -0
  204. package/src/v4/locales/mk.ts +127 -0
  205. package/src/v4/locales/ms.ts +124 -0
  206. package/src/v4/locales/nl.ts +126 -0
  207. package/src/v4/locales/no.ts +124 -0
  208. package/src/v4/locales/ota.ts +125 -0
  209. package/src/v4/locales/pl.ts +126 -0
  210. package/src/v4/locales/ps.ts +133 -0
  211. package/src/v4/locales/pt.ts +123 -0
  212. package/src/v4/locales/ru.ts +184 -0
  213. package/src/v4/locales/sl.ts +126 -0
  214. package/src/v4/locales/sv.ts +127 -0
  215. package/src/v4/locales/ta.ts +125 -0
  216. package/src/v4/locales/th.ts +126 -0
  217. package/src/v4/locales/tr.ts +121 -0
  218. package/src/v4/locales/ua.ts +126 -0
  219. package/src/v4/locales/ur.ts +126 -0
  220. package/src/v4/locales/vi.ts +125 -0
  221. package/src/v4/locales/zh-CN.ts +123 -0
  222. package/src/v4/locales/zh-TW.ts +125 -0
  223. package/src/v4/mini/checks.ts +32 -0
  224. package/src/v4/mini/coerce.ts +22 -0
  225. package/src/v4/mini/external.ts +40 -0
  226. package/src/v4/mini/index.ts +3 -0
  227. package/src/v4/mini/iso.ts +62 -0
  228. package/src/v4/mini/parse.ts +1 -0
  229. package/src/v4/mini/schemas.ts +1579 -0
  230. package/src/v4/mini/tests/assignability.test.ts +129 -0
  231. package/src/v4/mini/tests/brand.test.ts +51 -0
  232. package/src/v4/mini/tests/checks.test.ts +144 -0
  233. package/src/v4/mini/tests/computed.test.ts +36 -0
  234. package/src/v4/mini/tests/error.test.ts +22 -0
  235. package/src/v4/mini/tests/functions.test.ts +43 -0
  236. package/src/v4/mini/tests/index.test.ts +871 -0
  237. package/src/v4/mini/tests/number.test.ts +95 -0
  238. package/src/v4/mini/tests/object.test.ts +185 -0
  239. package/src/v4/mini/tests/prototypes.test.ts +43 -0
  240. package/src/v4/mini/tests/recursive-types.test.ts +275 -0
  241. package/src/v4/mini/tests/string.test.ts +293 -0
  242. package/src/v4-mini/index.ts +1 -0
  243. package/v4/classic/compat.cjs +1 -7
  244. package/v4/classic/compat.d.cts +0 -2
  245. package/v4/classic/compat.d.ts +0 -2
  246. package/v4/classic/compat.js +0 -6
  247. package/v4/classic/external.cjs +2 -1
  248. package/v4/classic/external.d.cts +1 -1
  249. package/v4/classic/external.d.ts +1 -1
  250. package/v4/classic/external.js +1 -1
  251. package/v4/classic/schemas.d.cts +4 -4
  252. package/v4/classic/schemas.d.ts +4 -4
  253. package/v4/core/api.cjs +11 -10
  254. package/v4/core/api.js +11 -10
  255. package/v4/core/checks.cjs +6 -4
  256. package/v4/core/checks.js +6 -4
  257. package/v4/core/core.cjs +5 -1
  258. package/v4/core/core.d.cts +2 -0
  259. package/v4/core/core.d.ts +2 -0
  260. package/v4/core/core.js +4 -0
  261. package/v4/core/schemas.cjs +12 -13
  262. package/v4/core/schemas.js +12 -13
  263. package/v4/core/util.cjs +3 -0
  264. package/v4/core/util.d.cts +1 -1
  265. package/v4/core/util.d.ts +1 -1
  266. package/v4/core/util.js +3 -0
  267. package/v4/locales/eo.cjs +144 -0
  268. package/v4/locales/eo.d.cts +5 -0
  269. package/v4/locales/eo.d.ts +5 -0
  270. package/v4/locales/eo.js +116 -0
  271. package/v4/locales/index.cjs +3 -1
  272. package/v4/locales/index.d.cts +1 -0
  273. package/v4/locales/index.d.ts +1 -0
  274. package/v4/locales/index.js +1 -0
  275. package/v4/mini/external.cjs +2 -1
  276. package/v4/mini/external.d.cts +1 -1
  277. package/v4/mini/external.d.ts +1 -1
  278. package/v4/mini/external.js +1 -1
@@ -0,0 +1,23 @@
1
+ // @ts-ignore TS6133
2
+ import { expect, test } from "vitest";
3
+
4
+ import { type SyncParseReturnType, isAborted, isDirty, isValid } from "../helpers/parseUtil.js";
5
+
6
+ test("parseUtil isInvalid should use structural typing", () => {
7
+ // Test for issue #556: https://github.com/colinhacks/zod/issues/556
8
+ const aborted: SyncParseReturnType = { status: "aborted" };
9
+ const dirty: SyncParseReturnType = { status: "dirty", value: "whatever" };
10
+ const valid: SyncParseReturnType = { status: "valid", value: "whatever" };
11
+
12
+ expect(isAborted(aborted)).toBe(true);
13
+ expect(isAborted(dirty)).toBe(false);
14
+ expect(isAborted(valid)).toBe(false);
15
+
16
+ expect(isDirty(aborted)).toBe(false);
17
+ expect(isDirty(dirty)).toBe(true);
18
+ expect(isDirty(valid)).toBe(false);
19
+
20
+ expect(isValid(aborted)).toBe(false);
21
+ expect(isValid(dirty)).toBe(false);
22
+ expect(isValid(valid)).toBe(true);
23
+ });
@@ -0,0 +1,41 @@
1
+ // @ts-ignore TS6133
2
+ import { expect, test } from "vitest";
3
+
4
+ import * as z from "zod/v3";
5
+
6
+ test("parse strict object with unknown keys", () => {
7
+ expect(() =>
8
+ z
9
+ .object({ name: z.string() })
10
+ .strict()
11
+ .parse({ name: "bill", unknownKey: 12 } as any)
12
+ ).toThrow();
13
+ });
14
+
15
+ test("parse nonstrict object with unknown keys", () => {
16
+ z.object({ name: z.string() }).nonstrict().parse({ name: "bill", unknownKey: 12 });
17
+ });
18
+
19
+ test("invalid left side of intersection", () => {
20
+ expect(() => z.intersection(z.string(), z.number()).parse(12 as any)).toThrow();
21
+ });
22
+
23
+ test("invalid right side of intersection", () => {
24
+ expect(() => z.intersection(z.string(), z.number()).parse("12" as any)).toThrow();
25
+ });
26
+
27
+ test("parsing non-array in tuple schema", () => {
28
+ expect(() => z.tuple([]).parse("12" as any)).toThrow();
29
+ });
30
+
31
+ test("incorrect num elements in tuple", () => {
32
+ expect(() => z.tuple([]).parse(["asdf"] as any)).toThrow();
33
+ });
34
+
35
+ test("invalid enum value", () => {
36
+ expect(() => z.enum(["Blue"]).parse("Red" as any)).toThrow();
37
+ });
38
+
39
+ test("parsing unknown", () => {
40
+ z.string().parse("Red" as unknown);
41
+ });
@@ -0,0 +1,243 @@
1
+ // @ts-ignore TS6133
2
+ import { expect, test } from "vitest";
3
+
4
+ import * as z from "zod/v3";
5
+ import { ZodNullable, ZodOptional } from "zod/v3";
6
+ import { util } from "../helpers/util.js";
7
+
8
+ const nested = z.object({
9
+ name: z.string(),
10
+ age: z.number(),
11
+ outer: z.object({
12
+ inner: z.string(),
13
+ }),
14
+ array: z.array(z.object({ asdf: z.string() })),
15
+ });
16
+
17
+ test("shallow inference", () => {
18
+ const shallow = nested.partial();
19
+ type shallow = z.infer<typeof shallow>;
20
+ type correct = {
21
+ name?: string | undefined;
22
+ age?: number | undefined;
23
+ outer?: { inner: string } | undefined;
24
+ array?: { asdf: string }[];
25
+ };
26
+ util.assertEqual<shallow, correct>(true);
27
+ });
28
+
29
+ test("shallow partial parse", () => {
30
+ const shallow = nested.partial();
31
+ shallow.parse({});
32
+ shallow.parse({
33
+ name: "asdf",
34
+ age: 23143,
35
+ });
36
+ });
37
+
38
+ test("deep partial inference", () => {
39
+ const deep = nested.deepPartial();
40
+ const asdf = deep.shape.array.unwrap().element.shape.asdf.unwrap();
41
+ asdf.parse("asdf");
42
+ type deep = z.infer<typeof deep>;
43
+ type correct = {
44
+ array?: { asdf?: string }[];
45
+ name?: string | undefined;
46
+ age?: number | undefined;
47
+ outer?: { inner?: string | undefined } | undefined;
48
+ };
49
+
50
+ util.assertEqual<deep, correct>(true);
51
+ });
52
+
53
+ test("deep partial parse", () => {
54
+ const deep = nested.deepPartial();
55
+
56
+ expect(deep.shape.name instanceof z.ZodOptional).toBe(true);
57
+ expect(deep.shape.outer instanceof z.ZodOptional).toBe(true);
58
+ expect(deep.shape.outer._def.innerType instanceof z.ZodObject).toBe(true);
59
+ expect(deep.shape.outer._def.innerType.shape.inner instanceof z.ZodOptional).toBe(true);
60
+ expect(deep.shape.outer._def.innerType.shape.inner._def.innerType instanceof z.ZodString).toBe(true);
61
+ });
62
+
63
+ test("deep partial runtime tests", () => {
64
+ const deep = nested.deepPartial();
65
+ deep.parse({});
66
+ deep.parse({
67
+ outer: {},
68
+ });
69
+ deep.parse({
70
+ name: "asdf",
71
+ age: 23143,
72
+ outer: {
73
+ inner: "adsf",
74
+ },
75
+ });
76
+ });
77
+
78
+ test("deep partial optional/nullable", () => {
79
+ const schema = z
80
+ .object({
81
+ name: z.string().optional(),
82
+ age: z.number().nullable(),
83
+ })
84
+ .deepPartial();
85
+
86
+ expect(schema.shape.name.unwrap()).toBeInstanceOf(ZodOptional);
87
+ expect(schema.shape.age.unwrap()).toBeInstanceOf(ZodNullable);
88
+ });
89
+
90
+ test("deep partial tuple", () => {
91
+ const schema = z
92
+ .object({
93
+ tuple: z.tuple([
94
+ z.object({
95
+ name: z.string().optional(),
96
+ age: z.number().nullable(),
97
+ }),
98
+ ]),
99
+ })
100
+ .deepPartial();
101
+
102
+ expect(schema.shape.tuple.unwrap().items[0].shape.name).toBeInstanceOf(ZodOptional);
103
+ });
104
+
105
+ test("deep partial inference", () => {
106
+ const mySchema = z.object({
107
+ name: z.string(),
108
+ array: z.array(z.object({ asdf: z.string() })),
109
+ tuple: z.tuple([z.object({ value: z.string() })]),
110
+ });
111
+
112
+ const partialed = mySchema.deepPartial();
113
+ type partialed = z.infer<typeof partialed>;
114
+ type expected = {
115
+ name?: string | undefined;
116
+ array?:
117
+ | {
118
+ asdf?: string | undefined;
119
+ }[]
120
+ | undefined;
121
+ tuple?: [{ value?: string }] | undefined;
122
+ };
123
+ util.assertEqual<expected, partialed>(true);
124
+ });
125
+
126
+ test("required", () => {
127
+ const object = z.object({
128
+ name: z.string(),
129
+ age: z.number().optional(),
130
+ field: z.string().optional().default("asdf"),
131
+ nullableField: z.number().nullable(),
132
+ nullishField: z.string().nullish(),
133
+ });
134
+
135
+ const requiredObject = object.required();
136
+ expect(requiredObject.shape.name).toBeInstanceOf(z.ZodString);
137
+ expect(requiredObject.shape.age).toBeInstanceOf(z.ZodNumber);
138
+ expect(requiredObject.shape.field).toBeInstanceOf(z.ZodDefault);
139
+ expect(requiredObject.shape.nullableField).toBeInstanceOf(z.ZodNullable);
140
+ expect(requiredObject.shape.nullishField).toBeInstanceOf(z.ZodNullable);
141
+ });
142
+
143
+ test("required inference", () => {
144
+ const object = z.object({
145
+ name: z.string(),
146
+ age: z.number().optional(),
147
+ field: z.string().optional().default("asdf"),
148
+ nullableField: z.number().nullable(),
149
+ nullishField: z.string().nullish(),
150
+ });
151
+
152
+ const requiredObject = object.required();
153
+
154
+ type required = z.infer<typeof requiredObject>;
155
+ type expected = {
156
+ name: string;
157
+ age: number;
158
+ field: string;
159
+ nullableField: number | null;
160
+ nullishField: string | null;
161
+ };
162
+ util.assertEqual<expected, required>(true);
163
+ });
164
+
165
+ test("required with mask", () => {
166
+ const object = z.object({
167
+ name: z.string(),
168
+ age: z.number().optional(),
169
+ field: z.string().optional().default("asdf"),
170
+ country: z.string().optional(),
171
+ });
172
+
173
+ const requiredObject = object.required({ age: true });
174
+ expect(requiredObject.shape.name).toBeInstanceOf(z.ZodString);
175
+ expect(requiredObject.shape.age).toBeInstanceOf(z.ZodNumber);
176
+ expect(requiredObject.shape.field).toBeInstanceOf(z.ZodDefault);
177
+ expect(requiredObject.shape.country).toBeInstanceOf(z.ZodOptional);
178
+ });
179
+
180
+ test("required with mask -- ignore falsy values", () => {
181
+ const object = z.object({
182
+ name: z.string(),
183
+ age: z.number().optional(),
184
+ field: z.string().optional().default("asdf"),
185
+ country: z.string().optional(),
186
+ });
187
+
188
+ // @ts-expect-error
189
+ const requiredObject = object.required({ age: true, country: false });
190
+ expect(requiredObject.shape.name).toBeInstanceOf(z.ZodString);
191
+ expect(requiredObject.shape.age).toBeInstanceOf(z.ZodNumber);
192
+ expect(requiredObject.shape.field).toBeInstanceOf(z.ZodDefault);
193
+ expect(requiredObject.shape.country).toBeInstanceOf(z.ZodOptional);
194
+ });
195
+
196
+ test("partial with mask", async () => {
197
+ const object = z.object({
198
+ name: z.string(),
199
+ age: z.number().optional(),
200
+ field: z.string().optional().default("asdf"),
201
+ country: z.string(),
202
+ });
203
+
204
+ const masked = object.partial({ age: true, field: true, name: true }).strict();
205
+
206
+ expect(masked.shape.name).toBeInstanceOf(z.ZodOptional);
207
+ expect(masked.shape.age).toBeInstanceOf(z.ZodOptional);
208
+ expect(masked.shape.field).toBeInstanceOf(z.ZodOptional);
209
+ expect(masked.shape.country).toBeInstanceOf(z.ZodString);
210
+
211
+ masked.parse({ country: "US" });
212
+ await masked.parseAsync({ country: "US" });
213
+ });
214
+
215
+ test("partial with mask -- ignore falsy values", async () => {
216
+ const object = z.object({
217
+ name: z.string(),
218
+ age: z.number().optional(),
219
+ field: z.string().optional().default("asdf"),
220
+ country: z.string(),
221
+ });
222
+
223
+ // @ts-expect-error
224
+ const masked = object.partial({ name: true, country: false }).strict();
225
+
226
+ expect(masked.shape.name).toBeInstanceOf(z.ZodOptional);
227
+ expect(masked.shape.age).toBeInstanceOf(z.ZodOptional);
228
+ expect(masked.shape.field).toBeInstanceOf(z.ZodDefault);
229
+ expect(masked.shape.country).toBeInstanceOf(z.ZodString);
230
+
231
+ masked.parse({ country: "US" });
232
+ await masked.parseAsync({ country: "US" });
233
+ });
234
+
235
+ test("deeppartial array", () => {
236
+ const schema = z.object({ array: z.string().array().min(42) }).deepPartial();
237
+
238
+ // works as expected
239
+ schema.parse({});
240
+
241
+ // should be false, but is true
242
+ expect(schema.safeParse({ array: [] }).success).toBe(false);
243
+ });
@@ -0,0 +1,111 @@
1
+ // @ts-ignore TS6133
2
+ import { expect, test } from "vitest";
3
+
4
+ import * as z from "zod/v3";
5
+ import { util } from "../helpers/util.js";
6
+
7
+ const fish = z.object({
8
+ name: z.string(),
9
+ age: z.number(),
10
+ nested: z.object({}),
11
+ });
12
+
13
+ test("pick type inference", () => {
14
+ const nameonlyFish = fish.pick({ name: true });
15
+ type nameonlyFish = z.infer<typeof nameonlyFish>;
16
+ util.assertEqual<nameonlyFish, { name: string }>(true);
17
+ });
18
+
19
+ test("pick parse - success", () => {
20
+ const nameonlyFish = fish.pick({ name: true });
21
+ nameonlyFish.parse({ name: "bob" });
22
+
23
+ // @ts-expect-error checking runtime picks `name` only.
24
+ const anotherNameonlyFish = fish.pick({ name: true, age: false });
25
+ anotherNameonlyFish.parse({ name: "bob" });
26
+ });
27
+
28
+ test("pick parse - fail", () => {
29
+ fish.pick({ name: true }).parse({ name: "12" } as any);
30
+ fish.pick({ name: true }).parse({ name: "bob", age: 12 } as any);
31
+ fish.pick({ age: true }).parse({ age: 12 } as any);
32
+
33
+ const nameonlyFish = fish.pick({ name: true }).strict();
34
+ const bad1 = () => nameonlyFish.parse({ name: 12 } as any);
35
+ const bad2 = () => nameonlyFish.parse({ name: "bob", age: 12 } as any);
36
+ const bad3 = () => nameonlyFish.parse({ age: 12 } as any);
37
+
38
+ // @ts-expect-error checking runtime picks `name` only.
39
+ const anotherNameonlyFish = fish.pick({ name: true, age: false }).strict();
40
+ const bad4 = () => anotherNameonlyFish.parse({ name: "bob", age: 12 } as any);
41
+
42
+ expect(bad1).toThrow();
43
+ expect(bad2).toThrow();
44
+ expect(bad3).toThrow();
45
+ expect(bad4).toThrow();
46
+ });
47
+
48
+ test("omit type inference", () => {
49
+ const nonameFish = fish.omit({ name: true });
50
+ type nonameFish = z.infer<typeof nonameFish>;
51
+ util.assertEqual<nonameFish, { age: number; nested: {} }>(true);
52
+ });
53
+
54
+ test("omit parse - success", () => {
55
+ const nonameFish = fish.omit({ name: true });
56
+ nonameFish.parse({ age: 12, nested: {} });
57
+
58
+ // @ts-expect-error checking runtime omits `name` only.
59
+ const anotherNonameFish = fish.omit({ name: true, age: false });
60
+ anotherNonameFish.parse({ age: 12, nested: {} });
61
+ });
62
+
63
+ test("omit parse - fail", () => {
64
+ const nonameFish = fish.omit({ name: true });
65
+ const bad1 = () => nonameFish.parse({ name: 12 } as any);
66
+ const bad2 = () => nonameFish.parse({ age: 12 } as any);
67
+ const bad3 = () => nonameFish.parse({} as any);
68
+
69
+ // @ts-expect-error checking runtime omits `name` only.
70
+ const anotherNonameFish = fish.omit({ name: true, age: false });
71
+ const bad4 = () => anotherNonameFish.parse({ nested: {} } as any);
72
+
73
+ expect(bad1).toThrow();
74
+ expect(bad2).toThrow();
75
+ expect(bad3).toThrow();
76
+ expect(bad4).toThrow();
77
+ });
78
+
79
+ test("nonstrict inference", () => {
80
+ const laxfish = fish.pick({ name: true }).catchall(z.any());
81
+ type laxfish = z.infer<typeof laxfish>;
82
+ util.assertEqual<laxfish, { name: string } & { [k: string]: any }>(true);
83
+ });
84
+
85
+ test("nonstrict parsing - pass", () => {
86
+ const laxfish = fish.passthrough().pick({ name: true });
87
+ laxfish.parse({ name: "asdf", whatever: "asdf" });
88
+ laxfish.parse({ name: "asdf", age: 12, nested: {} });
89
+ });
90
+
91
+ test("nonstrict parsing - fail", () => {
92
+ const laxfish = fish.passthrough().pick({ name: true });
93
+ const bad = () => laxfish.parse({ whatever: "asdf" } as any);
94
+ expect(bad).toThrow();
95
+ });
96
+
97
+ test("pick/omit/required/partial - do not allow unknown keys", () => {
98
+ const schema = z.object({
99
+ name: z.string(),
100
+ age: z.number(),
101
+ });
102
+
103
+ // @ts-expect-error
104
+ schema.pick({ $unknown: true });
105
+ // @ts-expect-error
106
+ schema.omit({ $unknown: true });
107
+ // @ts-expect-error
108
+ schema.required({ $unknown: true });
109
+ // @ts-expect-error
110
+ schema.partial({ $unknown: true });
111
+ });
@@ -0,0 +1,29 @@
1
+ // @ts-ignore TS6133
2
+ import { expect, test } from "vitest";
3
+
4
+ import * as z from "zod/v3";
5
+
6
+ test("string to number pipeline", () => {
7
+ const schema = z.string().transform(Number).pipe(z.number());
8
+ expect(schema.parse("1234")).toEqual(1234);
9
+ });
10
+
11
+ test("string to number pipeline async", async () => {
12
+ const schema = z
13
+ .string()
14
+ .transform(async (val) => Number(val))
15
+ .pipe(z.number());
16
+ expect(await schema.parseAsync("1234")).toEqual(1234);
17
+ });
18
+
19
+ test("break if dirty", () => {
20
+ const schema = z
21
+ .string()
22
+ .refine((c) => c === "1234")
23
+ .transform(async (val) => Number(val))
24
+ .pipe(z.number().refine((v) => v < 100));
25
+ const r1: any = schema.safeParse("12345");
26
+ expect(r1.error.issues.length).toBe(1);
27
+ const r2: any = schema.safeParse("3");
28
+ expect(r2.error.issues.length).toBe(1);
29
+ });
@@ -0,0 +1,186 @@
1
+ // @ts-ignore TS6133
2
+ import { expect, test } from "vitest";
3
+
4
+ import * as z from "zod/v3";
5
+ import { util } from "../helpers/util.js";
6
+
7
+ test("preprocess", () => {
8
+ const schema = z.preprocess((data) => [data], z.string().array());
9
+
10
+ const value = schema.parse("asdf");
11
+ expect(value).toEqual(["asdf"]);
12
+ util.assertEqual<(typeof schema)["_input"], unknown>(true);
13
+ });
14
+
15
+ test("async preprocess", async () => {
16
+ const schema = z.preprocess(async (data) => [data], z.string().array());
17
+
18
+ const value = await schema.parseAsync("asdf");
19
+ expect(value).toEqual(["asdf"]);
20
+ });
21
+
22
+ test("preprocess ctx.addIssue with parse", () => {
23
+ expect(() => {
24
+ z.preprocess((data, ctx) => {
25
+ ctx.addIssue({
26
+ code: "custom",
27
+ message: `${data} is not one of our allowed strings`,
28
+ });
29
+ return data;
30
+ }, z.string()).parse("asdf");
31
+ }).toThrow(
32
+ JSON.stringify(
33
+ [
34
+ {
35
+ code: "custom",
36
+ message: "asdf is not one of our allowed strings",
37
+ path: [],
38
+ },
39
+ ],
40
+ null,
41
+ 2
42
+ )
43
+ );
44
+ });
45
+
46
+ test("preprocess ctx.addIssue non-fatal by default", () => {
47
+ try {
48
+ z.preprocess((data, ctx) => {
49
+ ctx.addIssue({
50
+ code: "custom",
51
+ message: `custom error`,
52
+ });
53
+ return data;
54
+ }, z.string()).parse(1234);
55
+ } catch (err) {
56
+ z.ZodError.assert(err);
57
+ expect(err.issues.length).toEqual(2);
58
+ }
59
+ });
60
+
61
+ test("preprocess ctx.addIssue fatal true", () => {
62
+ try {
63
+ z.preprocess((data, ctx) => {
64
+ ctx.addIssue({
65
+ code: "custom",
66
+ message: `custom error`,
67
+ fatal: true,
68
+ });
69
+ return data;
70
+ }, z.string()).parse(1234);
71
+ } catch (err) {
72
+ z.ZodError.assert(err);
73
+ expect(err.issues.length).toEqual(1);
74
+ }
75
+ });
76
+
77
+ test("async preprocess ctx.addIssue with parse", async () => {
78
+ const schema = z.preprocess(async (data, ctx) => {
79
+ ctx.addIssue({
80
+ code: "custom",
81
+ message: `custom error`,
82
+ });
83
+ return data;
84
+ }, z.string());
85
+
86
+ expect(await schema.safeParseAsync("asdf")).toMatchInlineSnapshot(`
87
+ {
88
+ "error": [ZodError: [
89
+ {
90
+ "code": "custom",
91
+ "message": "custom error",
92
+ "path": []
93
+ }
94
+ ]],
95
+ "success": false,
96
+ }
97
+ `);
98
+ });
99
+
100
+ test("preprocess ctx.addIssue with parseAsync", async () => {
101
+ const result = await z
102
+ .preprocess(async (data, ctx) => {
103
+ ctx.addIssue({
104
+ code: "custom",
105
+ message: `${data} is not one of our allowed strings`,
106
+ });
107
+ return data;
108
+ }, z.string())
109
+ .safeParseAsync("asdf");
110
+
111
+ expect(JSON.parse(JSON.stringify(result))).toEqual({
112
+ success: false,
113
+ error: {
114
+ issues: [
115
+ {
116
+ code: "custom",
117
+ message: "asdf is not one of our allowed strings",
118
+ path: [],
119
+ },
120
+ ],
121
+ name: "ZodError",
122
+ },
123
+ });
124
+ });
125
+
126
+ test("z.NEVER in preprocess", () => {
127
+ const foo = z.preprocess((val, ctx) => {
128
+ if (!val) {
129
+ ctx.addIssue({ code: z.ZodIssueCode.custom, message: "bad" });
130
+ return z.NEVER;
131
+ }
132
+ return val;
133
+ }, z.number());
134
+
135
+ type foo = z.infer<typeof foo>;
136
+ util.assertEqual<foo, number>(true);
137
+ const arg = foo.safeParse(undefined);
138
+ expect(arg.error!.issues).toHaveLength(2);
139
+ expect(arg.error!.issues[0].message).toEqual("bad");
140
+ });
141
+ test("preprocess as the second property of object", () => {
142
+ const schema = z.object({
143
+ nonEmptyStr: z.string().min(1),
144
+ positiveNum: z.preprocess((v) => Number(v), z.number().positive()),
145
+ });
146
+ const result = schema.safeParse({
147
+ nonEmptyStr: "",
148
+ positiveNum: "",
149
+ });
150
+ expect(result.success).toEqual(false);
151
+ if (!result.success) {
152
+ expect(result.error.issues.length).toEqual(2);
153
+ expect(result.error.issues[0].code).toEqual(z.ZodIssueCode.too_small);
154
+ expect(result.error.issues[1].code).toEqual(z.ZodIssueCode.too_small);
155
+ }
156
+ });
157
+
158
+ test("preprocess validates with sibling errors", () => {
159
+ expect(() => {
160
+ z.object({
161
+ // Must be first
162
+ missing: z.string().refine(() => false),
163
+ preprocess: z.preprocess((data: any) => data?.trim(), z.string().regex(/ asdf/)),
164
+ }).parse({ preprocess: " asdf" });
165
+ }).toThrow(
166
+ JSON.stringify(
167
+ [
168
+ {
169
+ code: "invalid_type",
170
+ expected: "string",
171
+ received: "undefined",
172
+ path: ["missing"],
173
+ message: "Required",
174
+ },
175
+ {
176
+ validation: "regex",
177
+ code: "invalid_string",
178
+ message: "Invalid",
179
+ path: ["preprocess"],
180
+ },
181
+ ],
182
+ null,
183
+ 2
184
+ )
185
+ );
186
+ });