@hy_ong/zod-kit 0.0.2 → 0.0.5

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 (51) hide show
  1. package/.claude/settings.local.json +23 -0
  2. package/LICENSE +21 -0
  3. package/README.md +7 -7
  4. package/debug.js +21 -0
  5. package/debug.ts +16 -0
  6. package/dist/index.cjs +1663 -189
  7. package/dist/index.d.cts +324 -32
  8. package/dist/index.d.ts +324 -32
  9. package/dist/index.js +1634 -187
  10. package/eslint.config.mts +8 -0
  11. package/package.json +10 -9
  12. package/src/config.ts +1 -1
  13. package/src/i18n/locales/en.json +123 -49
  14. package/src/i18n/locales/zh-TW.json +123 -46
  15. package/src/index.ts +13 -7
  16. package/src/validators/common/boolean.ts +97 -0
  17. package/src/validators/common/date.ts +171 -0
  18. package/src/validators/common/email.ts +200 -0
  19. package/src/validators/common/id.ts +259 -0
  20. package/src/validators/common/number.ts +194 -0
  21. package/src/validators/common/password.ts +214 -0
  22. package/src/validators/common/text.ts +151 -0
  23. package/src/validators/common/url.ts +207 -0
  24. package/src/validators/taiwan/business-id.ts +140 -0
  25. package/src/validators/taiwan/fax.ts +182 -0
  26. package/src/validators/taiwan/mobile.ts +110 -0
  27. package/src/validators/taiwan/national-id.ts +208 -0
  28. package/src/validators/taiwan/tel.ts +182 -0
  29. package/tests/common/boolean.test.ts +340 -92
  30. package/tests/common/date.test.ts +458 -0
  31. package/tests/common/email.test.ts +232 -60
  32. package/tests/common/id.test.ts +535 -0
  33. package/tests/common/number.test.ts +230 -60
  34. package/tests/common/password.test.ts +281 -54
  35. package/tests/common/text.test.ts +227 -30
  36. package/tests/common/url.test.ts +492 -67
  37. package/tests/taiwan/business-id.test.ts +240 -0
  38. package/tests/taiwan/fax.test.ts +463 -0
  39. package/tests/taiwan/mobile.test.ts +373 -0
  40. package/tests/taiwan/national-id.test.ts +435 -0
  41. package/tests/taiwan/tel.test.ts +467 -0
  42. package/eslint.config.mjs +0 -10
  43. package/src/common/boolean.ts +0 -37
  44. package/src/common/date.ts +0 -44
  45. package/src/common/email.ts +0 -45
  46. package/src/common/integer.ts +0 -47
  47. package/src/common/number.ts +0 -38
  48. package/src/common/password.ts +0 -34
  49. package/src/common/text.ts +0 -35
  50. package/src/common/url.ts +0 -38
  51. package/tests/common/integer.test.ts +0 -90
package/dist/index.cjs CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,89 +17,191 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
21
31
  var index_exports = {};
22
32
  __export(index_exports, {
33
+ ID_PATTERNS: () => ID_PATTERNS,
23
34
  boolean: () => boolean,
35
+ businessId: () => businessId,
36
+ date: () => date,
37
+ detectIdType: () => detectIdType,
24
38
  email: () => email,
39
+ fax: () => fax,
25
40
  getLocale: () => getLocale,
26
- integer: () => integer,
41
+ id: () => id,
42
+ mobile: () => mobile,
43
+ nationalId: () => nationalId,
27
44
  number: () => number,
28
45
  password: () => password,
29
46
  setLocale: () => setLocale,
47
+ tel: () => tel,
30
48
  text: () => text,
31
- url: () => url
49
+ url: () => url,
50
+ validateCitizenId: () => validateCitizenId,
51
+ validateIdType: () => validateIdType,
52
+ validateNewResidentId: () => validateNewResidentId,
53
+ validateOldResidentId: () => validateOldResidentId,
54
+ validateTaiwanBusinessId: () => validateTaiwanBusinessId,
55
+ validateTaiwanFax: () => validateTaiwanFax,
56
+ validateTaiwanMobile: () => validateTaiwanMobile,
57
+ validateTaiwanNationalId: () => validateTaiwanNationalId,
58
+ validateTaiwanTel: () => validateTaiwanTel
32
59
  });
33
60
  module.exports = __toCommonJS(index_exports);
34
61
 
35
- // src/common/boolean.ts
62
+ // src/validators/common/boolean.ts
36
63
  var import_zod = require("zod");
37
64
 
38
65
  // src/i18n/locales/zh-TW.json
39
66
  var zh_TW_default = {
40
67
  common: {
41
68
  boolean: {
42
- required: "\u8ACB\u8F38\u5165 ${label}",
43
- shouldBe: {
44
- true: "${label} \u5FC5\u9808\u70BA\u662F",
45
- false: "${label} \u5FC5\u9808\u70BA\u5426"
46
- }
69
+ required: "\u5FC5\u586B",
70
+ shouldBeTrue: "\u5FC5\u9808\u70BA\u662F",
71
+ shouldBeFalse: "\u5FC5\u9808\u70BA\u5426",
72
+ invalid: "\u5FC5\u9808\u70BA\u5E03\u6797\u503C"
47
73
  },
48
74
  email: {
49
- required: "\u8ACB\u8F38\u5165 ${label}",
50
- min: "${label} \u9577\u5EA6\u81F3\u5C11 ${min} \u5B57\u5143",
51
- max: "${label} \u9577\u5EA6\u6700\u591A ${max} \u5B57\u5143",
52
- includes: "${label} \u5FC5\u9808\u5305\u542B\u300C${includes}\u300D",
53
- invalid: "${label} \u683C\u5F0F\u932F\u8AA4",
54
- domain: "${label} \u5FC5\u9808\u70BA @${domain} \u7DB2\u57DF"
75
+ required: "\u5FC5\u586B",
76
+ invalid: "\u96FB\u5B50\u90F5\u4EF6\u683C\u5F0F\u932F\u8AA4",
77
+ minLength: "\u9577\u5EA6\u81F3\u5C11 ${minLength} \u5B57\u5143",
78
+ maxLength: "\u9577\u5EA6\u6700\u591A ${maxLength} \u5B57\u5143",
79
+ includes: "\u5FC5\u9808\u5305\u542B\u300C${includes}\u300D",
80
+ domain: "\u5FC5\u9808\u70BA ${domain} \u7DB2\u57DF",
81
+ domainBlacklist: "\u4E0D\u5141\u8A31\u4F7F\u7528 ${domain} \u7DB2\u57DF",
82
+ businessOnly: "\u50C5\u5141\u8A31\u4F01\u696D\u90F5\u7BB1\u5730\u5740",
83
+ noDisposable: "\u4E0D\u5141\u8A31\u4F7F\u7528\u81E8\u6642\u90F5\u7BB1\u5730\u5740"
55
84
  },
56
85
  url: {
57
- required: "\u8ACB\u8F38\u5165 ${label}",
58
- min: "${label} \u9577\u5EA6\u81F3\u5C11 ${min} \u5B57\u5143",
59
- max: "${label} \u9577\u5EA6\u6700\u591A ${max} \u5B57\u5143",
60
- includes: "${label} \u5FC5\u9808\u5305\u542B\u300C${includes}\u300D",
61
- invalid: "${label} \u683C\u5F0F\u932F\u8AA4"
86
+ required: "\u5FC5\u586B",
87
+ invalid: "\u7121\u6548\u7684 URL \u683C\u5F0F",
88
+ min: "\u9577\u5EA6\u81F3\u5C11 ${min} \u5B57\u5143",
89
+ max: "\u9577\u5EA6\u6700\u591A ${max} \u5B57\u5143",
90
+ includes: "\u5FC5\u9808\u5305\u542B\u300C${includes}\u300D",
91
+ excludes: "\u4E0D\u5F97\u5305\u542B\u300C${excludes}\u300D",
92
+ protocol: "\u5354\u8B70\u5FC5\u9808\u70BA\uFF1A${protocols}",
93
+ domain: "\u7DB2\u57DF\u5FC5\u9808\u70BA\uFF1A${domains}",
94
+ domainBlacklist: "\u4E0D\u5141\u8A31\u4F7F\u7528\u7DB2\u57DF ${domain}",
95
+ port: "\u9023\u63A5\u57E0\u5FC5\u9808\u70BA\uFF1A${ports}",
96
+ pathStartsWith: "\u8DEF\u5F91\u5FC5\u9808\u4EE5\u300C${path}\u300D\u958B\u982D",
97
+ pathEndsWith: "\u8DEF\u5F91\u5FC5\u9808\u4EE5\u300C${path}\u300D\u7D50\u5C3E",
98
+ hasQuery: "URL \u5FC5\u9808\u5305\u542B\u67E5\u8A62\u53C3\u6578",
99
+ noQuery: "URL \u4E0D\u5F97\u5305\u542B\u67E5\u8A62\u53C3\u6578",
100
+ hasFragment: "URL \u5FC5\u9808\u5305\u542B\u9328\u9EDE",
101
+ noFragment: "URL \u4E0D\u5F97\u5305\u542B\u9328\u9EDE",
102
+ localhost: "\u4E0D\u5141\u8A31\u4F7F\u7528\u672C\u6A5F URL",
103
+ noLocalhost: "\u4E0D\u5141\u8A31\u4F7F\u7528\u672C\u6A5F URL"
62
104
  },
63
105
  password: {
64
- required: "\u8ACB\u8F38\u5165 ${label}",
65
- min: "${label} \u9577\u5EA6\u81F3\u5C11 ${min} \u5B57\u5143",
66
- max: "${label} \u9577\u5EA6\u6700\u591A ${max} \u5B57\u5143",
67
- uppercase: "${label} \u5FC5\u9808\u5305\u542B\u81F3\u5C11\u4E00\u500B\u5927\u5BEB\u5B57\u6BCD",
68
- lowercase: "${label} \u5FC5\u9808\u5305\u542B\u81F3\u5C11\u4E00\u500B\u5C0F\u5BEB\u5B57\u6BCD",
69
- digits: "${label} \u5FC5\u9808\u5305\u542B\u81F3\u5C11\u4E00\u500B\u6578\u5B57",
70
- special: "${label} \u5FC5\u9808\u5305\u542B\u81F3\u5C11\u4E00\u500B\u7279\u6B8A\u7B26\u865F"
106
+ required: "\u5FC5\u586B",
107
+ min: "\u9577\u5EA6\u81F3\u5C11 ${min} \u5B57\u5143",
108
+ max: "\u9577\u5EA6\u6700\u591A ${max} \u5B57\u5143",
109
+ uppercase: "\u5FC5\u9808\u5305\u542B\u81F3\u5C11\u4E00\u500B\u5927\u5BEB\u5B57\u6BCD",
110
+ lowercase: "\u5FC5\u9808\u5305\u542B\u81F3\u5C11\u4E00\u500B\u5C0F\u5BEB\u5B57\u6BCD",
111
+ digits: "\u5FC5\u9808\u5305\u542B\u81F3\u5C11\u4E00\u500B\u6578\u5B57",
112
+ special: "\u5FC5\u9808\u5305\u542B\u81F3\u5C11\u4E00\u500B\u7279\u6B8A\u7B26\u865F",
113
+ noRepeating: "\u4E0D\u53EF\u5305\u542B\u91CD\u8907\u5B57\u5143",
114
+ noSequential: "\u4E0D\u53EF\u5305\u542B\u9023\u7E8C\u5B57\u5143",
115
+ noCommonWords: "\u4E0D\u53EF\u5305\u542B\u5E38\u898B\u5BC6\u78BC\u6216\u6A21\u5F0F",
116
+ minStrength: "\u5BC6\u78BC\u5F37\u5EA6\u5FC5\u9808\u81F3\u5C11\u70BA ${minStrength}",
117
+ excludes: "\u4E0D\u5F97\u5305\u542B\u300C${excludes}\u300D",
118
+ includes: "\u5FC5\u9808\u5305\u542B\u300C${includes}\u300D",
119
+ invalid: "\u5BC6\u78BC\u683C\u5F0F\u932F\u8AA4"
71
120
  },
72
121
  number: {
73
- required: "\u8ACB\u8F38\u5165 ${label}",
74
- min: "${label} \u6700\u5C0F\u503C ${min}",
75
- max: "${label} \u6700\u5927\u503C ${max}"
122
+ required: "\u5FC5\u586B",
123
+ invalid: "\u5FC5\u9808\u70BA\u6709\u6548\u6578\u5B57",
124
+ integer: "\u5FC5\u9808\u70BA\u6574\u6578",
125
+ float: "\u5FC5\u9808\u70BA\u5C0F\u6578",
126
+ min: "\u6700\u5C0F\u503C ${min}",
127
+ max: "\u6700\u5927\u503C ${max}",
128
+ positive: "\u5FC5\u9808\u70BA\u6B63\u6578",
129
+ negative: "\u5FC5\u9808\u70BA\u8CA0\u6578",
130
+ nonNegative: "\u4E0D\u53EF\u70BA\u8CA0\u6578",
131
+ nonPositive: "\u4E0D\u53EF\u70BA\u6B63\u6578",
132
+ multipleOf: "\u5FC5\u9808\u70BA ${multipleOf} \u7684\u500D\u6578",
133
+ finite: "\u5FC5\u9808\u70BA\u6709\u9650\u6578\u5B57",
134
+ precision: "\u5C0F\u6578\u4F4D\u6578\u4E0D\u53EF\u8D85\u904E ${precision} \u4F4D"
76
135
  },
77
136
  id: {
78
- required: "\u8ACB\u9078\u64C7 ${label}",
79
- invalid: "${label} \u7121\u6548"
137
+ required: "\u5FC5\u586B",
138
+ invalid: "\u7121\u6548\u7684 ID \u683C\u5F0F",
139
+ minLength: "\u9577\u5EA6\u81F3\u5C11 ${minLength} \u5B57\u5143",
140
+ maxLength: "\u9577\u5EA6\u6700\u591A ${maxLength} \u5B57\u5143",
141
+ numeric: "\u5FC5\u9808\u70BA\u6578\u5B57 ID",
142
+ uuid: "\u5FC5\u9808\u70BA\u6709\u6548\u7684 UUID",
143
+ objectId: "\u5FC5\u9808\u70BA\u6709\u6548\u7684 MongoDB ObjectId",
144
+ nanoid: "\u5FC5\u9808\u70BA\u6709\u6548\u7684 Nano ID",
145
+ snowflake: "\u5FC5\u9808\u70BA\u6709\u6548\u7684 Snowflake ID",
146
+ cuid: "\u5FC5\u9808\u70BA\u6709\u6548\u7684 CUID",
147
+ ulid: "\u5FC5\u9808\u70BA\u6709\u6548\u7684 ULID",
148
+ shortid: "\u5FC5\u9808\u70BA\u6709\u6548\u7684 Short ID",
149
+ customFormat: "\u7121\u6548\u7684 ID \u683C\u5F0F",
150
+ includes: "\u5FC5\u9808\u5305\u542B\u300C${includes}\u300D",
151
+ excludes: "\u4E0D\u5F97\u5305\u542B\u300C${excludes}\u300D",
152
+ startsWith: "\u5FC5\u9808\u4EE5\u300C${startsWith}\u300D\u958B\u982D",
153
+ endsWith: "\u5FC5\u9808\u4EE5\u300C${endsWith}\u300D\u7D50\u5C3E"
154
+ },
155
+ text: {
156
+ required: "\u5FC5\u586B",
157
+ notEmpty: "\u4E0D\u53EF\u70BA\u7A7A\u767D\u6216\u50C5\u542B\u7A7A\u683C",
158
+ minLength: "\u9577\u5EA6\u81F3\u5C11 ${minLength} \u5B57\u5143",
159
+ maxLength: "\u9577\u5EA6\u6700\u591A ${maxLength} \u5B57\u5143",
160
+ startsWith: "\u5FC5\u9808\u4EE5\u300C${startsWith}\u300D\u958B\u982D",
161
+ endsWith: "\u5FC5\u9808\u4EE5\u300C${endsWith}\u300D\u7D50\u5C3E",
162
+ includes: "\u5FC5\u9808\u5305\u542B\u300C${includes}\u300D",
163
+ excludes: "\u4E0D\u5F97\u5305\u542B\u300C${excludes}\u300D",
164
+ invalid: "\u683C\u5F0F\u932F\u8AA4"
80
165
  },
81
- integer: {
82
- required: "\u8ACB\u8F38\u5165 ${label}",
83
- min: "${label} \u6700\u5C0F\u503C ${min}",
84
- max: "${label} \u6700\u5927\u503C ${max}",
85
- integer: "${label} \u5FC5\u9808\u70BA\u6574\u6578"
166
+ date: {
167
+ required: "\u5FC5\u586B",
168
+ invalid: "\u7121\u6548\u65E5\u671F",
169
+ format: "\u5FC5\u9808\u70BA ${format} \u683C\u5F0F",
170
+ min: "\u65E5\u671F\u4E0D\u5F97\u65E9\u65BC ${min}",
171
+ max: "\u65E5\u671F\u4E0D\u5F97\u665A\u65BC ${max}",
172
+ includes: "\u5FC5\u9808\u5305\u542B\u300C${includes}\u300D",
173
+ excludes: "\u4E0D\u5F97\u5305\u542B\u300C${excludes}\u300D",
174
+ past: "\u5FC5\u9808\u70BA\u904E\u53BB\u7684\u65E5\u671F",
175
+ future: "\u5FC5\u9808\u70BA\u672A\u4F86\u7684\u65E5\u671F",
176
+ today: "\u5FC5\u9808\u70BA\u4ECA\u5929",
177
+ notToday: "\u4E0D\u5F97\u70BA\u4ECA\u5929",
178
+ weekday: "\u5FC5\u9808\u70BA\u5DE5\u4F5C\u65E5\uFF08\u9031\u4E00\u81F3\u9031\u4E94\uFF09",
179
+ weekend: "\u5FC5\u9808\u70BA\u9031\u672B\uFF08\u9031\u516D\u81F3\u9031\u65E5\uFF09"
180
+ }
181
+ },
182
+ taiwan: {
183
+ businessId: {
184
+ required: "\u5FC5\u586B",
185
+ invalid: "\u7121\u6548\u7684\u7D71\u4E00\u7DE8\u865F"
86
186
  },
87
- float: {
88
- required: "\u8ACB\u8F38\u5165 ${label}",
89
- float: "${label} \u5FC5\u9808\u70BA\u6D6E\u9EDE\u6578",
90
- min: "${label} \u6700\u5C0F\u503C ${min}",
91
- max: "${label} \u6700\u5927\u503C ${max}"
187
+ nationalId: {
188
+ required: "\u5FC5\u586B",
189
+ invalid: "\u7121\u6548\u7684\u8EAB\u5206\u8B49\u5B57\u865F"
92
190
  },
93
- text: {
94
- required: "\u8ACB\u8F38\u5165 ${label}",
95
- min: "${label} \u9577\u5EA6\u81F3\u5C11 ${min} \u5B57\u5143",
96
- max: "${label} \u9577\u5EA6\u6700\u591A ${max} \u5B57\u5143",
97
- startsWith: "${label} \u5FC5\u9808\u4EE5\u300C${startsWith}\u300D\u958B\u982D",
98
- endsWith: "${label} \u5FC5\u9808\u4EE5\u300C${endsWith}\u300D\u7D50\u5C3E",
99
- includes: "${label} \u5FC5\u9808\u5305\u542B\u300C${includes}\u300D",
100
- invalid: "${label} \u683C\u5F0F\u932F\u8AA4"
191
+ mobile: {
192
+ required: "\u5FC5\u586B",
193
+ invalid: "\u7121\u6548\u7684\u624B\u6A5F\u865F\u78BC\u683C\u5F0F",
194
+ notInWhitelist: "\u4E0D\u5728\u5141\u8A31\u7684\u624B\u6A5F\u865F\u78BC\u6E05\u55AE\u4E2D"
195
+ },
196
+ tel: {
197
+ required: "\u5FC5\u586B",
198
+ invalid: "\u7121\u6548\u7684\u5E02\u8A71\u865F\u78BC\u683C\u5F0F",
199
+ notInWhitelist: "\u4E0D\u5728\u5141\u8A31\u7684\u5E02\u8A71\u865F\u78BC\u6E05\u55AE\u4E2D"
200
+ },
201
+ fax: {
202
+ required: "\u5FC5\u586B",
203
+ invalid: "\u7121\u6548\u7684\u50B3\u771F\u865F\u78BC\u683C\u5F0F",
204
+ notInWhitelist: "\u4E0D\u5728\u5141\u8A31\u7684\u50B3\u771F\u865F\u78BC\u6E05\u55AE\u4E2D"
101
205
  }
102
206
  }
103
207
  };
@@ -106,74 +210,148 @@ var zh_TW_default = {
106
210
  var en_default = {
107
211
  common: {
108
212
  boolean: {
109
- required: "${label} is required",
110
- shouldBe: {
111
- true: "${label} must be True",
112
- false: "${label} must be False"
113
- }
213
+ required: "Required",
214
+ shouldBeTrue: "Must be True",
215
+ shouldBeFalse: "Must be False",
216
+ invalid: "Must be a boolean value"
114
217
  },
115
218
  email: {
116
- required: "${label} is required",
117
- min: "${label} must be at least ${min} characters",
118
- max: "${label} must be at most ${max} characters",
119
- includes: "${label} must include ${includes}",
120
- invalid: "${label} is invalid format",
121
- domain: "${label} must be under the domain @${domain}"
219
+ required: "Required",
220
+ invalid: "Invalid email format",
221
+ minLength: "Must be at least ${minLength} characters",
222
+ maxLength: "Must be at most ${maxLength} characters",
223
+ includes: "Must include ${includes}",
224
+ domain: "Must be from domain: ${domain}",
225
+ domainBlacklist: "Domain ${domain} is not allowed",
226
+ businessOnly: "Only business email addresses are allowed",
227
+ noDisposable: "Disposable email addresses are not allowed"
122
228
  },
123
229
  url: {
124
- required: "${label} is required",
125
- min: "${label} must be at least ${min} characters",
126
- max: "${label} must be at most ${max} characters",
127
- includes: "${label} must include ${includes}",
128
- invalid: "${label} is invalid format"
230
+ required: "Required",
231
+ invalid: "Invalid URL format",
232
+ min: "Must be at least ${min} characters",
233
+ max: "Must be at most ${max} characters",
234
+ includes: "Must include ${includes}",
235
+ excludes: "Must not contain ${excludes}",
236
+ protocol: "Protocol must be one of: ${protocols}",
237
+ domain: "Domain must be one of: ${domains}",
238
+ domainBlacklist: "Domain ${domain} is not allowed",
239
+ port: "Port must be one of: ${ports}",
240
+ pathStartsWith: "Path must start with ${path}",
241
+ pathEndsWith: "Path must end with ${path}",
242
+ hasQuery: "URL must have query parameters",
243
+ noQuery: "URL must not have query parameters",
244
+ hasFragment: "URL must have a fragment",
245
+ noFragment: "URL must not have a fragment",
246
+ localhost: "Localhost URLs are not allowed",
247
+ noLocalhost: "Localhost URLs are not allowed"
129
248
  },
130
249
  password: {
131
- required: "${label} is required",
132
- min: "${label} must be at least ${min} characters",
133
- max: "${label} must be at most ${max} characters",
134
- uppercase: "${label} must include at least one uppercase letter",
135
- lowercase: "${label} must include at least one lowercase letter",
136
- digits: "${label} must include at least one digit",
137
- special: "${label} must include at least one special character"
250
+ required: "Required",
251
+ min: "Must be at least ${min} characters",
252
+ max: "Must be at most ${max} characters",
253
+ uppercase: "Must include at least one uppercase letter",
254
+ lowercase: "Must include at least one lowercase letter",
255
+ digits: "Must include at least one digit",
256
+ special: "Must include at least one special character",
257
+ noRepeating: "Must not contain repeating characters",
258
+ noSequential: "Must not contain sequential characters",
259
+ noCommonWords: "Must not contain common words or patterns",
260
+ minStrength: "Password strength must be at least ${minStrength}",
261
+ excludes: "Must not contain ${excludes}",
262
+ includes: "Must include ${includes}",
263
+ invalid: "Invalid password format"
138
264
  },
139
265
  number: {
140
- required: "${label} is required",
141
- min: "${label} must be at least ${min}",
142
- max: "${label} must be at most ${max}"
266
+ required: "Required",
267
+ invalid: "Must be a valid number",
268
+ integer: "Must be an integer",
269
+ float: "Must be a decimal number",
270
+ min: "Must be at least ${min}",
271
+ max: "Must be at most ${max}",
272
+ positive: "Must be positive",
273
+ negative: "Must be negative",
274
+ nonNegative: "Must be non-negative",
275
+ nonPositive: "Must be non-positive",
276
+ multipleOf: "Must be a multiple of ${multipleOf}",
277
+ finite: "Must be a finite number",
278
+ precision: "Must have at most ${precision} decimal places"
143
279
  },
144
- integer: {
145
- required: "${label} is required",
146
- min: "${label} must be at least ${min}",
147
- max: "${label} must be at most ${max}",
148
- integer: "${label} must be an integer"
149
- },
150
- float: {
151
- required: "${label} is required",
152
- min: "${label} must be at least ${min}",
153
- max: "${label} must be at most ${max}",
154
- float: "${label} must be an float"
280
+ id: {
281
+ required: "Required",
282
+ invalid: "Invalid ID format",
283
+ minLength: "Must be at least ${minLength} characters",
284
+ maxLength: "Must be at most ${maxLength} characters",
285
+ numeric: "Must be a numeric ID",
286
+ uuid: "Must be a valid UUID",
287
+ objectId: "Must be a valid MongoDB ObjectId",
288
+ nanoid: "Must be a valid Nano ID",
289
+ snowflake: "Must be a valid Snowflake ID",
290
+ cuid: "Must be a valid CUID",
291
+ ulid: "Must be a valid ULID",
292
+ shortid: "Must be a valid Short ID",
293
+ customFormat: "Invalid ID format",
294
+ includes: "Must include ${includes}",
295
+ excludes: "Must not contain ${excludes}",
296
+ startsWith: "Must start with ${startsWith}",
297
+ endsWith: "Must end with ${endsWith}"
155
298
  },
156
299
  text: {
157
- required: "${label} is required",
158
- min: "${label} must be at least ${min} characters",
159
- max: "${label} must be at most ${max} characters",
160
- startsWith: "${label} must start with ${startsWith}",
161
- endsWith: "${label} must end with ${endsWith}",
162
- includes: "${label} must include ${includes}",
163
- invalid: "${label} is invalid format"
300
+ required: "Required",
301
+ notEmpty: "Cannot be empty or whitespace only",
302
+ minLength: "Must be at least ${minLength} characters",
303
+ maxLength: "Must be at most ${maxLength} characters",
304
+ startsWith: "Must start with ${startsWith}",
305
+ endsWith: "Must end with ${endsWith}",
306
+ includes: "Must include ${includes}",
307
+ excludes: "Must not contain ${excludes}",
308
+ invalid: "Invalid format"
164
309
  },
165
310
  date: {
166
- required: "${label} is required",
167
- min: "${label} must be at least ${min} characters",
168
- max: "${label} must be at most ${max} characters",
169
- includes: "${label} must include ${includes}",
170
- format: "${label} must be in ${format} format"
311
+ required: "Required",
312
+ invalid: "Invalid date",
313
+ format: "Must be in ${format} format",
314
+ min: "Date must be on or after ${min}",
315
+ max: "Date must be on or before ${max}",
316
+ includes: "Must include ${includes}",
317
+ excludes: "Must not contain ${excludes}",
318
+ past: "Date must be in the past",
319
+ future: "Date must be in the future",
320
+ today: "Date must be today",
321
+ notToday: "Date must not be today",
322
+ weekday: "Date must be a weekday (Monday-Friday)",
323
+ weekend: "Date must be a weekend (Saturday-Sunday)"
324
+ }
325
+ },
326
+ taiwan: {
327
+ businessId: {
328
+ required: "Required",
329
+ invalid: "Invalid Taiwan Business ID"
330
+ },
331
+ nationalId: {
332
+ required: "Required",
333
+ invalid: "Invalid Taiwan National ID"
334
+ },
335
+ mobile: {
336
+ required: "Required",
337
+ invalid: "Invalid Taiwan mobile phone format",
338
+ notInWhitelist: "Not in allowed mobile phone list"
339
+ },
340
+ tel: {
341
+ required: "Required",
342
+ invalid: "Invalid Taiwan telephone format",
343
+ notInWhitelist: "Not in allowed telephone list"
344
+ },
345
+ fax: {
346
+ required: "Required",
347
+ invalid: "Invalid Taiwan fax format",
348
+ notInWhitelist: "Not in allowed fax list"
171
349
  }
172
350
  }
173
351
  };
174
352
 
175
353
  // src/config.ts
176
- var currentLocale = "zh-TW";
354
+ var currentLocale = "en";
177
355
  var setLocale = (locale) => {
178
356
  currentLocale = locale;
179
357
  };
@@ -195,149 +373,1445 @@ function getNestedValue(obj, path) {
195
373
  return typeof result === "string" ? result : void 0;
196
374
  }
197
375
 
198
- // src/common/boolean.ts
376
+ // src/validators/common/boolean.ts
199
377
  function boolean(options) {
200
- const { required = true, label, defaultValue = null, shouldBe } = options ?? {};
378
+ const {
379
+ required = true,
380
+ defaultValue = null,
381
+ shouldBe,
382
+ truthyValues = [true, "true", 1, "1", "yes", "on"],
383
+ falsyValues = [false, "false", 0, "0", "no", "off"],
384
+ strict = false,
385
+ transform,
386
+ i18n
387
+ } = options ?? {};
388
+ const getMessage = (key, params) => {
389
+ if (i18n) {
390
+ const currentLocale2 = getLocale();
391
+ const customMessages = i18n[currentLocale2];
392
+ if (customMessages && customMessages[key]) {
393
+ const template = customMessages[key];
394
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
395
+ }
396
+ }
397
+ return t(`common.boolean.${key}`, params);
398
+ };
201
399
  let result = import_zod.z.preprocess(
202
400
  (val) => {
203
401
  if (val === "" || val === void 0 || val === null) return defaultValue;
204
- if (val === "true" || val === 1 || val === "1") return true;
205
- if (val === "false" || val === 0 || val === "0") return false;
402
+ if (strict && typeof val !== "boolean" && val !== null) {
403
+ return val;
404
+ }
405
+ if (truthyValues.includes(val)) {
406
+ let processed = true;
407
+ if (transform) processed = transform(processed);
408
+ return processed;
409
+ }
410
+ if (falsyValues.includes(val)) {
411
+ let processed = false;
412
+ if (transform) processed = transform(processed);
413
+ return processed;
414
+ }
206
415
  return val;
207
416
  },
208
417
  import_zod.z.union([import_zod.z.literal(true), import_zod.z.literal(false), import_zod.z.literal(null)])
209
418
  );
210
419
  if (required && defaultValue === null) {
211
- result = result.refine((val) => val !== null, { message: t("common.boolean.required", { label }) });
420
+ result = result.refine((val) => val !== null, { message: getMessage("required") });
212
421
  }
213
422
  if (shouldBe === true) {
214
- result = result.refine((val) => val === true, { message: t("common.boolean.shouldBe.true", { label }) });
423
+ result = result.refine((val) => val === true, { message: getMessage("shouldBeTrue") });
215
424
  } else if (shouldBe === false) {
216
- result = result.refine((val) => val === false, { message: t("common.boolean.shouldBe.false", { label }) });
425
+ result = result.refine((val) => val === false, { message: getMessage("shouldBeFalse") });
426
+ }
427
+ if (strict) {
428
+ result = result.refine(
429
+ (val) => {
430
+ return val === null || typeof val === "boolean";
431
+ },
432
+ { message: getMessage("invalid") }
433
+ );
217
434
  }
218
435
  return result;
219
436
  }
220
437
 
221
- // src/common/email.ts
438
+ // src/validators/common/date.ts
222
439
  var import_zod2 = require("zod");
223
- function email(options) {
224
- const { required = true, label, domain, min, max, includes } = options ?? {};
225
- const baseSchema = required ? import_zod2.z.preprocess(
226
- (val) => val === "" || val === null || val === void 0 ? null : val,
227
- import_zod2.z.email({
228
- error: (issue) => {
229
- if (issue.code === "invalid_type") return t("common.email.required", { label });
230
- else if (issue.code === "invalid_format") return t("common.email.invalid", { label });
231
- return t("common.email.invalid", { label });
232
- }
233
- })
234
- ) : import_zod2.z.preprocess((val) => val === "" || val === null || val === void 0 ? null : val, import_zod2.z.email({ message: t("common.email.invalid", { label }) }).nullable());
235
- const schema = baseSchema.refine((val) => required ? val !== "" && val !== "null" && val !== "undefined" : true, { message: t("common.text.required", { label }) }).refine((val) => val === null || min === void 0 || val.length >= min, { message: t("common.text.min", { label, min }) }).refine((val) => val === null || max === void 0 || val.length <= max, { message: t("common.text.max", { label, max }) }).refine((val) => val === null || includes === void 0 || val.includes(includes), { message: t("common.text.includes", { label, includes }) }).refine(
236
- (val) => {
237
- if (val === null || domain === void 0) return true;
238
- return val.split("@")[1]?.toLowerCase() === domain.toLowerCase();
239
- },
240
- { message: t("common.email.domain", { label, domain }) }
241
- );
440
+ var import_dayjs = __toESM(require("dayjs"), 1);
441
+ var import_customParseFormat = __toESM(require("dayjs/plugin/customParseFormat"), 1);
442
+ var import_isSameOrAfter = __toESM(require("dayjs/plugin/isSameOrAfter"), 1);
443
+ var import_isSameOrBefore = __toESM(require("dayjs/plugin/isSameOrBefore"), 1);
444
+ var import_isToday = __toESM(require("dayjs/plugin/isToday"), 1);
445
+ var import_weekday = __toESM(require("dayjs/plugin/weekday"), 1);
446
+ import_dayjs.default.extend(import_isSameOrAfter.default);
447
+ import_dayjs.default.extend(import_isSameOrBefore.default);
448
+ import_dayjs.default.extend(import_customParseFormat.default);
449
+ import_dayjs.default.extend(import_isToday.default);
450
+ import_dayjs.default.extend(import_weekday.default);
451
+ function date(options) {
452
+ const {
453
+ required = true,
454
+ min,
455
+ max,
456
+ format = "YYYY-MM-DD",
457
+ includes,
458
+ excludes,
459
+ mustBePast,
460
+ mustBeFuture,
461
+ mustBeToday,
462
+ mustNotBeToday,
463
+ weekdaysOnly,
464
+ weekendsOnly,
465
+ transform,
466
+ defaultValue = null,
467
+ i18n
468
+ } = options ?? {};
469
+ const actualDefaultValue = defaultValue ?? (required ? "" : null);
470
+ const getMessage = (key, params) => {
471
+ if (i18n) {
472
+ const currentLocale2 = getLocale();
473
+ const customMessages = i18n[currentLocale2];
474
+ if (customMessages && customMessages[key]) {
475
+ const template = customMessages[key];
476
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
477
+ }
478
+ }
479
+ return t(`common.date.${key}`, params);
480
+ };
481
+ const preprocessFn = (val) => {
482
+ if (val === "" || val === null || val === void 0) {
483
+ return actualDefaultValue;
484
+ }
485
+ let processed = String(val).trim();
486
+ if (transform) {
487
+ processed = transform(processed);
488
+ }
489
+ return processed;
490
+ };
491
+ const baseSchema = required ? import_zod2.z.preprocess(preprocessFn, import_zod2.z.string()) : import_zod2.z.preprocess(preprocessFn, import_zod2.z.string().nullable());
492
+ const schema = baseSchema.refine((val) => {
493
+ if (val === null) return true;
494
+ if (required && (val === "" || val === "null" || val === "undefined")) {
495
+ throw new import_zod2.z.ZodError([{ code: "custom", message: getMessage("required"), path: [] }]);
496
+ }
497
+ if (val !== null && !(0, import_dayjs.default)(val, format, true).isValid()) {
498
+ throw new import_zod2.z.ZodError([{ code: "custom", message: getMessage("format", { format }), path: [] }]);
499
+ }
500
+ const dateObj = (0, import_dayjs.default)(val, format);
501
+ if (val !== null && min !== void 0 && !dateObj.isSameOrAfter((0, import_dayjs.default)(min, format))) {
502
+ throw new import_zod2.z.ZodError([{ code: "custom", message: getMessage("min", { min }), path: [] }]);
503
+ }
504
+ if (val !== null && max !== void 0 && !dateObj.isSameOrBefore((0, import_dayjs.default)(max, format))) {
505
+ throw new import_zod2.z.ZodError([{ code: "custom", message: getMessage("max", { max }), path: [] }]);
506
+ }
507
+ if (val !== null && includes !== void 0 && !val.includes(includes)) {
508
+ throw new import_zod2.z.ZodError([{ code: "custom", message: getMessage("includes", { includes }), path: [] }]);
509
+ }
510
+ if (val !== null && excludes !== void 0) {
511
+ const excludeList = Array.isArray(excludes) ? excludes : [excludes];
512
+ for (const exclude of excludeList) {
513
+ if (val.includes(exclude)) {
514
+ throw new import_zod2.z.ZodError([{ code: "custom", message: getMessage("excludes", { excludes: exclude }), path: [] }]);
515
+ }
516
+ }
517
+ }
518
+ const today = (0, import_dayjs.default)().startOf("day");
519
+ const targetDate = dateObj.startOf("day");
520
+ if (val !== null && mustBePast && !targetDate.isBefore(today)) {
521
+ throw new import_zod2.z.ZodError([{ code: "custom", message: getMessage("past"), path: [] }]);
522
+ }
523
+ if (val !== null && mustBeFuture && !targetDate.isAfter(today)) {
524
+ throw new import_zod2.z.ZodError([{ code: "custom", message: getMessage("future"), path: [] }]);
525
+ }
526
+ if (val !== null && mustBeToday && !targetDate.isSame(today)) {
527
+ throw new import_zod2.z.ZodError([{ code: "custom", message: getMessage("today"), path: [] }]);
528
+ }
529
+ if (val !== null && mustNotBeToday && targetDate.isSame(today)) {
530
+ throw new import_zod2.z.ZodError([{ code: "custom", message: getMessage("notToday"), path: [] }]);
531
+ }
532
+ if (val !== null && weekdaysOnly && (dateObj.day() === 0 || dateObj.day() === 6)) {
533
+ throw new import_zod2.z.ZodError([{ code: "custom", message: getMessage("weekday"), path: [] }]);
534
+ }
535
+ if (val !== null && weekendsOnly && dateObj.day() !== 0 && dateObj.day() !== 6) {
536
+ throw new import_zod2.z.ZodError([{ code: "custom", message: getMessage("weekend"), path: [] }]);
537
+ }
538
+ return true;
539
+ });
242
540
  return schema;
243
541
  }
244
542
 
245
- // src/common/url.ts
543
+ // src/validators/common/email.ts
246
544
  var import_zod3 = require("zod");
247
- function url(options) {
248
- const { required = true, label, min, max, includes } = options ?? {};
249
- const baseSchema = required ? import_zod3.z.preprocess(
250
- (val) => val === "" || val === null || val === void 0 ? null : val,
251
- import_zod3.z.url({
252
- error: (issue) => {
253
- if (issue.code === "invalid_type") return t("common.url.required", { label });
254
- else if (issue.code === "invalid_format") return t("common.url.invalid", { label });
255
- return t("common.url.invalid", { label });
256
- }
257
- })
258
- ) : import_zod3.z.preprocess((val) => val === "" || val === null || val === void 0 ? null : val, import_zod3.z.url({ message: t("common.url.invalid", { label }) }).nullable());
259
- const schema = baseSchema.refine((val) => required ? val !== "" && val !== "null" && val !== "undefined" : true, { message: t("common.text.required", { label }) }).refine((val) => val === null || min === void 0 || val.length >= min, { message: t("common.text.min", { label, min }) }).refine((val) => val === null || max === void 0 || val.length <= max, { message: t("common.text.max", { label, max }) }).refine((val) => val === null || includes === void 0 || val.includes(includes), { message: t("common.text.includes", { label, includes }) });
545
+ function email(options) {
546
+ const {
547
+ required = true,
548
+ domain,
549
+ domainBlacklist,
550
+ minLength,
551
+ maxLength,
552
+ includes,
553
+ excludes,
554
+ allowSubdomains = true,
555
+ businessOnly = false,
556
+ noDisposable = false,
557
+ lowercase = true,
558
+ transform,
559
+ defaultValue,
560
+ i18n
561
+ } = options ?? {};
562
+ const getMessage = (key, params) => {
563
+ if (i18n) {
564
+ const currentLocale2 = getLocale();
565
+ const customMessages = i18n[currentLocale2];
566
+ if (customMessages && customMessages[key]) {
567
+ const template = customMessages[key];
568
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
569
+ }
570
+ }
571
+ return t(`common.email.${key}`, params);
572
+ };
573
+ const disposableDomains = ["10minutemail.com", "tempmail.org", "guerrillamail.com", "mailinator.com", "yopmail.com", "temp-mail.org", "throwaway.email", "getnada.com", "maildrop.cc"];
574
+ const freeEmailDomains = ["gmail.com", "yahoo.com", "hotmail.com", "outlook.com", "icloud.com", "aol.com", "protonmail.com", "zoho.com"];
575
+ const actualDefaultValue = defaultValue ?? null;
576
+ const baseSchema = import_zod3.z.preprocess(
577
+ (val) => {
578
+ if (val === "" || val === null || val === void 0) {
579
+ return actualDefaultValue;
580
+ }
581
+ let processed = String(val).trim();
582
+ if (lowercase) {
583
+ processed = processed.toLowerCase();
584
+ }
585
+ if (transform) {
586
+ processed = transform(processed);
587
+ }
588
+ return processed;
589
+ },
590
+ import_zod3.z.union([import_zod3.z.string().email(), import_zod3.z.null()])
591
+ );
592
+ const schema = baseSchema.refine((val) => {
593
+ if (required && val === null) {
594
+ throw new import_zod3.z.ZodError([{ code: "custom", message: getMessage("required"), path: [] }]);
595
+ }
596
+ if (val === null) return true;
597
+ if (typeof val !== "string") {
598
+ throw new import_zod3.z.ZodError([{ code: "custom", message: getMessage("invalid"), path: [] }]);
599
+ }
600
+ if (minLength !== void 0 && val.length < minLength) {
601
+ throw new import_zod3.z.ZodError([{ code: "custom", message: getMessage("minLength", { minLength }), path: [] }]);
602
+ }
603
+ if (maxLength !== void 0 && val.length > maxLength) {
604
+ throw new import_zod3.z.ZodError([{ code: "custom", message: getMessage("maxLength", { maxLength }), path: [] }]);
605
+ }
606
+ if (includes !== void 0 && !val.includes(includes)) {
607
+ throw new import_zod3.z.ZodError([{ code: "custom", message: getMessage("includes", { includes }), path: [] }]);
608
+ }
609
+ if (excludes !== void 0) {
610
+ const excludeList = Array.isArray(excludes) ? excludes : [excludes];
611
+ for (const exclude of excludeList) {
612
+ if (val.includes(exclude)) {
613
+ throw new import_zod3.z.ZodError([{ code: "custom", message: getMessage("includes", { includes: exclude }), path: [] }]);
614
+ }
615
+ }
616
+ }
617
+ const emailDomain = val.split("@")[1]?.toLowerCase();
618
+ if (!emailDomain) {
619
+ throw new import_zod3.z.ZodError([{ code: "custom", message: getMessage("invalid"), path: [] }]);
620
+ }
621
+ if (businessOnly) {
622
+ const isFreeProvider = freeEmailDomains.some((freeDomain) => {
623
+ if (allowSubdomains) {
624
+ return emailDomain === freeDomain || emailDomain.endsWith("." + freeDomain);
625
+ }
626
+ return emailDomain === freeDomain;
627
+ });
628
+ if (isFreeProvider) {
629
+ throw new import_zod3.z.ZodError([{ code: "custom", message: getMessage("businessOnly"), path: [] }]);
630
+ }
631
+ }
632
+ if (domainBlacklist && domainBlacklist.length > 0) {
633
+ const isBlacklisted = domainBlacklist.some((blacklistedDomain) => {
634
+ const lowerDomain = blacklistedDomain.toLowerCase();
635
+ if (allowSubdomains) {
636
+ return emailDomain === lowerDomain || emailDomain.endsWith("." + lowerDomain);
637
+ }
638
+ return emailDomain === lowerDomain;
639
+ });
640
+ if (isBlacklisted) {
641
+ throw new import_zod3.z.ZodError([{ code: "custom", message: getMessage("domainBlacklist", { domain: emailDomain }), path: [] }]);
642
+ }
643
+ }
644
+ if (domain !== void 0) {
645
+ const allowedDomains = Array.isArray(domain) ? domain : [domain];
646
+ const isAllowed = allowedDomains.some((allowedDomain) => {
647
+ const lowerDomain = allowedDomain.toLowerCase();
648
+ if (allowSubdomains) {
649
+ return emailDomain === lowerDomain || emailDomain.endsWith("." + lowerDomain);
650
+ }
651
+ return emailDomain === lowerDomain;
652
+ });
653
+ if (!isAllowed) {
654
+ throw new import_zod3.z.ZodError([{ code: "custom", message: getMessage("domain", { domain: Array.isArray(domain) ? domain.join(", ") : domain }), path: [] }]);
655
+ }
656
+ }
657
+ if (noDisposable) {
658
+ const isDisposable = disposableDomains.some((disposableDomain) => {
659
+ if (allowSubdomains) {
660
+ return emailDomain === disposableDomain || emailDomain.endsWith("." + disposableDomain);
661
+ }
662
+ return emailDomain === disposableDomain;
663
+ });
664
+ if (isDisposable) {
665
+ throw new import_zod3.z.ZodError([{ code: "custom", message: getMessage("noDisposable"), path: [] }]);
666
+ }
667
+ }
668
+ return true;
669
+ });
260
670
  return schema;
261
671
  }
262
672
 
263
- // src/common/text.ts
673
+ // src/validators/common/id.ts
264
674
  var import_zod4 = require("zod");
265
- function text(options) {
266
- const { required = true, label, min, max, startsWith, endsWith, includes, regex, defaultValue = null } = options ?? {};
267
- const baseSchema = required ? import_zod4.z.preprocess((val) => val === "" || val === null || val === void 0 ? defaultValue : val, import_zod4.z.coerce.string().trim()) : import_zod4.z.preprocess((val) => val === "" || val === null || val === void 0 ? defaultValue : val, import_zod4.z.coerce.string().trim().nullable());
268
- const schema = baseSchema.refine((val) => required ? val !== "" && val !== "null" && val !== "undefined" : true, { message: t("common.text.required", { label }) }).refine((val) => val === null || min === void 0 || val.length >= min, { message: t("common.text.min", { label, min }) }).refine((val) => val === null || max === void 0 || val.length <= max, { message: t("common.text.max", { label, max }) }).refine((val) => val === null || startsWith === void 0 || val.startsWith(startsWith), { message: t("common.text.startsWith", { label, startsWith }) }).refine((val) => val === null || endsWith === void 0 || val.endsWith(endsWith), { message: t("common.text.endsWith", { label, endsWith }) }).refine((val) => val === null || includes === void 0 || val.includes(includes), { message: t("common.text.includes", { label, includes }) }).refine((val) => val === null || regex === void 0 || regex.test(val), { message: t("common.text.invalid", { label, regex }) });
675
+ var ID_PATTERNS = {
676
+ numeric: /^\d+$/,
677
+ uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
678
+ objectId: /^[0-9a-f]{24}$/i,
679
+ nanoid: /^[A-Za-z0-9_-]{21}$/,
680
+ snowflake: /^\d{19}$/,
681
+ cuid: /^c[a-z0-9]{24}$/,
682
+ ulid: /^[0-9A-HJKMNP-TV-Z]{26}$/,
683
+ shortid: /^[A-Za-z0-9_-]{7,14}$/
684
+ };
685
+ var detectIdType = (value) => {
686
+ const orderedTypes = [
687
+ ["uuid", ID_PATTERNS.uuid],
688
+ ["objectId", ID_PATTERNS.objectId],
689
+ ["snowflake", ID_PATTERNS.snowflake],
690
+ ["cuid", ID_PATTERNS.cuid],
691
+ ["ulid", ID_PATTERNS.ulid],
692
+ ["nanoid", ID_PATTERNS.nanoid],
693
+ ["numeric", ID_PATTERNS.numeric],
694
+ ["shortid", ID_PATTERNS.shortid]
695
+ // 放最後,因為最通用
696
+ ];
697
+ for (const [type, pattern] of orderedTypes) {
698
+ if (pattern.test(value)) {
699
+ return type;
700
+ }
701
+ }
702
+ return null;
703
+ };
704
+ var validateIdType = (value, type) => {
705
+ if (type === "auto") {
706
+ return detectIdType(value) !== null;
707
+ }
708
+ const pattern = ID_PATTERNS[type];
709
+ return pattern ? pattern.test(value) : false;
710
+ };
711
+ function id(options) {
712
+ const {
713
+ required = true,
714
+ type = "auto",
715
+ minLength,
716
+ maxLength,
717
+ allowedTypes,
718
+ customRegex,
719
+ includes,
720
+ excludes,
721
+ startsWith,
722
+ endsWith,
723
+ caseSensitive = true,
724
+ transform,
725
+ defaultValue,
726
+ i18n
727
+ } = options ?? {};
728
+ const actualDefaultValue = defaultValue ?? (required ? "" : null);
729
+ const getMessage = (key, params) => {
730
+ if (i18n) {
731
+ const currentLocale2 = getLocale();
732
+ const customMessages = i18n[currentLocale2];
733
+ if (customMessages && customMessages[key]) {
734
+ const template = customMessages[key];
735
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
736
+ }
737
+ }
738
+ return t(`common.id.${key}`, params);
739
+ };
740
+ const preprocessFn = (val) => {
741
+ if (val === "" || val === null || val === void 0) {
742
+ return actualDefaultValue;
743
+ }
744
+ let processed = String(val);
745
+ if (transform) {
746
+ processed = transform(processed);
747
+ }
748
+ return processed;
749
+ };
750
+ const baseSchema = required ? import_zod4.z.preprocess(preprocessFn, import_zod4.z.string()) : import_zod4.z.preprocess(preprocessFn, import_zod4.z.string().nullable());
751
+ const schema = baseSchema.refine((val) => {
752
+ if (val === null) return true;
753
+ if (required && (val === "" || val === "null" || val === "undefined")) {
754
+ throw new import_zod4.z.ZodError([{ code: "custom", message: getMessage("required"), path: [] }]);
755
+ }
756
+ const comparisonVal = !caseSensitive ? val.toLowerCase() : val;
757
+ if (val !== null && minLength !== void 0 && val.length < minLength) {
758
+ throw new import_zod4.z.ZodError([{ code: "custom", message: getMessage("minLength", { minLength }), path: [] }]);
759
+ }
760
+ if (val !== null && maxLength !== void 0 && val.length > maxLength) {
761
+ throw new import_zod4.z.ZodError([{ code: "custom", message: getMessage("maxLength", { maxLength }), path: [] }]);
762
+ }
763
+ const hasContentValidations = customRegex !== void 0 || startsWith !== void 0 || endsWith !== void 0 || includes !== void 0 || excludes !== void 0;
764
+ if (val !== null && customRegex !== void 0) {
765
+ if (!customRegex.test(val)) {
766
+ throw new import_zod4.z.ZodError([{ code: "custom", message: getMessage("customFormat"), path: [] }]);
767
+ }
768
+ } else if (val !== null && !hasContentValidations) {
769
+ let isValidId;
770
+ if (allowedTypes && allowedTypes.length > 0) {
771
+ isValidId = allowedTypes.some((allowedType) => validateIdType(val, allowedType));
772
+ if (!isValidId) {
773
+ const typeNames = allowedTypes.join(", ");
774
+ throw new import_zod4.z.ZodError([{ code: "custom", message: getMessage("invalid") + ` (allowed types: ${typeNames})`, path: [] }]);
775
+ }
776
+ } else if (type !== "auto") {
777
+ isValidId = validateIdType(val, type);
778
+ if (!isValidId) {
779
+ throw new import_zod4.z.ZodError([{ code: "custom", message: getMessage(type) || getMessage("invalid"), path: [] }]);
780
+ }
781
+ } else {
782
+ isValidId = detectIdType(val) !== null;
783
+ if (!isValidId) {
784
+ throw new import_zod4.z.ZodError([{ code: "custom", message: getMessage("invalid"), path: [] }]);
785
+ }
786
+ }
787
+ } else if (val !== null && hasContentValidations && type !== "auto" && !customRegex) {
788
+ if (allowedTypes && allowedTypes.length > 0) {
789
+ const isValidType = allowedTypes.some((allowedType) => validateIdType(val, allowedType));
790
+ if (!isValidType) {
791
+ const typeNames = allowedTypes.join(", ");
792
+ throw new import_zod4.z.ZodError([{ code: "custom", message: getMessage("invalid") + ` (allowed types: ${typeNames})`, path: [] }]);
793
+ }
794
+ } else {
795
+ if (!validateIdType(val, type)) {
796
+ throw new import_zod4.z.ZodError([{ code: "custom", message: getMessage(type) || getMessage("invalid"), path: [] }]);
797
+ }
798
+ }
799
+ }
800
+ const searchStartsWith = !caseSensitive && startsWith ? startsWith.toLowerCase() : startsWith;
801
+ const searchEndsWith = !caseSensitive && endsWith ? endsWith.toLowerCase() : endsWith;
802
+ const searchIncludes = !caseSensitive && includes ? includes.toLowerCase() : includes;
803
+ if (val !== null && startsWith !== void 0 && !comparisonVal.startsWith(searchStartsWith)) {
804
+ throw new import_zod4.z.ZodError([{ code: "custom", message: getMessage("startsWith", { startsWith }), path: [] }]);
805
+ }
806
+ if (val !== null && endsWith !== void 0 && !comparisonVal.endsWith(searchEndsWith)) {
807
+ throw new import_zod4.z.ZodError([{ code: "custom", message: getMessage("endsWith", { endsWith }), path: [] }]);
808
+ }
809
+ if (val !== null && includes !== void 0 && !comparisonVal.includes(searchIncludes)) {
810
+ throw new import_zod4.z.ZodError([{ code: "custom", message: getMessage("includes", { includes }), path: [] }]);
811
+ }
812
+ if (val !== null && excludes !== void 0) {
813
+ const excludeList = Array.isArray(excludes) ? excludes : [excludes];
814
+ for (const exclude of excludeList) {
815
+ const searchExclude = !caseSensitive ? exclude.toLowerCase() : exclude;
816
+ if (comparisonVal.includes(searchExclude)) {
817
+ throw new import_zod4.z.ZodError([{ code: "custom", message: getMessage("excludes", { excludes: exclude }), path: [] }]);
818
+ }
819
+ }
820
+ }
821
+ return true;
822
+ }).transform((val) => {
823
+ if (val === null) return val;
824
+ const shouldPreserveCase = type === "uuid" || type === "objectId";
825
+ if (!caseSensitive && !shouldPreserveCase) {
826
+ return val.toLowerCase();
827
+ }
828
+ return val;
829
+ });
269
830
  return schema;
270
831
  }
271
832
 
272
- // src/common/number.ts
833
+ // src/validators/common/number.ts
273
834
  var import_zod5 = require("zod");
274
835
  function number(options) {
275
- const { required = true, label, min, max, defaultValue } = options ?? {};
836
+ const {
837
+ required = true,
838
+ min,
839
+ max,
840
+ defaultValue,
841
+ type = "both",
842
+ positive,
843
+ negative,
844
+ nonNegative,
845
+ nonPositive,
846
+ multipleOf,
847
+ precision,
848
+ finite = true,
849
+ transform,
850
+ parseCommas = false,
851
+ i18n
852
+ } = options ?? {};
853
+ const getMessage = (key, params) => {
854
+ if (i18n) {
855
+ const currentLocale2 = getLocale();
856
+ const customMessages = i18n[currentLocale2];
857
+ if (customMessages && customMessages[key]) {
858
+ const template = customMessages[key];
859
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
860
+ }
861
+ }
862
+ return t(`common.number.${key}`, params);
863
+ };
864
+ const actualDefaultValue = defaultValue ?? null;
276
865
  const schema = import_zod5.z.preprocess(
277
866
  (val) => {
278
- if (val === "" || val === void 0 || val === null) return defaultValue ?? null;
279
- return typeof val === "string" ? Number(val) : val;
280
- },
281
- import_zod5.z.union([
282
- import_zod5.z.number({
283
- error: (issue) => {
284
- if (issue.code === "invalid_type") return t("common.number.integer", { label });
285
- return t("common.number.required", { label });
867
+ if (val === "" || val === void 0 || val === null) {
868
+ return actualDefaultValue;
869
+ }
870
+ if (typeof val === "string") {
871
+ let processedVal = val.trim();
872
+ if (parseCommas) {
873
+ processedVal = processedVal.replace(/,/g, "");
874
+ }
875
+ const parsed = Number(processedVal);
876
+ if (isNaN(parsed)) {
877
+ return parsed;
878
+ }
879
+ if (transform) {
880
+ return transform(parsed);
881
+ }
882
+ return parsed;
883
+ }
884
+ if (typeof val === "number") {
885
+ if (transform && Number.isFinite(val)) {
886
+ return transform(val);
286
887
  }
287
- }),
288
- import_zod5.z.null()
289
- ])
290
- ).refine((val) => !required || val !== null, { message: t("common.number.required", { label }) }).refine((val) => val === null || min === void 0 || val >= min, { message: t("common.number.min", { label, min }) }).refine((val) => val === null || max === void 0 || val <= max, { message: t("common.number.max", { label, max }) });
888
+ return val;
889
+ }
890
+ return val;
891
+ },
892
+ import_zod5.z.union([import_zod5.z.number(), import_zod5.z.null(), import_zod5.z.nan(), import_zod5.z.custom((val) => val === Infinity || val === -Infinity)])
893
+ ).refine((val) => {
894
+ if (required && val === null) {
895
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("required"), path: [] }]);
896
+ }
897
+ if (val === null) return true;
898
+ if (typeof val === "number" && isNaN(val)) {
899
+ if (type === "integer") {
900
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("integer"), path: [] }]);
901
+ } else if (type === "float") {
902
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("float"), path: [] }]);
903
+ } else {
904
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("invalid"), path: [] }]);
905
+ }
906
+ }
907
+ if (typeof val !== "number") {
908
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("invalid"), path: [] }]);
909
+ }
910
+ if (finite && !Number.isFinite(val)) {
911
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("finite"), path: [] }]);
912
+ }
913
+ if (type === "integer" && !Number.isInteger(val)) {
914
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("integer"), path: [] }]);
915
+ }
916
+ if (type === "float" && Number.isInteger(val)) {
917
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("float"), path: [] }]);
918
+ }
919
+ if (positive && val <= 0) {
920
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("positive"), path: [] }]);
921
+ }
922
+ if (negative && val >= 0) {
923
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("negative"), path: [] }]);
924
+ }
925
+ if (nonNegative && val < 0) {
926
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("nonNegative"), path: [] }]);
927
+ }
928
+ if (nonPositive && val > 0) {
929
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("nonPositive"), path: [] }]);
930
+ }
931
+ if (min !== void 0 && val < min) {
932
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("min", { min }), path: [] }]);
933
+ }
934
+ if (max !== void 0 && val > max) {
935
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("max", { max }), path: [] }]);
936
+ }
937
+ if (multipleOf !== void 0 && val % multipleOf !== 0) {
938
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("multipleOf", { multipleOf }), path: [] }]);
939
+ }
940
+ if (precision !== void 0) {
941
+ const decimalPlaces = (val.toString().split(".")[1] || "").length;
942
+ if (decimalPlaces > precision) {
943
+ throw new import_zod5.z.ZodError([{ code: "custom", message: getMessage("precision", { precision }), path: [] }]);
944
+ }
945
+ }
946
+ return true;
947
+ });
291
948
  return schema;
292
949
  }
293
950
 
294
- // src/common/password.ts
951
+ // src/validators/common/password.ts
295
952
  var import_zod6 = require("zod");
953
+ var COMMON_PASSWORDS = [
954
+ "password",
955
+ "123456",
956
+ "123456789",
957
+ "12345678",
958
+ "12345",
959
+ "1234567",
960
+ "admin",
961
+ "qwerty",
962
+ "abc123",
963
+ "password123",
964
+ "letmein",
965
+ "welcome",
966
+ "monkey",
967
+ "dragon",
968
+ "sunshine",
969
+ "princess"
970
+ ];
971
+ var calculatePasswordStrength = (password2) => {
972
+ let score = 0;
973
+ if (password2.length >= 8) score += 1;
974
+ if (password2.length >= 12) score += 1;
975
+ if (password2.length >= 16) score += 1;
976
+ if (/[a-z]/.test(password2)) score += 1;
977
+ if (/[A-Z]/.test(password2)) score += 1;
978
+ if (/[0-9]/.test(password2)) score += 1;
979
+ if (/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password2)) score += 1;
980
+ if (/(.)\1{2,}/.test(password2)) score -= 1;
981
+ if (/(?:abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz|012|123|234|345|456|567|678|789)/i.test(password2)) score -= 1;
982
+ if (score <= 2) return "weak";
983
+ if (score <= 4) return "medium";
984
+ if (score <= 6) return "strong";
985
+ return "very-strong";
986
+ };
296
987
  function password(options) {
297
- const { required = true, label, min, max, uppercase, lowercase, digits, special } = options ?? {};
298
- const baseSchema = required ? import_zod6.z.preprocess((val) => val === "" || val === null || val === void 0 ? null : val, import_zod6.z.coerce.string().trim()) : import_zod6.z.preprocess((val) => val === "" || val === null || val === void 0 ? null : val, import_zod6.z.coerce.string().trim().nullable());
299
- const schema = baseSchema.refine((val) => required ? val !== "" && val !== "null" && val !== "undefined" : true, { message: t("common.password.required", { label }) }).refine((val) => val === null || min === void 0 || val.length >= min, { message: t("common.password.min", { label, min }) }).refine((val) => val === null || max === void 0 || val.length <= max, { message: t("common.password.max", { label, max }) }).refine((val) => val === null || !uppercase || /[A-Z]/.test(val), { message: t("common.password.uppercase", { label }) }).refine((val) => val === null || !lowercase || /[a-z]/.test(val), { message: t("common.password.lowercase", { label }) }).refine((val) => val === null || !special || /[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]+/.test(val), { message: t("common.password.special", { label }) }).refine((val) => val === null || !digits || /[0-9]/.test(val), { message: t("common.password.digits", { label }) });
988
+ const {
989
+ required = true,
990
+ min,
991
+ max,
992
+ uppercase,
993
+ lowercase,
994
+ digits,
995
+ special,
996
+ noRepeating,
997
+ noSequential,
998
+ noCommonWords,
999
+ minStrength,
1000
+ excludes,
1001
+ includes,
1002
+ regex,
1003
+ transform,
1004
+ defaultValue,
1005
+ i18n
1006
+ } = options ?? {};
1007
+ const actualDefaultValue = defaultValue ?? (required ? "" : null);
1008
+ const getMessage = (key, params) => {
1009
+ if (i18n) {
1010
+ const currentLocale2 = getLocale();
1011
+ const customMessages = i18n[currentLocale2];
1012
+ if (customMessages && customMessages[key]) {
1013
+ const template = customMessages[key];
1014
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
1015
+ }
1016
+ }
1017
+ return t(`common.password.${key}`, params);
1018
+ };
1019
+ const preprocessFn = (val) => {
1020
+ if (val === "" || val === null || val === void 0) {
1021
+ return actualDefaultValue;
1022
+ }
1023
+ let processed = String(val);
1024
+ if (transform) {
1025
+ processed = transform(processed);
1026
+ }
1027
+ return processed;
1028
+ };
1029
+ const baseSchema = required ? import_zod6.z.preprocess(preprocessFn, import_zod6.z.string()) : import_zod6.z.preprocess(preprocessFn, import_zod6.z.string().nullable());
1030
+ const schema = baseSchema.refine((val) => {
1031
+ if (val === null) return true;
1032
+ if (required && (val === "" || val === "null" || val === "undefined")) {
1033
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("required"), path: [] }]);
1034
+ }
1035
+ if (val !== null && min !== void 0 && val.length < min) {
1036
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("min", { min }), path: [] }]);
1037
+ }
1038
+ if (val !== null && max !== void 0 && val.length > max) {
1039
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("max", { max }), path: [] }]);
1040
+ }
1041
+ if (val !== null && uppercase && !/[A-Z]/.test(val)) {
1042
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("uppercase"), path: [] }]);
1043
+ }
1044
+ if (val !== null && lowercase && !/[a-z]/.test(val)) {
1045
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("lowercase"), path: [] }]);
1046
+ }
1047
+ if (val !== null && digits && !/[0-9]/.test(val)) {
1048
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("digits"), path: [] }]);
1049
+ }
1050
+ if (val !== null && special && !/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(val)) {
1051
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("special"), path: [] }]);
1052
+ }
1053
+ if (val !== null && noRepeating && /(.)\1{2,}/.test(val)) {
1054
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("noRepeating"), path: [] }]);
1055
+ }
1056
+ if (val !== null && noSequential && /(?:abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz|012|123|234|345|456|567|678|789)/i.test(val)) {
1057
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("noSequential"), path: [] }]);
1058
+ }
1059
+ if (val !== null && noCommonWords && COMMON_PASSWORDS.some((common) => val.toLowerCase().includes(common.toLowerCase()))) {
1060
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("noCommonWords"), path: [] }]);
1061
+ }
1062
+ if (val !== null && minStrength) {
1063
+ const strength = calculatePasswordStrength(val);
1064
+ const strengthLevels = ["weak", "medium", "strong", "very-strong"];
1065
+ const currentLevel = strengthLevels.indexOf(strength);
1066
+ const requiredLevel = strengthLevels.indexOf(minStrength);
1067
+ if (currentLevel < requiredLevel) {
1068
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("minStrength", { minStrength }), path: [] }]);
1069
+ }
1070
+ }
1071
+ if (val !== null && includes !== void 0 && !val.includes(includes)) {
1072
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("includes", { includes }), path: [] }]);
1073
+ }
1074
+ if (val !== null && excludes !== void 0) {
1075
+ const excludeList = Array.isArray(excludes) ? excludes : [excludes];
1076
+ for (const exclude of excludeList) {
1077
+ if (val.includes(exclude)) {
1078
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("excludes", { excludes: exclude }), path: [] }]);
1079
+ }
1080
+ }
1081
+ }
1082
+ if (val !== null && regex !== void 0 && !regex.test(val)) {
1083
+ throw new import_zod6.z.ZodError([{ code: "custom", message: getMessage("invalid", { regex }), path: [] }]);
1084
+ }
1085
+ return true;
1086
+ });
300
1087
  return schema;
301
1088
  }
302
1089
 
303
- // src/common/integer.ts
1090
+ // src/validators/common/text.ts
304
1091
  var import_zod7 = require("zod");
305
- function integer(options) {
306
- const { required = true, label, min, max, defaultValue } = options ?? {};
307
- const schema = import_zod7.z.preprocess(
308
- (val) => {
309
- if (val === "" || val === void 0 || val === null) return defaultValue ?? null;
310
- return typeof val === "string" ? Number(val) : val;
311
- },
312
- import_zod7.z.union([
313
- import_zod7.z.number({
314
- error: (issue) => {
315
- if (issue.code === "invalid_type") return t("common.integer.integer", { label });
316
- return t("common.integer.required", { label });
1092
+ function text(options) {
1093
+ const { required = true, minLength, maxLength, startsWith, endsWith, includes, excludes, regex, trimMode = "trim", casing = "none", transform, notEmpty, defaultValue, i18n } = options ?? {};
1094
+ const actualDefaultValue = defaultValue ?? (required ? "" : null);
1095
+ const getMessage = (key, params) => {
1096
+ if (i18n) {
1097
+ const currentLocale2 = getLocale();
1098
+ const customMessages = i18n[currentLocale2];
1099
+ if (customMessages && customMessages[key]) {
1100
+ const template = customMessages[key];
1101
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
1102
+ }
1103
+ }
1104
+ return t(`common.text.${key}`, params);
1105
+ };
1106
+ const applyTrim = (str) => {
1107
+ switch (trimMode) {
1108
+ case "trimStart":
1109
+ return str.trimStart();
1110
+ case "trimEnd":
1111
+ return str.trimEnd();
1112
+ case "none":
1113
+ return str;
1114
+ default:
1115
+ return str.trim();
1116
+ }
1117
+ };
1118
+ const applyCasing = (str) => {
1119
+ switch (casing) {
1120
+ case "upper":
1121
+ return str.toUpperCase();
1122
+ case "lower":
1123
+ return str.toLowerCase();
1124
+ case "title":
1125
+ return str.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase());
1126
+ default:
1127
+ return str;
1128
+ }
1129
+ };
1130
+ const preprocessFn = (val) => {
1131
+ if (val === "" || val === null || val === void 0) {
1132
+ return actualDefaultValue;
1133
+ }
1134
+ let processed = String(val);
1135
+ processed = applyTrim(processed);
1136
+ processed = applyCasing(processed);
1137
+ if (transform) {
1138
+ processed = transform(processed);
1139
+ }
1140
+ return processed;
1141
+ };
1142
+ const baseSchema = required ? import_zod7.z.preprocess(preprocessFn, import_zod7.z.string()) : import_zod7.z.preprocess(preprocessFn, import_zod7.z.string().nullable());
1143
+ const schema = baseSchema.refine((val) => {
1144
+ if (val === null) return true;
1145
+ if (required && (val === "" || val === "null" || val === "undefined")) {
1146
+ throw new import_zod7.z.ZodError([{ code: "custom", message: getMessage("required"), path: [] }]);
1147
+ }
1148
+ if (notEmpty && val !== null && val.trim() === "") {
1149
+ throw new import_zod7.z.ZodError([{ code: "custom", message: getMessage("notEmpty"), path: [] }]);
1150
+ }
1151
+ if (val !== null && minLength !== void 0 && val.length < minLength) {
1152
+ throw new import_zod7.z.ZodError([{ code: "custom", message: getMessage("minLength", { minLength }), path: [] }]);
1153
+ }
1154
+ if (val !== null && maxLength !== void 0 && val.length > maxLength) {
1155
+ throw new import_zod7.z.ZodError([{ code: "custom", message: getMessage("maxLength", { maxLength }), path: [] }]);
1156
+ }
1157
+ if (val !== null && startsWith !== void 0 && !val.startsWith(startsWith)) {
1158
+ throw new import_zod7.z.ZodError([{ code: "custom", message: getMessage("startsWith", { startsWith }), path: [] }]);
1159
+ }
1160
+ if (val !== null && endsWith !== void 0 && !val.endsWith(endsWith)) {
1161
+ throw new import_zod7.z.ZodError([{ code: "custom", message: getMessage("endsWith", { endsWith }), path: [] }]);
1162
+ }
1163
+ if (val !== null && includes !== void 0 && !val.includes(includes)) {
1164
+ throw new import_zod7.z.ZodError([{ code: "custom", message: getMessage("includes", { includes }), path: [] }]);
1165
+ }
1166
+ if (val !== null && excludes !== void 0) {
1167
+ const excludeList = Array.isArray(excludes) ? excludes : [excludes];
1168
+ for (const exclude of excludeList) {
1169
+ if (val.includes(exclude)) {
1170
+ throw new import_zod7.z.ZodError([{ code: "custom", message: getMessage("excludes", { excludes: exclude }), path: [] }]);
1171
+ }
1172
+ }
1173
+ }
1174
+ if (val !== null && regex !== void 0 && !regex.test(val)) {
1175
+ throw new import_zod7.z.ZodError([{ code: "custom", message: getMessage("invalid", { regex }), path: [] }]);
1176
+ }
1177
+ return true;
1178
+ });
1179
+ return schema;
1180
+ }
1181
+
1182
+ // src/validators/common/url.ts
1183
+ var import_zod8 = require("zod");
1184
+ function url(options) {
1185
+ const {
1186
+ required = true,
1187
+ min,
1188
+ max,
1189
+ includes,
1190
+ excludes,
1191
+ protocols,
1192
+ allowedDomains,
1193
+ blockedDomains,
1194
+ allowedPorts,
1195
+ blockedPorts,
1196
+ pathStartsWith,
1197
+ pathEndsWith,
1198
+ mustHaveQuery,
1199
+ mustNotHaveQuery,
1200
+ mustHaveFragment,
1201
+ mustNotHaveFragment,
1202
+ allowLocalhost = true,
1203
+ blockLocalhost,
1204
+ transform,
1205
+ defaultValue = null,
1206
+ i18n
1207
+ } = options ?? {};
1208
+ const actualDefaultValue = defaultValue ?? (required ? "" : null);
1209
+ const getMessage = (key, params) => {
1210
+ if (i18n) {
1211
+ const currentLocale2 = getLocale();
1212
+ const customMessages = i18n[currentLocale2];
1213
+ if (customMessages && customMessages[key]) {
1214
+ const template = customMessages[key];
1215
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
1216
+ }
1217
+ }
1218
+ return t(`common.url.${key}`, params);
1219
+ };
1220
+ const preprocessFn = (val) => {
1221
+ if (val === "" || val === null || val === void 0) {
1222
+ return actualDefaultValue;
1223
+ }
1224
+ let processed = String(val).trim();
1225
+ if (transform) {
1226
+ processed = transform(processed);
1227
+ }
1228
+ return processed;
1229
+ };
1230
+ const baseSchema = required ? import_zod8.z.preprocess(preprocessFn, import_zod8.z.string()) : import_zod8.z.preprocess(preprocessFn, import_zod8.z.string().nullable());
1231
+ const schema = baseSchema.refine((val) => {
1232
+ if (val === null) return true;
1233
+ if (required && (val === "" || val === "null" || val === "undefined")) {
1234
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("required"), path: [] }]);
1235
+ }
1236
+ let urlObj;
1237
+ try {
1238
+ urlObj = new URL(val);
1239
+ } catch {
1240
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("invalid"), path: [] }]);
1241
+ }
1242
+ if (val !== null && min !== void 0 && val.length < min) {
1243
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("min", { min }), path: [] }]);
1244
+ }
1245
+ if (val !== null && max !== void 0 && val.length > max) {
1246
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("max", { max }), path: [] }]);
1247
+ }
1248
+ if (val !== null && includes !== void 0 && !val.includes(includes)) {
1249
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("includes", { includes }), path: [] }]);
1250
+ }
1251
+ if (val !== null && excludes !== void 0) {
1252
+ const excludeList = Array.isArray(excludes) ? excludes : [excludes];
1253
+ for (const exclude of excludeList) {
1254
+ if (val.includes(exclude)) {
1255
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("excludes", { excludes: exclude }), path: [] }]);
317
1256
  }
318
- }),
319
- import_zod7.z.null()
320
- ])
321
- ).refine((val) => !required || val !== null, {
322
- message: t("common.integer.required", { label })
323
- }).refine((val) => val === null || Number.isInteger(val), {
324
- message: t("common.integer.integer", { label })
325
- }).refine((val) => val === null || min === void 0 || val >= min, {
326
- message: t("common.integer.min", { label, min })
327
- }).refine((val) => val === null || max === void 0 || val <= max, {
328
- message: t("common.integer.max", { label, max })
1257
+ }
1258
+ }
1259
+ if (protocols && !protocols.includes(urlObj.protocol.slice(0, -1))) {
1260
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("protocol", { protocols: protocols.join(", ") }), path: [] }]);
1261
+ }
1262
+ const hostname = urlObj.hostname.toLowerCase();
1263
+ if (allowedDomains && !allowedDomains.some((domain) => hostname === domain || hostname.endsWith(`.${domain}`))) {
1264
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("domain", { domains: allowedDomains.join(", ") }), path: [] }]);
1265
+ }
1266
+ if (blockedDomains && blockedDomains.some((domain) => hostname === domain || hostname.endsWith(`.${domain}`))) {
1267
+ const blockedDomain = blockedDomains.find((domain) => hostname === domain || hostname.endsWith(`.${domain}`));
1268
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("domainBlacklist", { domain: blockedDomain }), path: [] }]);
1269
+ }
1270
+ const port = urlObj.port ? parseInt(urlObj.port) : urlObj.protocol === "https:" ? 443 : 80;
1271
+ if (allowedPorts && !allowedPorts.includes(port)) {
1272
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("port", { ports: allowedPorts.join(", ") }), path: [] }]);
1273
+ }
1274
+ if (blockedPorts && blockedPorts.includes(port)) {
1275
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("port", { port }), path: [] }]);
1276
+ }
1277
+ if (pathStartsWith && !urlObj.pathname.startsWith(pathStartsWith)) {
1278
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("pathStartsWith", { path: pathStartsWith }), path: [] }]);
1279
+ }
1280
+ if (pathEndsWith && !urlObj.pathname.endsWith(pathEndsWith)) {
1281
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("pathEndsWith", { path: pathEndsWith }), path: [] }]);
1282
+ }
1283
+ if (mustHaveQuery && !urlObj.search) {
1284
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("hasQuery"), path: [] }]);
1285
+ }
1286
+ if (mustNotHaveQuery && urlObj.search) {
1287
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("noQuery"), path: [] }]);
1288
+ }
1289
+ if (mustHaveFragment && !urlObj.hash) {
1290
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("hasFragment"), path: [] }]);
1291
+ }
1292
+ if (mustNotHaveFragment && urlObj.hash) {
1293
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("noFragment"), path: [] }]);
1294
+ }
1295
+ const isLocalhost = hostname === "localhost" || hostname === "127.0.0.1" || hostname.startsWith("192.168.") || hostname.startsWith("10.") || hostname.match(/^172\.(1[6-9]|2[0-9]|3[0-1])\./);
1296
+ if (blockLocalhost && isLocalhost) {
1297
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("noLocalhost"), path: [] }]);
1298
+ }
1299
+ if (!allowLocalhost && isLocalhost) {
1300
+ throw new import_zod8.z.ZodError([{ code: "custom", message: getMessage("localhost"), path: [] }]);
1301
+ }
1302
+ return true;
1303
+ });
1304
+ return schema;
1305
+ }
1306
+
1307
+ // src/validators/taiwan/business-id.ts
1308
+ var import_zod9 = require("zod");
1309
+ var validateTaiwanBusinessId = (value) => {
1310
+ if (!/^\d{8}$/.test(value)) {
1311
+ return false;
1312
+ }
1313
+ const digits = value.split("").map(Number);
1314
+ const coefficients = [1, 2, 1, 2, 1, 2, 4];
1315
+ let sum = 0;
1316
+ for (let i = 0; i < 7; i++) {
1317
+ const product = digits[i] * coefficients[i];
1318
+ sum += Math.floor(product / 10) + product % 10;
1319
+ }
1320
+ sum += digits[7];
1321
+ if (sum % 5 === 0) {
1322
+ return true;
1323
+ }
1324
+ if (sum % 10 === 0) {
1325
+ return true;
1326
+ }
1327
+ if (digits[6] === 7) {
1328
+ let altSum = 0;
1329
+ for (let i = 0; i < 7; i++) {
1330
+ const product = digits[i] * coefficients[i];
1331
+ altSum += Math.floor(product / 10) + product % 10;
1332
+ }
1333
+ altSum += 1 + digits[7];
1334
+ if (altSum % 5 === 0 || altSum % 10 === 0) {
1335
+ return true;
1336
+ }
1337
+ }
1338
+ return false;
1339
+ };
1340
+ function businessId(options) {
1341
+ const {
1342
+ required = true,
1343
+ transform,
1344
+ defaultValue,
1345
+ i18n
1346
+ } = options ?? {};
1347
+ const actualDefaultValue = defaultValue ?? (required ? "" : null);
1348
+ const getMessage = (key, params) => {
1349
+ if (i18n) {
1350
+ const currentLocale2 = getLocale();
1351
+ const customMessages = i18n[currentLocale2];
1352
+ if (customMessages && customMessages[key]) {
1353
+ const template = customMessages[key];
1354
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
1355
+ }
1356
+ }
1357
+ return t(`taiwan.businessId.${key}`, params);
1358
+ };
1359
+ const preprocessFn = (val) => {
1360
+ if (val === "" || val === null || val === void 0) {
1361
+ return actualDefaultValue;
1362
+ }
1363
+ let processed = String(val).trim();
1364
+ if (processed === "" && !required) {
1365
+ return null;
1366
+ }
1367
+ if (transform) {
1368
+ processed = transform(processed);
1369
+ }
1370
+ return processed;
1371
+ };
1372
+ const baseSchema = required ? import_zod9.z.preprocess(preprocessFn, import_zod9.z.string()) : import_zod9.z.preprocess(preprocessFn, import_zod9.z.string().nullable());
1373
+ const schema = baseSchema.refine((val) => {
1374
+ if (val === null) return true;
1375
+ if (required && (val === "" || val === "null" || val === "undefined")) {
1376
+ throw new import_zod9.z.ZodError([{ code: "custom", message: getMessage("required"), path: [] }]);
1377
+ }
1378
+ if (val === null) return true;
1379
+ if (!required && val === "") return true;
1380
+ if (!validateTaiwanBusinessId(val)) {
1381
+ throw new import_zod9.z.ZodError([{ code: "custom", message: getMessage("invalid"), path: [] }]);
1382
+ }
1383
+ return true;
1384
+ });
1385
+ return schema;
1386
+ }
1387
+
1388
+ // src/validators/taiwan/national-id.ts
1389
+ var import_zod10 = require("zod");
1390
+ var CITY_CODES = {
1391
+ "A": 10,
1392
+ "B": 11,
1393
+ "C": 12,
1394
+ "D": 13,
1395
+ "E": 14,
1396
+ "F": 15,
1397
+ "G": 16,
1398
+ "H": 17,
1399
+ "I": 34,
1400
+ "J": 18,
1401
+ "K": 19,
1402
+ "L": 20,
1403
+ "M": 21,
1404
+ "N": 22,
1405
+ "O": 35,
1406
+ "P": 23,
1407
+ "Q": 24,
1408
+ "R": 25,
1409
+ "S": 26,
1410
+ "T": 27,
1411
+ "U": 28,
1412
+ "V": 29,
1413
+ "W": 32,
1414
+ "X": 30,
1415
+ "Y": 31,
1416
+ "Z": 33
1417
+ };
1418
+ var validateCitizenId = (value) => {
1419
+ if (!/^[A-Z][1-2]\d{8}$/.test(value)) {
1420
+ return false;
1421
+ }
1422
+ const letter = value[0];
1423
+ const digits = value.slice(1).split("").map(Number);
1424
+ const cityCode = CITY_CODES[letter];
1425
+ if (!cityCode) return false;
1426
+ const cityDigits = [Math.floor(cityCode / 10), cityCode % 10];
1427
+ const coefficients = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1];
1428
+ let sum = cityDigits[0] * coefficients[0] + cityDigits[1] * coefficients[1];
1429
+ for (let i = 0; i < 8; i++) {
1430
+ sum += digits[i] * coefficients[i + 2];
1431
+ }
1432
+ const checksum = (10 - sum % 10) % 10;
1433
+ return checksum === digits[8];
1434
+ };
1435
+ var validateOldResidentId = (value) => {
1436
+ if (!/^[A-Z][ABCD]\d{8}$/.test(value)) {
1437
+ return false;
1438
+ }
1439
+ const letter = value[0];
1440
+ const genderCode = value[1];
1441
+ const digits = value.slice(2).split("").map(Number);
1442
+ const cityCode = CITY_CODES[letter];
1443
+ if (!cityCode) return false;
1444
+ const genderValue = genderCode === "A" || genderCode === "C" ? 1 : 0;
1445
+ const cityDigits = [Math.floor(cityCode / 10), cityCode % 10];
1446
+ const coefficients = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1];
1447
+ let sum = cityDigits[0] * coefficients[0] + cityDigits[1] * coefficients[1] + genderValue * coefficients[2];
1448
+ for (let i = 0; i < 7; i++) {
1449
+ sum += digits[i] * coefficients[i + 3];
1450
+ }
1451
+ const checksum = (10 - sum % 10) % 10;
1452
+ return checksum === digits[7];
1453
+ };
1454
+ var validateNewResidentId = (value) => {
1455
+ if (!/^[A-Z][89]\d{8}$/.test(value)) {
1456
+ return false;
1457
+ }
1458
+ const letter = value[0];
1459
+ const digits = value.slice(1).split("").map(Number);
1460
+ const cityCode = CITY_CODES[letter];
1461
+ if (!cityCode) return false;
1462
+ const cityDigits = [Math.floor(cityCode / 10), cityCode % 10];
1463
+ const coefficients = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1];
1464
+ let sum = cityDigits[0] * coefficients[0] + cityDigits[1] * coefficients[1];
1465
+ for (let i = 0; i < 8; i++) {
1466
+ sum += digits[i] * coefficients[i + 2];
1467
+ }
1468
+ const checksum = (10 - sum % 10) % 10;
1469
+ return checksum === digits[8];
1470
+ };
1471
+ var validateTaiwanNationalId = (value, type = "both", allowOldResident = true) => {
1472
+ if (!/^[A-Z].{9}$/.test(value)) {
1473
+ return false;
1474
+ }
1475
+ switch (type) {
1476
+ case "citizen":
1477
+ return validateCitizenId(value);
1478
+ case "resident":
1479
+ return (allowOldResident ? validateOldResidentId(value) : false) || validateNewResidentId(value);
1480
+ case "both":
1481
+ return validateCitizenId(value) || (allowOldResident ? validateOldResidentId(value) : false) || validateNewResidentId(value);
1482
+ default:
1483
+ return false;
1484
+ }
1485
+ };
1486
+ function nationalId(options) {
1487
+ const {
1488
+ required = true,
1489
+ type = "both",
1490
+ allowOldResident = true,
1491
+ transform,
1492
+ defaultValue,
1493
+ i18n
1494
+ } = options ?? {};
1495
+ const actualDefaultValue = defaultValue ?? (required ? "" : null);
1496
+ const getMessage = (key, params) => {
1497
+ if (i18n) {
1498
+ const currentLocale2 = getLocale();
1499
+ const customMessages = i18n[currentLocale2];
1500
+ if (customMessages && customMessages[key]) {
1501
+ const template = customMessages[key];
1502
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
1503
+ }
1504
+ }
1505
+ return t(`taiwan.nationalId.${key}`, params);
1506
+ };
1507
+ const preprocessFn = (val) => {
1508
+ if (val === "" || val === null || val === void 0) {
1509
+ return actualDefaultValue;
1510
+ }
1511
+ let processed = String(val).trim().toUpperCase();
1512
+ if (processed === "" && !required) {
1513
+ return null;
1514
+ }
1515
+ if (transform) {
1516
+ processed = transform(processed);
1517
+ }
1518
+ return processed;
1519
+ };
1520
+ const baseSchema = required ? import_zod10.z.preprocess(preprocessFn, import_zod10.z.string()) : import_zod10.z.preprocess(preprocessFn, import_zod10.z.string().nullable());
1521
+ const schema = baseSchema.refine((val) => {
1522
+ if (val === null) return true;
1523
+ if (required && (val === "" || val === "null" || val === "undefined")) {
1524
+ throw new import_zod10.z.ZodError([{ code: "custom", message: getMessage("required"), path: [] }]);
1525
+ }
1526
+ if (val === null) return true;
1527
+ if (!required && val === "") return true;
1528
+ if (!validateTaiwanNationalId(val, type, allowOldResident)) {
1529
+ throw new import_zod10.z.ZodError([{ code: "custom", message: getMessage("invalid"), path: [] }]);
1530
+ }
1531
+ return true;
1532
+ });
1533
+ return schema;
1534
+ }
1535
+
1536
+ // src/validators/taiwan/mobile.ts
1537
+ var import_zod11 = require("zod");
1538
+ var validateTaiwanMobile = (value) => {
1539
+ return /^09[0-9]\d{7}$/.test(value);
1540
+ };
1541
+ function mobile(options) {
1542
+ const { required = true, whitelist, transform, defaultValue, i18n } = options ?? {};
1543
+ const actualDefaultValue = defaultValue ?? (required ? "" : null);
1544
+ const getMessage = (key, params) => {
1545
+ if (i18n) {
1546
+ const currentLocale2 = getLocale();
1547
+ const customMessages = i18n[currentLocale2];
1548
+ if (customMessages && customMessages[key]) {
1549
+ const template = customMessages[key];
1550
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
1551
+ }
1552
+ }
1553
+ return t(`taiwan.mobile.${key}`, params);
1554
+ };
1555
+ const preprocessFn = (val) => {
1556
+ if (val === null || val === void 0) {
1557
+ return actualDefaultValue;
1558
+ }
1559
+ let processed = String(val).trim();
1560
+ if (processed === "") {
1561
+ if (whitelist && whitelist.includes("")) {
1562
+ return "";
1563
+ }
1564
+ if (!required) {
1565
+ return actualDefaultValue;
1566
+ }
1567
+ return actualDefaultValue;
1568
+ }
1569
+ if (transform) {
1570
+ processed = transform(processed);
1571
+ }
1572
+ return processed;
1573
+ };
1574
+ const baseSchema = required ? import_zod11.z.preprocess(preprocessFn, import_zod11.z.string()) : import_zod11.z.preprocess(preprocessFn, import_zod11.z.string().nullable());
1575
+ const schema = baseSchema.refine((val) => {
1576
+ if (val === null) return true;
1577
+ if (required && (val === "" || val === "null" || val === "undefined")) {
1578
+ throw new import_zod11.z.ZodError([{ code: "custom", message: getMessage("required"), path: [] }]);
1579
+ }
1580
+ if (val === null) return true;
1581
+ if (!required && val === "") return true;
1582
+ if (whitelist && whitelist.length > 0) {
1583
+ if (whitelist.includes(val)) {
1584
+ return true;
1585
+ }
1586
+ throw new import_zod11.z.ZodError([{ code: "custom", message: getMessage("notInWhitelist"), path: [] }]);
1587
+ }
1588
+ if (!validateTaiwanMobile(val)) {
1589
+ throw new import_zod11.z.ZodError([{ code: "custom", message: getMessage("invalid"), path: [] }]);
1590
+ }
1591
+ return true;
1592
+ });
1593
+ return schema;
1594
+ }
1595
+
1596
+ // src/validators/taiwan/tel.ts
1597
+ var import_zod12 = require("zod");
1598
+ var validateTaiwanTel = (value) => {
1599
+ const cleanValue = value.replace(/[-\s]/g, "");
1600
+ if (!/^0\d{7,10}$/.test(cleanValue)) {
1601
+ return false;
1602
+ }
1603
+ const areaCode4 = cleanValue.substring(0, 4);
1604
+ if (areaCode4 === "0826") {
1605
+ return cleanValue.length === 9 && /^0826[6]\d{4}$/.test(cleanValue);
1606
+ }
1607
+ if (areaCode4 === "0836") {
1608
+ return cleanValue.length === 9 && /^0836[2-9]\d{4}$/.test(cleanValue);
1609
+ }
1610
+ const areaCode3 = cleanValue.substring(0, 3);
1611
+ if (areaCode3 === "037") {
1612
+ return cleanValue.length === 9 && /^037[2-9]\d{5}$/.test(cleanValue);
1613
+ }
1614
+ if (areaCode3 === "049") {
1615
+ return cleanValue.length === 10 && /^049[2-9]\d{6}$/.test(cleanValue);
1616
+ }
1617
+ if (areaCode3 === "082") {
1618
+ return cleanValue.length === 9 && /^082[2-57-9]\d{5}$/.test(cleanValue);
1619
+ }
1620
+ if (areaCode3 === "089") {
1621
+ return cleanValue.length === 9 && /^089[2-9]\d{5}$/.test(cleanValue);
1622
+ }
1623
+ const areaCode2 = cleanValue.substring(0, 2);
1624
+ if (areaCode2 === "02") {
1625
+ return cleanValue.length === 10 && /^02[235-8]\d{7}$/.test(cleanValue);
1626
+ }
1627
+ if (["03", "04", "05", "06"].includes(areaCode2)) {
1628
+ return cleanValue.length === 9;
1629
+ }
1630
+ if (areaCode2 === "07") {
1631
+ return cleanValue.length === 9 && /^07[2-9]\d{6}$/.test(cleanValue);
1632
+ }
1633
+ if (areaCode2 === "08") {
1634
+ return cleanValue.length === 9 && /^08[478]\d{6}$/.test(cleanValue);
1635
+ }
1636
+ return false;
1637
+ };
1638
+ function tel(options) {
1639
+ const { required = true, whitelist, transform, defaultValue, i18n } = options ?? {};
1640
+ const actualDefaultValue = defaultValue ?? (required ? "" : null);
1641
+ const getMessage = (key, params) => {
1642
+ if (i18n) {
1643
+ const currentLocale2 = getLocale();
1644
+ const customMessages = i18n[currentLocale2];
1645
+ if (customMessages && customMessages[key]) {
1646
+ const template = customMessages[key];
1647
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
1648
+ }
1649
+ }
1650
+ return t(`taiwan.tel.${key}`, params);
1651
+ };
1652
+ const preprocessFn = (val) => {
1653
+ if (val === null || val === void 0) {
1654
+ return actualDefaultValue;
1655
+ }
1656
+ let processed = String(val).trim();
1657
+ if (processed === "") {
1658
+ if (whitelist && whitelist.includes("")) {
1659
+ return "";
1660
+ }
1661
+ if (!required) {
1662
+ return actualDefaultValue;
1663
+ }
1664
+ return actualDefaultValue;
1665
+ }
1666
+ if (transform) {
1667
+ processed = transform(processed);
1668
+ }
1669
+ return processed;
1670
+ };
1671
+ const baseSchema = required ? import_zod12.z.preprocess(preprocessFn, import_zod12.z.string()) : import_zod12.z.preprocess(preprocessFn, import_zod12.z.string().nullable());
1672
+ const schema = baseSchema.refine((val) => {
1673
+ if (val === null) return true;
1674
+ if (required && (val === "" || val === "null" || val === "undefined")) {
1675
+ throw new import_zod12.z.ZodError([{ code: "custom", message: getMessage("required"), path: [] }]);
1676
+ }
1677
+ if (val === null) return true;
1678
+ if (!required && val === "") return true;
1679
+ if (whitelist && whitelist.length > 0) {
1680
+ if (whitelist.includes(val)) {
1681
+ return true;
1682
+ }
1683
+ throw new import_zod12.z.ZodError([{ code: "custom", message: getMessage("notInWhitelist"), path: [] }]);
1684
+ }
1685
+ if (!validateTaiwanTel(val)) {
1686
+ throw new import_zod12.z.ZodError([{ code: "custom", message: getMessage("invalid"), path: [] }]);
1687
+ }
1688
+ return true;
1689
+ });
1690
+ return schema;
1691
+ }
1692
+
1693
+ // src/validators/taiwan/fax.ts
1694
+ var import_zod13 = require("zod");
1695
+ var validateTaiwanFax = (value) => {
1696
+ const cleanValue = value.replace(/[-\s]/g, "");
1697
+ if (!/^0\d{7,10}$/.test(cleanValue)) {
1698
+ return false;
1699
+ }
1700
+ const areaCode4 = cleanValue.substring(0, 4);
1701
+ if (areaCode4 === "0826") {
1702
+ return cleanValue.length === 9 && /^0826[6]\d{4}$/.test(cleanValue);
1703
+ }
1704
+ if (areaCode4 === "0836") {
1705
+ return cleanValue.length === 9 && /^0836[2-9]\d{4}$/.test(cleanValue);
1706
+ }
1707
+ const areaCode3 = cleanValue.substring(0, 3);
1708
+ if (areaCode3 === "037") {
1709
+ return cleanValue.length === 9 && /^037[2-9]\d{5}$/.test(cleanValue);
1710
+ }
1711
+ if (areaCode3 === "049") {
1712
+ return cleanValue.length === 10 && /^049[2-9]\d{6}$/.test(cleanValue);
1713
+ }
1714
+ if (areaCode3 === "082") {
1715
+ return cleanValue.length === 9 && /^082[2-57-9]\d{5}$/.test(cleanValue);
1716
+ }
1717
+ if (areaCode3 === "089") {
1718
+ return cleanValue.length === 9 && /^089[2-9]\d{5}$/.test(cleanValue);
1719
+ }
1720
+ const areaCode2 = cleanValue.substring(0, 2);
1721
+ if (areaCode2 === "02") {
1722
+ return cleanValue.length === 10 && /^02[235-8]\d{7}$/.test(cleanValue);
1723
+ }
1724
+ if (["03", "04", "05", "06"].includes(areaCode2)) {
1725
+ return cleanValue.length === 9;
1726
+ }
1727
+ if (areaCode2 === "07") {
1728
+ return cleanValue.length === 9 && /^07[2-9]\d{6}$/.test(cleanValue);
1729
+ }
1730
+ if (areaCode2 === "08") {
1731
+ return cleanValue.length === 9 && /^08[478]\d{6}$/.test(cleanValue);
1732
+ }
1733
+ return false;
1734
+ };
1735
+ function fax(options) {
1736
+ const { required = true, whitelist, transform, defaultValue, i18n } = options ?? {};
1737
+ const actualDefaultValue = defaultValue ?? (required ? "" : null);
1738
+ const getMessage = (key, params) => {
1739
+ if (i18n) {
1740
+ const currentLocale2 = getLocale();
1741
+ const customMessages = i18n[currentLocale2];
1742
+ if (customMessages && customMessages[key]) {
1743
+ const template = customMessages[key];
1744
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
1745
+ }
1746
+ }
1747
+ return t(`taiwan.fax.${key}`, params);
1748
+ };
1749
+ const preprocessFn = (val) => {
1750
+ if (val === null || val === void 0) {
1751
+ return actualDefaultValue;
1752
+ }
1753
+ let processed = String(val).trim();
1754
+ if (processed === "") {
1755
+ if (whitelist && whitelist.includes("")) {
1756
+ return "";
1757
+ }
1758
+ if (!required) {
1759
+ return actualDefaultValue;
1760
+ }
1761
+ return actualDefaultValue;
1762
+ }
1763
+ if (transform) {
1764
+ processed = transform(processed);
1765
+ }
1766
+ return processed;
1767
+ };
1768
+ const baseSchema = required ? import_zod13.z.preprocess(preprocessFn, import_zod13.z.string()) : import_zod13.z.preprocess(preprocessFn, import_zod13.z.string().nullable());
1769
+ const schema = baseSchema.refine((val) => {
1770
+ if (val === null) return true;
1771
+ if (required && (val === "" || val === "null" || val === "undefined")) {
1772
+ throw new import_zod13.z.ZodError([{ code: "custom", message: getMessage("required"), path: [] }]);
1773
+ }
1774
+ if (val === null) return true;
1775
+ if (!required && val === "") return true;
1776
+ if (whitelist && whitelist.length > 0) {
1777
+ if (whitelist.includes(val)) {
1778
+ return true;
1779
+ }
1780
+ throw new import_zod13.z.ZodError([{ code: "custom", message: getMessage("notInWhitelist"), path: [] }]);
1781
+ }
1782
+ if (!validateTaiwanFax(val)) {
1783
+ throw new import_zod13.z.ZodError([{ code: "custom", message: getMessage("invalid"), path: [] }]);
1784
+ }
1785
+ return true;
329
1786
  });
330
1787
  return schema;
331
1788
  }
332
1789
  // Annotate the CommonJS export names for ESM import in node:
333
1790
  0 && (module.exports = {
1791
+ ID_PATTERNS,
334
1792
  boolean,
1793
+ businessId,
1794
+ date,
1795
+ detectIdType,
335
1796
  email,
1797
+ fax,
336
1798
  getLocale,
337
- integer,
1799
+ id,
1800
+ mobile,
1801
+ nationalId,
338
1802
  number,
339
1803
  password,
340
1804
  setLocale,
1805
+ tel,
341
1806
  text,
342
- url
1807
+ url,
1808
+ validateCitizenId,
1809
+ validateIdType,
1810
+ validateNewResidentId,
1811
+ validateOldResidentId,
1812
+ validateTaiwanBusinessId,
1813
+ validateTaiwanFax,
1814
+ validateTaiwanMobile,
1815
+ validateTaiwanNationalId,
1816
+ validateTaiwanTel
343
1817
  });