zod 4.6.3 → 4.6.4

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 (231) hide show
  1. package/package.json +1 -1
  2. package/src/v4/classic/schemas.ts +9 -4
  3. package/src/v4/classic/tests/assignability.test.ts +1 -0
  4. package/src/v4/classic/tests/instance-footprint.test.ts +22 -0
  5. package/src/v4/classic/tests/number.test.ts +39 -0
  6. package/src/v4/classic/tests/string.test.ts +70 -1
  7. package/src/v4/classic/tests/to-json-schema.test.ts +87 -35
  8. package/src/v4/core/api.ts +17 -22
  9. package/src/v4/core/compile.ts +27 -6
  10. package/src/v4/core/core.ts +1 -3
  11. package/src/v4/core/json-schema-processors.ts +9 -13
  12. package/src/v4/core/regexes.ts +4 -0
  13. package/src/v4/core/schemas.ts +35 -11
  14. package/src/v4/core/tests/compile-differential.test.ts +35 -0
  15. package/src/v4/core/tests/compile.test.ts +177 -0
  16. package/src/v4/core/tests/url-no-canparse.test.ts +118 -16
  17. package/src/v4/core/versions.ts +1 -1
  18. package/src/v4/locales/ar.ts +1 -0
  19. package/src/v4/locales/az.ts +1 -0
  20. package/src/v4/locales/be.ts +1 -0
  21. package/src/v4/locales/bg.ts +1 -0
  22. package/src/v4/locales/bn.ts +1 -0
  23. package/src/v4/locales/ca.ts +1 -0
  24. package/src/v4/locales/ckb.ts +1 -0
  25. package/src/v4/locales/cs.ts +1 -0
  26. package/src/v4/locales/da.ts +1 -0
  27. package/src/v4/locales/de.ts +1 -0
  28. package/src/v4/locales/el.ts +1 -0
  29. package/src/v4/locales/en.ts +1 -0
  30. package/src/v4/locales/eo.ts +1 -0
  31. package/src/v4/locales/es.ts +1 -0
  32. package/src/v4/locales/fa.ts +1 -0
  33. package/src/v4/locales/fi.ts +1 -0
  34. package/src/v4/locales/fr-CA.ts +1 -0
  35. package/src/v4/locales/fr.ts +1 -0
  36. package/src/v4/locales/gu.ts +1 -0
  37. package/src/v4/locales/he.ts +1 -0
  38. package/src/v4/locales/hi.ts +1 -0
  39. package/src/v4/locales/hr.ts +1 -0
  40. package/src/v4/locales/hu.ts +1 -0
  41. package/src/v4/locales/hy.ts +1 -0
  42. package/src/v4/locales/id.ts +1 -0
  43. package/src/v4/locales/is.ts +1 -0
  44. package/src/v4/locales/it.ts +1 -0
  45. package/src/v4/locales/ja.ts +1 -0
  46. package/src/v4/locales/ka.ts +1 -0
  47. package/src/v4/locales/km.ts +1 -0
  48. package/src/v4/locales/kn.ts +1 -0
  49. package/src/v4/locales/ko.ts +1 -0
  50. package/src/v4/locales/lt.ts +1 -0
  51. package/src/v4/locales/mk.ts +1 -0
  52. package/src/v4/locales/ms.ts +1 -0
  53. package/src/v4/locales/ne.ts +1 -0
  54. package/src/v4/locales/nl.ts +1 -0
  55. package/src/v4/locales/nn.ts +1 -0
  56. package/src/v4/locales/no.ts +1 -0
  57. package/src/v4/locales/ota.ts +1 -0
  58. package/src/v4/locales/pl.ts +1 -0
  59. package/src/v4/locales/ps.ts +1 -0
  60. package/src/v4/locales/pt-BR.ts +1 -0
  61. package/src/v4/locales/pt.ts +1 -0
  62. package/src/v4/locales/ro.ts +1 -0
  63. package/src/v4/locales/ru.ts +1 -0
  64. package/src/v4/locales/sk.ts +1 -0
  65. package/src/v4/locales/sl.ts +1 -0
  66. package/src/v4/locales/sv.ts +1 -0
  67. package/src/v4/locales/ta.ts +1 -0
  68. package/src/v4/locales/tg.ts +1 -0
  69. package/src/v4/locales/th.ts +1 -0
  70. package/src/v4/locales/tk.ts +1 -0
  71. package/src/v4/locales/tr.ts +1 -0
  72. package/src/v4/locales/uk.ts +1 -0
  73. package/src/v4/locales/ur.ts +1 -0
  74. package/src/v4/locales/uz.ts +1 -0
  75. package/src/v4/locales/vi.ts +1 -0
  76. package/src/v4/locales/yo.ts +1 -0
  77. package/src/v4/locales/zh-CN.ts +1 -0
  78. package/src/v4/locales/zh-TW.ts +1 -0
  79. package/src/v4/mini/schemas.ts +12 -4
  80. package/src/v4/mini/tests/index.test.ts +56 -0
  81. package/src/v4/mini/tests/string.test.ts +7 -0
  82. package/v4/classic/schemas.cjs +9 -4
  83. package/v4/classic/schemas.d.cts +1 -0
  84. package/v4/classic/schemas.d.ts +1 -0
  85. package/v4/classic/schemas.js +8 -4
  86. package/v4/core/api.cjs +9 -20
  87. package/v4/core/api.d.cts +6 -2
  88. package/v4/core/api.d.ts +6 -2
  89. package/v4/core/api.js +9 -20
  90. package/v4/core/compile.cjs +7 -6
  91. package/v4/core/compile.js +8 -7
  92. package/v4/core/core.cjs +1 -1
  93. package/v4/core/core.js +1 -1
  94. package/v4/core/json-schema-processors.cjs +7 -10
  95. package/v4/core/json-schema-processors.js +7 -10
  96. package/v4/core/regexes.cjs +4 -2
  97. package/v4/core/regexes.d.cts +1 -0
  98. package/v4/core/regexes.d.ts +1 -0
  99. package/v4/core/regexes.js +2 -0
  100. package/v4/core/schemas.cjs +32 -11
  101. package/v4/core/schemas.d.cts +5 -3
  102. package/v4/core/schemas.d.ts +5 -3
  103. package/v4/core/schemas.js +30 -11
  104. package/v4/core/versions.cjs +1 -1
  105. package/v4/core/versions.js +1 -1
  106. package/v4/locales/ar.cjs +1 -0
  107. package/v4/locales/ar.js +1 -0
  108. package/v4/locales/az.cjs +1 -0
  109. package/v4/locales/az.js +1 -0
  110. package/v4/locales/be.cjs +1 -0
  111. package/v4/locales/be.js +1 -0
  112. package/v4/locales/bg.cjs +1 -0
  113. package/v4/locales/bg.js +1 -0
  114. package/v4/locales/bn.cjs +1 -0
  115. package/v4/locales/bn.js +1 -0
  116. package/v4/locales/ca.cjs +1 -0
  117. package/v4/locales/ca.js +1 -0
  118. package/v4/locales/ckb.cjs +1 -0
  119. package/v4/locales/ckb.js +1 -0
  120. package/v4/locales/cs.cjs +1 -0
  121. package/v4/locales/cs.js +1 -0
  122. package/v4/locales/da.cjs +1 -0
  123. package/v4/locales/da.js +1 -0
  124. package/v4/locales/de.cjs +1 -0
  125. package/v4/locales/de.js +1 -0
  126. package/v4/locales/el.cjs +1 -0
  127. package/v4/locales/el.js +1 -0
  128. package/v4/locales/en.cjs +1 -0
  129. package/v4/locales/en.js +1 -0
  130. package/v4/locales/eo.cjs +1 -0
  131. package/v4/locales/eo.js +1 -0
  132. package/v4/locales/es.cjs +1 -0
  133. package/v4/locales/es.js +1 -0
  134. package/v4/locales/fa.cjs +1 -0
  135. package/v4/locales/fa.js +1 -0
  136. package/v4/locales/fi.cjs +1 -0
  137. package/v4/locales/fi.js +1 -0
  138. package/v4/locales/fr-CA.cjs +1 -0
  139. package/v4/locales/fr-CA.js +1 -0
  140. package/v4/locales/fr.cjs +1 -0
  141. package/v4/locales/fr.js +1 -0
  142. package/v4/locales/gu.cjs +1 -0
  143. package/v4/locales/gu.js +1 -0
  144. package/v4/locales/he.cjs +1 -0
  145. package/v4/locales/he.js +1 -0
  146. package/v4/locales/hi.cjs +1 -0
  147. package/v4/locales/hi.js +1 -0
  148. package/v4/locales/hr.cjs +1 -0
  149. package/v4/locales/hr.js +1 -0
  150. package/v4/locales/hu.cjs +1 -0
  151. package/v4/locales/hu.js +1 -0
  152. package/v4/locales/hy.cjs +1 -0
  153. package/v4/locales/hy.js +1 -0
  154. package/v4/locales/id.cjs +1 -0
  155. package/v4/locales/id.js +1 -0
  156. package/v4/locales/is.cjs +1 -0
  157. package/v4/locales/is.js +1 -0
  158. package/v4/locales/it.cjs +1 -0
  159. package/v4/locales/it.js +1 -0
  160. package/v4/locales/ja.cjs +1 -0
  161. package/v4/locales/ja.js +1 -0
  162. package/v4/locales/ka.cjs +1 -0
  163. package/v4/locales/ka.js +1 -0
  164. package/v4/locales/km.cjs +1 -0
  165. package/v4/locales/km.js +1 -0
  166. package/v4/locales/kn.cjs +1 -0
  167. package/v4/locales/kn.js +1 -0
  168. package/v4/locales/ko.cjs +1 -0
  169. package/v4/locales/ko.js +1 -0
  170. package/v4/locales/lt.cjs +1 -0
  171. package/v4/locales/lt.js +1 -0
  172. package/v4/locales/mk.cjs +1 -0
  173. package/v4/locales/mk.js +1 -0
  174. package/v4/locales/ms.cjs +1 -0
  175. package/v4/locales/ms.js +1 -0
  176. package/v4/locales/ne.cjs +1 -0
  177. package/v4/locales/ne.js +1 -0
  178. package/v4/locales/nl.cjs +1 -0
  179. package/v4/locales/nl.js +1 -0
  180. package/v4/locales/nn.cjs +1 -0
  181. package/v4/locales/nn.js +1 -0
  182. package/v4/locales/no.cjs +1 -0
  183. package/v4/locales/no.js +1 -0
  184. package/v4/locales/ota.cjs +1 -0
  185. package/v4/locales/ota.js +1 -0
  186. package/v4/locales/pl.cjs +1 -0
  187. package/v4/locales/pl.js +1 -0
  188. package/v4/locales/ps.cjs +1 -0
  189. package/v4/locales/ps.js +1 -0
  190. package/v4/locales/pt-BR.cjs +1 -0
  191. package/v4/locales/pt-BR.js +1 -0
  192. package/v4/locales/pt.cjs +1 -0
  193. package/v4/locales/pt.js +1 -0
  194. package/v4/locales/ro.cjs +1 -0
  195. package/v4/locales/ro.js +1 -0
  196. package/v4/locales/ru.cjs +1 -0
  197. package/v4/locales/ru.js +1 -0
  198. package/v4/locales/sk.cjs +1 -0
  199. package/v4/locales/sk.js +1 -0
  200. package/v4/locales/sl.cjs +1 -0
  201. package/v4/locales/sl.js +1 -0
  202. package/v4/locales/sv.cjs +1 -0
  203. package/v4/locales/sv.js +1 -0
  204. package/v4/locales/ta.cjs +1 -0
  205. package/v4/locales/ta.js +1 -0
  206. package/v4/locales/tg.cjs +1 -0
  207. package/v4/locales/tg.js +1 -0
  208. package/v4/locales/th.cjs +1 -0
  209. package/v4/locales/th.js +1 -0
  210. package/v4/locales/tk.cjs +1 -0
  211. package/v4/locales/tk.js +1 -0
  212. package/v4/locales/tr.cjs +1 -0
  213. package/v4/locales/tr.js +1 -0
  214. package/v4/locales/uk.cjs +1 -0
  215. package/v4/locales/uk.js +1 -0
  216. package/v4/locales/ur.cjs +1 -0
  217. package/v4/locales/ur.js +1 -0
  218. package/v4/locales/uz.cjs +1 -0
  219. package/v4/locales/uz.js +1 -0
  220. package/v4/locales/vi.cjs +1 -0
  221. package/v4/locales/vi.js +1 -0
  222. package/v4/locales/yo.cjs +1 -0
  223. package/v4/locales/yo.js +1 -0
  224. package/v4/locales/zh-CN.cjs +1 -0
  225. package/v4/locales/zh-CN.js +1 -0
  226. package/v4/locales/zh-TW.cjs +1 -0
  227. package/v4/locales/zh-TW.js +1 -0
  228. package/v4/mini/schemas.cjs +10 -4
  229. package/v4/mini/schemas.d.cts +1 -0
  230. package/v4/mini/schemas.d.ts +1 -0
  231. package/v4/mini/schemas.js +9 -4
package/v4/core/api.d.cts CHANGED
@@ -17,7 +17,9 @@ AlsoOmit extends Exclude<keyof T["_zod"]["def"], "check" | "error"> = never> = P
17
17
  export type StringFormatParams<T extends schemas.$ZodStringFormat = schemas.$ZodStringFormat, AlsoOmit extends Exclude<keyof T["_zod"]["def"], "type" | "coerce" | "checks" | "error" | "check" | "format"> = never> = Params<T, NonNullable<T["_zod"]["isst"] | T["_zod"]["issc"]>, "type" | "coerce" | "checks" | "error" | "check" | "format" | AlsoOmit>;
18
18
  export type CheckStringFormatParams<T extends schemas.$ZodStringFormat = schemas.$ZodStringFormat, AlsoOmit extends Exclude<keyof T["_zod"]["def"], "type" | "coerce" | "checks" | "error" | "check" | "format"> = never> = Params<T, NonNullable<T["_zod"]["issc"]>, "type" | "coerce" | "checks" | "error" | "check" | "format" | AlsoOmit>;
19
19
  export type CheckTypeParams<T extends schemas.$ZodType & checks.$ZodCheck = schemas.$ZodType & checks.$ZodCheck, AlsoOmit extends Exclude<keyof T["_zod"]["def"], "type" | "checks" | "error" | "check"> = never> = Params<T, NonNullable<T["_zod"]["isst"] | T["_zod"]["issc"]>, "type" | "checks" | "error" | "check" | AlsoOmit>;
20
- export type $ZodStringParams = TypeParams<schemas.$ZodString<string>, "coerce">;
20
+ export type $ZodStringParams = TypeParams<schemas.$ZodString<string>, "coerce"> & {
21
+ checks?: readonly checks.$ZodCheck<string>[];
22
+ };
21
23
  export declare function _string<T extends schemas.$ZodString>(Class: util.SchemaClass<T>, params?: string | $ZodStringParams): T;
22
24
  export declare function _coercedString<T extends schemas.$ZodString>(Class: util.SchemaClass<T>, params?: string | $ZodStringParams): T;
23
25
  export type $ZodStringFormatParams = CheckTypeParams<schemas.$ZodStringFormat, "format" | "coerce" | "when" | "pattern">;
@@ -131,7 +133,9 @@ export declare function _isoTime<T extends schemas.$ZodISOTime>(Class: util.Sche
131
133
  export type $ZodISODurationParams = StringFormatParams<schemas.$ZodISODuration, "when">;
132
134
  export type $ZodCheckISODurationParams = CheckStringFormatParams<schemas.$ZodISODuration, "when">;
133
135
  export declare function _isoDuration<T extends schemas.$ZodISODuration>(Class: util.SchemaClass<T>, params?: string | $ZodISODurationParams | $ZodCheckISODurationParams): T;
134
- export type $ZodNumberParams = TypeParams<schemas.$ZodNumber<number>, "coerce">;
136
+ export type $ZodNumberParams = TypeParams<schemas.$ZodNumber<number>, "coerce"> & {
137
+ checks?: readonly checks.$ZodCheck<number>[];
138
+ };
135
139
  export type $ZodNumberFormatParams = CheckTypeParams<schemas.$ZodNumberFormat, "format" | "coerce">;
136
140
  export type $ZodCheckNumberFormatParams = CheckParams<checks.$ZodCheckNumberFormat, "format" | "when">;
137
141
  export declare function _number<T extends schemas.$ZodNumber>(Class: util.SchemaClass<T>, params?: string | $ZodNumberParams): T;
package/v4/core/api.d.ts CHANGED
@@ -17,7 +17,9 @@ AlsoOmit extends Exclude<keyof T["_zod"]["def"], "check" | "error"> = never> = P
17
17
  export type StringFormatParams<T extends schemas.$ZodStringFormat = schemas.$ZodStringFormat, AlsoOmit extends Exclude<keyof T["_zod"]["def"], "type" | "coerce" | "checks" | "error" | "check" | "format"> = never> = Params<T, NonNullable<T["_zod"]["isst"] | T["_zod"]["issc"]>, "type" | "coerce" | "checks" | "error" | "check" | "format" | AlsoOmit>;
18
18
  export type CheckStringFormatParams<T extends schemas.$ZodStringFormat = schemas.$ZodStringFormat, AlsoOmit extends Exclude<keyof T["_zod"]["def"], "type" | "coerce" | "checks" | "error" | "check" | "format"> = never> = Params<T, NonNullable<T["_zod"]["issc"]>, "type" | "coerce" | "checks" | "error" | "check" | "format" | AlsoOmit>;
19
19
  export type CheckTypeParams<T extends schemas.$ZodType & checks.$ZodCheck = schemas.$ZodType & checks.$ZodCheck, AlsoOmit extends Exclude<keyof T["_zod"]["def"], "type" | "checks" | "error" | "check"> = never> = Params<T, NonNullable<T["_zod"]["isst"] | T["_zod"]["issc"]>, "type" | "checks" | "error" | "check" | AlsoOmit>;
20
- export type $ZodStringParams = TypeParams<schemas.$ZodString<string>, "coerce">;
20
+ export type $ZodStringParams = TypeParams<schemas.$ZodString<string>, "coerce"> & {
21
+ checks?: readonly checks.$ZodCheck<string>[];
22
+ };
21
23
  export declare function _string<T extends schemas.$ZodString>(Class: util.SchemaClass<T>, params?: string | $ZodStringParams): T;
22
24
  export declare function _coercedString<T extends schemas.$ZodString>(Class: util.SchemaClass<T>, params?: string | $ZodStringParams): T;
23
25
  export type $ZodStringFormatParams = CheckTypeParams<schemas.$ZodStringFormat, "format" | "coerce" | "when" | "pattern">;
@@ -131,7 +133,9 @@ export declare function _isoTime<T extends schemas.$ZodISOTime>(Class: util.Sche
131
133
  export type $ZodISODurationParams = StringFormatParams<schemas.$ZodISODuration, "when">;
132
134
  export type $ZodCheckISODurationParams = CheckStringFormatParams<schemas.$ZodISODuration, "when">;
133
135
  export declare function _isoDuration<T extends schemas.$ZodISODuration>(Class: util.SchemaClass<T>, params?: string | $ZodISODurationParams | $ZodCheckISODurationParams): T;
134
- export type $ZodNumberParams = TypeParams<schemas.$ZodNumber<number>, "coerce">;
136
+ export type $ZodNumberParams = TypeParams<schemas.$ZodNumber<number>, "coerce"> & {
137
+ checks?: readonly checks.$ZodCheck<number>[];
138
+ };
135
139
  export type $ZodNumberFormatParams = CheckTypeParams<schemas.$ZodNumberFormat, "format" | "coerce">;
136
140
  export type $ZodCheckNumberFormatParams = CheckParams<checks.$ZodCheckNumberFormat, "format" | "when">;
137
141
  export declare function _number<T extends schemas.$ZodNumber>(Class: util.SchemaClass<T>, params?: string | $ZodNumberParams): T;
package/v4/core/api.js CHANGED
@@ -2,20 +2,18 @@ import * as checks from "./checks.js";
2
2
  import * as registries from "./registries.js";
3
3
  import * as schemas from "./schemas.js";
4
4
  import * as util from "./util.js";
5
+ function snapshotChecks(def) {
6
+ if (def.checks)
7
+ def.checks = [...def.checks];
8
+ return def;
9
+ }
5
10
  // @__NO_SIDE_EFFECTS__
6
11
  export function _string(Class, params) {
7
- return new Class({
8
- type: "string",
9
- ...util.normalizeParams(params),
10
- });
12
+ return new Class(snapshotChecks({ type: "string", ...util.normalizeParams(params) }));
11
13
  }
12
14
  // @__NO_SIDE_EFFECTS__
13
15
  export function _coercedString(Class, params) {
14
- return new Class({
15
- type: "string",
16
- coerce: true,
17
- ...util.normalizeParams(params),
18
- });
16
+ return new Class(snapshotChecks({ type: "string", coerce: true, ...util.normalizeParams(params) }));
19
17
  }
20
18
  // @__NO_SIDE_EFFECTS__
21
19
  export function _email(Class, params) {
@@ -324,20 +322,11 @@ export function _isoDuration(Class, params) {
324
322
  }
325
323
  // @__NO_SIDE_EFFECTS__
326
324
  export function _number(Class, params) {
327
- return new Class({
328
- type: "number",
329
- checks: [],
330
- ...util.normalizeParams(params),
331
- });
325
+ return new Class(snapshotChecks({ type: "number", checks: [], ...util.normalizeParams(params) }));
332
326
  }
333
327
  // @__NO_SIDE_EFFECTS__
334
328
  export function _coercedNumber(Class, params) {
335
- return new Class({
336
- type: "number",
337
- coerce: true,
338
- checks: [],
339
- ...util.normalizeParams(params),
340
- });
329
+ return new Class(snapshotChecks({ type: "number", coerce: true, checks: [], ...util.normalizeParams(params) }));
341
330
  }
342
331
  // @__NO_SIDE_EFFECTS__
343
332
  export function _int(Class, params) {
@@ -608,8 +608,7 @@ const PATTERN_IS_COMPLETE = new Set([
608
608
  "uuid",
609
609
  "xid",
610
610
  ]);
611
- // Returns the accessor holding the (possibly normalized) value after the check — url/normalize formats produce a new value like overwrite does. Never assigns to the incoming accessor: it may be a `const` or a property expression on user input.
612
- function generateStringFormatCheck(doc, ctx, def, accessor) {
611
+ function generateStringFormatCheck(doc, ctx, def, accessor, needsValue = true) {
613
612
  // Some string formats do runtime validation beyond their advertised pattern. For cheap pure utility checks, hoist the runtime function and call it so the fast path stays correct without cloning the utility logic into codegen.
614
613
  const fmt = def.format;
615
614
  if (fmt === "base64") {
@@ -655,7 +654,7 @@ function generateStringFormatCheck(doc, ctx, def, accessor) {
655
654
  formatDef.hostname !== undefined ||
656
655
  formatDef.protocol !== undefined) {
657
656
  // Same three predicates the runtime calls, in the same order, so there is no second URL implementation to drift. Which options exist is known now, so the calls the runtime makes conditionally are emitted conditionally instead.
658
- const parseConst = addConstant(ctx, schemas_js_1.parseURLObject);
657
+ const parseConst = addConstant(ctx, schemas_js_1.validateURL);
659
658
  const defConst = addConstant(ctx, def);
660
659
  const trimVar = newVar(ctx);
661
660
  const urlVar = newVar(ctx);
@@ -670,6 +669,8 @@ function generateStringFormatCheck(doc, ctx, def, accessor) {
670
669
  const protocolConst = addConstant(ctx, schemas_js_1.urlProtocolOk);
671
670
  doc.write(`if (!${protocolConst}(${urlVar}, ${defConst}.protocol)) return INVALID;`);
672
671
  }
672
+ if (!needsValue)
673
+ return null;
673
674
  const outputVar = newVar(ctx);
674
675
  const outputExpr = formatDef.normalize ? `${urlVar}.href` : `${addConstant(ctx, schemas_js_1.stripTabAndNewline)}(${trimVar})`;
675
676
  doc.write(`const ${outputVar} = ${outputExpr};`);
@@ -734,7 +735,7 @@ function generateCheck(doc, ctx, schema, accessor, needsValue = true) {
734
735
  let typeAccessor;
735
736
  switch (type) {
736
737
  case "string":
737
- typeAccessor = generateStringCheck(doc, ctx, schema, accessor);
738
+ typeAccessor = generateStringCheck(doc, ctx, schema, accessor, buildsValue);
738
739
  break;
739
740
  case "number":
740
741
  typeAccessor = generateNumberCheck(doc, schema, accessor);
@@ -863,13 +864,13 @@ function generateCheck(doc, ctx, schema, accessor, needsValue = true) {
863
864
  // Generate checks after the type-specific validation (may transform value)
864
865
  return generateChecks(doc, ctx, schema, typeAccessor);
865
866
  }
866
- function generateStringCheck(doc, ctx, schema, accessor) {
867
+ function generateStringCheck(doc, ctx, schema, accessor, needsValue = true) {
867
868
  doc.write(`if (typeof ${accessor} !== "string") return INVALID;`);
868
869
  // z.email() carries its format on the def, z.string().email() in def.checks; both route here so the format table has no second copy to drift from.
869
870
  const def = schema._zod.def;
870
871
  if (def.format === undefined)
871
872
  return accessor;
872
- return generateStringFormatCheck(doc, ctx, def, accessor);
873
+ return generateStringFormatCheck(doc, ctx, def, accessor, needsValue);
873
874
  }
874
875
  function generateNumberCheck(doc, schema, accessor) {
875
876
  // Runtime z.number() rejects NaN and ±Infinity. Number.isFinite covers both.
@@ -2,7 +2,7 @@ import { $ZodAsyncError } from "./core.js";
2
2
  import { Doc } from "./doc.js";
3
3
  import { isBackEdge, isRecursiveSchema } from "./memoizer.js";
4
4
  import * as regexes from "./regexes.js";
5
- import { isValidBase64, isValidBase64URL, isValidCIDRv6, isValidCreditCard, isValidIBAN, isValidIPv6, isValidJWT, mergeValues, parseURLObject, stripTabAndNewline, urlHostnameOk, urlProtocolOk, } from "./schemas.js";
5
+ import { isValidBase64, isValidBase64URL, isValidCIDRv6, isValidCreditCard, isValidIBAN, isValidIPv6, isValidJWT, mergeValues, stripTabAndNewline, urlHostnameOk, urlProtocolOk, validateURL, } from "./schemas.js";
6
6
  import * as util from "./util.js";
7
7
  /** @internal Sentinel the compiled fast path returns when validation fails. */
8
8
  export const INVALID = Symbol.for("zod.compile.invalid");
@@ -577,8 +577,7 @@ const PATTERN_IS_COMPLETE = new Set([
577
577
  "uuid",
578
578
  "xid",
579
579
  ]);
580
- // Returns the accessor holding the (possibly normalized) value after the check — url/normalize formats produce a new value like overwrite does. Never assigns to the incoming accessor: it may be a `const` or a property expression on user input.
581
- function generateStringFormatCheck(doc, ctx, def, accessor) {
580
+ function generateStringFormatCheck(doc, ctx, def, accessor, needsValue = true) {
582
581
  // Some string formats do runtime validation beyond their advertised pattern. For cheap pure utility checks, hoist the runtime function and call it so the fast path stays correct without cloning the utility logic into codegen.
583
582
  const fmt = def.format;
584
583
  if (fmt === "base64") {
@@ -624,7 +623,7 @@ function generateStringFormatCheck(doc, ctx, def, accessor) {
624
623
  formatDef.hostname !== undefined ||
625
624
  formatDef.protocol !== undefined) {
626
625
  // Same three predicates the runtime calls, in the same order, so there is no second URL implementation to drift. Which options exist is known now, so the calls the runtime makes conditionally are emitted conditionally instead.
627
- const parseConst = addConstant(ctx, parseURLObject);
626
+ const parseConst = addConstant(ctx, validateURL);
628
627
  const defConst = addConstant(ctx, def);
629
628
  const trimVar = newVar(ctx);
630
629
  const urlVar = newVar(ctx);
@@ -639,6 +638,8 @@ function generateStringFormatCheck(doc, ctx, def, accessor) {
639
638
  const protocolConst = addConstant(ctx, urlProtocolOk);
640
639
  doc.write(`if (!${protocolConst}(${urlVar}, ${defConst}.protocol)) return INVALID;`);
641
640
  }
641
+ if (!needsValue)
642
+ return null;
642
643
  const outputVar = newVar(ctx);
643
644
  const outputExpr = formatDef.normalize ? `${urlVar}.href` : `${addConstant(ctx, stripTabAndNewline)}(${trimVar})`;
644
645
  doc.write(`const ${outputVar} = ${outputExpr};`);
@@ -703,7 +704,7 @@ function generateCheck(doc, ctx, schema, accessor, needsValue = true) {
703
704
  let typeAccessor;
704
705
  switch (type) {
705
706
  case "string":
706
- typeAccessor = generateStringCheck(doc, ctx, schema, accessor);
707
+ typeAccessor = generateStringCheck(doc, ctx, schema, accessor, buildsValue);
707
708
  break;
708
709
  case "number":
709
710
  typeAccessor = generateNumberCheck(doc, schema, accessor);
@@ -832,13 +833,13 @@ function generateCheck(doc, ctx, schema, accessor, needsValue = true) {
832
833
  // Generate checks after the type-specific validation (may transform value)
833
834
  return generateChecks(doc, ctx, schema, typeAccessor);
834
835
  }
835
- function generateStringCheck(doc, ctx, schema, accessor) {
836
+ function generateStringCheck(doc, ctx, schema, accessor, needsValue = true) {
836
837
  doc.write(`if (typeof ${accessor} !== "string") return INVALID;`);
837
838
  // z.email() carries its format on the def, z.string().email() in def.checks; both route here so the format table has no second copy to drift from.
838
839
  const def = schema._zod.def;
839
840
  if (def.format === undefined)
840
841
  return accessor;
841
- return generateStringFormatCheck(doc, ctx, def, accessor);
842
+ return generateStringFormatCheck(doc, ctx, def, accessor, needsValue);
842
843
  }
843
844
  function generateNumberCheck(doc, schema, accessor) {
844
845
  // Runtime z.number() rejects NaN and ±Infinity. Number.isFinite covers both.
package/v4/core/core.cjs CHANGED
@@ -63,7 +63,7 @@ proto, params) {
63
63
  _zodDesc.value = undefined;
64
64
  }
65
65
  }
66
- if (inst._zod.traits.has(name)) {
66
+ else if (inst._zod.traits.has(name)) {
67
67
  return;
68
68
  }
69
69
  inst._zod.traits.add(name);
package/v4/core/core.js CHANGED
@@ -58,7 +58,7 @@ proto, params) {
58
58
  _zodDesc.value = undefined;
59
59
  }
60
60
  }
61
- if (inst._zod.traits.has(name)) {
61
+ else if (inst._zod.traits.has(name)) {
62
62
  return;
63
63
  }
64
64
  inst._zod.traits.add(name);
@@ -447,18 +447,15 @@ const objectProcessor = (schema, ctx, _json, params) => {
447
447
  }));
448
448
  }
449
449
  // required keys
450
- const allKeys = new Set(Object.keys(shape));
451
- const requiredKeys = new Set([...allKeys].filter((key) => {
450
+ const requiredKeys = [];
451
+ for (const key of Object.keys(shape)) {
452
452
  const field = def.shape[key];
453
- if (ctx.io === "input") {
454
- return inputOptin(field) === undefined;
453
+ if (ctx.io === "input" ? inputOptin(field) === undefined : field._zod.optout === undefined) {
454
+ requiredKeys.push(key);
455
455
  }
456
- else {
457
- return field._zod.optout === undefined;
458
- }
459
- }));
460
- if (requiredKeys.size > 0) {
461
- json.required = Array.from(requiredKeys);
456
+ }
457
+ if (requiredKeys.length > 0) {
458
+ json.required = requiredKeys;
462
459
  }
463
460
  // catchall
464
461
  if (def.catchall?._zod.def.type === "never") {
@@ -395,18 +395,15 @@ export const objectProcessor = (schema, ctx, _json, params) => {
395
395
  }));
396
396
  }
397
397
  // required keys
398
- const allKeys = new Set(Object.keys(shape));
399
- const requiredKeys = new Set([...allKeys].filter((key) => {
398
+ const requiredKeys = [];
399
+ for (const key of Object.keys(shape)) {
400
400
  const field = def.shape[key];
401
- if (ctx.io === "input") {
402
- return inputOptin(field) === undefined;
401
+ if (ctx.io === "input" ? inputOptin(field) === undefined : field._zod.optout === undefined) {
402
+ requiredKeys.push(key);
403
403
  }
404
- else {
405
- return field._zod.optout === undefined;
406
- }
407
- }));
408
- if (requiredKeys.size > 0) {
409
- json.required = Array.from(requiredKeys);
404
+ }
405
+ if (requiredKeys.length > 0) {
406
+ json.required = requiredKeys;
410
407
  }
411
408
  // catchall
412
409
  if (def.catchall?._zod.def.type === "never") {
@@ -23,8 +23,8 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.sha1_base64url = exports.sha1_base64 = exports.sha1_hex = exports.md5_base64url = exports.md5_base64 = exports.md5_hex = exports.hex = exports.uppercase = exports.lowercase = exports.undefined = exports.null = exports.boolean = exports.number = exports.integer = exports.bigint = exports.string = exports.anyString = exports.date = exports.iban = exports.creditCard = exports.e164 = exports.httpProtocol = exports.domain = exports.hostname = exports.base64url = exports.base64 = exports.cidrv6 = exports.cidrv4 = exports.mac = exports.ipv6 = exports.ipv4 = exports.browserEmail = exports.idnEmail = exports.unicodeEmail = exports.rfc5322Email = exports.html5Email = exports.email = exports.uuid7 = exports.uuid6 = exports.uuid4 = exports.uuid = exports.guid = exports.extendedDuration = exports.duration = exports.nanoid = exports.ksuid = exports.xid = exports.ulid = exports.cuid2 = exports.cuid = void 0;
27
- exports.sha512_base64url = exports.sha512_base64 = exports.sha512_hex = exports.sha384_base64url = exports.sha384_base64 = exports.sha384_hex = exports.sha256_base64url = exports.sha256_base64 = exports.sha256_hex = void 0;
26
+ exports.sha1_base64 = exports.sha1_hex = exports.md5_base64url = exports.md5_base64 = exports.md5_hex = exports.hex = exports.uppercase = exports.lowercase = exports.undefined = exports.null = exports.boolean = exports.number = exports.integer = exports.bigint = exports.string = exports.anyString = exports.date = exports.iban = exports.currencyCode = exports.creditCard = exports.e164 = exports.httpProtocol = exports.domain = exports.hostname = exports.base64url = exports.base64 = exports.cidrv6 = exports.cidrv4 = exports.mac = exports.ipv6 = exports.ipv4 = exports.browserEmail = exports.idnEmail = exports.unicodeEmail = exports.rfc5322Email = exports.html5Email = exports.email = exports.uuid7 = exports.uuid6 = exports.uuid4 = exports.uuid = exports.guid = exports.extendedDuration = exports.duration = exports.nanoid = exports.ksuid = exports.xid = exports.ulid = exports.cuid2 = exports.cuid = void 0;
27
+ exports.sha512_base64url = exports.sha512_base64 = exports.sha512_hex = exports.sha384_base64url = exports.sha384_base64 = exports.sha384_hex = exports.sha256_base64url = exports.sha256_base64 = exports.sha256_hex = exports.sha1_base64url = void 0;
28
28
  exports.nanoidOfLength = nanoidOfLength;
29
29
  exports.emoji = emoji;
30
30
  exports.time = time;
@@ -99,6 +99,8 @@ exports.httpProtocol = /^https?$/;
99
99
  exports.e164 = /^\+[1-9]\d{6,14}$/;
100
100
  // Credit card shape: 12–19 digits, optionally separated by single spaces or single hyphens. ISO/IEC 7812 caps the PAN at 19 digits; 12 is the shortest issued length (Maestro).
101
101
  exports.creditCard = /^\d(?:[ -]?\d){11,18}$/;
102
+ // ISO 4217 alpha codes from the SIX list, regenerated by scripts/update-iso-4217.ts
103
+ exports.currencyCode = /^(?:AED|AFN|ALL|AMD|AOA|ARS|AUD|AWG|AZN|BAM|BBD|BDT|BHD|BIF|BMD|BND|BOB|BOV|BRL|BSD|BTN|BWP|BYN|BZD|CAD|CDF|CHE|CHF|CHW|CLF|CLP|CNY|COP|COU|CRC|CUP|CVE|CZK|DJF|DKK|DOP|DZD|EGP|ERN|ETB|EUR|FJD|FKP|GBP|GEL|GHS|GIP|GMD|GNF|GTQ|GYD|HKD|HNL|HTG|HUF|IDR|ILS|INR|IQD|IRR|ISK|JMD|JOD|JPY|KES|KGS|KHR|KMF|KPW|KRW|KWD|KYD|KZT|LAK|LBP|LKR|LRD|LSL|LYD|MAD|MDL|MGA|MKD|MMK|MNT|MOP|MRU|MUR|MVR|MWK|MXN|MXV|MYR|MZN|NAD|NGN|NIO|NOK|NPR|NZD|OMR|PAB|PEN|PGK|PHP|PKR|PLN|PYG|QAR|RON|RSD|RUB|RWF|SAR|SBD|SCR|SDG|SEK|SGD|SHP|SLE|SOS|SRD|SSP|STN|SVC|SYP|SZL|THB|TJS|TMT|TND|TOP|TRY|TTD|TWD|TZS|UAH|UGX|USD|USN|UYI|UYU|UYW|UZS|VED|VES|VND|VUV|WST|XAD|XAF|XAG|XAU|XBA|XBB|XBC|XBD|XCD|XCG|XDR|XOF|XPD|XPF|XPT|XSU|XTS|XUA|XXX|YER|ZAR|ZMW|ZWG)$/;
102
104
  // iban electronic format: 2-letter country, check digits 02-98 (the only values `98 - remainder` can produce), 11-30 bban characters
103
105
  exports.iban = /^[A-Z]{2}(?!00|01|99)\d{2}[A-Z0-9]{11,30}$/;
104
106
  const dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`;
@@ -46,6 +46,7 @@ export declare const domain: RegExp;
46
46
  export declare const httpProtocol: RegExp;
47
47
  export declare const e164: RegExp;
48
48
  export declare const creditCard: RegExp;
49
+ export declare const currencyCode: RegExp;
49
50
  export declare const iban: RegExp;
50
51
  export declare const date: RegExp;
51
52
  export declare function time(args: {
@@ -46,6 +46,7 @@ export declare const domain: RegExp;
46
46
  export declare const httpProtocol: RegExp;
47
47
  export declare const e164: RegExp;
48
48
  export declare const creditCard: RegExp;
49
+ export declare const currencyCode: RegExp;
49
50
  export declare const iban: RegExp;
50
51
  export declare const date: RegExp;
51
52
  export declare function time(args: {
@@ -66,6 +66,8 @@ export const httpProtocol = /^https?$/;
66
66
  export const e164 = /^\+[1-9]\d{6,14}$/;
67
67
  // Credit card shape: 12–19 digits, optionally separated by single spaces or single hyphens. ISO/IEC 7812 caps the PAN at 19 digits; 12 is the shortest issued length (Maestro).
68
68
  export const creditCard = /^\d(?:[ -]?\d){11,18}$/;
69
+ // ISO 4217 alpha codes from the SIX list, regenerated by scripts/update-iso-4217.ts
70
+ export const currencyCode = /^(?:AED|AFN|ALL|AMD|AOA|ARS|AUD|AWG|AZN|BAM|BBD|BDT|BHD|BIF|BMD|BND|BOB|BOV|BRL|BSD|BTN|BWP|BYN|BZD|CAD|CDF|CHE|CHF|CHW|CLF|CLP|CNY|COP|COU|CRC|CUP|CVE|CZK|DJF|DKK|DOP|DZD|EGP|ERN|ETB|EUR|FJD|FKP|GBP|GEL|GHS|GIP|GMD|GNF|GTQ|GYD|HKD|HNL|HTG|HUF|IDR|ILS|INR|IQD|IRR|ISK|JMD|JOD|JPY|KES|KGS|KHR|KMF|KPW|KRW|KWD|KYD|KZT|LAK|LBP|LKR|LRD|LSL|LYD|MAD|MDL|MGA|MKD|MMK|MNT|MOP|MRU|MUR|MVR|MWK|MXN|MXV|MYR|MZN|NAD|NGN|NIO|NOK|NPR|NZD|OMR|PAB|PEN|PGK|PHP|PKR|PLN|PYG|QAR|RON|RSD|RUB|RWF|SAR|SBD|SCR|SDG|SEK|SGD|SHP|SLE|SOS|SRD|SSP|STN|SVC|SYP|SZL|THB|TJS|TMT|TND|TOP|TRY|TTD|TWD|TZS|UAH|UGX|USD|USN|UYI|UYU|UYW|UZS|VED|VES|VND|VUV|WST|XAD|XAF|XAG|XAU|XBA|XBB|XBC|XBD|XCD|XCG|XDR|XOF|XPD|XPF|XPT|XSU|XTS|XUA|XXX|YER|ZAR|ZMW|ZWG)$/;
69
71
  // iban electronic format: 2-letter country, check digits 02-98 (the only values `98 - remainder` can produce), 11-30 bban characters
70
72
  export const iban = /^[A-Z]{2}(?!00|01|99)\d{2}[A-Z0-9]{11,30}$/;
71
73
  const dateSource = `(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))`;
@@ -26,6 +26,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.$ZodObject = exports.$ZodArray = exports.$ZodDate = exports.$ZodVoid = exports.$ZodNever = exports.$ZodUnknown = exports.$ZodAny = exports.$ZodNull = exports.$ZodUndefined = exports.$ZodSymbol = exports.$ZodBigIntFormat = exports.$ZodBigInt = exports.$ZodBoolean = exports.$ZodNumberFormat = exports.$ZodNumber = exports.$ZodCustomStringFormat = exports.$ZodJWT = exports.$ZodIBAN = exports.$ZodCreditCard = exports.$ZodE164 = exports.$ZodBase64URL = exports.base64urlCharset = exports.$ZodBase64 = exports.base64Charset = exports.$ZodCIDRv6 = exports.$ZodCIDRv4 = exports.$ZodMAC = exports.$ZodIPv6 = exports.$ZodIPv4 = exports.$ZodISODuration = exports.$ZodISOTime = exports.$ZodISODate = exports.$ZodISODateTime = exports.$ZodKSUID = exports.$ZodXID = exports.$ZodULID = exports.$ZodCUID2 = exports.$ZodCUID = exports.$ZodNanoID = exports.$ZodEmoji = exports.$ZodURL = exports.URL_UNPARSEABLE = exports.URL_BAD_FORMAT = exports.$ZodEmail = exports.$ZodUUID = exports.$ZodGUID = exports.$ZodStringFormat = exports.$ZodString = exports.clone = exports.$ZodType = void 0;
27
27
  exports.$ZodCustom = exports.$ZodLazy = exports.$ZodPromise = exports.$ZodFunction = exports.$ZodTemplateLiteral = exports.$ZodReadonly = exports.$ZodPreprocess = exports.$ZodCodec = exports.$ZodPipe = exports.$ZodNaN = exports.$ZodCatch = exports.$ZodSuccess = exports.$ZodNonOptional = exports.$ZodPrefault = exports.$ZodDefault = exports.$ZodNullable = exports.$ZodExactOptional = exports.$ZodOptional = exports.$ZodTransform = exports.$ZodFile = exports.$ZodLiteral = exports.$ZodEnum = exports.$ZodSet = exports.$ZodMap = exports.$ZodRecord = exports.$ZodTuple = exports.$ZodIntersection = exports.$ZodDiscriminatedUnion = exports.$ZodXor = exports.$ZodUnion = exports.$ZodObjectJIT = void 0;
28
28
  exports.standardProps = standardProps;
29
+ exports.canParseURL = canParseURL;
30
+ exports.validateURL = validateURL;
29
31
  exports.parseURLObject = parseURLObject;
30
32
  exports.stripTabAndNewline = stripTabAndNewline;
31
33
  exports.urlHostnameOk = urlHostnameOk;
@@ -251,15 +253,37 @@ exports.$ZodEmail = core.$constructor("$ZodEmail", (inst, def) => {
251
253
  });
252
254
  /** The `://` guard rejected the input before the URL constructor saw it. */
253
255
  exports.URL_BAD_FORMAT = 1;
254
- /** The URL constructor rejected the input. */
256
+ /** The URL parser rejected the input. */
255
257
  exports.URL_UNPARSEABLE = 2;
256
- /** Parses a URL for `$ZodURL`, applying the one guard the URL constructor cannot express. Returns the parsed URL, or a code naming the stage that rejected it — the runtime needs that distinction to pick an issue note, and compiled code only needs to know it is not a URL. */
258
+ function canParseURL(input) {
259
+ try {
260
+ if (typeof URL !== "undefined" && typeof URL.canParse === "function")
261
+ return URL.canParse(input);
262
+ new URL(input);
263
+ return true;
264
+ }
265
+ catch {
266
+ return false;
267
+ }
268
+ }
269
+ function validateURL(trimmed, def) {
270
+ if (!("normalize" in def) && !("hostname" in def) && !("protocol" in def)) {
271
+ return canParseURL(trimmed) || exports.URL_UNPARSEABLE;
272
+ }
273
+ return parseURLObject(trimmed, def);
274
+ }
275
+ /** Parses a URL while preserving the non-normalizing HTTP guard. */
257
276
  function parseURLObject(trimmed, def) {
258
277
  // When normalize is off, require :// for http/https URLs. This prevents strings like "http:example.com" or "https:/path" from being silently accepted
259
278
  if (!def.normalize && def.protocol?.source === regexes.httpProtocol.source && !/^https?:\/\//i.test(trimmed)) {
260
279
  return exports.URL_BAD_FORMAT;
261
280
  }
262
281
  try {
282
+ if (typeof URL !== "undefined") {
283
+ const URLStatic = URL;
284
+ if (typeof URLStatic.parse === "function")
285
+ return URLStatic.parse(trimmed) ?? exports.URL_UNPARSEABLE;
286
+ }
263
287
  // @ts-ignore
264
288
  return new URL(trimmed);
265
289
  }
@@ -286,7 +310,7 @@ exports.$ZodURL = core.$constructor("$ZodURL", (inst, def) => {
286
310
  try {
287
311
  // Trim whitespace from input
288
312
  const trimmed = payload.value.trim();
289
- const url = parseURLObject(trimmed, def);
313
+ const url = validateURL(trimmed, def);
290
314
  if (url === exports.URL_BAD_FORMAT) {
291
315
  payload.issues.push({
292
316
  code: "invalid_format",
@@ -308,6 +332,10 @@ exports.$ZodURL = core.$constructor("$ZodURL", (inst, def) => {
308
332
  });
309
333
  return;
310
334
  }
335
+ if (url === true) {
336
+ payload.value = stripTabAndNewline(trimmed);
337
+ return;
338
+ }
311
339
  if (def.hostname && !urlHostnameOk(url, def.hostname)) {
312
340
  payload.issues.push({
313
341
  code: "invalid_format",
@@ -405,14 +433,7 @@ const ipv6Alphabet = /^[0-9a-fA-F:.]+$/;
405
433
  function isValidIPv6(value) {
406
434
  if (!ipv6Alphabet.test(value))
407
435
  return false;
408
- try {
409
- // @ts-ignore
410
- new URL(`http://[${value}]`);
411
- return true;
412
- }
413
- catch {
414
- return false;
415
- }
436
+ return canParseURL(`http://[${value}]`);
416
437
  }
417
438
  exports.$ZodIPv6 = core.$constructor("$ZodIPv6", (inst, def) => {
418
439
  def.pattern ?? (def.pattern = regexes.ipv6);
@@ -188,9 +188,11 @@ export interface $ZodURL extends $ZodType {
188
188
  }
189
189
  /** The `://` guard rejected the input before the URL constructor saw it. */
190
190
  export declare const URL_BAD_FORMAT = 1;
191
- /** The URL constructor rejected the input. */
191
+ /** The URL parser rejected the input. */
192
192
  export declare const URL_UNPARSEABLE = 2;
193
- /** Parses a URL for `$ZodURL`, applying the one guard the URL constructor cannot express. Returns the parsed URL, or a code naming the stage that rejected it — the runtime needs that distinction to pick an issue note, and compiled code only needs to know it is not a URL. */
193
+ export declare function canParseURL(input: string): boolean;
194
+ export declare function validateURL(trimmed: string, def: Pick<$ZodURLDef, "protocol" | "hostname" | "normalize">): URL | true | typeof URL_BAD_FORMAT | typeof URL_UNPARSEABLE;
195
+ /** Parses a URL while preserving the non-normalizing HTTP guard. */
194
196
  export declare function parseURLObject(trimmed: string, def: Pick<$ZodURLDef, "protocol" | "normalize">): URL | typeof URL_BAD_FORMAT | typeof URL_UNPARSEABLE;
195
197
  /** The URL parser deletes every ASCII tab, LF and CR from its input before it parses, so `new URL("https://exa\nmple.com")` reports on `example.com`. Applying the same deletion to the returned value closes the half of that divergence which can move the host; the parser's other rewrite, stripping C0 controls at the edges, cannot. */
196
198
  export declare function stripTabAndNewline(value: string): string;
@@ -1268,4 +1270,4 @@ export interface $ZodCustom<O = unknown, I = unknown> extends $ZodType {
1268
1270
  }
1269
1271
  export declare const $ZodCustom: core.$constructor<$ZodCustom>;
1270
1272
  export type $ZodTypes = $ZodString | $ZodNumber | $ZodBigInt | $ZodBoolean | $ZodDate | $ZodSymbol | $ZodUndefined | $ZodNullable | $ZodNull | $ZodAny | $ZodUnknown | $ZodNever | $ZodVoid | $ZodArray | $ZodObject | $ZodUnion | $ZodIntersection | $ZodTuple | $ZodRecord | $ZodMap | $ZodSet | $ZodLiteral | $ZodEnum | $ZodFunction | $ZodPromise | $ZodLazy | $ZodOptional | $ZodDefault | $ZodPrefault | $ZodTemplateLiteral | $ZodCustom | $ZodTransform | $ZodNonOptional | $ZodReadonly | $ZodNaN | $ZodPipe | $ZodSuccess | $ZodCatch | $ZodFile;
1271
- export type $ZodStringFormatTypes = $ZodGUID | $ZodUUID | $ZodEmail | $ZodURL | $ZodEmoji | $ZodNanoID | $ZodCUID | $ZodCUID2 | $ZodULID | $ZodXID | $ZodKSUID | $ZodISODateTime | $ZodISODate | $ZodISOTime | $ZodISODuration | $ZodIPv4 | $ZodIPv6 | $ZodMAC | $ZodCIDRv4 | $ZodCIDRv6 | $ZodBase64 | $ZodBase64URL | $ZodE164 | $ZodCreditCard | $ZodIBAN | $ZodJWT | $ZodCustomStringFormat<"hex"> | $ZodCustomStringFormat<util.HashFormat> | $ZodCustomStringFormat<"hostname">;
1273
+ export type $ZodStringFormatTypes = $ZodGUID | $ZodUUID | $ZodEmail | $ZodURL | $ZodEmoji | $ZodNanoID | $ZodCUID | $ZodCUID2 | $ZodULID | $ZodXID | $ZodKSUID | $ZodISODateTime | $ZodISODate | $ZodISOTime | $ZodISODuration | $ZodIPv4 | $ZodIPv6 | $ZodMAC | $ZodCIDRv4 | $ZodCIDRv6 | $ZodBase64 | $ZodBase64URL | $ZodE164 | $ZodCreditCard | $ZodIBAN | $ZodJWT | $ZodCustomStringFormat<"hex"> | $ZodCustomStringFormat<util.HashFormat> | $ZodCustomStringFormat<"hostname"> | $ZodCustomStringFormat<"currency_code">;
@@ -188,9 +188,11 @@ export interface $ZodURL extends $ZodType {
188
188
  }
189
189
  /** The `://` guard rejected the input before the URL constructor saw it. */
190
190
  export declare const URL_BAD_FORMAT = 1;
191
- /** The URL constructor rejected the input. */
191
+ /** The URL parser rejected the input. */
192
192
  export declare const URL_UNPARSEABLE = 2;
193
- /** Parses a URL for `$ZodURL`, applying the one guard the URL constructor cannot express. Returns the parsed URL, or a code naming the stage that rejected it — the runtime needs that distinction to pick an issue note, and compiled code only needs to know it is not a URL. */
193
+ export declare function canParseURL(input: string): boolean;
194
+ export declare function validateURL(trimmed: string, def: Pick<$ZodURLDef, "protocol" | "hostname" | "normalize">): URL | true | typeof URL_BAD_FORMAT | typeof URL_UNPARSEABLE;
195
+ /** Parses a URL while preserving the non-normalizing HTTP guard. */
194
196
  export declare function parseURLObject(trimmed: string, def: Pick<$ZodURLDef, "protocol" | "normalize">): URL | typeof URL_BAD_FORMAT | typeof URL_UNPARSEABLE;
195
197
  /** The URL parser deletes every ASCII tab, LF and CR from its input before it parses, so `new URL("https://exa\nmple.com")` reports on `example.com`. Applying the same deletion to the returned value closes the half of that divergence which can move the host; the parser's other rewrite, stripping C0 controls at the edges, cannot. */
196
198
  export declare function stripTabAndNewline(value: string): string;
@@ -1268,4 +1270,4 @@ export interface $ZodCustom<O = unknown, I = unknown> extends $ZodType {
1268
1270
  }
1269
1271
  export declare const $ZodCustom: core.$constructor<$ZodCustom>;
1270
1272
  export type $ZodTypes = $ZodString | $ZodNumber | $ZodBigInt | $ZodBoolean | $ZodDate | $ZodSymbol | $ZodUndefined | $ZodNullable | $ZodNull | $ZodAny | $ZodUnknown | $ZodNever | $ZodVoid | $ZodArray | $ZodObject | $ZodUnion | $ZodIntersection | $ZodTuple | $ZodRecord | $ZodMap | $ZodSet | $ZodLiteral | $ZodEnum | $ZodFunction | $ZodPromise | $ZodLazy | $ZodOptional | $ZodDefault | $ZodPrefault | $ZodTemplateLiteral | $ZodCustom | $ZodTransform | $ZodNonOptional | $ZodReadonly | $ZodNaN | $ZodPipe | $ZodSuccess | $ZodCatch | $ZodFile;
1271
- export type $ZodStringFormatTypes = $ZodGUID | $ZodUUID | $ZodEmail | $ZodURL | $ZodEmoji | $ZodNanoID | $ZodCUID | $ZodCUID2 | $ZodULID | $ZodXID | $ZodKSUID | $ZodISODateTime | $ZodISODate | $ZodISOTime | $ZodISODuration | $ZodIPv4 | $ZodIPv6 | $ZodMAC | $ZodCIDRv4 | $ZodCIDRv6 | $ZodBase64 | $ZodBase64URL | $ZodE164 | $ZodCreditCard | $ZodIBAN | $ZodJWT | $ZodCustomStringFormat<"hex"> | $ZodCustomStringFormat<util.HashFormat> | $ZodCustomStringFormat<"hostname">;
1273
+ export type $ZodStringFormatTypes = $ZodGUID | $ZodUUID | $ZodEmail | $ZodURL | $ZodEmoji | $ZodNanoID | $ZodCUID | $ZodCUID2 | $ZodULID | $ZodXID | $ZodKSUID | $ZodISODateTime | $ZodISODate | $ZodISOTime | $ZodISODuration | $ZodIPv4 | $ZodIPv6 | $ZodMAC | $ZodCIDRv4 | $ZodCIDRv6 | $ZodBase64 | $ZodBase64URL | $ZodE164 | $ZodCreditCard | $ZodIBAN | $ZodJWT | $ZodCustomStringFormat<"hex"> | $ZodCustomStringFormat<util.HashFormat> | $ZodCustomStringFormat<"hostname"> | $ZodCustomStringFormat<"currency_code">;
@@ -209,15 +209,37 @@ export const $ZodEmail = /*@__PURE__*/ core.$constructor("$ZodEmail", (inst, def
209
209
  });
210
210
  /** The `://` guard rejected the input before the URL constructor saw it. */
211
211
  export const URL_BAD_FORMAT = 1;
212
- /** The URL constructor rejected the input. */
212
+ /** The URL parser rejected the input. */
213
213
  export const URL_UNPARSEABLE = 2;
214
- /** Parses a URL for `$ZodURL`, applying the one guard the URL constructor cannot express. Returns the parsed URL, or a code naming the stage that rejected it — the runtime needs that distinction to pick an issue note, and compiled code only needs to know it is not a URL. */
214
+ export function canParseURL(input) {
215
+ try {
216
+ if (typeof URL !== "undefined" && typeof URL.canParse === "function")
217
+ return URL.canParse(input);
218
+ new URL(input);
219
+ return true;
220
+ }
221
+ catch {
222
+ return false;
223
+ }
224
+ }
225
+ export function validateURL(trimmed, def) {
226
+ if (!("normalize" in def) && !("hostname" in def) && !("protocol" in def)) {
227
+ return canParseURL(trimmed) || URL_UNPARSEABLE;
228
+ }
229
+ return parseURLObject(trimmed, def);
230
+ }
231
+ /** Parses a URL while preserving the non-normalizing HTTP guard. */
215
232
  export function parseURLObject(trimmed, def) {
216
233
  // When normalize is off, require :// for http/https URLs. This prevents strings like "http:example.com" or "https:/path" from being silently accepted
217
234
  if (!def.normalize && def.protocol?.source === regexes.httpProtocol.source && !/^https?:\/\//i.test(trimmed)) {
218
235
  return URL_BAD_FORMAT;
219
236
  }
220
237
  try {
238
+ if (typeof URL !== "undefined") {
239
+ const URLStatic = URL;
240
+ if (typeof URLStatic.parse === "function")
241
+ return URLStatic.parse(trimmed) ?? URL_UNPARSEABLE;
242
+ }
221
243
  // @ts-ignore
222
244
  return new URL(trimmed);
223
245
  }
@@ -244,7 +266,7 @@ export const $ZodURL = /*@__PURE__*/ core.$constructor("$ZodURL", (inst, def) =>
244
266
  try {
245
267
  // Trim whitespace from input
246
268
  const trimmed = payload.value.trim();
247
- const url = parseURLObject(trimmed, def);
269
+ const url = validateURL(trimmed, def);
248
270
  if (url === URL_BAD_FORMAT) {
249
271
  payload.issues.push({
250
272
  code: "invalid_format",
@@ -266,6 +288,10 @@ export const $ZodURL = /*@__PURE__*/ core.$constructor("$ZodURL", (inst, def) =>
266
288
  });
267
289
  return;
268
290
  }
291
+ if (url === true) {
292
+ payload.value = stripTabAndNewline(trimmed);
293
+ return;
294
+ }
269
295
  if (def.hostname && !urlHostnameOk(url, def.hostname)) {
270
296
  payload.issues.push({
271
297
  code: "invalid_format",
@@ -363,14 +389,7 @@ const ipv6Alphabet = /^[0-9a-fA-F:.]+$/;
363
389
  export function isValidIPv6(value) {
364
390
  if (!ipv6Alphabet.test(value))
365
391
  return false;
366
- try {
367
- // @ts-ignore
368
- new URL(`http://[${value}]`);
369
- return true;
370
- }
371
- catch {
372
- return false;
373
- }
392
+ return canParseURL(`http://[${value}]`);
374
393
  }
375
394
  export const $ZodIPv6 = /*@__PURE__*/ core.$constructor("$ZodIPv6", (inst, def) => {
376
395
  def.pattern ?? (def.pattern = regexes.ipv6);
@@ -4,7 +4,7 @@ exports.version = void 0;
4
4
  exports.version = {
5
5
  major: 4,
6
6
  minor: 6,
7
- patch: 3,
7
+ patch: 4,
8
8
  };
9
9
 
10
10
  // seal-cjs-exports
@@ -1,5 +1,5 @@
1
1
  export const version = {
2
2
  major: 4,
3
3
  minor: 6,
4
- patch: 3,
4
+ patch: 4,
5
5
  };
package/v4/locales/ar.cjs CHANGED
@@ -65,6 +65,7 @@ const error = () => {
65
65
  json_string: "نَص على هيئة JSON",
66
66
  e164: "رقم هاتف بمعيار E.164",
67
67
  credit_card: "رقم بطاقة الائتمان",
68
+ currency_code: "رمز العملة",
68
69
  iban: "IBAN",
69
70
  jwt: "JWT",
70
71
  template_literal: "مدخل",
package/v4/locales/ar.js CHANGED
@@ -39,6 +39,7 @@ const error = () => {
39
39
  json_string: "نَص على هيئة JSON",
40
40
  e164: "رقم هاتف بمعيار E.164",
41
41
  credit_card: "رقم بطاقة الائتمان",
42
+ currency_code: "رمز العملة",
42
43
  iban: "IBAN",
43
44
  jwt: "JWT",
44
45
  template_literal: "مدخل",
package/v4/locales/az.cjs CHANGED
@@ -65,6 +65,7 @@ const error = () => {
65
65
  json_string: "JSON string",
66
66
  e164: "E.164 number",
67
67
  credit_card: "kredit kartı nömrəsi",
68
+ currency_code: "valyuta kodu",
68
69
  iban: "IBAN",
69
70
  jwt: "JWT",
70
71
  template_literal: "input",
package/v4/locales/az.js CHANGED
@@ -39,6 +39,7 @@ const error = () => {
39
39
  json_string: "JSON string",
40
40
  e164: "E.164 number",
41
41
  credit_card: "kredit kartı nömrəsi",
42
+ currency_code: "valyuta kodu",
42
43
  iban: "IBAN",
43
44
  jwt: "JWT",
44
45
  template_literal: "input",
package/v4/locales/be.cjs CHANGED
@@ -115,6 +115,7 @@ const error = () => {
115
115
  json_string: "JSON радок",
116
116
  e164: "нумар E.164",
117
117
  credit_card: "нумар крэдытнай карты",
118
+ currency_code: "код валюты",
118
119
  iban: "IBAN",
119
120
  jwt: "JWT",
120
121
  template_literal: "увод",
package/v4/locales/be.js CHANGED
@@ -89,6 +89,7 @@ const error = () => {
89
89
  json_string: "JSON радок",
90
90
  e164: "нумар E.164",
91
91
  credit_card: "нумар крэдытнай карты",
92
+ currency_code: "код валюты",
92
93
  iban: "IBAN",
93
94
  jwt: "JWT",
94
95
  template_literal: "увод",