zod 4.5.4 → 4.6.0

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 (347) hide show
  1. package/compile.cjs +19 -0
  2. package/index.cjs +19 -0
  3. package/locales/index.cjs +19 -0
  4. package/mini/index.cjs +19 -0
  5. package/package.json +8 -7
  6. package/src/v3/helpers/errorUtil.ts +1 -1
  7. package/src/v4/classic/checks.ts +0 -1
  8. package/src/v4/classic/external.ts +2 -0
  9. package/src/v4/classic/from-json-schema.ts +248 -25
  10. package/src/v4/classic/schemas.ts +255 -164
  11. package/src/v4/classic/tests/assignability.test.ts +59 -9
  12. package/src/v4/classic/tests/bigint.test.ts +6 -0
  13. package/src/v4/classic/tests/continuability.test.ts +2 -2
  14. package/src/v4/classic/tests/cyclic-data.test.ts +274 -0
  15. package/src/v4/classic/tests/enum.test.ts +9 -0
  16. package/src/v4/classic/tests/error.test.ts +130 -1
  17. package/src/v4/classic/tests/firstparty.test.ts +4 -0
  18. package/src/v4/classic/tests/from-json-schema.test.ts +157 -0
  19. package/src/v4/classic/tests/iban.test.ts +81 -0
  20. package/src/v4/classic/tests/instance-footprint.test.ts +18 -2
  21. package/src/v4/classic/tests/instanceof.test.ts +27 -7
  22. package/src/v4/classic/tests/issue-schema.test.ts +88 -56
  23. package/src/v4/classic/tests/object.test.ts +56 -0
  24. package/src/v4/classic/tests/optin-ladder.test.ts +3 -2
  25. package/src/v4/classic/tests/properties.test.ts +225 -0
  26. package/src/v4/classic/tests/recursive-types.test.ts +1 -1
  27. package/src/v4/classic/tests/standard-schema.test.ts +19 -0
  28. package/src/v4/classic/tests/string.test.ts +25 -0
  29. package/src/v4/classic/tests/template-literal.test.ts +33 -1
  30. package/src/v4/classic/tests/to-json-schema.test.ts +147 -3
  31. package/src/v4/classic/tests/validate.test.ts +569 -0
  32. package/src/v4/core/api.ts +30 -6
  33. package/src/v4/core/checks.ts +1 -101
  34. package/src/v4/core/compile.ts +193 -81
  35. package/src/v4/core/doc.ts +6 -2
  36. package/src/v4/core/errors.ts +3 -6
  37. package/src/v4/core/json-schema-generator.ts +2 -2
  38. package/src/v4/core/json-schema-processors.ts +226 -68
  39. package/src/v4/core/memoizer.ts +78 -28
  40. package/src/v4/core/parse.ts +37 -16
  41. package/src/v4/core/regexes.ts +10 -4
  42. package/src/v4/core/schemas.ts +314 -83
  43. package/src/v4/core/tests/cached.test.ts +54 -0
  44. package/src/v4/core/tests/compile-generative.test.ts +445 -0
  45. package/src/v4/core/tests/compile.test.ts +222 -2
  46. package/src/v4/core/tests/email-regex.test.ts +140 -0
  47. package/src/v4/core/tests/polyfill-collision.test.ts +46 -0
  48. package/src/v4/core/to-json-schema.ts +10 -8
  49. package/src/v4/core/util.ts +222 -147
  50. package/src/v4/core/versions.ts +2 -2
  51. package/src/v4/core/visit.ts +11 -0
  52. package/src/v4/locales/ar.ts +1 -0
  53. package/src/v4/locales/az.ts +1 -0
  54. package/src/v4/locales/be.ts +1 -0
  55. package/src/v4/locales/bg.ts +1 -0
  56. package/src/v4/locales/bn.ts +1 -0
  57. package/src/v4/locales/ca.ts +1 -0
  58. package/src/v4/locales/ckb.ts +1 -0
  59. package/src/v4/locales/cs.ts +1 -0
  60. package/src/v4/locales/da.ts +1 -0
  61. package/src/v4/locales/de.ts +1 -0
  62. package/src/v4/locales/el.ts +1 -0
  63. package/src/v4/locales/en.ts +1 -0
  64. package/src/v4/locales/eo.ts +1 -0
  65. package/src/v4/locales/es.ts +1 -0
  66. package/src/v4/locales/fa.ts +1 -0
  67. package/src/v4/locales/fi.ts +1 -0
  68. package/src/v4/locales/fr-CA.ts +1 -0
  69. package/src/v4/locales/fr.ts +1 -0
  70. package/src/v4/locales/gu.ts +1 -0
  71. package/src/v4/locales/he.ts +1 -0
  72. package/src/v4/locales/hi.ts +1 -0
  73. package/src/v4/locales/hr.ts +1 -0
  74. package/src/v4/locales/hu.ts +1 -0
  75. package/src/v4/locales/hy.ts +1 -0
  76. package/src/v4/locales/id.ts +1 -0
  77. package/src/v4/locales/is.ts +1 -0
  78. package/src/v4/locales/it.ts +1 -0
  79. package/src/v4/locales/ja.ts +1 -0
  80. package/src/v4/locales/ka.ts +1 -0
  81. package/src/v4/locales/km.ts +1 -0
  82. package/src/v4/locales/kn.ts +1 -0
  83. package/src/v4/locales/ko.ts +1 -0
  84. package/src/v4/locales/lt.ts +1 -0
  85. package/src/v4/locales/mk.ts +1 -0
  86. package/src/v4/locales/ms.ts +1 -0
  87. package/src/v4/locales/ne.ts +1 -0
  88. package/src/v4/locales/nl.ts +1 -0
  89. package/src/v4/locales/nn.ts +1 -0
  90. package/src/v4/locales/no.ts +1 -0
  91. package/src/v4/locales/ota.ts +1 -0
  92. package/src/v4/locales/pl.ts +1 -0
  93. package/src/v4/locales/ps.ts +1 -0
  94. package/src/v4/locales/pt-BR.ts +1 -0
  95. package/src/v4/locales/pt.ts +1 -0
  96. package/src/v4/locales/ro.ts +1 -0
  97. package/src/v4/locales/ru.ts +1 -0
  98. package/src/v4/locales/sk.ts +1 -0
  99. package/src/v4/locales/sl.ts +1 -0
  100. package/src/v4/locales/sv.ts +1 -0
  101. package/src/v4/locales/ta.ts +1 -0
  102. package/src/v4/locales/th.ts +1 -0
  103. package/src/v4/locales/tk.ts +1 -0
  104. package/src/v4/locales/tr.ts +1 -0
  105. package/src/v4/locales/uk.ts +1 -0
  106. package/src/v4/locales/ur.ts +1 -0
  107. package/src/v4/locales/uz.ts +1 -0
  108. package/src/v4/locales/vi.ts +1 -0
  109. package/src/v4/locales/yo.ts +1 -0
  110. package/src/v4/locales/zh-CN.ts +1 -0
  111. package/src/v4/locales/zh-TW.ts +1 -0
  112. package/src/v4/mini/checks.ts +0 -1
  113. package/src/v4/mini/external.ts +2 -0
  114. package/src/v4/mini/schemas.ts +38 -2
  115. package/src/v4/mini/tests/checks.test.ts +1 -1
  116. package/src/v4/mini/tests/computed.test.ts +11 -17
  117. package/src/v4/mini/tests/index.test.ts +8 -0
  118. package/src/v4/mini/tests/string.test.ts +16 -0
  119. package/v3/ZodError.cjs +19 -0
  120. package/v3/errors.cjs +19 -0
  121. package/v3/external.cjs +19 -0
  122. package/v3/helpers/enumUtil.cjs +19 -0
  123. package/v3/helpers/errorUtil.cjs +20 -1
  124. package/v3/helpers/errorUtil.js +1 -1
  125. package/v3/helpers/parseUtil.cjs +19 -0
  126. package/v3/helpers/partialUtil.cjs +19 -0
  127. package/v3/helpers/typeAliases.cjs +19 -0
  128. package/v3/helpers/util.cjs +19 -0
  129. package/v3/index.cjs +19 -0
  130. package/v3/standard-schema.cjs +19 -0
  131. package/v3/types.cjs +19 -0
  132. package/v4/classic/checks.cjs +20 -2
  133. package/v4/classic/checks.d.cts +1 -1
  134. package/v4/classic/checks.d.ts +1 -1
  135. package/v4/classic/checks.js +1 -1
  136. package/v4/classic/coerce.cjs +19 -0
  137. package/v4/classic/compat.cjs +19 -0
  138. package/v4/classic/deep-partial.cjs +19 -0
  139. package/v4/classic/errors.cjs +19 -0
  140. package/v4/classic/external.cjs +22 -1
  141. package/v4/classic/external.d.cts +1 -1
  142. package/v4/classic/external.d.ts +1 -1
  143. package/v4/classic/external.js +1 -1
  144. package/v4/classic/from-json-schema.cjs +264 -24
  145. package/v4/classic/from-json-schema.js +245 -24
  146. package/v4/classic/in-out.cjs +19 -0
  147. package/v4/classic/index.cjs +19 -0
  148. package/v4/classic/iso.cjs +19 -0
  149. package/v4/classic/parse.cjs +19 -0
  150. package/v4/classic/schemas.cjs +100 -31
  151. package/v4/classic/schemas.d.cts +17 -1
  152. package/v4/classic/schemas.d.ts +17 -1
  153. package/v4/classic/schemas.js +77 -29
  154. package/v4/core/api.cjs +37 -2
  155. package/v4/core/api.d.cts +6 -4
  156. package/v4/core/api.d.ts +6 -4
  157. package/v4/core/api.js +17 -2
  158. package/v4/core/checks.cjs +19 -96
  159. package/v4/core/checks.d.cts +1 -1
  160. package/v4/core/checks.d.ts +1 -1
  161. package/v4/core/checks.js +0 -96
  162. package/v4/core/compile.cjs +164 -65
  163. package/v4/core/compile.d.cts +18 -4
  164. package/v4/core/compile.d.ts +18 -4
  165. package/v4/core/compile.js +145 -66
  166. package/v4/core/core.cjs +19 -0
  167. package/v4/core/doc.cjs +26 -2
  168. package/v4/core/doc.js +7 -2
  169. package/v4/core/errors.cjs +21 -5
  170. package/v4/core/errors.js +2 -5
  171. package/v4/core/index.cjs +19 -0
  172. package/v4/core/json-schema-generator.cjs +20 -1
  173. package/v4/core/json-schema-generator.js +2 -2
  174. package/v4/core/json-schema-processors.cjs +215 -63
  175. package/v4/core/json-schema-processors.d.cts +17 -0
  176. package/v4/core/json-schema-processors.d.ts +17 -0
  177. package/v4/core/json-schema-processors.js +195 -64
  178. package/v4/core/json-schema.cjs +19 -0
  179. package/v4/core/memoizer.cjs +114 -23
  180. package/v4/core/memoizer.js +72 -23
  181. package/v4/core/parse.cjs +56 -16
  182. package/v4/core/parse.js +37 -16
  183. package/v4/core/regexes.cjs +29 -6
  184. package/v4/core/regexes.d.cts +2 -0
  185. package/v4/core/regexes.d.ts +2 -0
  186. package/v4/core/regexes.js +8 -4
  187. package/v4/core/registries.cjs +19 -0
  188. package/v4/core/schemas.cjs +285 -66
  189. package/v4/core/schemas.d.cts +34 -3
  190. package/v4/core/schemas.d.ts +34 -3
  191. package/v4/core/schemas.js +264 -65
  192. package/v4/core/standard-schema.cjs +19 -0
  193. package/v4/core/to-json-schema.cjs +29 -7
  194. package/v4/core/to-json-schema.d.cts +7 -3
  195. package/v4/core/to-json-schema.d.ts +7 -3
  196. package/v4/core/to-json-schema.js +8 -7
  197. package/v4/core/util.cjs +181 -143
  198. package/v4/core/util.d.cts +25 -4
  199. package/v4/core/util.d.ts +25 -4
  200. package/v4/core/util.js +160 -143
  201. package/v4/core/versions.cjs +21 -2
  202. package/v4/core/versions.d.cts +1 -1
  203. package/v4/core/versions.d.ts +1 -1
  204. package/v4/core/versions.js +2 -2
  205. package/v4/core/visit.cjs +31 -0
  206. package/v4/core/visit.js +12 -0
  207. package/v4/index.cjs +19 -0
  208. package/v4/locales/ar.cjs +1 -0
  209. package/v4/locales/ar.js +1 -0
  210. package/v4/locales/az.cjs +1 -0
  211. package/v4/locales/az.js +1 -0
  212. package/v4/locales/be.cjs +1 -0
  213. package/v4/locales/be.js +1 -0
  214. package/v4/locales/bg.cjs +1 -0
  215. package/v4/locales/bg.js +1 -0
  216. package/v4/locales/bn.cjs +1 -0
  217. package/v4/locales/bn.js +1 -0
  218. package/v4/locales/ca.cjs +1 -0
  219. package/v4/locales/ca.js +1 -0
  220. package/v4/locales/ckb.cjs +1 -0
  221. package/v4/locales/ckb.js +1 -0
  222. package/v4/locales/cs.cjs +1 -0
  223. package/v4/locales/cs.js +1 -0
  224. package/v4/locales/da.cjs +1 -0
  225. package/v4/locales/da.js +1 -0
  226. package/v4/locales/de.cjs +1 -0
  227. package/v4/locales/de.js +1 -0
  228. package/v4/locales/el.cjs +1 -0
  229. package/v4/locales/el.js +1 -0
  230. package/v4/locales/en.cjs +1 -0
  231. package/v4/locales/en.js +1 -0
  232. package/v4/locales/eo.cjs +1 -0
  233. package/v4/locales/eo.js +1 -0
  234. package/v4/locales/es.cjs +1 -0
  235. package/v4/locales/es.js +1 -0
  236. package/v4/locales/fa.cjs +1 -0
  237. package/v4/locales/fa.js +1 -0
  238. package/v4/locales/fi.cjs +1 -0
  239. package/v4/locales/fi.js +1 -0
  240. package/v4/locales/fr-CA.cjs +1 -0
  241. package/v4/locales/fr-CA.js +1 -0
  242. package/v4/locales/fr.cjs +1 -0
  243. package/v4/locales/fr.js +1 -0
  244. package/v4/locales/gu.cjs +1 -0
  245. package/v4/locales/gu.js +1 -0
  246. package/v4/locales/he.cjs +1 -0
  247. package/v4/locales/he.js +1 -0
  248. package/v4/locales/hi.cjs +1 -0
  249. package/v4/locales/hi.js +1 -0
  250. package/v4/locales/hr.cjs +1 -0
  251. package/v4/locales/hr.js +1 -0
  252. package/v4/locales/hu.cjs +1 -0
  253. package/v4/locales/hu.js +1 -0
  254. package/v4/locales/hy.cjs +1 -0
  255. package/v4/locales/hy.js +1 -0
  256. package/v4/locales/id.cjs +1 -0
  257. package/v4/locales/id.js +1 -0
  258. package/v4/locales/index.cjs +19 -0
  259. package/v4/locales/is.cjs +1 -0
  260. package/v4/locales/is.js +1 -0
  261. package/v4/locales/it.cjs +1 -0
  262. package/v4/locales/it.js +1 -0
  263. package/v4/locales/ja.cjs +1 -0
  264. package/v4/locales/ja.js +1 -0
  265. package/v4/locales/ka.cjs +1 -0
  266. package/v4/locales/ka.js +1 -0
  267. package/v4/locales/km.cjs +1 -0
  268. package/v4/locales/km.js +1 -0
  269. package/v4/locales/kn.cjs +1 -0
  270. package/v4/locales/kn.js +1 -0
  271. package/v4/locales/ko.cjs +1 -0
  272. package/v4/locales/ko.js +1 -0
  273. package/v4/locales/lt.cjs +1 -0
  274. package/v4/locales/lt.js +1 -0
  275. package/v4/locales/mk.cjs +1 -0
  276. package/v4/locales/mk.js +1 -0
  277. package/v4/locales/ms.cjs +1 -0
  278. package/v4/locales/ms.js +1 -0
  279. package/v4/locales/ne.cjs +1 -0
  280. package/v4/locales/ne.js +1 -0
  281. package/v4/locales/nl.cjs +1 -0
  282. package/v4/locales/nl.js +1 -0
  283. package/v4/locales/nn.cjs +1 -0
  284. package/v4/locales/nn.js +1 -0
  285. package/v4/locales/no.cjs +1 -0
  286. package/v4/locales/no.js +1 -0
  287. package/v4/locales/ota.cjs +1 -0
  288. package/v4/locales/ota.js +1 -0
  289. package/v4/locales/pl.cjs +1 -0
  290. package/v4/locales/pl.js +1 -0
  291. package/v4/locales/ps.cjs +1 -0
  292. package/v4/locales/ps.js +1 -0
  293. package/v4/locales/pt-BR.cjs +1 -0
  294. package/v4/locales/pt-BR.js +1 -0
  295. package/v4/locales/pt.cjs +1 -0
  296. package/v4/locales/pt.js +1 -0
  297. package/v4/locales/ro.cjs +1 -0
  298. package/v4/locales/ro.js +1 -0
  299. package/v4/locales/ru.cjs +1 -0
  300. package/v4/locales/ru.js +1 -0
  301. package/v4/locales/sk.cjs +1 -0
  302. package/v4/locales/sk.js +1 -0
  303. package/v4/locales/sl.cjs +1 -0
  304. package/v4/locales/sl.js +1 -0
  305. package/v4/locales/sv.cjs +1 -0
  306. package/v4/locales/sv.js +1 -0
  307. package/v4/locales/ta.cjs +1 -0
  308. package/v4/locales/ta.js +1 -0
  309. package/v4/locales/th.cjs +1 -0
  310. package/v4/locales/th.js +1 -0
  311. package/v4/locales/tk.cjs +1 -0
  312. package/v4/locales/tk.js +1 -0
  313. package/v4/locales/tr.cjs +1 -0
  314. package/v4/locales/tr.js +1 -0
  315. package/v4/locales/uk.cjs +1 -0
  316. package/v4/locales/uk.js +1 -0
  317. package/v4/locales/ur.cjs +1 -0
  318. package/v4/locales/ur.js +1 -0
  319. package/v4/locales/uz.cjs +1 -0
  320. package/v4/locales/uz.js +1 -0
  321. package/v4/locales/vi.cjs +1 -0
  322. package/v4/locales/vi.js +1 -0
  323. package/v4/locales/yo.cjs +1 -0
  324. package/v4/locales/yo.js +1 -0
  325. package/v4/locales/zh-CN.cjs +1 -0
  326. package/v4/locales/zh-CN.js +1 -0
  327. package/v4/locales/zh-TW.cjs +1 -0
  328. package/v4/locales/zh-TW.js +1 -0
  329. package/v4/mini/checks.cjs +20 -2
  330. package/v4/mini/checks.d.cts +1 -1
  331. package/v4/mini/checks.d.ts +1 -1
  332. package/v4/mini/checks.js +1 -1
  333. package/v4/mini/coerce.cjs +19 -0
  334. package/v4/mini/deep-partial.cjs +19 -0
  335. package/v4/mini/external.cjs +22 -1
  336. package/v4/mini/external.d.cts +1 -1
  337. package/v4/mini/external.d.ts +1 -1
  338. package/v4/mini/external.js +1 -1
  339. package/v4/mini/in-out.cjs +19 -0
  340. package/v4/mini/index.cjs +19 -0
  341. package/v4/mini/iso.cjs +19 -0
  342. package/v4/mini/parse.cjs +19 -0
  343. package/v4/mini/schemas.cjs +42 -4
  344. package/v4/mini/schemas.d.cts +8 -0
  345. package/v4/mini/schemas.d.ts +8 -0
  346. package/v4/mini/schemas.js +19 -2
  347. package/v4-mini/index.cjs +19 -0
@@ -5,7 +5,7 @@ import * as core from "./core.js";
5
5
  import { Doc } from "./doc.js";
6
6
  import type * as errors from "./errors.js";
7
7
  import type * as JSONSchema from "./json-schema.js";
8
- import { parse, parseAsync, safeParse, safeParseAsync } from "./parse.js";
8
+ import { parse, parseAsync } from "./parse.js";
9
9
  import * as regexes from "./regexes.js";
10
10
  import type { StandardSchemaV1 } from "./standard-schema.js";
11
11
  import type { ProcessParams, ToJSONSchemaContext } from "./to-json-schema.js";
@@ -30,6 +30,8 @@ export interface ParseContextInternal<T extends errors.$ZodIssueBase = never> ex
30
30
  readonly async?: boolean | undefined;
31
31
  readonly direction?: "forward" | "backward";
32
32
  readonly skipChecks?: boolean;
33
+ /** Set only by `validate`/`validateAsync`. A container may stop before its next child, never inside one, so a map entry and a tuple's fixed items parse whole. */
34
+ readonly abortEarly?: boolean;
33
35
  }
34
36
 
35
37
  /** Gives a container cycle support: `attach` wraps its parse, and `alloc` registers the object it builds into before any child is parsed so a reference back to the same input resolves to it. */
@@ -94,7 +96,8 @@ export interface $ZodTypeDef {
94
96
  | "promise"
95
97
  | "lazy"
96
98
  | "function"
97
- | "custom";
99
+ | "custom"
100
+ | "properties";
98
101
  error?: errors.$ZodErrorMap<never> | undefined;
99
102
  checks?: checks.$ZodCheck<never>[];
100
103
  }
@@ -332,17 +335,25 @@ export const $ZodType: core.$constructor<$ZodType> = /*@__PURE__*/ core.$constru
332
335
  );
333
336
 
334
337
  /** The Standard Schema surface for `inst`. Shared so wrappers can extend it without forcing it. */
335
- const toStandardResult = (r: util.SafeParseResult<unknown>) =>
336
- r.success ? { value: r.data } : { issues: r.error?.issues };
338
+ // a Standard Schema result only reports issues, so a failure finalizes them straight off the raw payload: no ZodError, and no lazy result to read through
339
+ const toStandardResult = (r: ParsePayload, ctx: ParseContextInternal) =>
340
+ r.issues.length ? { issues: r.issues.map((iss) => util.finalizeIssue(iss, ctx, core.config())) } : { value: r.value };
341
+
342
+ async function validateAsync(inst: $ZodType, value: unknown) {
343
+ const ctx: ParseContextInternal = { async: true };
344
+ return toStandardResult((await inst._zod.run({ value, issues: [] }, ctx)) as ParsePayload, ctx);
345
+ }
337
346
 
338
347
  export function standardProps(inst: $ZodType): StandardSchemaV1.Props<any, any> {
339
348
  return {
340
349
  validate: (value: unknown) => {
350
+ const ctx: ParseContextInternal = { async: false };
341
351
  try {
342
- return toStandardResult(safeParse(inst, value));
343
- } catch (_) {
344
- return safeParseAsync(inst, value).then(toStandardResult);
345
- }
352
+ const r = inst._zod.run({ value, issues: [] }, ctx);
353
+ if (!(r instanceof Promise)) return toStandardResult(r, ctx);
354
+ } catch (_) {}
355
+ // async function so a synchronously throwing check rejects instead of escaping validate
356
+ return validateAsync(inst, value);
346
357
  },
347
358
  vendor: "zod",
348
359
  version: 1 as const,
@@ -388,7 +399,8 @@ export interface $ZodString<Input = unknown> extends _$ZodType<$ZodStringInterna
388
399
 
389
400
  export const $ZodString: core.$constructor<$ZodString> = /*@__PURE__*/ core.$constructor("$ZodString", (inst, def) => {
390
401
  $ZodType.init(inst, def);
391
- inst._zod.pattern = [...(inst?._zod.bag?.patterns ?? [])].pop() ?? regexes.string(inst._zod.bag);
402
+ // a format's own pattern, else unbounded; a template literal derives the check-aware form itself
403
+ inst._zod.pattern = (def as $ZodStringFormatDef).pattern ?? regexes.anyString;
392
404
  inst._zod.parse = (payload, _) => {
393
405
  if (def.coerce)
394
406
  try {
@@ -777,14 +789,6 @@ export const $ZodISODateTime: core.$constructor<$ZodISODateTime> = /*@__PURE__*/
777
789
  (inst, def): void => {
778
790
  def.pattern ??= regexes.datetime(def);
779
791
  $ZodStringFormat.init(inst, def);
780
-
781
- // these two drop the offset or seconds `date-time` requires — on the bag not the def, since `z.string().check(...)` lands the format on a different schema
782
- if (def.local || def.precision === -1) {
783
- inst._zod.bag.laxFormat = true;
784
- inst._zod.onattach.push((s) => {
785
- (s._zod.bag as $ZodStringInternals<unknown>["bag"]).laxFormat = true;
786
- });
787
- }
788
792
  }
789
793
  );
790
794
 
@@ -861,8 +865,6 @@ export interface $ZodIPv4 extends $ZodType {
861
865
  export const $ZodIPv4: core.$constructor<$ZodIPv4> = /*@__PURE__*/ core.$constructor("$ZodIPv4", (inst, def): void => {
862
866
  def.pattern ??= regexes.ipv4;
863
867
  $ZodStringFormat.init(inst, def);
864
-
865
- inst._zod.bag.format = `ipv4`;
866
868
  });
867
869
 
868
870
  ////////////////////////////// ZodIPv6 //////////////////////////////
@@ -897,8 +899,6 @@ export const $ZodIPv6: core.$constructor<$ZodIPv6> = /*@__PURE__*/ core.$constru
897
899
  def.pattern ??= regexes.ipv6;
898
900
  $ZodStringFormat.init(inst, def);
899
901
 
900
- inst._zod.bag.format = `ipv6`;
901
-
902
902
  inst._zod.check = (payload) => {
903
903
  if (!isValidIPv6(payload.value)) {
904
904
  payload.issues.push({
@@ -928,8 +928,6 @@ export interface $ZodMAC extends $ZodType {
928
928
  export const $ZodMAC: core.$constructor<$ZodMAC> = /*@__PURE__*/ core.$constructor("$ZodMAC", (inst, def): void => {
929
929
  def.pattern ??= regexes.mac(def.delimiter);
930
930
  $ZodStringFormat.init(inst, def);
931
-
932
- inst._zod.bag.format = `mac`;
933
931
  });
934
932
 
935
933
  ////////////////////////////// ZodCIDRv4 //////////////////////////////
@@ -1021,14 +1019,15 @@ export interface $ZodBase64 extends $ZodType {
1021
1019
  _zod: $ZodBase64Internals;
1022
1020
  }
1023
1021
 
1022
+ // lax on purpose: the quantified regexes.base64 overflows the regex stack on multi-MB input and its leading ^$| alternation leaks through template-literal composition; isValidBase64 enforces length and padding
1023
+ export const base64Charset: RegExp = /^[0-9a-zA-Z+/]*={0,2}$/;
1024
+
1024
1025
  export const $ZodBase64: core.$constructor<$ZodBase64> = /*@__PURE__*/ core.$constructor(
1025
1026
  "$ZodBase64",
1026
1027
  (inst, def): void => {
1027
- def.pattern ??= regexes.base64;
1028
+ def.pattern ??= base64Charset;
1028
1029
  $ZodStringFormat.init(inst, def);
1029
1030
 
1030
- inst._zod.bag.contentEncoding = "base64";
1031
-
1032
1031
  inst._zod.check = (payload) => {
1033
1032
  if (isValidBase64(payload.value)) return;
1034
1033
 
@@ -1043,9 +1042,12 @@ export const $ZodBase64: core.$constructor<$ZodBase64> = /*@__PURE__*/ core.$con
1043
1042
  }
1044
1043
  );
1045
1044
 
1046
- ////////////////////////////// ZodBase64 //////////////////////////////
1045
+ ////////////////////////////// ZodBase64URL //////////////////////////////
1046
+ // lax on purpose: the quantified regexes.base64url overflows the regex stack on multi-MB input; isValidBase64 enforces length on the padded string
1047
+ export const base64urlCharset: RegExp = /^[A-Za-z0-9_-]*$/;
1048
+
1047
1049
  export function isValidBase64URL(data: string): boolean {
1048
- if (!regexes.base64url.test(data)) return false;
1050
+ if (!base64urlCharset.test(data)) return false;
1049
1051
  const base64 = data.replace(/[-_]/g, (c) => (c === "-" ? "+" : "/"));
1050
1052
  const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "=");
1051
1053
  return isValidBase64(padded);
@@ -1061,11 +1063,9 @@ export interface $ZodBase64URL extends $ZodType {
1061
1063
  export const $ZodBase64URL: core.$constructor<$ZodBase64URL> = /*@__PURE__*/ core.$constructor(
1062
1064
  "$ZodBase64URL",
1063
1065
  (inst, def): void => {
1064
- def.pattern ??= regexes.base64url;
1066
+ def.pattern ??= base64urlCharset;
1065
1067
  $ZodStringFormat.init(inst, def);
1066
1068
 
1067
- inst._zod.bag.contentEncoding = "base64url";
1068
-
1069
1069
  inst._zod.check = (payload) => {
1070
1070
  if (isValidBase64URL(payload.value)) return;
1071
1071
 
@@ -1104,7 +1104,7 @@ function isLuhnAlgo(digits: string): boolean {
1104
1104
  let bit = 1;
1105
1105
  let sum = 0;
1106
1106
  while (length) {
1107
- const value = +digits[--length]!;
1107
+ const value = digits.charCodeAt(--length) - 48;
1108
1108
  bit ^= 1;
1109
1109
  sum += bit ? [0, 2, 4, 6, 8, 1, 3, 5, 7, 9][value]! : value;
1110
1110
  }
@@ -1144,6 +1144,53 @@ export const $ZodCreditCard: core.$constructor<$ZodCreditCard> = /*@__PURE__*/ c
1144
1144
  }
1145
1145
  );
1146
1146
 
1147
+ ////////////////////////////// ZodIBAN //////////////////////////////
1148
+
1149
+ // iso 7064 mod 97-10 checksum without BigInt
1150
+ function isIso7064Mod97(iban: string): boolean {
1151
+ let remainder = 0;
1152
+ const len = iban.length;
1153
+ for (let i = 4; i < len; i++) {
1154
+ const code = iban.charCodeAt(i);
1155
+ remainder = (code >= 65 ? remainder * 100 + (code - 55) : remainder * 10 + (code - 48)) % 97;
1156
+ }
1157
+ for (let i = 0; i < 4; i++) {
1158
+ const code = iban.charCodeAt(i);
1159
+ remainder = (code >= 65 ? remainder * 100 + (code - 55) : remainder * 10 + (code - 48)) % 97;
1160
+ }
1161
+ return remainder === 1;
1162
+ }
1163
+
1164
+ export function isValidIBAN(input: string): boolean {
1165
+ if (!regexes.iban.test(input)) return false;
1166
+ return isIso7064Mod97(input);
1167
+ }
1168
+
1169
+ export interface $ZodIBANDef extends $ZodStringFormatDef<"iban"> {}
1170
+ export interface $ZodIBANInternals extends $ZodStringFormatInternals<"iban"> {
1171
+ def: $ZodIBANDef;
1172
+ }
1173
+
1174
+ export interface $ZodIBAN extends $ZodType {
1175
+ _zod: $ZodIBANInternals;
1176
+ }
1177
+
1178
+ export const $ZodIBAN: core.$constructor<$ZodIBAN> = /*@__PURE__*/ core.$constructor("$ZodIBAN", (inst, def): void => {
1179
+ // shape only — checksum is not expressible as a pattern
1180
+ def.pattern ??= regexes.iban;
1181
+ $ZodStringFormat.init(inst, def);
1182
+ inst._zod.check = (payload) => {
1183
+ if (isValidIBAN(payload.value)) return;
1184
+ payload.issues.push({
1185
+ code: "invalid_format",
1186
+ format: "iban",
1187
+ input: payload.value,
1188
+ inst,
1189
+ continue: !def.abort,
1190
+ });
1191
+ };
1192
+ });
1193
+
1147
1194
  ////////////////////////////// ZodJWT //////////////////////////////
1148
1195
 
1149
1196
  export function isValidJWT(token: string, algorithm: util.JWTAlgorithm | null = null): boolean {
@@ -1260,7 +1307,7 @@ export interface $ZodNumber<Input = unknown> extends $ZodType {
1260
1307
  export const $ZodNumber: core.$constructor<$ZodNumber> = /*@__PURE__*/ core.$constructor("$ZodNumber", (inst, def) => {
1261
1308
  $ZodType.init(inst, def);
1262
1309
 
1263
- inst._zod.pattern = inst._zod.bag.pattern ?? regexes.number;
1310
+ inst._zod.pattern = regexes.number;
1264
1311
  inst._zod.parse = (payload, _ctx) => {
1265
1312
  if (def.coerce)
1266
1313
  try {
@@ -1804,6 +1851,7 @@ export const $ZodArray: core.$constructor<$ZodArray> = /*@__PURE__*/ core.$const
1804
1851
 
1805
1852
  payload.value = memo ? memo.alloc(inst, payload, Array(input.length), ctx) : Array(input.length);
1806
1853
  const proms: Promise<any>[] = [];
1854
+ const abortEarly = ctx?.abortEarly;
1807
1855
  for (let i = 0; i < input.length; i++) {
1808
1856
  const item = input[i];
1809
1857
  const result = def.element._zod.run(
@@ -1818,6 +1866,8 @@ export const $ZodArray: core.$constructor<$ZodArray> = /*@__PURE__*/ core.$const
1818
1866
  proms.push(result.then((result) => handleArrayResult(result, payload, i)));
1819
1867
  } else {
1820
1868
  handleArrayResult(result, payload, i);
1869
+ // the element's payload is authoritative here, since handleArrayResult forwards every issue; an object's is not, because it drops a failed absent optional
1870
+ if (abortEarly && result.issues.length !== 0 && util.aborted(result)) break;
1821
1871
  }
1822
1872
  }
1823
1873
 
@@ -2022,9 +2072,10 @@ function handleCatchall(
2022
2072
  proms: Promise<any>[],
2023
2073
  input: any,
2024
2074
  payload: ParsePayload,
2025
- ctx: ParseContext,
2075
+ ctx: ParseContextInternal,
2026
2076
  def: ReturnType<typeof normalizeDef>,
2027
- inst: $ZodObject
2077
+ inst: $ZodObject,
2078
+ abortEarly: boolean
2028
2079
  ) {
2029
2080
  const unrecognized: string[] = [];
2030
2081
  const keySet = def.keySet;
@@ -2032,7 +2083,13 @@ function handleCatchall(
2032
2083
  const t = _catchall.def.type;
2033
2084
  const optin = _catchall.optin;
2034
2085
  const optout = _catchall.optout;
2086
+ // starts at 0, not the current length: the shape phase already ran and may have aborted
2087
+ let seen = 0;
2035
2088
  for (const key in input) {
2089
+ if (abortEarly && payload.issues.length !== seen) {
2090
+ if (util.aborted(payload, seen)) break;
2091
+ seen = payload.issues.length;
2092
+ }
2036
2093
  // Must precede the __proto__ branch: a declared key is not unrecognized, even though the shape loop deliberately strips __proto__ from the parsed output.
2037
2094
  if (keySet.has(key)) continue;
2038
2095
  // Don't copy an undeclared __proto__ into the result; assignment to a plain {} would replace the result prototype. But in strict mode it is still an unknown key, so report it before skipping.
@@ -2070,28 +2127,22 @@ function handleCatchall(
2070
2127
  });
2071
2128
  }
2072
2129
 
2073
- // Whichever object a def's `shape` currently answers from: the one the caller passed until the first read, the frozen copy after it. Keyed by def, so a def rebuilt by a builder is simply absent rather than inheriting the source's. Read its keys with `Object.keys`, which does not invoke them — that is what lets a discriminated union check its discriminator without resolving an option whose getters reference the union being constructed.
2074
- const propShapes = new WeakMap<object, Record<string, unknown>>();
2075
-
2076
2130
  export const $ZodObject: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$constructor("$ZodObject", (inst, def) => {
2077
2131
  // requires cast because technically $ZodObject doesn't extend
2078
2132
  $ZodType.init(inst, def);
2079
- // const sh = def.shape;
2080
2133
  const desc = Object.getOwnPropertyDescriptor(def, "shape");
2081
- if (!desc?.get) {
2082
- const sh = def.shape;
2083
- propShapes.set(def, sh);
2084
- Object.defineProperty(def, "shape", {
2085
- get: () => {
2086
- const newSh = { ...sh };
2087
- Object.defineProperty(def, "shape", {
2088
- value: newSh,
2089
- });
2090
- propShapes.set(def, newSh);
2091
-
2092
- return newSh;
2093
- },
2094
- });
2134
+ // a cloned def carries its source's accessor, which knows the shape it answers from; adopting that keeps the clone's keys readable without running it
2135
+ const sh = desc?.get ? (desc.get as util.ShapeGetter).raw : (def.shape ?? {});
2136
+ if (sh) {
2137
+ // Freezes the shape on first read, so its getters resolve once and every later read sees the same schemas.
2138
+ const get: util.ShapeGetter = () => {
2139
+ const newSh = { ...sh };
2140
+ Object.defineProperty(def, "shape", { value: newSh });
2141
+ get.raw = newSh;
2142
+ return newSh;
2143
+ };
2144
+ get.raw = sh;
2145
+ Object.defineProperty(def, "shape", { get });
2095
2146
  }
2096
2147
 
2097
2148
  const _normalized = util.cached(() => normalizeDef(def));
@@ -2137,8 +2188,14 @@ export const $ZodObject: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$con
2137
2188
 
2138
2189
  const proms: Promise<any>[] = [];
2139
2190
  const shape = value.shape;
2191
+ const abortEarly = ctx?.abortEarly;
2192
+ let seen = payload.issues.length;
2140
2193
 
2141
2194
  for (const key of value.allKeys) {
2195
+ if (abortEarly && payload.issues.length !== seen) {
2196
+ if (util.aborted(payload, seen)) break;
2197
+ seen = payload.issues.length;
2198
+ }
2142
2199
  if (key === "__proto__") continue;
2143
2200
  const el = (shape as any)[key]!;
2144
2201
  const optin = el._zod.optin;
@@ -2156,7 +2213,7 @@ export const $ZodObject: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$con
2156
2213
  return proms.length ? Promise.all(proms).then(() => payload) : payload;
2157
2214
  }
2158
2215
 
2159
- return handleCatchall(proms, input, payload, ctx, _normalized.value, inst);
2216
+ return handleCatchall(proms, input, payload, ctx, _normalized.value, inst, abortEarly === true);
2160
2217
  };
2161
2218
  });
2162
2219
 
@@ -2179,12 +2236,18 @@ export const $ZodObjectJIT: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$
2179
2236
 
2180
2237
  const parseStr = (k: string) => `shape[${k}]._zod.run({ value: input[${k}], issues: [] }, ctx)`;
2181
2238
 
2182
- // Prefixes in place, like util.prefixIssues does for every interpreted path.
2239
+ // prefixes in place, like util.prefixIssues. newResult must land before the early return: a catchall runs after this and would otherwise write onto the caller's input
2183
2240
  const prefixStr = (id: string, k: string) => `
2241
+ let ${id}_ab = false;
2184
2242
  for (let i = 0; i < ${id}.issues.length; i++) {
2185
2243
  const iss = ${id}.issues[i];
2186
2244
  iss.path = iss.path ? [${k}, ...iss.path] : [${k}];
2187
2245
  payload.issues.push(iss);
2246
+ if (iss.continue !== true) ${id}_ab = true;
2247
+ }
2248
+ if (${id}_ab && ctx && ctx.abortEarly) {
2249
+ payload.value = newResult;
2250
+ return payload;
2188
2251
  }`;
2189
2252
 
2190
2253
  doc.write(`const input = payload.value;`);
@@ -2236,6 +2299,10 @@ export const $ZodObjectJIT: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$
2236
2299
  input: undefined,
2237
2300
  path: [${k}]
2238
2301
  });
2302
+ if (ctx && ctx.abortEarly) {
2303
+ payload.value = newResult;
2304
+ return payload;
2305
+ }
2239
2306
  }
2240
2307
 
2241
2308
  if (${id}_present) {
@@ -2296,7 +2363,7 @@ export const $ZodObjectJIT: core.$constructor<$ZodObject> = /*@__PURE__*/ core.$
2296
2363
  payload = fastpass(payload, ctx);
2297
2364
 
2298
2365
  if (!catchall) return payload;
2299
- return handleCatchall([], input, payload, ctx, value, inst);
2366
+ return handleCatchall([], input, payload, ctx, value, inst, ctx?.abortEarly === true);
2300
2367
  }
2301
2368
 
2302
2369
  return superParse(payload, ctx);
@@ -2610,9 +2677,9 @@ export const $ZodDiscriminatedUnion: core.$constructor<$ZodDiscriminatedUnion> =
2610
2677
  return propValues;
2611
2678
  });
2612
2679
 
2613
- // Checked now rather than in the lookup map below, so an option that lacks the discriminator fails at the `discriminatedUnion` call instead of on the first object parsed. Options whose shape cannot be enumerated without resolving it — pipes, lazies, and objects rebuilt by a builder such as `.extend()` — are left to the map.
2680
+ // Checked now rather than in the lookup map below, so an option that lacks the discriminator fails at the `discriminatedUnion` call instead of on the first object parsed. Options whose shape cannot be enumerated without resolving it — pipes and lazies — are left to the map.
2614
2681
  def.options.forEach((option, i) => {
2615
- const propShape = propShapes.get(option._zod.def);
2682
+ const propShape = util.rawShape(option._zod.def);
2616
2683
  if (propShape && !Object.prototype.hasOwnProperty.call(propShape, def.discriminator)) {
2617
2684
  throw new Error(`Invalid discriminated union option at index "${i}"`);
2618
2685
  }
@@ -2959,6 +3026,9 @@ export const $ZodTuple: core.$constructor<$ZodTuple> = /*@__PURE__*/ core.$const
2959
3026
 
2960
3027
  // Run every item in parallel, collecting results into an indexed array. The post-processing in `handleTupleResults` walks them in order so it can decide whether an absent optional-output error can truncate the tail or must be reported to preserve required output.
2961
3028
  const itemResults: ParsePayload[] = new Array(items.length);
3029
+ // only tracked when there is a rest loop to skip
3030
+ const abortEarly = def.rest ? ctx?.abortEarly : undefined;
3031
+ let itemAborted = false;
2962
3032
  for (let i = 0; i < items.length; i++) {
2963
3033
  const r = items[i]._zod.run({ value: input[i], issues: [] }, ctx);
2964
3034
  if (r instanceof Promise) {
@@ -2969,13 +3039,20 @@ export const $ZodTuple: core.$constructor<$ZodTuple> = /*@__PURE__*/ core.$const
2969
3039
  );
2970
3040
  } else {
2971
3041
  itemResults[i] = r;
3042
+ if (abortEarly && !itemAborted && r.issues.length) itemAborted = util.aborted(r);
2972
3043
  }
2973
3044
  }
2974
3045
 
2975
- if (def.rest) {
3046
+ // sound because rest is non-empty exactly when every fixed index is present, the one case handleTupleResults cannot discard an item's issues
3047
+ if (def.rest && !itemAborted) {
2976
3048
  let i = items.length - 1;
2977
3049
  const rest = input.slice(items.length);
3050
+ let seen = payload.issues.length;
2978
3051
  for (const el of rest) {
3052
+ if (abortEarly && payload.issues.length !== seen) {
3053
+ if (util.aborted(payload, seen)) break;
3054
+ seen = payload.issues.length;
3055
+ }
2979
3056
  i++;
2980
3057
  const result = def.rest._zod.run({ value: el, issues: [] }, ctx);
2981
3058
  if (result instanceof Promise) {
@@ -3145,6 +3222,7 @@ export const $ZodRecord: core.$constructor<$ZodRecord> = /*@__PURE__*/ core.$con
3145
3222
  return payload;
3146
3223
  }
3147
3224
 
3225
+ // no guard in either loop below: a record's invalid_key aborts but an enclosing intersection can reconcile it, so a stopped loop hides keys the sibling does not own and the intersection then rejects nothing
3148
3226
  const proms: Promise<any>[] = [];
3149
3227
 
3150
3228
  const values = def.keyType._zod.values;
@@ -3349,8 +3427,14 @@ export const $ZodMap: core.$constructor<$ZodMap> = /*@__PURE__*/ core.$construct
3349
3427
 
3350
3428
  const proms: Promise<any>[] = [];
3351
3429
  payload.value = memo ? memo.alloc(inst, payload, new Map(), ctx) : new Map();
3430
+ const abortEarly = ctx?.abortEarly;
3431
+ let seen = payload.issues.length;
3352
3432
 
3353
3433
  for (const [key, value] of input) {
3434
+ if (abortEarly && payload.issues.length !== seen) {
3435
+ if (util.aborted(payload, seen)) break;
3436
+ seen = payload.issues.length;
3437
+ }
3354
3438
  const keyResult = def.keyType._zod.run({ value: key, issues: [] }, ctx);
3355
3439
  const valueResult = def.valueType._zod.run({ value: value, issues: [] }, ctx);
3356
3440
 
@@ -3454,7 +3538,13 @@ export const $ZodSet: core.$constructor<$ZodSet> = /*@__PURE__*/ core.$construct
3454
3538
 
3455
3539
  const proms: Promise<any>[] = [];
3456
3540
  payload.value = memo ? memo.alloc(inst, payload, new Set(), ctx) : new Set();
3541
+ const abortEarly = ctx?.abortEarly;
3542
+ let seen = payload.issues.length;
3457
3543
  for (const item of input) {
3544
+ if (abortEarly && payload.issues.length !== seen) {
3545
+ if (util.aborted(payload, seen)) break;
3546
+ seen = payload.issues.length;
3547
+ }
3458
3548
  const result = def.valueType._zod.run({ value: item, issues: [] }, ctx);
3459
3549
  if (result instanceof Promise) {
3460
3550
  proms.push(result.then((result) => handleSetResult(result, payload)));
@@ -3513,12 +3603,13 @@ export const $ZodEnum: core.$constructor<$ZodEnum> = /*@__PURE__*/ core.$constru
3513
3603
  const valuesSet = new Set<util.Primitive>(values);
3514
3604
  inst._zod.values = valuesSet;
3515
3605
 
3516
- const patternValues = values.filter((k) => util.propertyKeyTypes.has(typeof k));
3517
-
3518
- // unmatchable fallback, RE2-safe: an empty alternation would compile to /^()$/, which matches ""
3519
- inst._zod.pattern = new RegExp(
3520
- patternValues.length ? `^(${patternValues.map((o) => util.escapeRegex(o.toString())).join("|")})$` : "^[^\\s\\S]$"
3521
- );
3606
+ util.defineLazyInternal(inst, "pattern", (zod) => {
3607
+ const patternValues = util.getEnumValues(zod.def.entries).filter((k) => util.propertyKeyTypes.has(typeof k));
3608
+ // unmatchable fallback, RE2-safe: an empty alternation would compile to /^()$/, which matches ""
3609
+ return new RegExp(
3610
+ patternValues.length ? `^(${patternValues.map((o) => util.escapeRegex(o.toString())).join("|")})$` : "^[^\\s\\S]$"
3611
+ );
3612
+ });
3522
3613
 
3523
3614
  inst._zod.parse = (payload, _ctx) => {
3524
3615
  const input = payload.value;
@@ -3568,14 +3659,19 @@ export const $ZodLiteral: core.$constructor<$ZodLiteral> = /*@__PURE__*/ core.$c
3568
3659
  const values = new Set<util.Literal>(def.values);
3569
3660
  inst._zod.values = values;
3570
3661
 
3571
- // unmatchable fallback, RE2-safe: an empty alternation would compile to /^()$/, which matches ""
3572
- inst._zod.pattern = new RegExp(
3573
- def.values.length
3574
- ? `^(${def.values
3575
- .map((o) => (typeof o === "string" ? util.escapeRegex(o) : o ? util.escapeRegex(o.toString()) : String(o)))
3576
- .join("|")})$`
3577
- : "^[^\\s\\S]$"
3578
- );
3662
+ util.defineLazyInternal(inst, "pattern", (zod) => {
3663
+ const vals = zod.def.values;
3664
+ // unmatchable fallback, RE2-safe: an empty alternation would compile to /^()$/, which matches ""
3665
+ return new RegExp(
3666
+ vals.length
3667
+ ? `^(${vals
3668
+ .map((o: util.Literal) =>
3669
+ typeof o === "string" ? util.escapeRegex(o) : o ? util.escapeRegex(o.toString()) : String(o)
3670
+ )
3671
+ .join("|")})$`
3672
+ : "^[^\\s\\S]$"
3673
+ );
3674
+ });
3579
3675
 
3580
3676
  inst._zod.parse = (payload, _ctx) => {
3581
3677
  const input = payload.value;
@@ -4574,6 +4670,51 @@ export type $PartsToTemplateLiteral<Parts extends $ZodTemplateLiteralPart[]> = [
4574
4670
  : never
4575
4671
  : never;
4576
4672
 
4673
+ // a leaf's pattern source with its own checks folded in: the last pattern-carrying check wins, else length bounds narrow the catch-all, else an integer format narrows the number form. the fold lives here instead of on `_zod.pattern` so a bundle without template literals never pays for it
4674
+ function leafPattern(schema: $ZodType): string | undefined {
4675
+ const def = schema._zod.def as { pattern?: RegExp; format?: string; checks?: checks.$ZodCheck[] };
4676
+ let pattern = def.pattern;
4677
+ let isInt = !!def.format?.includes("int");
4678
+ let minimum: number | undefined;
4679
+ let maximum: number | undefined;
4680
+ for (const ch of def.checks ?? []) {
4681
+ const d = ch._zod.def as { pattern?: RegExp; format?: string; minimum?: number; maximum?: number; length?: number };
4682
+ if (d.pattern) pattern = d.pattern;
4683
+ isInt ||= !!d.format?.includes("int");
4684
+ const lo = d.minimum ?? d.length;
4685
+ const hi = d.maximum ?? d.length;
4686
+ if (lo !== undefined && (minimum === undefined || lo > minimum)) minimum = lo;
4687
+ if (hi !== undefined && (maximum === undefined || hi < maximum)) maximum = hi;
4688
+ }
4689
+ if (pattern) return pattern.source;
4690
+ // an empty range matches nothing at runtime, and `{8,5}` is not a legal quantifier
4691
+ if (minimum !== undefined && maximum !== undefined && minimum > maximum) return "(?!)";
4692
+ if (minimum !== undefined || maximum !== undefined) return regexes.string({ minimum, maximum }).source;
4693
+ const own = schema._zod.pattern;
4694
+ return (isInt && own === regexes.number ? regexes.integer : own)?.source;
4695
+ }
4696
+
4697
+ // a part's pattern source. a wrapper's pattern embeds its inner pattern's source verbatim, so the folded form is substituted in place without knowing the wrapper's own composition; a union's options are joined the way the union builds its own pattern
4698
+ function partPattern(schema: $ZodType): string | undefined {
4699
+ const def = schema._zod.def as { innerType?: $ZodType; options?: $ZodType[] };
4700
+ const own = schema._zod.pattern?.source;
4701
+ // lazy resolves its inner on the internals, not the def
4702
+ const inner = def.innerType ?? (schema._zod as { innerType?: $ZodType }).innerType;
4703
+ if (inner) {
4704
+ const before = inner._zod.pattern?.source;
4705
+ const after = partPattern(inner);
4706
+ if (own && before && after && after !== before) {
4707
+ return own.replace(util.cleanRegex(before), () => util.cleanRegex(after));
4708
+ }
4709
+ return own;
4710
+ }
4711
+ if (def.options) {
4712
+ const sources = def.options.map(partPattern);
4713
+ if (sources.every(Boolean)) return `^(${sources.map((s) => util.cleanRegex(s!)).join("|")})$`;
4714
+ }
4715
+ return leafPattern(schema);
4716
+ }
4717
+
4577
4718
  export const $ZodTemplateLiteral: core.$constructor<$ZodTemplateLiteral> = /*@__PURE__*/ core.$constructor(
4578
4719
  "$ZodTemplateLiteral",
4579
4720
  (inst, def) => {
@@ -4582,18 +4723,11 @@ export const $ZodTemplateLiteral: core.$constructor<$ZodTemplateLiteral> = /*@__
4582
4723
  for (const part of def.parts) {
4583
4724
  if (typeof part === "object" && part !== null) {
4584
4725
  // is Zod schema
4585
- if (!part._zod.pattern) {
4586
- // if (!source)
4726
+ const source = partPattern(part);
4727
+ if (!source) {
4587
4728
  throw new Error(`Invalid template literal part, no pattern found: ${[...(part as any)._zod.traits].shift()}`);
4588
4729
  }
4589
-
4590
- const source = part._zod.pattern instanceof RegExp ? part._zod.pattern.source : part._zod.pattern;
4591
-
4592
- if (!source) throw new Error(`Invalid template literal part: ${part._zod.traits}`);
4593
-
4594
- const start = source.startsWith("^") ? 1 : 0;
4595
- const end = source.endsWith("$") ? source.length - 1 : source.length;
4596
- regexParts.push(source.slice(start, end));
4730
+ regexParts.push(util.cleanRegex(source));
4597
4731
  } else if (part === null || util.primitiveTypes.has(typeof part)) {
4598
4732
  regexParts.push(util.escapeRegex(`${part}`));
4599
4733
  } else {
@@ -4956,6 +5090,101 @@ function handleRefineResult(result: unknown, payload: ParsePayload, input: unkno
4956
5090
  }
4957
5091
  }
4958
5092
 
5093
+ ////////////////////////////////////////
5094
+ ////////////////////////////////////////
5095
+ ////////// //////////
5096
+ ////////// $ZodProperties //////////
5097
+ ////////// //////////
5098
+ ////////////////////////////////////////
5099
+ ////////////////////////////////////////
5100
+ export interface $ZodPropertiesDef<Shape extends $ZodShape = $ZodShape> extends $ZodTypeDef, checks.$ZodCheckDef {
5101
+ type: "properties";
5102
+ check: "properties";
5103
+ shape: Shape;
5104
+ }
5105
+
5106
+ // both sides infer the INPUT type: the shape is asserted and its results discarded, so a default, catch or transform inside it would make an output-typed inference a lie. The check side widens a literal to its primitive, so spreading over a `string` property still type-checks (#6520).
5107
+ export interface $ZodPropertiesInternals<Shape extends $ZodShape = $ZodShape>
5108
+ extends $ZodTypeInternals<$InferObjectInput<Shape, {}>, $InferObjectInput<Shape, {}>>,
5109
+ checks.$ZodCheckInternals<{ -readonly [k in keyof Shape]: util.Widen<core.input<Shape[k]>> }> {
5110
+ def: $ZodPropertiesDef<Shape>;
5111
+ isst: errors.$ZodIssueInvalidType;
5112
+ issc: errors.$ZodIssue;
5113
+ }
5114
+
5115
+ export interface $ZodProperties<Shape extends $ZodShape = $ZodShape> extends $ZodType {
5116
+ _zod: $ZodPropertiesInternals<Shape>;
5117
+ // yields the schema itself, so pre-4.6 `.check(...z.properties(shape))` spread call sites keep working
5118
+ [Symbol.iterator](): Iterator<this>;
5119
+ }
5120
+
5121
+ // asserts in place: the child result's value is discarded, matching z.property(), because a nested object or array schema rebuilds its output even when nothing transformed
5122
+ function handlePropertiesResult(result: ParsePayload, payload: ParsePayload, key: string | symbol): void {
5123
+ if (result.issues.length) {
5124
+ payload.issues.push(...util.prefixIssues(key, result.issues));
5125
+ }
5126
+ }
5127
+
5128
+ export const $ZodProperties: core.$constructor<$ZodProperties> = /*@__PURE__*/ core.$constructor(
5129
+ "$ZodProperties",
5130
+ (inst, def) => {
5131
+ // $ZodType.init prepends an instance that already carries the $ZodCheck trait to its own `checks`, which would run the shape a second time and cost the parse context. Initializing the check trait after it keeps the schema role in `parse`, where the context arrives.
5132
+ $ZodType.init(inst, def);
5133
+ checks.$ZodCheck.init(inst, def);
5134
+
5135
+ const memo = core.globalConfig.memoizer;
5136
+ memo?.attach(inst);
5137
+
5138
+ // key and schema snapshotted together: reading one live and the other cached lets a later mutation of the caller's shape object pair a stale key with a missing schema
5139
+ let entries!: [string | symbol, $ZodType][];
5140
+ const runShape = (payload: ParsePayload, ctx: ParseContextInternal): util.MaybeAsync<void> => {
5141
+ entries ??= Reflect.ownKeys(def.shape).map((key) => [key, (def.shape as any)[key] as $ZodType]);
5142
+ const input = payload.value as any;
5143
+ let proms: Promise<any>[] | undefined;
5144
+ for (const [key, schema] of entries) {
5145
+ const result = schema._zod.run({ value: input[key], issues: [] }, ctx);
5146
+ if (result instanceof Promise) {
5147
+ proms ??= [];
5148
+ proms.push(result.then((result) => handlePropertiesResult(result, payload, key)));
5149
+ } else {
5150
+ handlePropertiesResult(result, payload, key);
5151
+ }
5152
+ }
5153
+ if (proms) return Promise.all(proms).then(() => undefined);
5154
+ return undefined;
5155
+ };
5156
+
5157
+ inst._zod.parse = (payload, ctx) => {
5158
+ const input = payload.value;
5159
+ // as a schema this is the type gate, and it infers an object shape, so a primitive is a type error. A function passes: its properties read like any other object's, and z.instanceof allows one.
5160
+ if (input === null || (typeof input !== "object" && typeof input !== "function")) {
5161
+ payload.issues.push({ expected: "object", code: "invalid_type", input, inst });
5162
+ return payload;
5163
+ }
5164
+ // both sides declare the shape's input type, so the assertion runs forward in either direction; encoding the children backward would reject the very type this schema claims to take
5165
+ if (ctx.direction === "backward") ctx = { ...ctx, direction: "forward" };
5166
+ // the input is its own output here, so it registers as its own memo entry: a cycle re-entering this node hits the bucket instead of recursing forever
5167
+ if (memo) memo.alloc(inst, payload, input, ctx);
5168
+ const result = runShape(payload, ctx);
5169
+ return result instanceof Promise ? result.then(() => payload) : payload;
5170
+ };
5171
+
5172
+ // as a check the base schema already typed the value, so this only asserts the properties — which read on a primitive too, matching z.property() on a string's length. It gets no context of its own, so a cycle through a spread schema is not tracked.
5173
+ inst._zod.check = (payload) => {
5174
+ if (payload.value == null) {
5175
+ payload.issues.push({ expected: "object", code: "invalid_type", input: payload.value, inst });
5176
+ return undefined;
5177
+ }
5178
+ return runShape(payload, {});
5179
+ };
5180
+ },
5181
+ {
5182
+ *[Symbol.iterator]() {
5183
+ yield this;
5184
+ },
5185
+ }
5186
+ );
5187
+
4959
5188
  export type $ZodTypes =
4960
5189
  | $ZodString
4961
5190
  | $ZodNumber
@@ -4988,6 +5217,7 @@ export type $ZodTypes =
4988
5217
  | $ZodPrefault
4989
5218
  | $ZodTemplateLiteral
4990
5219
  | $ZodCustom
5220
+ | $ZodProperties
4991
5221
  | $ZodTransform
4992
5222
  | $ZodNonOptional
4993
5223
  | $ZodReadonly
@@ -5022,6 +5252,7 @@ export type $ZodStringFormatTypes =
5022
5252
  | $ZodBase64URL
5023
5253
  | $ZodE164
5024
5254
  | $ZodCreditCard
5255
+ | $ZodIBAN
5025
5256
  | $ZodJWT
5026
5257
  | $ZodCustomStringFormat<"hex">
5027
5258
  | $ZodCustomStringFormat<util.HashFormat>