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,551 @@
1
+ // @ts-ignore TS6133
2
+ import { expect, test } from "vitest";
3
+
4
+ import * as z from "zod/v3";
5
+ import { ZodError, ZodIssueCode } from "../ZodError.js";
6
+ import { ZodParsedType } from "../helpers/util.js";
7
+
8
+ test("error creation", () => {
9
+ const err1 = ZodError.create([]);
10
+ err1.addIssue({
11
+ code: ZodIssueCode.invalid_type,
12
+ expected: ZodParsedType.object,
13
+ received: ZodParsedType.string,
14
+ path: [],
15
+ message: "",
16
+ fatal: true,
17
+ });
18
+ err1.isEmpty;
19
+
20
+ const err2 = ZodError.create(err1.issues);
21
+ const err3 = new ZodError([]);
22
+ err3.addIssues(err1.issues);
23
+ err3.addIssue(err1.issues[0]);
24
+ err1.message;
25
+ err2.message;
26
+ err3.message;
27
+ });
28
+
29
+ const errorMap: z.ZodErrorMap = (error, ctx) => {
30
+ if (error.code === ZodIssueCode.invalid_type) {
31
+ if (error.expected === "string") {
32
+ return { message: "bad type!" };
33
+ }
34
+ }
35
+ if (error.code === ZodIssueCode.custom) {
36
+ return { message: `less-than-${error.params?.minimum}` };
37
+ }
38
+ return { message: ctx.defaultError };
39
+ };
40
+
41
+ test("type error with custom error map", () => {
42
+ try {
43
+ z.string().parse(234, { errorMap });
44
+ } catch (err) {
45
+ const zerr: z.ZodError = err as any;
46
+
47
+ expect(zerr.issues[0].code).toEqual(z.ZodIssueCode.invalid_type);
48
+ expect(zerr.issues[0].message).toEqual(`bad type!`);
49
+ }
50
+ });
51
+
52
+ test("refinement fail with params", () => {
53
+ try {
54
+ z.number()
55
+ .refine((val) => val >= 3, {
56
+ params: { minimum: 3 },
57
+ })
58
+ .parse(2, { errorMap });
59
+ } catch (err) {
60
+ const zerr: z.ZodError = err as any;
61
+ expect(zerr.issues[0].code).toEqual(z.ZodIssueCode.custom);
62
+ expect(zerr.issues[0].message).toEqual(`less-than-3`);
63
+ }
64
+ });
65
+
66
+ test("custom error with custom errormap", () => {
67
+ try {
68
+ z.string()
69
+ .refine((val) => val.length > 12, {
70
+ params: { minimum: 13 },
71
+ message: "override",
72
+ })
73
+ .parse("asdf", { errorMap });
74
+ } catch (err) {
75
+ const zerr: z.ZodError = err as any;
76
+ expect(zerr.issues[0].message).toEqual("override");
77
+ }
78
+ });
79
+
80
+ test("default error message", () => {
81
+ try {
82
+ z.number()
83
+ .refine((x) => x > 3)
84
+ .parse(2);
85
+ } catch (err) {
86
+ const zerr: z.ZodError = err as any;
87
+ expect(zerr.issues.length).toEqual(1);
88
+ expect(zerr.issues[0].message).toEqual("Invalid input");
89
+ }
90
+ });
91
+
92
+ test("override error in refine", () => {
93
+ try {
94
+ z.number()
95
+ .refine((x) => x > 3, "override")
96
+ .parse(2);
97
+ } catch (err) {
98
+ const zerr: z.ZodError = err as any;
99
+ expect(zerr.issues.length).toEqual(1);
100
+ expect(zerr.issues[0].message).toEqual("override");
101
+ }
102
+ });
103
+
104
+ test("override error in refinement", () => {
105
+ try {
106
+ z.number()
107
+ .refine((x) => x > 3, {
108
+ message: "override",
109
+ })
110
+ .parse(2);
111
+ } catch (err) {
112
+ const zerr: z.ZodError = err as any;
113
+ expect(zerr.issues.length).toEqual(1);
114
+ expect(zerr.issues[0].message).toEqual("override");
115
+ }
116
+ });
117
+
118
+ test("array minimum", () => {
119
+ try {
120
+ z.array(z.string()).min(3, "tooshort").parse(["asdf", "qwer"]);
121
+ } catch (err) {
122
+ const zerr: ZodError = err as any;
123
+ expect(zerr.issues[0].code).toEqual(ZodIssueCode.too_small);
124
+ expect(zerr.issues[0].message).toEqual("tooshort");
125
+ }
126
+ try {
127
+ z.array(z.string()).min(3).parse(["asdf", "qwer"]);
128
+ } catch (err) {
129
+ const zerr: ZodError = err as any;
130
+ expect(zerr.issues[0].code).toEqual(ZodIssueCode.too_small);
131
+ expect(zerr.issues[0].message).toEqual(`Array must contain at least 3 element(s)`);
132
+ }
133
+ });
134
+
135
+ // implement test for semi-smart union logic that checks for type error on either left or right
136
+ // test("union smart errors", () => {
137
+ // // expect.assertions(2);
138
+
139
+ // const p1 = z
140
+ // .union([z.string(), z.number().refine((x) => x > 0)])
141
+ // .safeParse(-3.2);
142
+
143
+ // if (p1.success === true) throw new Error();
144
+ // expect(p1.success).toBe(false);
145
+ // expect(p1.error.issues[0].code).toEqual(ZodIssueCode.custom);
146
+
147
+ // const p2 = z.union([z.string(), z.number()]).safeParse(false);
148
+ // // .catch(err => expect(err.issues[0].code).toEqual(ZodIssueCode.invalid_union));
149
+ // if (p2.success === true) throw new Error();
150
+ // expect(p2.success).toBe(false);
151
+ // expect(p2.error.issues[0].code).toEqual(ZodIssueCode.invalid_union);
152
+ // });
153
+
154
+ test("custom path in custom error map", () => {
155
+ const schema = z.object({
156
+ items: z.array(z.string()).refine((data) => data.length > 3, {
157
+ path: ["items-too-few"],
158
+ }),
159
+ });
160
+
161
+ const errorMap: z.ZodErrorMap = (error) => {
162
+ expect(error.path.length).toBe(2);
163
+ return { message: "doesnt matter" };
164
+ };
165
+ const result = schema.safeParse({ items: ["first"] }, { errorMap });
166
+ expect(result.success).toEqual(false);
167
+ if (!result.success) {
168
+ expect(result.error.issues[0].path).toEqual(["items", "items-too-few"]);
169
+ }
170
+ });
171
+
172
+ test("error metadata from value", () => {
173
+ const dynamicRefine = z.string().refine(
174
+ (val) => val === val.toUpperCase(),
175
+ (val) => ({ params: { val } })
176
+ );
177
+
178
+ const result = dynamicRefine.safeParse("asdf");
179
+ expect(result.success).toEqual(false);
180
+ if (!result.success) {
181
+ const sub = result.error.issues[0];
182
+ expect(result.error.issues[0].code).toEqual("custom");
183
+ if (sub.code === "custom") {
184
+ expect(sub.params!.val).toEqual("asdf");
185
+ }
186
+ }
187
+ });
188
+
189
+ // test("don't call refine after validation failed", () => {
190
+ // const asdf = z
191
+ // .union([
192
+ // z.number(),
193
+ // z.string().transform(z.number(), (val) => {
194
+ // return parseFloat(val);
195
+ // }),
196
+ // ])
197
+ // .refine((v) => v >= 1);
198
+
199
+ // expect(() => asdf.safeParse("foo")).not.toThrow();
200
+ // });
201
+
202
+ test("root level formatting", () => {
203
+ const schema = z.string().email();
204
+ const result = schema.safeParse("asdfsdf");
205
+ expect(result.success).toEqual(false);
206
+ if (!result.success) {
207
+ expect(result.error.format()._errors).toEqual(["Invalid email"]);
208
+ }
209
+ });
210
+
211
+ test("custom path", () => {
212
+ const schema = z
213
+ .object({
214
+ password: z.string(),
215
+ confirm: z.string(),
216
+ })
217
+ .refine((val) => val.confirm === val.password, { path: ["confirm"] });
218
+
219
+ const result = schema.safeParse({
220
+ password: "peanuts",
221
+ confirm: "qeanuts",
222
+ });
223
+
224
+ expect(result.success).toEqual(false);
225
+ if (!result.success) {
226
+ // nested errors
227
+ const error = result.error.format();
228
+ expect(error._errors).toEqual([]);
229
+ expect(error.password?._errors).toEqual(undefined);
230
+ expect(error.confirm?._errors).toEqual(["Invalid input"]);
231
+ }
232
+ });
233
+
234
+ test("custom path", () => {
235
+ const schema = z
236
+ .object({
237
+ password: z.string().min(6),
238
+ confirm: z.string().min(6),
239
+ })
240
+ .refine((val) => val.confirm === val.password);
241
+
242
+ const result = schema.safeParse({
243
+ password: "qwer",
244
+ confirm: "asdf",
245
+ });
246
+
247
+ expect(result.success).toEqual(false);
248
+ if (!result.success) {
249
+ expect(result.error.issues.length).toEqual(3);
250
+ }
251
+ });
252
+
253
+ const schema = z.object({
254
+ inner: z.object({
255
+ name: z
256
+ .string()
257
+ .refine((val) => val.length > 5)
258
+ .array()
259
+ .refine((val) => val.length <= 1),
260
+ }),
261
+ });
262
+
263
+ test("no abort early on refinements", () => {
264
+ const invalidItem = {
265
+ inner: { name: ["aasd", "asdfasdfasfd"] },
266
+ };
267
+
268
+ const result1 = schema.safeParse(invalidItem);
269
+ expect(result1.success).toEqual(false);
270
+ if (!result1.success) {
271
+ expect(result1.error.issues.length).toEqual(2);
272
+ }
273
+ });
274
+ test("formatting", () => {
275
+ const invalidItem = {
276
+ inner: { name: ["aasd", "asdfasdfasfd"] },
277
+ };
278
+ const invalidArray = {
279
+ inner: { name: ["asdfasdf", "asdfasdfasfd"] },
280
+ };
281
+ const result1 = schema.safeParse(invalidItem);
282
+ const result2 = schema.safeParse(invalidArray);
283
+
284
+ expect(result1.success).toEqual(false);
285
+ expect(result2.success).toEqual(false);
286
+ if (!result1.success) {
287
+ const error = result1.error.format();
288
+
289
+ expect(error._errors).toEqual([]);
290
+ expect(error.inner?._errors).toEqual([]);
291
+ // expect(error.inner?.name?._errors).toEqual(["Invalid input"]);
292
+ // expect(error.inner?.name?.[0]._errors).toEqual(["Invalid input"]);
293
+ expect(error.inner?.name?.[1]).toEqual(undefined);
294
+ }
295
+ if (!result2.success) {
296
+ type FormattedError = z.inferFormattedError<typeof schema>;
297
+ const error: FormattedError = result2.error.format();
298
+ expect(error._errors).toEqual([]);
299
+ expect(error.inner?._errors).toEqual([]);
300
+ expect(error.inner?.name?._errors).toEqual(["Invalid input"]);
301
+ expect(error.inner?.name?.[0]).toEqual(undefined);
302
+ expect(error.inner?.name?.[1]).toEqual(undefined);
303
+ expect(error.inner?.name?.[2]).toEqual(undefined);
304
+ }
305
+
306
+ // test custom mapper
307
+ if (!result2.success) {
308
+ type FormattedError = z.inferFormattedError<typeof schema, number>;
309
+ const error: FormattedError = result2.error.format(() => 5);
310
+ expect(error._errors).toEqual([]);
311
+ expect(error.inner?._errors).toEqual([]);
312
+ expect(error.inner?.name?._errors).toEqual([5]);
313
+ }
314
+ });
315
+
316
+ test("formatting with nullable and optional fields", () => {
317
+ const nameSchema = z.string().refine((val) => val.length > 5);
318
+ const schema = z.object({
319
+ nullableObject: z.object({ name: nameSchema }).nullable(),
320
+ nullableArray: z.array(nameSchema).nullable(),
321
+ nullableTuple: z.tuple([nameSchema, nameSchema, z.number()]).nullable(),
322
+ optionalObject: z.object({ name: nameSchema }).optional(),
323
+ optionalArray: z.array(nameSchema).optional(),
324
+ optionalTuple: z.tuple([nameSchema, nameSchema, z.number()]).optional(),
325
+ });
326
+ const invalidItem = {
327
+ nullableObject: { name: "abcd" },
328
+ nullableArray: ["abcd"],
329
+ nullableTuple: ["abcd", "abcd", 1],
330
+ optionalObject: { name: "abcd" },
331
+ optionalArray: ["abcd"],
332
+ optionalTuple: ["abcd", "abcd", 1],
333
+ };
334
+ const result = schema.safeParse(invalidItem);
335
+ expect(result.success).toEqual(false);
336
+ if (!result.success) {
337
+ type FormattedError = z.inferFormattedError<typeof schema>;
338
+ const error: FormattedError = result.error.format();
339
+ expect(error._errors).toEqual([]);
340
+ expect(error.nullableObject?._errors).toEqual([]);
341
+ expect(error.nullableObject?.name?._errors).toEqual(["Invalid input"]);
342
+ expect(error.nullableArray?._errors).toEqual([]);
343
+ expect(error.nullableArray?.[0]?._errors).toEqual(["Invalid input"]);
344
+ expect(error.nullableTuple?._errors).toEqual([]);
345
+ expect(error.nullableTuple?.[0]?._errors).toEqual(["Invalid input"]);
346
+ expect(error.nullableTuple?.[1]?._errors).toEqual(["Invalid input"]);
347
+ expect(error.optionalObject?._errors).toEqual([]);
348
+ expect(error.optionalObject?.name?._errors).toEqual(["Invalid input"]);
349
+ expect(error.optionalArray?._errors).toEqual([]);
350
+ expect(error.optionalArray?.[0]?._errors).toEqual(["Invalid input"]);
351
+ expect(error.optionalTuple?._errors).toEqual([]);
352
+ expect(error.optionalTuple?.[0]?._errors).toEqual(["Invalid input"]);
353
+ expect(error.optionalTuple?.[1]?._errors).toEqual(["Invalid input"]);
354
+ }
355
+ });
356
+
357
+ const stringWithCustomError = z.string({
358
+ errorMap: (issue, ctx) => ({
359
+ message: issue.code === "invalid_type" ? (ctx.data ? "Invalid name" : "Name is required") : ctx.defaultError,
360
+ }),
361
+ });
362
+
363
+ test("schema-bound error map", () => {
364
+ const result = stringWithCustomError.safeParse(1234);
365
+ expect(result.success).toEqual(false);
366
+ if (!result.success) {
367
+ expect(result.error.issues[0].message).toEqual("Invalid name");
368
+ }
369
+
370
+ const result2 = stringWithCustomError.safeParse(undefined);
371
+ expect(result2.success).toEqual(false);
372
+ if (!result2.success) {
373
+ expect(result2.error.issues[0].message).toEqual("Name is required");
374
+ }
375
+
376
+ // support contextual override
377
+ const result3 = stringWithCustomError.safeParse(undefined, {
378
+ errorMap: () => ({ message: "OVERRIDE" }),
379
+ });
380
+ expect(result3.success).toEqual(false);
381
+ if (!result3.success) {
382
+ expect(result3.error.issues[0].message).toEqual("OVERRIDE");
383
+ }
384
+ });
385
+
386
+ test("overrideErrorMap", () => {
387
+ // support overrideErrorMap
388
+ z.setErrorMap(() => ({ message: "OVERRIDE" }));
389
+ const result4 = stringWithCustomError.min(10).safeParse("tooshort");
390
+ expect(result4.success).toEqual(false);
391
+ if (!result4.success) {
392
+ expect(result4.error.issues[0].message).toEqual("OVERRIDE");
393
+ }
394
+ z.setErrorMap(z.defaultErrorMap);
395
+ });
396
+
397
+ test("invalid and required", () => {
398
+ const str = z.string({
399
+ invalid_type_error: "Invalid name",
400
+ required_error: "Name is required",
401
+ });
402
+ const result1 = str.safeParse(1234);
403
+ expect(result1.success).toEqual(false);
404
+ if (!result1.success) {
405
+ expect(result1.error.issues[0].message).toEqual("Invalid name");
406
+ }
407
+ const result2 = str.safeParse(undefined);
408
+ expect(result2.success).toEqual(false);
409
+ if (!result2.success) {
410
+ expect(result2.error.issues[0].message).toEqual("Name is required");
411
+ }
412
+ });
413
+
414
+ test("Fallback to default required error", () => {
415
+ const str = z.string({
416
+ invalid_type_error: "Invalid name",
417
+ // required_error: "Name is required",
418
+ });
419
+
420
+ const result2 = str.safeParse(undefined);
421
+ expect(result2.success).toEqual(false);
422
+ if (!result2.success) {
423
+ expect(result2.error.issues[0].message).toEqual("Required");
424
+ }
425
+ });
426
+
427
+ test("invalid and required and errorMap", () => {
428
+ expect(() => {
429
+ return z.string({
430
+ invalid_type_error: "Invalid name",
431
+ required_error: "Name is required",
432
+ errorMap: () => ({ message: "OVERRIDE" }),
433
+ });
434
+ }).toThrow();
435
+ });
436
+
437
+ test("strict error message", () => {
438
+ const errorMsg = "Invalid object";
439
+ const obj = z.object({ x: z.string() }).strict(errorMsg);
440
+ const result = obj.safeParse({ x: "a", y: "b" });
441
+ expect(result.success).toEqual(false);
442
+ if (!result.success) {
443
+ expect(result.error.issues[0].message).toEqual(errorMsg);
444
+ }
445
+ });
446
+
447
+ test("enum error message, invalid enum elementstring", () => {
448
+ try {
449
+ z.enum(["Tuna", "Trout"]).parse("Salmon");
450
+ } catch (err) {
451
+ const zerr: z.ZodError = err as any;
452
+ expect(zerr.issues.length).toEqual(1);
453
+ expect(zerr.issues[0].message).toEqual("Invalid enum value. Expected 'Tuna' | 'Trout', received 'Salmon'");
454
+ }
455
+ });
456
+
457
+ test("enum error message, invalid type", () => {
458
+ try {
459
+ z.enum(["Tuna", "Trout"]).parse(12);
460
+ } catch (err) {
461
+ const zerr: z.ZodError = err as any;
462
+ expect(zerr.issues.length).toEqual(1);
463
+ expect(zerr.issues[0].message).toEqual("Expected 'Tuna' | 'Trout', received number");
464
+ }
465
+ });
466
+
467
+ test("nativeEnum default error message", () => {
468
+ enum Fish {
469
+ Tuna = "Tuna",
470
+ Trout = "Trout",
471
+ }
472
+ try {
473
+ z.nativeEnum(Fish).parse("Salmon");
474
+ } catch (err) {
475
+ const zerr: z.ZodError = err as any;
476
+ expect(zerr.issues.length).toEqual(1);
477
+ expect(zerr.issues[0].message).toEqual("Invalid enum value. Expected 'Tuna' | 'Trout', received 'Salmon'");
478
+ }
479
+ });
480
+
481
+ test("literal default error message", () => {
482
+ try {
483
+ z.literal("Tuna").parse("Trout");
484
+ } catch (err) {
485
+ const zerr: z.ZodError = err as any;
486
+ expect(zerr.issues.length).toEqual(1);
487
+ expect(zerr.issues[0].message).toEqual(`Invalid literal value, expected "Tuna"`);
488
+ }
489
+ });
490
+
491
+ test("literal bigint default error message", () => {
492
+ try {
493
+ z.literal(BigInt(12)).parse(BigInt(13));
494
+ } catch (err) {
495
+ const zerr: z.ZodError = err as any;
496
+ expect(zerr.issues.length).toEqual(1);
497
+ expect(zerr.issues[0].message).toEqual(`Invalid literal value, expected "12"`);
498
+ }
499
+ });
500
+
501
+ test("enum with message returns the custom error message", () => {
502
+ const schema = z.enum(["apple", "banana"], {
503
+ message: "the value provided is invalid",
504
+ });
505
+
506
+ const result1 = schema.safeParse("berries");
507
+ expect(result1.success).toEqual(false);
508
+ if (!result1.success) {
509
+ expect(result1.error.issues[0].message).toEqual("the value provided is invalid");
510
+ }
511
+
512
+ const result2 = schema.safeParse(undefined);
513
+ expect(result2.success).toEqual(false);
514
+ if (!result2.success) {
515
+ expect(result2.error.issues[0].message).toEqual("the value provided is invalid");
516
+ }
517
+
518
+ const result3 = schema.safeParse("banana");
519
+ expect(result3.success).toEqual(true);
520
+
521
+ const result4 = schema.safeParse(null);
522
+ expect(result4.success).toEqual(false);
523
+ if (!result4.success) {
524
+ expect(result4.error.issues[0].message).toEqual("the value provided is invalid");
525
+ }
526
+ });
527
+
528
+ test("when the message is falsy, it is used as is provided", () => {
529
+ const schema = z.string().max(1, { message: "" });
530
+ const result = schema.safeParse("asdf");
531
+ expect(result.success).toEqual(false);
532
+ if (!result.success) {
533
+ expect(result.error.issues[0].message).toEqual("");
534
+ }
535
+ });
536
+
537
+ // test("dont short circuit on continuable errors", () => {
538
+ // const user = z
539
+ // .object({
540
+ // password: z.string().min(6),
541
+ // confirm: z.string(),
542
+ // })
543
+ // .refine((data) => data.password === data.confirm, {
544
+ // message: "Passwords don't match",
545
+ // path: ["confirm"],
546
+ // });
547
+ // const result = user.safeParse({ password: "asdf", confirm: "qwer" });
548
+ // if (!result.success) {
549
+ // expect(result.error.issues.length).toEqual(2);
550
+ // }
551
+ // });
@@ -0,0 +1,87 @@
1
+ // @ts-ignore TS6133
2
+ import { test } from "vitest";
3
+
4
+ import * as z from "zod/v3";
5
+ import { util } from "../helpers/util.js";
6
+
7
+ test("first party switch", () => {
8
+ const myType = z.string() as z.ZodFirstPartySchemaTypes;
9
+ const def = myType._def;
10
+
11
+ switch (def.typeName) {
12
+ case z.ZodFirstPartyTypeKind.ZodString:
13
+ break;
14
+ case z.ZodFirstPartyTypeKind.ZodNumber:
15
+ break;
16
+ case z.ZodFirstPartyTypeKind.ZodNaN:
17
+ break;
18
+ case z.ZodFirstPartyTypeKind.ZodBigInt:
19
+ break;
20
+ case z.ZodFirstPartyTypeKind.ZodBoolean:
21
+ break;
22
+ case z.ZodFirstPartyTypeKind.ZodDate:
23
+ break;
24
+ case z.ZodFirstPartyTypeKind.ZodUndefined:
25
+ break;
26
+ case z.ZodFirstPartyTypeKind.ZodNull:
27
+ break;
28
+ case z.ZodFirstPartyTypeKind.ZodAny:
29
+ break;
30
+ case z.ZodFirstPartyTypeKind.ZodUnknown:
31
+ break;
32
+ case z.ZodFirstPartyTypeKind.ZodNever:
33
+ break;
34
+ case z.ZodFirstPartyTypeKind.ZodVoid:
35
+ break;
36
+ case z.ZodFirstPartyTypeKind.ZodArray:
37
+ break;
38
+ case z.ZodFirstPartyTypeKind.ZodObject:
39
+ break;
40
+ case z.ZodFirstPartyTypeKind.ZodUnion:
41
+ break;
42
+ case z.ZodFirstPartyTypeKind.ZodDiscriminatedUnion:
43
+ break;
44
+ case z.ZodFirstPartyTypeKind.ZodIntersection:
45
+ break;
46
+ case z.ZodFirstPartyTypeKind.ZodTuple:
47
+ break;
48
+ case z.ZodFirstPartyTypeKind.ZodRecord:
49
+ break;
50
+ case z.ZodFirstPartyTypeKind.ZodMap:
51
+ break;
52
+ case z.ZodFirstPartyTypeKind.ZodSet:
53
+ break;
54
+ case z.ZodFirstPartyTypeKind.ZodFunction:
55
+ break;
56
+ case z.ZodFirstPartyTypeKind.ZodLazy:
57
+ break;
58
+ case z.ZodFirstPartyTypeKind.ZodLiteral:
59
+ break;
60
+ case z.ZodFirstPartyTypeKind.ZodEnum:
61
+ break;
62
+ case z.ZodFirstPartyTypeKind.ZodEffects:
63
+ break;
64
+ case z.ZodFirstPartyTypeKind.ZodNativeEnum:
65
+ break;
66
+ case z.ZodFirstPartyTypeKind.ZodOptional:
67
+ break;
68
+ case z.ZodFirstPartyTypeKind.ZodNullable:
69
+ break;
70
+ case z.ZodFirstPartyTypeKind.ZodDefault:
71
+ break;
72
+ case z.ZodFirstPartyTypeKind.ZodCatch:
73
+ break;
74
+ case z.ZodFirstPartyTypeKind.ZodPromise:
75
+ break;
76
+ case z.ZodFirstPartyTypeKind.ZodBranded:
77
+ break;
78
+ case z.ZodFirstPartyTypeKind.ZodPipeline:
79
+ break;
80
+ case z.ZodFirstPartyTypeKind.ZodSymbol:
81
+ break;
82
+ case z.ZodFirstPartyTypeKind.ZodReadonly:
83
+ break;
84
+ default:
85
+ util.assertNever(def);
86
+ }
87
+ });
@@ -0,0 +1,21 @@
1
+ // @ts-ignore TS6133
2
+ import { test } from "vitest";
3
+
4
+ import type { ZodFirstPartySchemaTypes, ZodFirstPartyTypeKind } from "zod/v3";
5
+ import { util } from "../helpers/util.js";
6
+
7
+ test("Identify missing [ZodFirstPartySchemaTypes]", () => {
8
+ type ZodFirstPartySchemaForType<T extends ZodFirstPartyTypeKind> = ZodFirstPartySchemaTypes extends infer Schema
9
+ ? Schema extends { _def: { typeName: T } }
10
+ ? Schema
11
+ : never
12
+ : never;
13
+ type ZodMappedTypes = {
14
+ [key in ZodFirstPartyTypeKind]: ZodFirstPartySchemaForType<key>;
15
+ };
16
+ type ZodFirstPartySchemaTypesMissingFromUnion = keyof {
17
+ [key in keyof ZodMappedTypes as ZodMappedTypes[key] extends { _def: never } ? key : never]: unknown;
18
+ };
19
+
20
+ util.assertEqual<ZodFirstPartySchemaTypesMissingFromUnion, never>(true);
21
+ });