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