zod 4.1.12 → 4.1.13

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 (82) hide show
  1. package/package.json +1 -1
  2. package/src/v4/classic/checks.ts +1 -0
  3. package/src/v4/classic/schemas.ts +20 -0
  4. package/src/v4/classic/tests/continuability.test.ts +22 -0
  5. package/src/v4/classic/tests/describe-meta-checks.test.ts +27 -0
  6. package/src/v4/classic/tests/index.test.ts +55 -1
  7. package/src/v4/classic/tests/promise.test.ts +1 -1
  8. package/src/v4/classic/tests/readonly.test.ts +1 -1
  9. package/src/v4/classic/tests/record.test.ts +141 -9
  10. package/src/v4/classic/tests/registries.test.ts +5 -1
  11. package/src/v4/classic/tests/string.test.ts +72 -0
  12. package/src/v4/classic/tests/template-literal.test.ts +8 -0
  13. package/src/v4/classic/tests/to-json-schema.test.ts +97 -0
  14. package/src/v4/classic/tests/tuple.test.ts +18 -0
  15. package/src/v4/classic/tests/url.test.ts +13 -0
  16. package/src/v4/core/api.ts +45 -0
  17. package/src/v4/core/core.ts +22 -9
  18. package/src/v4/core/regexes.ts +6 -1
  19. package/src/v4/core/registries.ts +12 -1
  20. package/src/v4/core/schemas.ts +50 -33
  21. package/src/v4/core/tests/extend.test.ts +42 -1
  22. package/src/v4/core/tests/locales/he.test.ts +379 -0
  23. package/src/v4/core/tests/locales/nl.test.ts +46 -0
  24. package/src/v4/core/tests/record-constructor.test.ts +67 -0
  25. package/src/v4/core/tests/recursive-tuples.test.ts +45 -0
  26. package/src/v4/core/to-json-schema.ts +55 -91
  27. package/src/v4/core/util.ts +11 -0
  28. package/src/v4/core/versions.ts +1 -1
  29. package/src/v4/locales/en.ts +1 -0
  30. package/src/v4/locales/he.ts +202 -71
  31. package/src/v4/locales/nl.ts +10 -10
  32. package/src/v4/mini/iso.ts +4 -4
  33. package/src/v4/mini/schemas.ts +17 -0
  34. package/src/v4/mini/tests/functions.test.ts +0 -38
  35. package/src/v4/mini/tests/index.test.ts +24 -1
  36. package/src/v4/mini/tests/string.test.ts +32 -0
  37. package/v3/ZodError.d.cts +1 -1
  38. package/v3/ZodError.d.ts +1 -1
  39. package/v4/classic/checks.cjs +2 -1
  40. package/v4/classic/checks.d.cts +1 -1
  41. package/v4/classic/checks.d.ts +1 -1
  42. package/v4/classic/checks.js +1 -1
  43. package/v4/classic/schemas.cjs +15 -2
  44. package/v4/classic/schemas.d.cts +8 -0
  45. package/v4/classic/schemas.d.ts +8 -0
  46. package/v4/classic/schemas.js +12 -0
  47. package/v4/core/api.cjs +40 -0
  48. package/v4/core/api.d.cts +7 -0
  49. package/v4/core/api.d.ts +7 -0
  50. package/v4/core/api.js +36 -0
  51. package/v4/core/core.cjs +20 -11
  52. package/v4/core/core.js +20 -11
  53. package/v4/core/regexes.cjs +31 -2
  54. package/v4/core/regexes.d.cts +1 -0
  55. package/v4/core/regexes.d.ts +1 -0
  56. package/v4/core/regexes.js +5 -0
  57. package/v4/core/registries.cjs +3 -1
  58. package/v4/core/registries.js +3 -1
  59. package/v4/core/schemas.cjs +32 -33
  60. package/v4/core/schemas.d.cts +12 -2
  61. package/v4/core/schemas.d.ts +12 -2
  62. package/v4/core/schemas.js +30 -31
  63. package/v4/core/to-json-schema.cjs +55 -92
  64. package/v4/core/to-json-schema.js +55 -92
  65. package/v4/core/util.cjs +11 -0
  66. package/v4/core/util.d.cts +1 -0
  67. package/v4/core/util.d.ts +1 -0
  68. package/v4/core/util.js +10 -0
  69. package/v4/core/versions.cjs +1 -1
  70. package/v4/core/versions.js +1 -1
  71. package/v4/locales/en.cjs +1 -0
  72. package/v4/locales/en.js +1 -0
  73. package/v4/locales/he.cjs +177 -66
  74. package/v4/locales/he.js +177 -66
  75. package/v4/locales/nl.cjs +8 -8
  76. package/v4/locales/nl.js +8 -8
  77. package/v4/mini/iso.cjs +4 -4
  78. package/v4/mini/iso.js +4 -4
  79. package/v4/mini/schemas.cjs +13 -2
  80. package/v4/mini/schemas.d.cts +6 -0
  81. package/v4/mini/schemas.d.ts +6 -0
  82. package/v4/mini/schemas.js +10 -0
@@ -330,13 +330,20 @@ export class JSONSchemaGenerator {
330
330
  }
331
331
  case "union": {
332
332
  const json: JSONSchema.BaseSchema = _json as any;
333
+ // Discriminated unions use oneOf (exactly one match) instead of anyOf (one or more matches)
334
+ // because the discriminator field ensures mutual exclusivity between options in JSON Schema
335
+ const isDiscriminated = (def as any).discriminator !== undefined;
333
336
  const options = def.options.map((x, i) =>
334
337
  this.process(x, {
335
338
  ...params,
336
- path: [...params.path, "anyOf", i],
339
+ path: [...params.path, isDiscriminated ? "oneOf" : "anyOf", i],
337
340
  })
338
341
  );
339
- json.anyOf = options;
342
+ if (isDiscriminated) {
343
+ json.oneOf = options;
344
+ } else {
345
+ json.anyOf = options;
346
+ }
340
347
  break;
341
348
  }
342
349
  case "intersection": {
@@ -947,98 +954,55 @@ function isTransforming(
947
954
  if (ctx.seen.has(_schema)) return false;
948
955
  ctx.seen.add(_schema);
949
956
 
950
- const schema = _schema as schemas.$ZodTypes;
951
- const def = schema._zod.def;
952
- switch (def.type) {
953
- case "string":
954
- case "number":
955
- case "bigint":
956
- case "boolean":
957
- case "date":
958
- case "symbol":
959
- case "undefined":
960
- case "null":
961
- case "any":
962
- case "unknown":
963
- case "never":
964
- case "void":
965
- case "literal":
966
- case "enum":
967
- case "nan":
968
- case "file":
969
- case "template_literal":
970
- return false;
971
- case "array": {
972
- return isTransforming(def.element, ctx);
973
- }
974
- case "object": {
975
- for (const key in def.shape) {
976
- if (isTransforming(def.shape[key]!, ctx)) return true;
977
- }
978
- return false;
979
- }
980
- case "union": {
981
- for (const option of def.options) {
982
- if (isTransforming(option, ctx)) return true;
983
- }
984
- return false;
985
- }
986
- case "intersection": {
987
- return isTransforming(def.left, ctx) || isTransforming(def.right, ctx);
988
- }
989
- case "tuple": {
990
- for (const item of def.items) {
991
- if (isTransforming(item, ctx)) return true;
992
- }
993
- if (def.rest && isTransforming(def.rest, ctx)) return true;
994
- return false;
995
- }
996
- case "record": {
997
- return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
998
- }
999
- case "map": {
1000
- return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
1001
- }
1002
- case "set": {
1003
- return isTransforming(def.valueType, ctx);
1004
- }
957
+ const def = (_schema as schemas.$ZodTypes)._zod.def;
1005
958
 
1006
- // inner types
1007
- case "promise":
1008
- case "optional":
1009
- case "nonoptional":
1010
- case "nullable":
1011
- case "readonly":
1012
- return isTransforming(def.innerType, ctx);
1013
- case "lazy":
1014
- return isTransforming(def.getter(), ctx);
1015
- case "default": {
1016
- return isTransforming(def.innerType, ctx);
1017
- }
1018
- case "prefault": {
1019
- return isTransforming(def.innerType, ctx);
1020
- }
1021
- case "custom": {
1022
- return false;
1023
- }
1024
- case "transform": {
1025
- return true;
1026
- }
1027
- case "pipe": {
1028
- return isTransforming(def.in, ctx) || isTransforming(def.out, ctx);
1029
- }
1030
- case "success": {
1031
- return false;
959
+ if (def.type === "transform") return true;
960
+
961
+ if (def.type === "array") return isTransforming(def.element, ctx);
962
+ if (def.type === "set") return isTransforming(def.valueType, ctx);
963
+ if (def.type === "lazy") return isTransforming(def.getter(), ctx);
964
+
965
+ if (
966
+ def.type === "promise" ||
967
+ def.type === "optional" ||
968
+ def.type === "nonoptional" ||
969
+ def.type === "nullable" ||
970
+ def.type === "readonly" ||
971
+ def.type === "default" ||
972
+ def.type === "prefault"
973
+ ) {
974
+ return isTransforming(def.innerType, ctx);
975
+ }
976
+
977
+ if (def.type === "intersection") {
978
+ return isTransforming(def.left, ctx) || isTransforming(def.right, ctx);
979
+ }
980
+ if (def.type === "record" || def.type === "map") {
981
+ return isTransforming(def.keyType, ctx) || isTransforming(def.valueType, ctx);
982
+ }
983
+ if (def.type === "pipe") {
984
+ return isTransforming(def.in, ctx) || isTransforming(def.out, ctx);
985
+ }
986
+
987
+ if (def.type === "object") {
988
+ for (const key in def.shape) {
989
+ if (isTransforming(def.shape[key]!, ctx)) return true;
1032
990
  }
1033
- case "catch": {
1034
- return false;
991
+ return false;
992
+ }
993
+ if (def.type === "union") {
994
+ for (const option of def.options) {
995
+ if (isTransforming(option, ctx)) return true;
1035
996
  }
1036
- case "function": {
1037
- return false;
997
+ return false;
998
+ }
999
+ if (def.type === "tuple") {
1000
+ for (const item of def.items) {
1001
+ if (isTransforming(item, ctx)) return true;
1038
1002
  }
1039
-
1040
- default:
1041
- def satisfies never;
1003
+ if (def.rest && isTransforming(def.rest, ctx)) return true;
1004
+ return false;
1042
1005
  }
1043
- throw new Error(`Unknown schema type: ${(def as any).type}`);
1006
+
1007
+ return false;
1044
1008
  }
@@ -351,6 +351,15 @@ export function esc(str: string): string {
351
351
  return JSON.stringify(str);
352
352
  }
353
353
 
354
+ export function slugify(input: string): string {
355
+ return input
356
+ .toLowerCase()
357
+ .trim()
358
+ .replace(/[^\w\s-]/g, "")
359
+ .replace(/[\s_-]+/g, "-")
360
+ .replace(/^-+|-+$/g, "");
361
+ }
362
+
354
363
  export const captureStackTrace: (targetObject: object, constructorOpt?: Function) => void = (
355
364
  "captureStackTrace" in Error ? Error.captureStackTrace : (..._args: any[]) => {}
356
365
  ) as any;
@@ -381,6 +390,8 @@ export function isPlainObject(o: any): o is Record<PropertyKey, unknown> {
381
390
  const ctor = o.constructor;
382
391
  if (ctor === undefined) return true;
383
392
 
393
+ if (typeof ctor !== "function") return true;
394
+
384
395
  // modified prototype
385
396
  const prot = ctor.prototype;
386
397
  if (isObject(prot) === false) return false;
@@ -1,5 +1,5 @@
1
1
  export const version = {
2
2
  major: 4,
3
3
  minor: 1,
4
- patch: 12 as number,
4
+ patch: 13 as number,
5
5
  } as const;
@@ -60,6 +60,7 @@ const error: () => errors.$ZodErrorMap = () => {
60
60
  duration: "ISO duration",
61
61
  ipv4: "IPv4 address",
62
62
  ipv6: "IPv6 address",
63
+ mac: "MAC address",
63
64
  cidrv4: "IPv4 range",
64
65
  cidrv6: "IPv6 range",
65
66
  base64: "base64-encoded string",
@@ -3,115 +3,246 @@ import type * as errors from "../core/errors.js";
3
3
  import * as util from "../core/util.js";
4
4
 
5
5
  const error: () => errors.$ZodErrorMap = () => {
6
- const Sizable: Record<string, { unit: string; verb: string }> = {
7
- string: { unit: "אותיות", verb: "לכלול" },
8
- file: { unit: "בייטים", verb: "לכלול" },
9
- array: { unit: "פריטים", verb: "לכלול" },
10
- set: { unit: "פריטים", verb: "לכלול" },
6
+ // Hebrew labels + grammatical gender
7
+ const TypeNames: Record<string, { label: string; gender: "m" | "f" }> = {
8
+ string: { label: "מחרוזת", gender: "f" },
9
+ number: { label: "מספר", gender: "m" },
10
+ boolean: { label: "ערך בוליאני", gender: "m" },
11
+ bigint: { label: "BigInt", gender: "m" },
12
+ date: { label: "תאריך", gender: "m" },
13
+ array: { label: "מערך", gender: "m" },
14
+ object: { label: "אובייקט", gender: "m" },
15
+ null: { label: "ערך ריק (null)", gender: "m" },
16
+ undefined: { label: "ערך לא מוגדר (undefined)", gender: "m" },
17
+ symbol: { label: "סימבול (Symbol)", gender: "m" },
18
+ function: { label: "פונקציה", gender: "f" },
19
+ map: { label: "מפה (Map)", gender: "f" },
20
+ set: { label: "קבוצה (Set)", gender: "f" },
21
+ file: { label: "קובץ", gender: "m" },
22
+ promise: { label: "Promise", gender: "m" },
23
+ NaN: { label: "NaN", gender: "m" },
24
+ unknown: { label: "ערך לא ידוע", gender: "m" },
25
+ value: { label: "ערך", gender: "m" },
11
26
  };
12
27
 
13
- function getSizing(origin: string): { unit: string; verb: string } | null {
28
+ // Sizing units for size-related messages + localized origin labels
29
+ const Sizable: Record<string, { unit: string; shortLabel?: string; longLabel?: string }> = {
30
+ string: { unit: "תווים", shortLabel: "קצר", longLabel: "ארוך" },
31
+ file: { unit: "בייטים", shortLabel: "קטן", longLabel: "גדול" },
32
+ array: { unit: "פריטים", shortLabel: "קטן", longLabel: "גדול" },
33
+ set: { unit: "פריטים", shortLabel: "קטן", longLabel: "גדול" },
34
+ number: { unit: "", shortLabel: "קטן", longLabel: "גדול" }, // no unit
35
+ };
36
+
37
+ // Helpers — labels, articles, and verbs
38
+ const typeEntry = (t?: string | null) => (t ? TypeNames[t] : undefined);
39
+
40
+ const typeLabel = (t?: string | null): string => {
41
+ const e = typeEntry(t);
42
+ if (e) return e.label;
43
+ // fallback: show raw string if unknown
44
+ return t ?? TypeNames.unknown.label;
45
+ };
46
+
47
+ const withDefinite = (t?: string | null): string => `ה${typeLabel(t)}`;
48
+
49
+ const verbFor = (t?: string | null): string => {
50
+ const e = typeEntry(t);
51
+ const gender = e?.gender ?? "m";
52
+ return gender === "f" ? "צריכה להיות" : "צריך להיות";
53
+ };
54
+
55
+ const getSizing = (origin?: string | null) => {
56
+ if (!origin) return null;
14
57
  return Sizable[origin] ?? null;
15
- }
58
+ };
16
59
 
60
+ // Robust type parser for "received" — returns a key we understand or a constructor name
17
61
  const parsedType = (data: any): string => {
18
62
  const t = typeof data;
19
-
20
63
  switch (t) {
21
- case "number": {
64
+ case "number":
22
65
  return Number.isNaN(data) ? "NaN" : "number";
23
- }
24
66
  case "object": {
25
- if (Array.isArray(data)) {
26
- return "array";
27
- }
28
- if (data === null) {
29
- return "null";
30
- }
31
-
67
+ if (Array.isArray(data)) return "array";
68
+ if (data === null) return "null";
32
69
  if (Object.getPrototypeOf(data) !== Object.prototype && data.constructor) {
33
- return data.constructor.name;
70
+ return data.constructor.name; // keep as-is (e.g., "Date")
34
71
  }
72
+ return "object";
35
73
  }
74
+ default:
75
+ return t;
36
76
  }
37
- return t;
38
77
  };
39
78
 
40
79
  const Nouns: {
41
- [k in $ZodStringFormats | (string & {})]?: string;
80
+ [k in $ZodStringFormats]: { label: string; gender: "m" | "f" };
42
81
  } = {
43
- regex: "קלט",
44
- email: "כתובת אימייל",
45
- url: "כתובת רשת",
46
- emoji: "אימוג'י",
47
- uuid: "UUID",
48
- uuidv4: "UUIDv4",
49
- uuidv6: "UUIDv6",
50
- nanoid: "nanoid",
51
- guid: "GUID",
52
- cuid: "cuid",
53
- cuid2: "cuid2",
54
- ulid: "ULID",
55
- xid: "XID",
56
- ksuid: "KSUID",
57
- datetime: "תאריך וזמן ISO",
58
- date: "תאריך ISO",
59
- time: "זמן ISO",
60
- duration: "משך זמן ISO",
61
- ipv4: "כתובת IPv4",
62
- ipv6: "כתובת IPv6",
63
- cidrv4: "טווח IPv4",
64
- cidrv6: "טווח IPv6",
65
- base64: "מחרוזת בבסיס 64",
66
- base64url: "מחרוזת בבסיס 64 לכתובות רשת",
67
- json_string: "מחרוזת JSON",
68
- e164: "מספר E.164",
69
- jwt: "JWT",
70
- template_literal: "קלט",
82
+ regex: { label: "קלט", gender: "m" },
83
+ email: { label: "כתובת אימייל", gender: "f" },
84
+ url: { label: "כתובת רשת", gender: "f" },
85
+ emoji: { label: "אימוג'י", gender: "m" },
86
+ uuid: { label: "UUID", gender: "m" },
87
+ nanoid: { label: "nanoid", gender: "m" },
88
+ guid: { label: "GUID", gender: "m" },
89
+ cuid: { label: "cuid", gender: "m" },
90
+ cuid2: { label: "cuid2", gender: "m" },
91
+ ulid: { label: "ULID", gender: "m" },
92
+ xid: { label: "XID", gender: "m" },
93
+ ksuid: { label: "KSUID", gender: "m" },
94
+ datetime: { label: "תאריך וזמן ISO", gender: "m" },
95
+ date: { label: "תאריך ISO", gender: "m" },
96
+ time: { label: "זמן ISO", gender: "m" },
97
+ duration: { label: "משך זמן ISO", gender: "m" },
98
+ ipv4: { label: "כתובת IPv4", gender: "f" },
99
+ ipv6: { label: "כתובת IPv6", gender: "f" },
100
+ cidrv4: { label: "טווח IPv4", gender: "m" },
101
+ cidrv6: { label: "טווח IPv6", gender: "m" },
102
+ base64: { label: "מחרוזת בבסיס 64", gender: "f" },
103
+ base64url: { label: "מחרוזת בבסיס 64 לכתובות רשת", gender: "f" },
104
+ json_string: { label: "מחרוזת JSON", gender: "f" },
105
+ e164: { label: "מספר E.164", gender: "m" },
106
+ jwt: { label: "JWT", gender: "m" },
107
+ ends_with: { label: "קלט", gender: "m" },
108
+ includes: { label: "קלט", gender: "m" },
109
+ lowercase: { label: "קלט", gender: "m" },
110
+ starts_with: { label: "קלט", gender: "m" },
111
+ uppercase: { label: "קלט", gender: "m" },
71
112
  };
72
113
 
73
114
  return (issue) => {
74
115
  switch (issue.code) {
75
- case "invalid_type":
76
- return `קלט לא תקין: צריך ${issue.expected}, התקבל ${parsedType(issue.input)}`;
77
- // return `Invalid input: expected ${issue.expected}, received ${util.getParsedType(issue.input)}`;
78
- case "invalid_value":
79
- if (issue.values.length === 1) return `קלט לא תקין: צריך ${util.stringifyPrimitive(issue.values[0])}`;
80
- return `קלט לא תקין: צריך אחת מהאפשרויות ${util.joinValues(issue.values, "|")}`;
116
+ case "invalid_type": {
117
+ // Expected type: show without definite article for clearer Hebrew
118
+ const expectedKey = issue.expected as string | undefined;
119
+ const expected = typeLabel(expectedKey);
120
+ // Received: show localized label if known, otherwise constructor/raw
121
+ const receivedKey = parsedType(issue.input);
122
+ const received = TypeNames[receivedKey]?.label ?? receivedKey;
123
+ return `קלט לא תקין: צריך להיות ${expected}, התקבל ${received}`;
124
+ }
125
+
126
+ case "invalid_value": {
127
+ if (issue.values.length === 1) {
128
+ return `ערך לא תקין: הערך חייב להיות ${util.stringifyPrimitive(issue.values[0])}`;
129
+ }
130
+ // Join values with proper Hebrew formatting
131
+ const stringified = issue.values.map((v) => util.stringifyPrimitive(v));
132
+ if (issue.values.length === 2) {
133
+ return `ערך לא תקין: האפשרויות המתאימות הן ${stringified[0]} או ${stringified[1]}`;
134
+ }
135
+ // For 3+ values: "a", "b" או "c"
136
+ const lastValue = stringified[stringified.length - 1];
137
+ const restValues = stringified.slice(0, -1).join(", ");
138
+ return `ערך לא תקין: האפשרויות המתאימות הן ${restValues} או ${lastValue}`;
139
+ }
140
+
81
141
  case "too_big": {
82
- const adj = issue.inclusive ? "<=" : "<";
83
142
  const sizing = getSizing(issue.origin);
84
- if (sizing)
85
- return `גדול מדי: ${issue.origin ?? "value"} צריך להיות ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elements"}`;
86
- return `גדול מדי: ${issue.origin ?? "value"} צריך להיות ${adj}${issue.maximum.toString()}`;
143
+ const subject = withDefinite(issue.origin ?? "value");
144
+
145
+ if (issue.origin === "string") {
146
+ // Special handling for strings - more natural Hebrew
147
+ return `${sizing?.longLabel ?? "ארוך"} מדי: ${subject} צריכה להכיל ${issue.maximum.toString()} ${sizing?.unit ?? ""} ${issue.inclusive ? "או פחות" : "לכל היותר"}`.trim();
148
+ }
149
+
150
+ if (issue.origin === "number") {
151
+ // Natural Hebrew for numbers
152
+ const comparison = issue.inclusive ? `קטן או שווה ל-${issue.maximum}` : `קטן מ-${issue.maximum}`;
153
+ return `גדול מדי: ${subject} צריך להיות ${comparison}`;
154
+ }
155
+
156
+ if (issue.origin === "array" || issue.origin === "set") {
157
+ // Natural Hebrew for arrays and sets
158
+ const verb = issue.origin === "set" ? "צריכה" : "צריך";
159
+ const comparison = issue.inclusive
160
+ ? `${issue.maximum} ${sizing?.unit ?? ""} או פחות`
161
+ : `פחות מ-${issue.maximum} ${sizing?.unit ?? ""}`;
162
+ return `גדול מדי: ${subject} ${verb} להכיל ${comparison}`.trim();
163
+ }
164
+
165
+ const adj = issue.inclusive ? "<=" : "<";
166
+ const be = verbFor(issue.origin ?? "value");
167
+ if (sizing?.unit) {
168
+ return `${sizing.longLabel} מדי: ${subject} ${be} ${adj}${issue.maximum.toString()} ${sizing.unit}`;
169
+ }
170
+ return `${sizing?.longLabel ?? "גדול"} מדי: ${subject} ${be} ${adj}${issue.maximum.toString()}`;
87
171
  }
172
+
88
173
  case "too_small": {
89
- const adj = issue.inclusive ? ">=" : ">";
90
174
  const sizing = getSizing(issue.origin);
91
- if (sizing) {
92
- return `קטן מדי: ${issue.origin} צריך להיות ${adj}${issue.minimum.toString()} ${sizing.unit}`;
175
+ const subject = withDefinite(issue.origin ?? "value");
176
+
177
+ if (issue.origin === "string") {
178
+ // Special handling for strings - more natural Hebrew
179
+ return `${sizing?.shortLabel ?? "קצר"} מדי: ${subject} צריכה להכיל ${issue.minimum.toString()} ${sizing?.unit ?? ""} ${issue.inclusive ? "או יותר" : "לפחות"}`.trim();
180
+ }
181
+
182
+ if (issue.origin === "number") {
183
+ // Natural Hebrew for numbers
184
+ const comparison = issue.inclusive ? `גדול או שווה ל-${issue.minimum}` : `גדול מ-${issue.minimum}`;
185
+ return `קטן מדי: ${subject} צריך להיות ${comparison}`;
186
+ }
187
+
188
+ if (issue.origin === "array" || issue.origin === "set") {
189
+ // Natural Hebrew for arrays and sets
190
+ const verb = issue.origin === "set" ? "צריכה" : "צריך";
191
+
192
+ // Special case for singular (minimum === 1)
193
+ if (issue.minimum === 1 && issue.inclusive) {
194
+ const singularPhrase = issue.origin === "set" ? "לפחות פריט אחד" : "לפחות פריט אחד";
195
+ return `קטן מדי: ${subject} ${verb} להכיל ${singularPhrase}`;
196
+ }
197
+
198
+ const comparison = issue.inclusive
199
+ ? `${issue.minimum} ${sizing?.unit ?? ""} או יותר`
200
+ : `יותר מ-${issue.minimum} ${sizing?.unit ?? ""}`;
201
+ return `קטן מדי: ${subject} ${verb} להכיל ${comparison}`.trim();
93
202
  }
94
203
 
95
- return `קטן מדי: ${issue.origin} צריך להיות ${adj}${issue.minimum.toString()}`;
204
+ const adj = issue.inclusive ? ">=" : ">";
205
+ const be = verbFor(issue.origin ?? "value");
206
+ if (sizing?.unit) {
207
+ return `${sizing.shortLabel} מדי: ${subject} ${be} ${adj}${issue.minimum.toString()} ${sizing.unit}`;
208
+ }
209
+ return `${sizing?.shortLabel ?? "קטן"} מדי: ${subject} ${be} ${adj}${issue.minimum.toString()}`;
96
210
  }
211
+
97
212
  case "invalid_format": {
98
213
  const _issue = issue as errors.$ZodStringFormatIssues;
99
- if (_issue.format === "starts_with") return `מחרוזת לא תקינה: חייבת להתחיל ב"${_issue.prefix}"`;
100
- if (_issue.format === "ends_with") return `מחרוזת לא תקינה: חייבת להסתיים ב "${_issue.suffix}"`;
101
- if (_issue.format === "includes") return `מחרוזת לא תקינה: חייבת לכלול "${_issue.includes}"`;
102
- if (_issue.format === "regex") return `מחרוזת לא תקינה: חייבת להתאים לתבנית ${_issue.pattern}`;
103
- return `${Nouns[_issue.format] ?? issue.format} לא תקין`;
214
+ // These apply to strings use feminine grammar + ה׳ הידיעה
215
+ if (_issue.format === "starts_with") return `המחרוזת חייבת להתחיל ב "${_issue.prefix}"`;
216
+ if (_issue.format === "ends_with") return `המחרוזת חייבת להסתיים ב "${_issue.suffix}"`;
217
+ if (_issue.format === "includes") return `המחרוזת חייבת לכלול "${_issue.includes}"`;
218
+ if (_issue.format === "regex") return `המחרוזת חייבת להתאים לתבנית ${_issue.pattern}`;
219
+
220
+ // Handle gender agreement for formats
221
+ const nounEntry = Nouns[_issue.format];
222
+ const noun = nounEntry?.label ?? _issue.format;
223
+ const gender = nounEntry?.gender ?? "m";
224
+ const adjective = gender === "f" ? "תקינה" : "תקין";
225
+ return `${noun} לא ${adjective}`;
104
226
  }
227
+
105
228
  case "not_multiple_of":
106
229
  return `מספר לא תקין: חייב להיות מכפלה של ${issue.divisor}`;
230
+
107
231
  case "unrecognized_keys":
108
232
  return `מפתח${issue.keys.length > 1 ? "ות" : ""} לא מזוה${issue.keys.length > 1 ? "ים" : "ה"}: ${util.joinValues(issue.keys, ", ")}`;
109
- case "invalid_key":
110
- return `מפתח לא תקין ב${issue.origin}`;
233
+
234
+ case "invalid_key": {
235
+ return `שדה לא תקין באובייקט`;
236
+ }
237
+
111
238
  case "invalid_union":
112
239
  return "קלט לא תקין";
113
- case "invalid_element":
114
- return `ערך לא תקין ב${issue.origin}`;
240
+
241
+ case "invalid_element": {
242
+ const place = withDefinite(issue.origin ?? "array");
243
+ return `ערך לא תקין ב${place}`;
244
+ }
245
+
115
246
  default:
116
247
  return `קלט לא תקין`;
117
248
  }
@@ -3,14 +3,14 @@ import type * as errors from "../core/errors.js";
3
3
  import * as util from "../core/util.js";
4
4
 
5
5
  const error: () => errors.$ZodErrorMap = () => {
6
- const Sizable: Record<string, { unit: string }> = {
7
- string: { unit: "tekens" },
8
- file: { unit: "bytes" },
9
- array: { unit: "elementen" },
10
- set: { unit: "elementen" },
6
+ const Sizable: Record<string, { unit: string; verb: string }> = {
7
+ string: { unit: "tekens", verb: "te hebben" },
8
+ file: { unit: "bytes", verb: "te hebben" },
9
+ array: { unit: "elementen", verb: "te hebben" },
10
+ set: { unit: "elementen", verb: "te hebben" },
11
11
  };
12
12
 
13
- function getSizing(origin: string): { unit: string } | null {
13
+ function getSizing(origin: string): { unit: string; verb: string } | null {
14
14
  return Sizable[origin] ?? null;
15
15
  }
16
16
 
@@ -81,17 +81,17 @@ const error: () => errors.$ZodErrorMap = () => {
81
81
  const adj = issue.inclusive ? "<=" : "<";
82
82
  const sizing = getSizing(issue.origin);
83
83
  if (sizing)
84
- return `Te lang: verwacht dat ${issue.origin ?? "waarde"} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elementen"} bevat`;
85
- return `Te lang: verwacht dat ${issue.origin ?? "waarde"} ${adj}${issue.maximum.toString()} is`;
84
+ return `Te groot: verwacht dat ${issue.origin ?? "waarde"} ${sizing.verb} ${adj}${issue.maximum.toString()} ${sizing.unit ?? "elementen"}`;
85
+ return `Te groot: verwacht dat ${issue.origin ?? "waarde"} ${adj}${issue.maximum.toString()} is`;
86
86
  }
87
87
  case "too_small": {
88
88
  const adj = issue.inclusive ? ">=" : ">";
89
89
  const sizing = getSizing(issue.origin);
90
90
  if (sizing) {
91
- return `Te kort: verwacht dat ${issue.origin} ${adj}${issue.minimum.toString()} ${sizing.unit} bevat`;
91
+ return `Te klein: verwacht dat ${issue.origin} ${sizing.verb} ${adj}${issue.minimum.toString()} ${sizing.unit}`;
92
92
  }
93
93
 
94
- return `Te kort: verwacht dat ${issue.origin} ${adj}${issue.minimum.toString()} is`;
94
+ return `Te klein: verwacht dat ${issue.origin} ${adj}${issue.minimum.toString()} is`;
95
95
  }
96
96
  case "invalid_format": {
97
97
  const _issue = issue as errors.$ZodStringFormatIssues;
@@ -6,7 +6,7 @@ export interface ZodMiniISODateTime extends schemas.ZodMiniStringFormat<"datetim
6
6
  _zod: core.$ZodISODateTimeInternals;
7
7
  }
8
8
  export const ZodMiniISODateTime: core.$constructor<ZodMiniISODateTime> = /*@__PURE__*/ core.$constructor(
9
- "$ZodISODateTime",
9
+ "ZodMiniISODateTime",
10
10
  (inst, def) => {
11
11
  core.$ZodISODateTime.init(inst, def);
12
12
  schemas.ZodMiniStringFormat.init(inst, def);
@@ -21,7 +21,7 @@ export interface ZodMiniISODate extends schemas.ZodMiniStringFormat<"date"> {
21
21
  _zod: core.$ZodISODateInternals;
22
22
  }
23
23
  export const ZodMiniISODate: core.$constructor<ZodMiniISODate> = /*@__PURE__*/ core.$constructor(
24
- "$ZodISODate",
24
+ "ZodMiniISODate",
25
25
  (inst, def) => {
26
26
  core.$ZodISODate.init(inst, def);
27
27
  schemas.ZodMiniStringFormat.init(inst, def);
@@ -36,7 +36,7 @@ export interface ZodMiniISOTime extends schemas.ZodMiniStringFormat<"time"> {
36
36
  _zod: core.$ZodISOTimeInternals;
37
37
  }
38
38
  export const ZodMiniISOTime: core.$constructor<ZodMiniISOTime> = /*@__PURE__*/ core.$constructor(
39
- "$ZodISOTime",
39
+ "ZodMiniISOTime",
40
40
  (inst, def) => {
41
41
  core.$ZodISOTime.init(inst, def);
42
42
  schemas.ZodMiniStringFormat.init(inst, def);
@@ -51,7 +51,7 @@ export interface ZodMiniISODuration extends schemas.ZodMiniStringFormat<"duratio
51
51
  _zod: core.$ZodISODurationInternals;
52
52
  }
53
53
  export const ZodMiniISODuration: core.$constructor<ZodMiniISODuration> = /*@__PURE__*/ core.$constructor(
54
- "$ZodISODuration",
54
+ "ZodMiniISODuration",
55
55
  (inst, def) => {
56
56
  core.$ZodISODuration.init(inst, def);
57
57
  schemas.ZodMiniStringFormat.init(inst, def);
@@ -366,6 +366,19 @@ export function cidrv6(params?: string | core.$ZodCIDRv6Params): ZodMiniCIDRv6 {
366
366
  return core._cidrv6(ZodMiniCIDRv6, params);
367
367
  }
368
368
 
369
+ // ZodMiniMAC
370
+ export interface ZodMiniMAC extends _ZodMiniString<core.$ZodMACInternals> {
371
+ // _zod: core.$ZodMACInternals;
372
+ }
373
+ export const ZodMiniMAC: core.$constructor<ZodMiniMAC> = /*@__PURE__*/ core.$constructor("ZodMiniMAC", (inst, def) => {
374
+ core.$ZodMAC.init(inst, def);
375
+ ZodMiniStringFormat.init(inst, def);
376
+ });
377
+
378
+ export function mac(params?: string | core.$ZodMACParams): ZodMiniMAC {
379
+ return core._mac(ZodMiniMAC, params);
380
+ }
381
+
369
382
  // ZodMiniBase64
370
383
  export interface ZodMiniBase64 extends _ZodMiniString<core.$ZodBase64Internals> {
371
384
  // _zod: core.$ZodBase64Internals;
@@ -1601,6 +1614,10 @@ export function superRefine<T>(
1601
1614
  return core._superRefine(fn);
1602
1615
  }
1603
1616
 
1617
+ // Re-export describe and meta from core
1618
+ export const describe = core.describe;
1619
+ export const meta = core.meta;
1620
+
1604
1621
  // instanceof
1605
1622
  abstract class Class {
1606
1623
  constructor(..._args: any[]) {}