zod 4.5.3 → 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 (348) 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 +316 -0
  15. package/src/v4/classic/tests/default.test.ts +46 -0
  16. package/src/v4/classic/tests/enum.test.ts +9 -0
  17. package/src/v4/classic/tests/error.test.ts +130 -1
  18. package/src/v4/classic/tests/firstparty.test.ts +4 -0
  19. package/src/v4/classic/tests/from-json-schema.test.ts +157 -0
  20. package/src/v4/classic/tests/iban.test.ts +81 -0
  21. package/src/v4/classic/tests/instance-footprint.test.ts +18 -2
  22. package/src/v4/classic/tests/instanceof.test.ts +27 -7
  23. package/src/v4/classic/tests/issue-schema.test.ts +88 -56
  24. package/src/v4/classic/tests/object.test.ts +56 -0
  25. package/src/v4/classic/tests/optin-ladder.test.ts +3 -2
  26. package/src/v4/classic/tests/properties.test.ts +225 -0
  27. package/src/v4/classic/tests/recursive-types.test.ts +1 -1
  28. package/src/v4/classic/tests/standard-schema.test.ts +19 -0
  29. package/src/v4/classic/tests/string.test.ts +25 -0
  30. package/src/v4/classic/tests/template-literal.test.ts +33 -1
  31. package/src/v4/classic/tests/to-json-schema.test.ts +147 -3
  32. package/src/v4/classic/tests/validate.test.ts +569 -0
  33. package/src/v4/core/api.ts +30 -6
  34. package/src/v4/core/checks.ts +1 -101
  35. package/src/v4/core/compile.ts +193 -81
  36. package/src/v4/core/doc.ts +6 -2
  37. package/src/v4/core/errors.ts +3 -6
  38. package/src/v4/core/json-schema-generator.ts +2 -2
  39. package/src/v4/core/json-schema-processors.ts +226 -68
  40. package/src/v4/core/memoizer.ts +162 -36
  41. package/src/v4/core/parse.ts +37 -16
  42. package/src/v4/core/regexes.ts +10 -4
  43. package/src/v4/core/schemas.ts +314 -83
  44. package/src/v4/core/tests/cached.test.ts +54 -0
  45. package/src/v4/core/tests/compile-generative.test.ts +445 -0
  46. package/src/v4/core/tests/compile.test.ts +222 -2
  47. package/src/v4/core/tests/email-regex.test.ts +140 -0
  48. package/src/v4/core/tests/polyfill-collision.test.ts +46 -0
  49. package/src/v4/core/to-json-schema.ts +10 -8
  50. package/src/v4/core/util.ts +222 -147
  51. package/src/v4/core/versions.ts +2 -2
  52. package/src/v4/core/visit.ts +11 -0
  53. package/src/v4/locales/ar.ts +1 -0
  54. package/src/v4/locales/az.ts +1 -0
  55. package/src/v4/locales/be.ts +1 -0
  56. package/src/v4/locales/bg.ts +1 -0
  57. package/src/v4/locales/bn.ts +1 -0
  58. package/src/v4/locales/ca.ts +1 -0
  59. package/src/v4/locales/ckb.ts +1 -0
  60. package/src/v4/locales/cs.ts +1 -0
  61. package/src/v4/locales/da.ts +1 -0
  62. package/src/v4/locales/de.ts +1 -0
  63. package/src/v4/locales/el.ts +1 -0
  64. package/src/v4/locales/en.ts +1 -0
  65. package/src/v4/locales/eo.ts +1 -0
  66. package/src/v4/locales/es.ts +1 -0
  67. package/src/v4/locales/fa.ts +1 -0
  68. package/src/v4/locales/fi.ts +1 -0
  69. package/src/v4/locales/fr-CA.ts +1 -0
  70. package/src/v4/locales/fr.ts +1 -0
  71. package/src/v4/locales/gu.ts +1 -0
  72. package/src/v4/locales/he.ts +1 -0
  73. package/src/v4/locales/hi.ts +1 -0
  74. package/src/v4/locales/hr.ts +1 -0
  75. package/src/v4/locales/hu.ts +1 -0
  76. package/src/v4/locales/hy.ts +1 -0
  77. package/src/v4/locales/id.ts +1 -0
  78. package/src/v4/locales/is.ts +1 -0
  79. package/src/v4/locales/it.ts +1 -0
  80. package/src/v4/locales/ja.ts +1 -0
  81. package/src/v4/locales/ka.ts +1 -0
  82. package/src/v4/locales/km.ts +1 -0
  83. package/src/v4/locales/kn.ts +1 -0
  84. package/src/v4/locales/ko.ts +1 -0
  85. package/src/v4/locales/lt.ts +1 -0
  86. package/src/v4/locales/mk.ts +1 -0
  87. package/src/v4/locales/ms.ts +1 -0
  88. package/src/v4/locales/ne.ts +1 -0
  89. package/src/v4/locales/nl.ts +1 -0
  90. package/src/v4/locales/nn.ts +1 -0
  91. package/src/v4/locales/no.ts +1 -0
  92. package/src/v4/locales/ota.ts +1 -0
  93. package/src/v4/locales/pl.ts +1 -0
  94. package/src/v4/locales/ps.ts +1 -0
  95. package/src/v4/locales/pt-BR.ts +1 -0
  96. package/src/v4/locales/pt.ts +1 -0
  97. package/src/v4/locales/ro.ts +1 -0
  98. package/src/v4/locales/ru.ts +1 -0
  99. package/src/v4/locales/sk.ts +1 -0
  100. package/src/v4/locales/sl.ts +1 -0
  101. package/src/v4/locales/sv.ts +1 -0
  102. package/src/v4/locales/ta.ts +1 -0
  103. package/src/v4/locales/th.ts +1 -0
  104. package/src/v4/locales/tk.ts +1 -0
  105. package/src/v4/locales/tr.ts +1 -0
  106. package/src/v4/locales/uk.ts +1 -0
  107. package/src/v4/locales/ur.ts +1 -0
  108. package/src/v4/locales/uz.ts +1 -0
  109. package/src/v4/locales/vi.ts +1 -0
  110. package/src/v4/locales/yo.ts +1 -0
  111. package/src/v4/locales/zh-CN.ts +1 -0
  112. package/src/v4/locales/zh-TW.ts +1 -0
  113. package/src/v4/mini/checks.ts +0 -1
  114. package/src/v4/mini/external.ts +2 -0
  115. package/src/v4/mini/schemas.ts +38 -2
  116. package/src/v4/mini/tests/checks.test.ts +1 -1
  117. package/src/v4/mini/tests/computed.test.ts +11 -17
  118. package/src/v4/mini/tests/index.test.ts +8 -0
  119. package/src/v4/mini/tests/string.test.ts +16 -0
  120. package/v3/ZodError.cjs +19 -0
  121. package/v3/errors.cjs +19 -0
  122. package/v3/external.cjs +19 -0
  123. package/v3/helpers/enumUtil.cjs +19 -0
  124. package/v3/helpers/errorUtil.cjs +20 -1
  125. package/v3/helpers/errorUtil.js +1 -1
  126. package/v3/helpers/parseUtil.cjs +19 -0
  127. package/v3/helpers/partialUtil.cjs +19 -0
  128. package/v3/helpers/typeAliases.cjs +19 -0
  129. package/v3/helpers/util.cjs +19 -0
  130. package/v3/index.cjs +19 -0
  131. package/v3/standard-schema.cjs +19 -0
  132. package/v3/types.cjs +19 -0
  133. package/v4/classic/checks.cjs +20 -2
  134. package/v4/classic/checks.d.cts +1 -1
  135. package/v4/classic/checks.d.ts +1 -1
  136. package/v4/classic/checks.js +1 -1
  137. package/v4/classic/coerce.cjs +19 -0
  138. package/v4/classic/compat.cjs +19 -0
  139. package/v4/classic/deep-partial.cjs +19 -0
  140. package/v4/classic/errors.cjs +19 -0
  141. package/v4/classic/external.cjs +22 -1
  142. package/v4/classic/external.d.cts +1 -1
  143. package/v4/classic/external.d.ts +1 -1
  144. package/v4/classic/external.js +1 -1
  145. package/v4/classic/from-json-schema.cjs +264 -24
  146. package/v4/classic/from-json-schema.js +245 -24
  147. package/v4/classic/in-out.cjs +19 -0
  148. package/v4/classic/index.cjs +19 -0
  149. package/v4/classic/iso.cjs +19 -0
  150. package/v4/classic/parse.cjs +19 -0
  151. package/v4/classic/schemas.cjs +100 -31
  152. package/v4/classic/schemas.d.cts +17 -1
  153. package/v4/classic/schemas.d.ts +17 -1
  154. package/v4/classic/schemas.js +77 -29
  155. package/v4/core/api.cjs +37 -2
  156. package/v4/core/api.d.cts +6 -4
  157. package/v4/core/api.d.ts +6 -4
  158. package/v4/core/api.js +17 -2
  159. package/v4/core/checks.cjs +19 -96
  160. package/v4/core/checks.d.cts +1 -1
  161. package/v4/core/checks.d.ts +1 -1
  162. package/v4/core/checks.js +0 -96
  163. package/v4/core/compile.cjs +164 -65
  164. package/v4/core/compile.d.cts +18 -4
  165. package/v4/core/compile.d.ts +18 -4
  166. package/v4/core/compile.js +145 -66
  167. package/v4/core/core.cjs +19 -0
  168. package/v4/core/doc.cjs +26 -2
  169. package/v4/core/doc.js +7 -2
  170. package/v4/core/errors.cjs +21 -5
  171. package/v4/core/errors.js +2 -5
  172. package/v4/core/index.cjs +19 -0
  173. package/v4/core/json-schema-generator.cjs +20 -1
  174. package/v4/core/json-schema-generator.js +2 -2
  175. package/v4/core/json-schema-processors.cjs +215 -63
  176. package/v4/core/json-schema-processors.d.cts +17 -0
  177. package/v4/core/json-schema-processors.d.ts +17 -0
  178. package/v4/core/json-schema-processors.js +195 -64
  179. package/v4/core/json-schema.cjs +19 -0
  180. package/v4/core/memoizer.cjs +204 -36
  181. package/v4/core/memoizer.js +162 -36
  182. package/v4/core/parse.cjs +56 -16
  183. package/v4/core/parse.js +37 -16
  184. package/v4/core/regexes.cjs +29 -6
  185. package/v4/core/regexes.d.cts +2 -0
  186. package/v4/core/regexes.d.ts +2 -0
  187. package/v4/core/regexes.js +8 -4
  188. package/v4/core/registries.cjs +19 -0
  189. package/v4/core/schemas.cjs +285 -66
  190. package/v4/core/schemas.d.cts +34 -3
  191. package/v4/core/schemas.d.ts +34 -3
  192. package/v4/core/schemas.js +264 -65
  193. package/v4/core/standard-schema.cjs +19 -0
  194. package/v4/core/to-json-schema.cjs +29 -7
  195. package/v4/core/to-json-schema.d.cts +7 -3
  196. package/v4/core/to-json-schema.d.ts +7 -3
  197. package/v4/core/to-json-schema.js +8 -7
  198. package/v4/core/util.cjs +181 -143
  199. package/v4/core/util.d.cts +25 -4
  200. package/v4/core/util.d.ts +25 -4
  201. package/v4/core/util.js +160 -143
  202. package/v4/core/versions.cjs +21 -2
  203. package/v4/core/versions.d.cts +1 -1
  204. package/v4/core/versions.d.ts +1 -1
  205. package/v4/core/versions.js +2 -2
  206. package/v4/core/visit.cjs +31 -0
  207. package/v4/core/visit.js +12 -0
  208. package/v4/index.cjs +19 -0
  209. package/v4/locales/ar.cjs +1 -0
  210. package/v4/locales/ar.js +1 -0
  211. package/v4/locales/az.cjs +1 -0
  212. package/v4/locales/az.js +1 -0
  213. package/v4/locales/be.cjs +1 -0
  214. package/v4/locales/be.js +1 -0
  215. package/v4/locales/bg.cjs +1 -0
  216. package/v4/locales/bg.js +1 -0
  217. package/v4/locales/bn.cjs +1 -0
  218. package/v4/locales/bn.js +1 -0
  219. package/v4/locales/ca.cjs +1 -0
  220. package/v4/locales/ca.js +1 -0
  221. package/v4/locales/ckb.cjs +1 -0
  222. package/v4/locales/ckb.js +1 -0
  223. package/v4/locales/cs.cjs +1 -0
  224. package/v4/locales/cs.js +1 -0
  225. package/v4/locales/da.cjs +1 -0
  226. package/v4/locales/da.js +1 -0
  227. package/v4/locales/de.cjs +1 -0
  228. package/v4/locales/de.js +1 -0
  229. package/v4/locales/el.cjs +1 -0
  230. package/v4/locales/el.js +1 -0
  231. package/v4/locales/en.cjs +1 -0
  232. package/v4/locales/en.js +1 -0
  233. package/v4/locales/eo.cjs +1 -0
  234. package/v4/locales/eo.js +1 -0
  235. package/v4/locales/es.cjs +1 -0
  236. package/v4/locales/es.js +1 -0
  237. package/v4/locales/fa.cjs +1 -0
  238. package/v4/locales/fa.js +1 -0
  239. package/v4/locales/fi.cjs +1 -0
  240. package/v4/locales/fi.js +1 -0
  241. package/v4/locales/fr-CA.cjs +1 -0
  242. package/v4/locales/fr-CA.js +1 -0
  243. package/v4/locales/fr.cjs +1 -0
  244. package/v4/locales/fr.js +1 -0
  245. package/v4/locales/gu.cjs +1 -0
  246. package/v4/locales/gu.js +1 -0
  247. package/v4/locales/he.cjs +1 -0
  248. package/v4/locales/he.js +1 -0
  249. package/v4/locales/hi.cjs +1 -0
  250. package/v4/locales/hi.js +1 -0
  251. package/v4/locales/hr.cjs +1 -0
  252. package/v4/locales/hr.js +1 -0
  253. package/v4/locales/hu.cjs +1 -0
  254. package/v4/locales/hu.js +1 -0
  255. package/v4/locales/hy.cjs +1 -0
  256. package/v4/locales/hy.js +1 -0
  257. package/v4/locales/id.cjs +1 -0
  258. package/v4/locales/id.js +1 -0
  259. package/v4/locales/index.cjs +19 -0
  260. package/v4/locales/is.cjs +1 -0
  261. package/v4/locales/is.js +1 -0
  262. package/v4/locales/it.cjs +1 -0
  263. package/v4/locales/it.js +1 -0
  264. package/v4/locales/ja.cjs +1 -0
  265. package/v4/locales/ja.js +1 -0
  266. package/v4/locales/ka.cjs +1 -0
  267. package/v4/locales/ka.js +1 -0
  268. package/v4/locales/km.cjs +1 -0
  269. package/v4/locales/km.js +1 -0
  270. package/v4/locales/kn.cjs +1 -0
  271. package/v4/locales/kn.js +1 -0
  272. package/v4/locales/ko.cjs +1 -0
  273. package/v4/locales/ko.js +1 -0
  274. package/v4/locales/lt.cjs +1 -0
  275. package/v4/locales/lt.js +1 -0
  276. package/v4/locales/mk.cjs +1 -0
  277. package/v4/locales/mk.js +1 -0
  278. package/v4/locales/ms.cjs +1 -0
  279. package/v4/locales/ms.js +1 -0
  280. package/v4/locales/ne.cjs +1 -0
  281. package/v4/locales/ne.js +1 -0
  282. package/v4/locales/nl.cjs +1 -0
  283. package/v4/locales/nl.js +1 -0
  284. package/v4/locales/nn.cjs +1 -0
  285. package/v4/locales/nn.js +1 -0
  286. package/v4/locales/no.cjs +1 -0
  287. package/v4/locales/no.js +1 -0
  288. package/v4/locales/ota.cjs +1 -0
  289. package/v4/locales/ota.js +1 -0
  290. package/v4/locales/pl.cjs +1 -0
  291. package/v4/locales/pl.js +1 -0
  292. package/v4/locales/ps.cjs +1 -0
  293. package/v4/locales/ps.js +1 -0
  294. package/v4/locales/pt-BR.cjs +1 -0
  295. package/v4/locales/pt-BR.js +1 -0
  296. package/v4/locales/pt.cjs +1 -0
  297. package/v4/locales/pt.js +1 -0
  298. package/v4/locales/ro.cjs +1 -0
  299. package/v4/locales/ro.js +1 -0
  300. package/v4/locales/ru.cjs +1 -0
  301. package/v4/locales/ru.js +1 -0
  302. package/v4/locales/sk.cjs +1 -0
  303. package/v4/locales/sk.js +1 -0
  304. package/v4/locales/sl.cjs +1 -0
  305. package/v4/locales/sl.js +1 -0
  306. package/v4/locales/sv.cjs +1 -0
  307. package/v4/locales/sv.js +1 -0
  308. package/v4/locales/ta.cjs +1 -0
  309. package/v4/locales/ta.js +1 -0
  310. package/v4/locales/th.cjs +1 -0
  311. package/v4/locales/th.js +1 -0
  312. package/v4/locales/tk.cjs +1 -0
  313. package/v4/locales/tk.js +1 -0
  314. package/v4/locales/tr.cjs +1 -0
  315. package/v4/locales/tr.js +1 -0
  316. package/v4/locales/uk.cjs +1 -0
  317. package/v4/locales/uk.js +1 -0
  318. package/v4/locales/ur.cjs +1 -0
  319. package/v4/locales/ur.js +1 -0
  320. package/v4/locales/uz.cjs +1 -0
  321. package/v4/locales/uz.js +1 -0
  322. package/v4/locales/vi.cjs +1 -0
  323. package/v4/locales/vi.js +1 -0
  324. package/v4/locales/yo.cjs +1 -0
  325. package/v4/locales/yo.js +1 -0
  326. package/v4/locales/zh-CN.cjs +1 -0
  327. package/v4/locales/zh-CN.js +1 -0
  328. package/v4/locales/zh-TW.cjs +1 -0
  329. package/v4/locales/zh-TW.js +1 -0
  330. package/v4/mini/checks.cjs +20 -2
  331. package/v4/mini/checks.d.cts +1 -1
  332. package/v4/mini/checks.d.ts +1 -1
  333. package/v4/mini/checks.js +1 -1
  334. package/v4/mini/coerce.cjs +19 -0
  335. package/v4/mini/deep-partial.cjs +19 -0
  336. package/v4/mini/external.cjs +22 -1
  337. package/v4/mini/external.d.cts +1 -1
  338. package/v4/mini/external.d.ts +1 -1
  339. package/v4/mini/external.js +1 -1
  340. package/v4/mini/in-out.cjs +19 -0
  341. package/v4/mini/index.cjs +19 -0
  342. package/v4/mini/iso.cjs +19 -0
  343. package/v4/mini/parse.cjs +19 -0
  344. package/v4/mini/schemas.cjs +42 -4
  345. package/v4/mini/schemas.d.cts +8 -0
  346. package/v4/mini/schemas.d.ts +8 -0
  347. package/v4/mini/schemas.js +19 -2
  348. package/v4-mini/index.cjs +19 -0
@@ -1,9 +1,33 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  Object.defineProperty(exports, "__esModule", { value: true });
3
26
  exports.$ZodCyclicError = void 0;
4
27
  exports.isRecursiveSchema = isRecursiveSchema;
5
28
  exports.memoizer = memoizer;
6
29
  exports.isBackEdge = isBackEdge;
30
+ const util = __importStar(require("./util.cjs"));
7
31
  class $ZodCyclicError extends Error {
8
32
  constructor() {
9
33
  super(`Cannot parse a reference cycle that closes through a transform`);
@@ -14,50 +38,168 @@ exports.$ZodCyclicError = $ZodCyclicError;
14
38
  /** Keyed off the context object every schema in one parse call already shares. */
15
39
  const STATE = "~memo";
16
40
  const NO_ISSUES = [];
41
+ // a value a cycle can close through; callables count, since z.properties asserts on one
42
+ function isRef(value) {
43
+ return value !== null && (typeof value === "object" || typeof value === "function");
44
+ }
17
45
  // Receivers prefix paths in place, so the cache and every hand-out need their own copies.
18
46
  function cloneIssues(issues) {
19
47
  return issues.map((iss) => (iss.path ? { ...iss, path: iss.path.slice() } : { ...iss }));
20
48
  }
21
49
  const recursive = /*@__PURE__*/ new WeakMap();
50
+ /** What the walk established, in order of certainty: ordered so the strongest answer among children wins. */
51
+ const NONE = 0;
52
+ const ASSUMED = 1;
53
+ const PROVEN = 2;
22
54
  /** Whether this schema's subtree contains a cycle, so one parse can re-enter it. */
23
- function isRecursive(inst, stack) {
55
+ function isRecursive(inst, stack, resolve) {
24
56
  const cached = recursive.get(inst);
25
57
  if (cached !== undefined)
26
- return cached;
58
+ return cached ? PROVEN : NONE;
27
59
  // Relative to the walk in progress, so not cached.
28
60
  if (stack.has(inst))
29
- return true;
61
+ return PROVEN;
30
62
  stack.add(inst);
31
- let result = false;
63
+ let result = NONE;
32
64
  const check = (child) => {
33
- if (!result && child?._zod && isRecursive(child, stack))
34
- result = true;
65
+ if (result !== PROVEN && child?._zod) {
66
+ const answer = isRecursive(child, stack, resolve);
67
+ if (answer > result)
68
+ result = answer;
69
+ }
35
70
  };
36
- const def = inst._zod.def;
37
- if (def.type === "lazy") {
38
- check(inst._zod.innerType);
39
- }
40
- else {
41
- // $ZodObject redefines `shape` as a non-enumerable accessor, so `for...in` misses it.
42
- const shape = def.shape;
43
- // `for...in` skips symbols, so a cycle through a declared symbol key would read as non-recursive
44
- if (shape)
45
- for (const key of Reflect.ownKeys(shape))
46
- check(shape[key]);
47
- for (const key in def) {
48
- const value = def[key];
49
- if (!value || typeof value !== "object")
71
+ // `Reflect.ownKeys` rather than `Object.keys`, so a cycle through a declared symbol key is still seen
72
+ const shape = (sh, spread) => {
73
+ let answer = NONE;
74
+ for (const key of Reflect.ownKeys(sh)) {
75
+ const desc = Object.getOwnPropertyDescriptor(sh, key);
76
+ // an object resolves its shape by spread, so a key it does not enumerate is never parsed; `z.properties` reads every own key and so keeps them all
77
+ if (spread && !desc.enumerable)
50
78
  continue;
51
- if (value._zod)
52
- check(value);
53
- else if (Array.isArray(value))
54
- for (const el of value)
55
- check(el);
79
+ // resolving runs user code, and a factory mints a fresh subtree per read, so an edge the walk can't follow counts as a cycle
80
+ const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve) : NONE;
81
+ if (child > answer)
82
+ answer = child;
83
+ }
84
+ return answer;
85
+ };
86
+ const merge = (answer) => {
87
+ if (answer > result)
88
+ result = answer;
89
+ };
90
+ const def = inst._zod.def;
91
+ const kind = def.type;
92
+ switch (kind) {
93
+ case "object": {
94
+ const raw = util.rawShape(def);
95
+ // a def with no raw shape answers `shape` from an accessor of its own, and running that can mint a whole fresh subtree
96
+ merge(raw ? shape(raw, true) : ASSUMED);
97
+ check(def.catchall);
98
+ break;
99
+ }
100
+ case "properties":
101
+ merge(shape(def.shape, false));
102
+ break;
103
+ case "array":
104
+ check(def.element);
105
+ break;
106
+ case "tuple":
107
+ for (const el of def.items)
108
+ check(el);
109
+ check(def.rest);
110
+ break;
111
+ case "record":
112
+ case "map":
113
+ check(def.keyType);
114
+ check(def.valueType);
115
+ break;
116
+ case "set":
117
+ check(def.valueType);
118
+ break;
119
+ case "union":
120
+ for (const el of def.options)
121
+ check(el);
122
+ break;
123
+ case "intersection":
124
+ check(def.left);
125
+ check(def.right);
126
+ break;
127
+ case "optional":
128
+ case "nullable":
129
+ case "default":
130
+ case "prefault":
131
+ case "catch":
132
+ case "readonly":
133
+ case "nonoptional":
134
+ case "promise":
135
+ case "success":
136
+ check(def.innerType);
137
+ break;
138
+ case "pipe":
139
+ check(def.in);
140
+ check(def.out);
141
+ break;
142
+ case "function":
143
+ check(def.input);
144
+ check(def.output);
145
+ break;
146
+ // `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
147
+ case "lazy": {
148
+ const inner = def._cachedInner ?? (resolve ? inst._zod.innerType : undefined);
149
+ // walked with resolution off: one hop sees past the deferral, and a lazy that yields only another unresolved lazy is generative, so it stops there
150
+ merge(inner ? isRecursive(inner, stack, false) : ASSUMED);
151
+ break;
152
+ }
153
+ // a leaf by choice: `parts` are regex fragments, not data positions
154
+ case "template_literal":
155
+ // leaves
156
+ case "string":
157
+ case "number":
158
+ case "int":
159
+ case "boolean":
160
+ case "bigint":
161
+ case "symbol":
162
+ case "undefined":
163
+ case "null":
164
+ case "void":
165
+ case "never":
166
+ case "any":
167
+ case "unknown":
168
+ case "date":
169
+ case "nan":
170
+ case "enum":
171
+ case "literal":
172
+ case "file":
173
+ case "transform":
174
+ case "custom":
175
+ break;
176
+ default: {
177
+ // a new built-in kind becomes a compile error here
178
+ kind;
179
+ // a user-defined kind can still hold children, and only its author knows where, so fall back to scanning the def — skipping accessors, since reading one can run user code
180
+ for (const key in def) {
181
+ const desc = Object.getOwnPropertyDescriptor(def, key);
182
+ if (!desc || desc.get)
183
+ continue;
184
+ const value = desc.value;
185
+ if (!value || typeof value !== "object")
186
+ continue;
187
+ if (value._zod)
188
+ check(value);
189
+ else if (Array.isArray(value))
190
+ for (const el of value)
191
+ check(el);
192
+ }
56
193
  }
57
194
  }
58
195
  stack.delete(inst);
59
- recursive.set(inst, result);
60
- return result;
196
+ return settle(inst, result);
197
+ }
198
+ /** An assumed answer must not outlive the resolution that settles it, so only a certain one is cached. */
199
+ function settle(inst, answer) {
200
+ if (answer !== ASSUMED)
201
+ recursive.set(inst, answer === PROVEN);
202
+ return answer;
61
203
  }
62
204
  /**
63
205
  * Whether one parse can re-enter this schema, i.e. its subtree contains a cycle.
@@ -66,12 +208,13 @@ function isRecursive(inst, stack) {
66
208
  * generated fast path has no context to key on.
67
209
  */
68
210
  function isRecursiveSchema(inst) {
69
- return isRecursive(inst, new Set());
211
+ // z.compile never parses, so nothing would ever resolve a lazy for it; it runs once and already treats a throw here as recursive
212
+ return isRecursive(inst, new Set(), true) !== NONE;
70
213
  }
71
214
  function bucketFor(state, inst) {
72
215
  let bucket = state.buckets.get(inst);
73
216
  if (!bucket) {
74
- bucket = new Map();
217
+ bucket = new WeakMap();
75
218
  state.buckets.set(inst, bucket);
76
219
  }
77
220
  return bucket;
@@ -110,7 +253,8 @@ const memo = {
110
253
  attach(inst) {
111
254
  var _a;
112
255
  let isRecursiveInst;
113
- // `bucket` memoized for one parse; a recursive schema is re-entered many times and its bucket never changes
256
+ let rechecked = false;
257
+ // a recursive schema is re-entered many times per parse and its bucket never changes
114
258
  let lastCtx;
115
259
  let lastBucket;
116
260
  // Wraps `parse` in a deferred so it sees the container's final parse. Core's own deferred copies `parse` into `run` when there are no checks, and it ran first, so `run` is patched to match; with checks, `run` reads `parse` dynamically.
@@ -119,21 +263,26 @@ const memo = {
119
263
  const base = inst._zod.parse;
120
264
  const wrapped = (payload, ctx) => {
121
265
  if (isRecursiveInst === undefined) {
122
- isRecursiveInst = isRecursive(inst, new Set());
123
- if (!isRecursiveInst) {
266
+ const walked = isRecursive(inst, new Set(), false);
267
+ if (walked === NONE) {
124
268
  // Nothing here can ever fire, so take it back out.
125
269
  inst._zod.parse = base;
126
270
  if (inst._zod.run === wrapped)
127
271
  inst._zod.run = base;
128
272
  return base(payload, ctx);
129
273
  }
274
+ // this parse resolves the deferred edges on its own path, so ask once more before latching
275
+ if (walked === PROVEN || rechecked)
276
+ isRecursiveInst = true;
277
+ else
278
+ rechecked = true;
130
279
  }
131
280
  const input = payload.value;
132
- if (input === null || typeof input !== "object")
281
+ if (!isRef(input))
133
282
  return base(payload, ctx);
134
283
  let state = ctx[STATE];
135
284
  if (!state) {
136
- state = { buckets: new Map(), backEdges: undefined };
285
+ state = { buckets: new WeakMap(), backEdges: undefined };
137
286
  ctx[STATE] = state;
138
287
  }
139
288
  let bucket;
@@ -155,7 +304,7 @@ const memo = {
155
304
  else {
156
305
  // Still being parsed: its own checks cover it, so skip them here.
157
306
  payload.memo = true;
158
- state.backEdges ?? (state.backEdges = new Set());
307
+ state.backEdges ?? (state.backEdges = new WeakSet());
159
308
  state.backEdges.add(hit.value);
160
309
  }
161
310
  return payload;
@@ -191,5 +340,24 @@ function memoizer() {
191
340
  /** Whether this value is a node a back-edge resolved to before it finished. */
192
341
  function isBackEdge(ctx, value) {
193
342
  const backEdges = ctx[STATE]?.backEdges;
194
- return backEdges !== undefined && value !== null && typeof value === "object" && backEdges.has(value);
343
+ return backEdges !== undefined && isRef(value) && backEdges.has(value);
195
344
  }
345
+
346
+ // seal-cjs-exports
347
+ (function () {
348
+ var keys = Object.getOwnPropertyNames(exports);
349
+ for (var i = 0; i < keys.length; i++) {
350
+ var desc = Object.getOwnPropertyDescriptor(exports, keys[i]);
351
+ if (!desc || !desc.get || !desc.configurable) continue;
352
+ var value;
353
+ try {
354
+ value = desc.get();
355
+ } catch (e) {
356
+ continue;
357
+ }
358
+ // a circular require may not have settled this one yet, so leave it live
359
+ if (value === undefined) continue;
360
+ Object.defineProperty(exports, keys[i], { value: value, writable: false, enumerable: desc.enumerable, configurable: false });
361
+ }
362
+ Object.freeze(exports);
363
+ })();
@@ -1,3 +1,4 @@
1
+ import * as util from "./util.js";
1
2
  export class $ZodCyclicError extends Error {
2
3
  constructor() {
3
4
  super(`Cannot parse a reference cycle that closes through a transform`);
@@ -7,50 +8,168 @@ export class $ZodCyclicError extends Error {
7
8
  /** Keyed off the context object every schema in one parse call already shares. */
8
9
  const STATE = "~memo";
9
10
  const NO_ISSUES = [];
11
+ // a value a cycle can close through; callables count, since z.properties asserts on one
12
+ function isRef(value) {
13
+ return value !== null && (typeof value === "object" || typeof value === "function");
14
+ }
10
15
  // Receivers prefix paths in place, so the cache and every hand-out need their own copies.
11
16
  function cloneIssues(issues) {
12
17
  return issues.map((iss) => (iss.path ? { ...iss, path: iss.path.slice() } : { ...iss }));
13
18
  }
14
19
  const recursive = /*@__PURE__*/ new WeakMap();
20
+ /** What the walk established, in order of certainty: ordered so the strongest answer among children wins. */
21
+ const NONE = 0;
22
+ const ASSUMED = 1;
23
+ const PROVEN = 2;
15
24
  /** Whether this schema's subtree contains a cycle, so one parse can re-enter it. */
16
- function isRecursive(inst, stack) {
25
+ function isRecursive(inst, stack, resolve) {
17
26
  const cached = recursive.get(inst);
18
27
  if (cached !== undefined)
19
- return cached;
28
+ return cached ? PROVEN : NONE;
20
29
  // Relative to the walk in progress, so not cached.
21
30
  if (stack.has(inst))
22
- return true;
31
+ return PROVEN;
23
32
  stack.add(inst);
24
- let result = false;
33
+ let result = NONE;
25
34
  const check = (child) => {
26
- if (!result && child?._zod && isRecursive(child, stack))
27
- result = true;
35
+ if (result !== PROVEN && child?._zod) {
36
+ const answer = isRecursive(child, stack, resolve);
37
+ if (answer > result)
38
+ result = answer;
39
+ }
28
40
  };
29
- const def = inst._zod.def;
30
- if (def.type === "lazy") {
31
- check(inst._zod.innerType);
32
- }
33
- else {
34
- // $ZodObject redefines `shape` as a non-enumerable accessor, so `for...in` misses it.
35
- const shape = def.shape;
36
- // `for...in` skips symbols, so a cycle through a declared symbol key would read as non-recursive
37
- if (shape)
38
- for (const key of Reflect.ownKeys(shape))
39
- check(shape[key]);
40
- for (const key in def) {
41
- const value = def[key];
42
- if (!value || typeof value !== "object")
41
+ // `Reflect.ownKeys` rather than `Object.keys`, so a cycle through a declared symbol key is still seen
42
+ const shape = (sh, spread) => {
43
+ let answer = NONE;
44
+ for (const key of Reflect.ownKeys(sh)) {
45
+ const desc = Object.getOwnPropertyDescriptor(sh, key);
46
+ // an object resolves its shape by spread, so a key it does not enumerate is never parsed; `z.properties` reads every own key and so keeps them all
47
+ if (spread && !desc.enumerable)
43
48
  continue;
44
- if (value._zod)
45
- check(value);
46
- else if (Array.isArray(value))
47
- for (const el of value)
48
- check(el);
49
+ // resolving runs user code, and a factory mints a fresh subtree per read, so an edge the walk can't follow counts as a cycle
50
+ const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve) : NONE;
51
+ if (child > answer)
52
+ answer = child;
53
+ }
54
+ return answer;
55
+ };
56
+ const merge = (answer) => {
57
+ if (answer > result)
58
+ result = answer;
59
+ };
60
+ const def = inst._zod.def;
61
+ const kind = def.type;
62
+ switch (kind) {
63
+ case "object": {
64
+ const raw = util.rawShape(def);
65
+ // a def with no raw shape answers `shape` from an accessor of its own, and running that can mint a whole fresh subtree
66
+ merge(raw ? shape(raw, true) : ASSUMED);
67
+ check(def.catchall);
68
+ break;
69
+ }
70
+ case "properties":
71
+ merge(shape(def.shape, false));
72
+ break;
73
+ case "array":
74
+ check(def.element);
75
+ break;
76
+ case "tuple":
77
+ for (const el of def.items)
78
+ check(el);
79
+ check(def.rest);
80
+ break;
81
+ case "record":
82
+ case "map":
83
+ check(def.keyType);
84
+ check(def.valueType);
85
+ break;
86
+ case "set":
87
+ check(def.valueType);
88
+ break;
89
+ case "union":
90
+ for (const el of def.options)
91
+ check(el);
92
+ break;
93
+ case "intersection":
94
+ check(def.left);
95
+ check(def.right);
96
+ break;
97
+ case "optional":
98
+ case "nullable":
99
+ case "default":
100
+ case "prefault":
101
+ case "catch":
102
+ case "readonly":
103
+ case "nonoptional":
104
+ case "promise":
105
+ case "success":
106
+ check(def.innerType);
107
+ break;
108
+ case "pipe":
109
+ check(def.in);
110
+ check(def.out);
111
+ break;
112
+ case "function":
113
+ check(def.input);
114
+ check(def.output);
115
+ break;
116
+ // `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
117
+ case "lazy": {
118
+ const inner = def._cachedInner ?? (resolve ? inst._zod.innerType : undefined);
119
+ // walked with resolution off: one hop sees past the deferral, and a lazy that yields only another unresolved lazy is generative, so it stops there
120
+ merge(inner ? isRecursive(inner, stack, false) : ASSUMED);
121
+ break;
122
+ }
123
+ // a leaf by choice: `parts` are regex fragments, not data positions
124
+ case "template_literal":
125
+ // leaves
126
+ case "string":
127
+ case "number":
128
+ case "int":
129
+ case "boolean":
130
+ case "bigint":
131
+ case "symbol":
132
+ case "undefined":
133
+ case "null":
134
+ case "void":
135
+ case "never":
136
+ case "any":
137
+ case "unknown":
138
+ case "date":
139
+ case "nan":
140
+ case "enum":
141
+ case "literal":
142
+ case "file":
143
+ case "transform":
144
+ case "custom":
145
+ break;
146
+ default: {
147
+ // a new built-in kind becomes a compile error here
148
+ kind;
149
+ // a user-defined kind can still hold children, and only its author knows where, so fall back to scanning the def — skipping accessors, since reading one can run user code
150
+ for (const key in def) {
151
+ const desc = Object.getOwnPropertyDescriptor(def, key);
152
+ if (!desc || desc.get)
153
+ continue;
154
+ const value = desc.value;
155
+ if (!value || typeof value !== "object")
156
+ continue;
157
+ if (value._zod)
158
+ check(value);
159
+ else if (Array.isArray(value))
160
+ for (const el of value)
161
+ check(el);
162
+ }
49
163
  }
50
164
  }
51
165
  stack.delete(inst);
52
- recursive.set(inst, result);
53
- return result;
166
+ return settle(inst, result);
167
+ }
168
+ /** An assumed answer must not outlive the resolution that settles it, so only a certain one is cached. */
169
+ function settle(inst, answer) {
170
+ if (answer !== ASSUMED)
171
+ recursive.set(inst, answer === PROVEN);
172
+ return answer;
54
173
  }
55
174
  /**
56
175
  * Whether one parse can re-enter this schema, i.e. its subtree contains a cycle.
@@ -59,12 +178,13 @@ function isRecursive(inst, stack) {
59
178
  * generated fast path has no context to key on.
60
179
  */
61
180
  export function isRecursiveSchema(inst) {
62
- return isRecursive(inst, new Set());
181
+ // z.compile never parses, so nothing would ever resolve a lazy for it; it runs once and already treats a throw here as recursive
182
+ return isRecursive(inst, new Set(), true) !== NONE;
63
183
  }
64
184
  function bucketFor(state, inst) {
65
185
  let bucket = state.buckets.get(inst);
66
186
  if (!bucket) {
67
- bucket = new Map();
187
+ bucket = new WeakMap();
68
188
  state.buckets.set(inst, bucket);
69
189
  }
70
190
  return bucket;
@@ -103,7 +223,8 @@ const memo = {
103
223
  attach(inst) {
104
224
  var _a;
105
225
  let isRecursiveInst;
106
- // `bucket` memoized for one parse; a recursive schema is re-entered many times and its bucket never changes
226
+ let rechecked = false;
227
+ // a recursive schema is re-entered many times per parse and its bucket never changes
107
228
  let lastCtx;
108
229
  let lastBucket;
109
230
  // Wraps `parse` in a deferred so it sees the container's final parse. Core's own deferred copies `parse` into `run` when there are no checks, and it ran first, so `run` is patched to match; with checks, `run` reads `parse` dynamically.
@@ -112,21 +233,26 @@ const memo = {
112
233
  const base = inst._zod.parse;
113
234
  const wrapped = (payload, ctx) => {
114
235
  if (isRecursiveInst === undefined) {
115
- isRecursiveInst = isRecursive(inst, new Set());
116
- if (!isRecursiveInst) {
236
+ const walked = isRecursive(inst, new Set(), false);
237
+ if (walked === NONE) {
117
238
  // Nothing here can ever fire, so take it back out.
118
239
  inst._zod.parse = base;
119
240
  if (inst._zod.run === wrapped)
120
241
  inst._zod.run = base;
121
242
  return base(payload, ctx);
122
243
  }
244
+ // this parse resolves the deferred edges on its own path, so ask once more before latching
245
+ if (walked === PROVEN || rechecked)
246
+ isRecursiveInst = true;
247
+ else
248
+ rechecked = true;
123
249
  }
124
250
  const input = payload.value;
125
- if (input === null || typeof input !== "object")
251
+ if (!isRef(input))
126
252
  return base(payload, ctx);
127
253
  let state = ctx[STATE];
128
254
  if (!state) {
129
- state = { buckets: new Map(), backEdges: undefined };
255
+ state = { buckets: new WeakMap(), backEdges: undefined };
130
256
  ctx[STATE] = state;
131
257
  }
132
258
  let bucket;
@@ -148,7 +274,7 @@ const memo = {
148
274
  else {
149
275
  // Still being parsed: its own checks cover it, so skip them here.
150
276
  payload.memo = true;
151
- state.backEdges ?? (state.backEdges = new Set());
277
+ state.backEdges ?? (state.backEdges = new WeakSet());
152
278
  state.backEdges.add(hit.value);
153
279
  }
154
280
  return payload;
@@ -184,5 +310,5 @@ export function memoizer() {
184
310
  /** Whether this value is a node a back-edge resolved to before it finished. */
185
311
  export function isBackEdge(ctx, value) {
186
312
  const backEdges = ctx[STATE]?.backEdges;
187
- return backEdges !== undefined && value !== null && typeof value === "object" && backEdges.has(value);
313
+ return backEdges !== undefined && isRef(value) && backEdges.has(value);
188
314
  }