zod 3.26.0-canary.20250703T011142 → 3.26.0-canary.20250703T025502

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 (269) hide show
  1. package/package.json +4 -4
  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/es.ts +125 -0
  191. package/src/v4/locales/fa.ts +134 -0
  192. package/src/v4/locales/fi.ts +131 -0
  193. package/src/v4/locales/fr-CA.ts +126 -0
  194. package/src/v4/locales/fr.ts +124 -0
  195. package/src/v4/locales/he.ts +125 -0
  196. package/src/v4/locales/hu.ts +126 -0
  197. package/src/v4/locales/id.ts +125 -0
  198. package/src/v4/locales/index.ts +38 -0
  199. package/src/v4/locales/it.ts +125 -0
  200. package/src/v4/locales/ja.ts +122 -0
  201. package/src/v4/locales/kh.ts +126 -0
  202. package/src/v4/locales/ko.ts +131 -0
  203. package/src/v4/locales/mk.ts +127 -0
  204. package/src/v4/locales/ms.ts +124 -0
  205. package/src/v4/locales/nl.ts +126 -0
  206. package/src/v4/locales/no.ts +124 -0
  207. package/src/v4/locales/ota.ts +125 -0
  208. package/src/v4/locales/pl.ts +126 -0
  209. package/src/v4/locales/ps.ts +133 -0
  210. package/src/v4/locales/pt.ts +123 -0
  211. package/src/v4/locales/ru.ts +184 -0
  212. package/src/v4/locales/sl.ts +126 -0
  213. package/src/v4/locales/sv.ts +127 -0
  214. package/src/v4/locales/ta.ts +125 -0
  215. package/src/v4/locales/th.ts +126 -0
  216. package/src/v4/locales/tr.ts +121 -0
  217. package/src/v4/locales/ua.ts +126 -0
  218. package/src/v4/locales/ur.ts +126 -0
  219. package/src/v4/locales/vi.ts +125 -0
  220. package/src/v4/locales/zh-CN.ts +123 -0
  221. package/src/v4/locales/zh-TW.ts +125 -0
  222. package/src/v4/mini/checks.ts +32 -0
  223. package/src/v4/mini/coerce.ts +22 -0
  224. package/src/v4/mini/external.ts +40 -0
  225. package/src/v4/mini/index.ts +3 -0
  226. package/src/v4/mini/iso.ts +62 -0
  227. package/src/v4/mini/parse.ts +1 -0
  228. package/src/v4/mini/schemas.ts +1579 -0
  229. package/src/v4/mini/tests/assignability.test.ts +129 -0
  230. package/src/v4/mini/tests/brand.test.ts +51 -0
  231. package/src/v4/mini/tests/checks.test.ts +144 -0
  232. package/src/v4/mini/tests/computed.test.ts +36 -0
  233. package/src/v4/mini/tests/error.test.ts +22 -0
  234. package/src/v4/mini/tests/functions.test.ts +43 -0
  235. package/src/v4/mini/tests/index.test.ts +871 -0
  236. package/src/v4/mini/tests/number.test.ts +95 -0
  237. package/src/v4/mini/tests/object.test.ts +185 -0
  238. package/src/v4/mini/tests/prototypes.test.ts +43 -0
  239. package/src/v4/mini/tests/recursive-types.test.ts +275 -0
  240. package/src/v4/mini/tests/string.test.ts +293 -0
  241. package/src/v4-mini/index.ts +1 -0
  242. package/v4/classic/compat.cjs +1 -7
  243. package/v4/classic/compat.d.cts +0 -2
  244. package/v4/classic/compat.d.ts +0 -2
  245. package/v4/classic/compat.js +0 -6
  246. package/v4/classic/external.cjs +2 -1
  247. package/v4/classic/external.d.cts +1 -1
  248. package/v4/classic/external.d.ts +1 -1
  249. package/v4/classic/external.js +1 -1
  250. package/v4/classic/schemas.d.cts +4 -4
  251. package/v4/classic/schemas.d.ts +4 -4
  252. package/v4/core/api.cjs +11 -10
  253. package/v4/core/api.js +11 -10
  254. package/v4/core/checks.cjs +6 -4
  255. package/v4/core/checks.js +6 -4
  256. package/v4/core/core.cjs +5 -1
  257. package/v4/core/core.d.cts +2 -0
  258. package/v4/core/core.d.ts +2 -0
  259. package/v4/core/core.js +4 -0
  260. package/v4/core/schemas.cjs +12 -13
  261. package/v4/core/schemas.js +12 -13
  262. package/v4/core/util.cjs +3 -0
  263. package/v4/core/util.d.cts +1 -1
  264. package/v4/core/util.d.ts +1 -1
  265. package/v4/core/util.js +3 -0
  266. package/v4/mini/external.cjs +2 -1
  267. package/v4/mini/external.d.cts +1 -1
  268. package/v4/mini/external.d.ts +1 -1
  269. package/v4/mini/external.js +1 -1
@@ -0,0 +1,313 @@
1
+ // @ts-ignore TS6133
2
+ import { expect, test } from "vitest";
3
+
4
+ import * as z from "zod/v3";
5
+ import { ZodIssueCode } from "../ZodError.js";
6
+ import { util } from "../helpers/util.js";
7
+
8
+ test("refinement", () => {
9
+ const obj1 = z.object({
10
+ first: z.string(),
11
+ second: z.string(),
12
+ });
13
+ const obj2 = obj1.partial().strict();
14
+
15
+ const obj3 = obj2.refine((data) => data.first || data.second, "Either first or second should be filled in.");
16
+
17
+ expect(obj1 === (obj2 as any)).toEqual(false);
18
+ expect(obj2 === (obj3 as any)).toEqual(false);
19
+
20
+ expect(() => obj1.parse({})).toThrow();
21
+ expect(() => obj2.parse({ third: "adsf" })).toThrow();
22
+ expect(() => obj3.parse({})).toThrow();
23
+ obj3.parse({ first: "a" });
24
+ obj3.parse({ second: "a" });
25
+ obj3.parse({ first: "a", second: "a" });
26
+ });
27
+
28
+ test("refinement 2", () => {
29
+ const validationSchema = z
30
+ .object({
31
+ email: z.string().email(),
32
+ password: z.string(),
33
+ confirmPassword: z.string(),
34
+ })
35
+ .refine((data) => data.password === data.confirmPassword, "Both password and confirmation must match");
36
+
37
+ expect(() =>
38
+ validationSchema.parse({
39
+ email: "aaaa@gmail.com",
40
+ password: "aaaaaaaa",
41
+ confirmPassword: "bbbbbbbb",
42
+ })
43
+ ).toThrow();
44
+ });
45
+
46
+ test("refinement type guard", () => {
47
+ const validationSchema = z.object({
48
+ a: z.string().refine((s): s is "a" => s === "a"),
49
+ });
50
+ type Input = z.input<typeof validationSchema>;
51
+ type Schema = z.infer<typeof validationSchema>;
52
+
53
+ util.assertEqual<"a", Input["a"]>(false);
54
+ util.assertEqual<string, Input["a"]>(true);
55
+
56
+ util.assertEqual<"a", Schema["a"]>(true);
57
+ util.assertEqual<string, Schema["a"]>(false);
58
+ });
59
+
60
+ test("refinement Promise", async () => {
61
+ const validationSchema = z
62
+ .object({
63
+ email: z.string().email(),
64
+ password: z.string(),
65
+ confirmPassword: z.string(),
66
+ })
67
+ .refine(
68
+ (data) => Promise.resolve().then(() => data.password === data.confirmPassword),
69
+ "Both password and confirmation must match"
70
+ );
71
+
72
+ await validationSchema.parseAsync({
73
+ email: "aaaa@gmail.com",
74
+ password: "password",
75
+ confirmPassword: "password",
76
+ });
77
+ });
78
+
79
+ test("custom path", async () => {
80
+ const result = await z
81
+ .object({
82
+ password: z.string(),
83
+ confirm: z.string(),
84
+ })
85
+ .refine((data) => data.confirm === data.password, { path: ["confirm"] })
86
+ .spa({ password: "asdf", confirm: "qewr" });
87
+ expect(result.success).toEqual(false);
88
+ if (!result.success) {
89
+ expect(result.error.issues[0].path).toEqual(["confirm"]);
90
+ }
91
+ });
92
+
93
+ test("use path in refinement context", async () => {
94
+ const noNested = z.string()._refinement((_val, ctx) => {
95
+ if (ctx.path.length > 0) {
96
+ ctx.addIssue({
97
+ code: ZodIssueCode.custom,
98
+ message: `schema cannot be nested. path: ${ctx.path.join(".")}`,
99
+ });
100
+ return false;
101
+ } else {
102
+ return true;
103
+ }
104
+ });
105
+
106
+ const data = z.object({
107
+ foo: noNested,
108
+ });
109
+
110
+ const t1 = await noNested.spa("asdf");
111
+ const t2 = await data.spa({ foo: "asdf" });
112
+
113
+ expect(t1.success).toBe(true);
114
+ expect(t2.success).toBe(false);
115
+ if (t2.success === false) {
116
+ expect(t2.error.issues[0].message).toEqual("schema cannot be nested. path: foo");
117
+ }
118
+ });
119
+
120
+ test("superRefine", () => {
121
+ const Strings = z.array(z.string()).superRefine((val, ctx) => {
122
+ if (val.length > 3) {
123
+ ctx.addIssue({
124
+ code: z.ZodIssueCode.too_big,
125
+ maximum: 3,
126
+ type: "array",
127
+ inclusive: true,
128
+ exact: true,
129
+ message: "Too many items 😡",
130
+ });
131
+ }
132
+
133
+ if (val.length !== new Set(val).size) {
134
+ ctx.addIssue({
135
+ code: z.ZodIssueCode.custom,
136
+ message: `No duplicates allowed.`,
137
+ });
138
+ }
139
+ });
140
+
141
+ const result = Strings.safeParse(["asfd", "asfd", "asfd", "asfd"]);
142
+
143
+ expect(result.success).toEqual(false);
144
+ if (!result.success) expect(result.error.issues.length).toEqual(2);
145
+
146
+ Strings.parse(["asfd", "qwer"]);
147
+ });
148
+
149
+ test("superRefine async", async () => {
150
+ const Strings = z.array(z.string()).superRefine(async (val, ctx) => {
151
+ if (val.length > 3) {
152
+ ctx.addIssue({
153
+ code: z.ZodIssueCode.too_big,
154
+ maximum: 3,
155
+ type: "array",
156
+ inclusive: true,
157
+ exact: true,
158
+ message: "Too many items 😡",
159
+ });
160
+ }
161
+
162
+ if (val.length !== new Set(val).size) {
163
+ ctx.addIssue({
164
+ code: z.ZodIssueCode.custom,
165
+ message: `No duplicates allowed.`,
166
+ });
167
+ }
168
+ });
169
+
170
+ const result = await Strings.safeParseAsync(["asfd", "asfd", "asfd", "asfd"]);
171
+
172
+ expect(result.success).toEqual(false);
173
+ if (!result.success) expect(result.error.issues.length).toEqual(2);
174
+
175
+ Strings.parseAsync(["asfd", "qwer"]);
176
+ });
177
+
178
+ test("superRefine - type narrowing", () => {
179
+ type NarrowType = { type: string; age: number };
180
+ const schema = z
181
+ .object({
182
+ type: z.string(),
183
+ age: z.number(),
184
+ })
185
+ .nullable()
186
+ .superRefine((arg, ctx): arg is NarrowType => {
187
+ if (!arg) {
188
+ // still need to make a call to ctx.addIssue
189
+ ctx.addIssue({
190
+ code: z.ZodIssueCode.custom,
191
+ message: "cannot be null",
192
+ fatal: true,
193
+ });
194
+ return false;
195
+ }
196
+ return true;
197
+ });
198
+
199
+ util.assertEqual<z.infer<typeof schema>, NarrowType>(true);
200
+
201
+ expect(schema.safeParse({ type: "test", age: 0 }).success).toEqual(true);
202
+ expect(schema.safeParse(null).success).toEqual(false);
203
+ });
204
+
205
+ test("chained mixed refining types", () => {
206
+ type firstRefinement = { first: string; second: number; third: true };
207
+ type secondRefinement = { first: "bob"; second: number; third: true };
208
+ type thirdRefinement = { first: "bob"; second: 33; third: true };
209
+ const schema = z
210
+ .object({
211
+ first: z.string(),
212
+ second: z.number(),
213
+ third: z.boolean(),
214
+ })
215
+ .nullable()
216
+ .refine((arg): arg is firstRefinement => !!arg?.third)
217
+ .superRefine((arg, ctx): arg is secondRefinement => {
218
+ util.assertEqual<typeof arg, firstRefinement>(true);
219
+ if (arg.first !== "bob") {
220
+ ctx.addIssue({
221
+ code: z.ZodIssueCode.custom,
222
+ message: "`first` property must be `bob`",
223
+ });
224
+ return false;
225
+ }
226
+ return true;
227
+ })
228
+ .refine((arg): arg is thirdRefinement => {
229
+ util.assertEqual<typeof arg, secondRefinement>(true);
230
+ return arg.second === 33;
231
+ });
232
+
233
+ util.assertEqual<z.infer<typeof schema>, thirdRefinement>(true);
234
+ });
235
+
236
+ test("get inner type", () => {
237
+ z.string()
238
+ .refine(() => true)
239
+ .innerType()
240
+ .parse("asdf");
241
+ });
242
+
243
+ test("chained refinements", () => {
244
+ const objectSchema = z
245
+ .object({
246
+ length: z.number(),
247
+ size: z.number(),
248
+ })
249
+ .refine(({ length }) => length > 5, {
250
+ path: ["length"],
251
+ message: "length greater than 5",
252
+ })
253
+ .refine(({ size }) => size > 7, {
254
+ path: ["size"],
255
+ message: "size greater than 7",
256
+ });
257
+ const r1 = objectSchema.safeParse({
258
+ length: 4,
259
+ size: 9,
260
+ });
261
+ expect(r1.success).toEqual(false);
262
+ if (!r1.success) expect(r1.error.issues.length).toEqual(1);
263
+
264
+ const r2 = objectSchema.safeParse({
265
+ length: 4,
266
+ size: 3,
267
+ });
268
+ expect(r2.success).toEqual(false);
269
+ if (!r2.success) expect(r2.error.issues.length).toEqual(2);
270
+ });
271
+
272
+ test("fatal superRefine", () => {
273
+ const Strings = z
274
+ .string()
275
+ .superRefine((val, ctx) => {
276
+ if (val === "") {
277
+ ctx.addIssue({
278
+ code: z.ZodIssueCode.custom,
279
+ message: "foo",
280
+ fatal: true,
281
+ });
282
+ }
283
+ })
284
+ .superRefine((val, ctx) => {
285
+ if (val !== " ") {
286
+ ctx.addIssue({
287
+ code: z.ZodIssueCode.custom,
288
+ message: "bar",
289
+ });
290
+ }
291
+ });
292
+
293
+ const result = Strings.safeParse("");
294
+
295
+ expect(result.success).toEqual(false);
296
+ if (!result.success) expect(result.error.issues.length).toEqual(1);
297
+ });
298
+
299
+ test("superRefine after skipped transform", () => {
300
+ const schema = z
301
+ .string()
302
+ .regex(/^\d+$/)
303
+ .transform((val) => Number(val))
304
+ .superRefine((val) => {
305
+ if (typeof val !== "number") {
306
+ throw new Error("Called without transform");
307
+ }
308
+ });
309
+
310
+ const result = schema.safeParse("");
311
+
312
+ expect(result.success).toEqual(false);
313
+ });
@@ -0,0 +1,27 @@
1
+ // @ts-ignore TS6133
2
+ import { expect, test } from "vitest";
3
+
4
+ import * as z from "zod/v3";
5
+ const stringSchema = z.string();
6
+
7
+ test("safeparse fail", () => {
8
+ const safe = stringSchema.safeParse(12);
9
+ expect(safe.success).toEqual(false);
10
+ expect(safe.error).toBeInstanceOf(z.ZodError);
11
+ });
12
+
13
+ test("safeparse pass", () => {
14
+ const safe = stringSchema.safeParse("12");
15
+ expect(safe.success).toEqual(true);
16
+ expect(safe.data).toEqual("12");
17
+ });
18
+
19
+ test("safeparse unexpected error", () => {
20
+ expect(() =>
21
+ stringSchema
22
+ .refine((data) => {
23
+ throw new Error(data);
24
+ })
25
+ .safeParse("12")
26
+ ).toThrow();
27
+ });
@@ -0,0 +1,142 @@
1
+ // @ts-ignore TS6133
2
+ import { expect, test } from "vitest";
3
+
4
+ import * as z from "zod/v3";
5
+ import { ZodIssueCode } from "zod/v3";
6
+ import { util } from "../helpers/util.js";
7
+
8
+ const stringSet = z.set(z.string());
9
+ type stringSet = z.infer<typeof stringSet>;
10
+
11
+ const minTwo = z.set(z.string()).min(2);
12
+ const maxTwo = z.set(z.string()).max(2);
13
+ const justTwo = z.set(z.string()).size(2);
14
+ const nonEmpty = z.set(z.string()).nonempty();
15
+ const nonEmptyMax = z.set(z.string()).nonempty().max(2);
16
+
17
+ test("type inference", () => {
18
+ util.assertEqual<stringSet, Set<string>>(true);
19
+ });
20
+
21
+ test("valid parse", () => {
22
+ const result = stringSet.safeParse(new Set(["first", "second"]));
23
+ expect(result.success).toEqual(true);
24
+ if (result.success) {
25
+ expect(result.data.has("first")).toEqual(true);
26
+ expect(result.data.has("second")).toEqual(true);
27
+ expect(result.data.has("third")).toEqual(false);
28
+ }
29
+
30
+ expect(() => {
31
+ minTwo.parse(new Set(["a", "b"]));
32
+ minTwo.parse(new Set(["a", "b", "c"]));
33
+ maxTwo.parse(new Set(["a", "b"]));
34
+ maxTwo.parse(new Set(["a"]));
35
+ justTwo.parse(new Set(["a", "b"]));
36
+ nonEmpty.parse(new Set(["a"]));
37
+ nonEmptyMax.parse(new Set(["a"]));
38
+ }).not.toThrow();
39
+ });
40
+
41
+ test("valid parse async", async () => {
42
+ const result = await stringSet.spa(new Set(["first", "second"]));
43
+ expect(result.success).toEqual(true);
44
+ if (result.success) {
45
+ expect(result.data.has("first")).toEqual(true);
46
+ expect(result.data.has("second")).toEqual(true);
47
+ expect(result.data.has("third")).toEqual(false);
48
+ }
49
+
50
+ const asyncResult = await stringSet.safeParse(new Set(["first", "second"]));
51
+ expect(asyncResult.success).toEqual(true);
52
+ if (asyncResult.success) {
53
+ expect(asyncResult.data.has("first")).toEqual(true);
54
+ expect(asyncResult.data.has("second")).toEqual(true);
55
+ expect(asyncResult.data.has("third")).toEqual(false);
56
+ }
57
+ });
58
+
59
+ test("valid parse: size-related methods", () => {
60
+ expect(() => {
61
+ minTwo.parse(new Set(["a", "b"]));
62
+ minTwo.parse(new Set(["a", "b", "c"]));
63
+ maxTwo.parse(new Set(["a", "b"]));
64
+ maxTwo.parse(new Set(["a"]));
65
+ justTwo.parse(new Set(["a", "b"]));
66
+ nonEmpty.parse(new Set(["a"]));
67
+ nonEmptyMax.parse(new Set(["a"]));
68
+ }).not.toThrow();
69
+
70
+ const sizeZeroResult = stringSet.parse(new Set());
71
+ expect(sizeZeroResult.size).toBe(0);
72
+
73
+ const sizeTwoResult = minTwo.parse(new Set(["a", "b"]));
74
+ expect(sizeTwoResult.size).toBe(2);
75
+ });
76
+
77
+ test("failing when parsing empty set in nonempty ", () => {
78
+ const result = nonEmpty.safeParse(new Set());
79
+ expect(result.success).toEqual(false);
80
+
81
+ if (result.success === false) {
82
+ expect(result.error.issues.length).toEqual(1);
83
+ expect(result.error.issues[0].code).toEqual(ZodIssueCode.too_small);
84
+ }
85
+ });
86
+
87
+ test("failing when set is smaller than min() ", () => {
88
+ const result = minTwo.safeParse(new Set(["just_one"]));
89
+ expect(result.success).toEqual(false);
90
+
91
+ if (result.success === false) {
92
+ expect(result.error.issues.length).toEqual(1);
93
+ expect(result.error.issues[0].code).toEqual(ZodIssueCode.too_small);
94
+ }
95
+ });
96
+
97
+ test("failing when set is bigger than max() ", () => {
98
+ const result = maxTwo.safeParse(new Set(["one", "two", "three"]));
99
+ expect(result.success).toEqual(false);
100
+
101
+ if (result.success === false) {
102
+ expect(result.error.issues.length).toEqual(1);
103
+ expect(result.error.issues[0].code).toEqual(ZodIssueCode.too_big);
104
+ }
105
+ });
106
+
107
+ test("doesn’t throw when an empty set is given", () => {
108
+ const result = stringSet.safeParse(new Set([]));
109
+ expect(result.success).toEqual(true);
110
+ });
111
+
112
+ test("throws when a Map is given", () => {
113
+ const result = stringSet.safeParse(new Map([]));
114
+ expect(result.success).toEqual(false);
115
+ if (result.success === false) {
116
+ expect(result.error.issues.length).toEqual(1);
117
+ expect(result.error.issues[0].code).toEqual(ZodIssueCode.invalid_type);
118
+ }
119
+ });
120
+
121
+ test("throws when the given set has invalid input", () => {
122
+ const result = stringSet.safeParse(new Set([Symbol()]));
123
+ expect(result.success).toEqual(false);
124
+ if (result.success === false) {
125
+ expect(result.error.issues.length).toEqual(1);
126
+ expect(result.error.issues[0].code).toEqual(ZodIssueCode.invalid_type);
127
+ expect(result.error.issues[0].path).toEqual([0]);
128
+ }
129
+ });
130
+
131
+ test("throws when the given set has multiple invalid entries", () => {
132
+ const result = stringSet.safeParse(new Set([1, 2] as any[]) as Set<any>);
133
+
134
+ expect(result.success).toEqual(false);
135
+ if (result.success === false) {
136
+ expect(result.error.issues.length).toEqual(2);
137
+ expect(result.error.issues[0].code).toEqual(ZodIssueCode.invalid_type);
138
+ expect(result.error.issues[0].path).toEqual([0]);
139
+ expect(result.error.issues[1].code).toEqual(ZodIssueCode.invalid_type);
140
+ expect(result.error.issues[1].path).toEqual([1]);
141
+ }
142
+ });
@@ -0,0 +1,83 @@
1
+ // import type { StandardSchemaV1 } from "@standard-schema/spec";
2
+ // @ts-ignore TS6133
3
+ import { expect, test } from "vitest";
4
+
5
+ import * as z from "zod/v3";
6
+ import { util } from "../helpers/util.js";
7
+ import type { StandardSchemaV1 } from "../standard-schema.js";
8
+
9
+ test("assignability", () => {
10
+ const _s1: StandardSchemaV1 = z.string();
11
+ const _s2: StandardSchemaV1<string> = z.string();
12
+ const _s3: StandardSchemaV1<string, string> = z.string();
13
+ const _s4: StandardSchemaV1<unknown, string> = z.string();
14
+ [_s1, _s2, _s3, _s4];
15
+ });
16
+
17
+ test("type inference", () => {
18
+ const stringToNumber = z.string().transform((x) => x.length);
19
+ type input = StandardSchemaV1.InferInput<typeof stringToNumber>;
20
+ util.assertEqual<input, string>(true);
21
+ type output = StandardSchemaV1.InferOutput<typeof stringToNumber>;
22
+ util.assertEqual<output, number>(true);
23
+ });
24
+
25
+ test("valid parse", () => {
26
+ const schema = z.string();
27
+ const result = schema["~standard"].validate("hello");
28
+ if (result instanceof Promise) {
29
+ throw new Error("Expected sync result");
30
+ }
31
+ expect(result.issues).toEqual(undefined);
32
+ if (result.issues) {
33
+ throw new Error("Expected no issues");
34
+ } else {
35
+ expect(result.value).toEqual("hello");
36
+ }
37
+ });
38
+
39
+ test("invalid parse", () => {
40
+ const schema = z.string();
41
+ const result = schema["~standard"].validate(1234);
42
+ if (result instanceof Promise) {
43
+ throw new Error("Expected sync result");
44
+ }
45
+ expect(result.issues).toBeDefined();
46
+ if (!result.issues) {
47
+ throw new Error("Expected issues");
48
+ }
49
+ expect(result.issues.length).toEqual(1);
50
+ expect(result.issues[0].path).toEqual([]);
51
+ });
52
+
53
+ test("valid parse async", async () => {
54
+ const schema = z.string().refine(async () => true);
55
+ const _result = schema["~standard"].validate("hello");
56
+ if (_result instanceof Promise) {
57
+ const result = await _result;
58
+ expect(result.issues).toEqual(undefined);
59
+ if (result.issues) {
60
+ throw new Error("Expected no issues");
61
+ } else {
62
+ expect(result.value).toEqual("hello");
63
+ }
64
+ } else {
65
+ throw new Error("Expected async result");
66
+ }
67
+ });
68
+
69
+ test("invalid parse async", async () => {
70
+ const schema = z.string().refine(async () => false);
71
+ const _result = schema["~standard"].validate("hello");
72
+ if (_result instanceof Promise) {
73
+ const result = await _result;
74
+ expect(result.issues).toBeDefined();
75
+ if (!result.issues) {
76
+ throw new Error("Expected issues");
77
+ }
78
+ expect(result.issues.length).toEqual(1);
79
+ expect(result.issues[0].path).toEqual([]);
80
+ } else {
81
+ throw new Error("Expected async result");
82
+ }
83
+ });