@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.
- package/.claude/settings.local.json +23 -0
- package/LICENSE +21 -0
- package/README.md +7 -7
- package/debug.js +21 -0
- package/debug.ts +16 -0
- package/dist/index.cjs +1663 -189
- package/dist/index.d.cts +324 -32
- package/dist/index.d.ts +324 -32
- package/dist/index.js +1634 -187
- package/eslint.config.mts +8 -0
- package/package.json +10 -9
- package/src/config.ts +1 -1
- package/src/i18n/locales/en.json +123 -49
- package/src/i18n/locales/zh-TW.json +123 -46
- 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 +281 -54
- package/tests/common/text.test.ts +227 -30
- 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 -37
- package/src/common/date.ts +0 -44
- package/src/common/email.ts +0 -45
- package/src/common/integer.ts +0 -47
- package/src/common/number.ts +0 -38
- package/src/common/password.ts +0 -34
- package/src/common/text.ts +0 -35
- package/src/common/url.ts +0 -38
- package/tests/common/integer.test.ts +0 -90
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hy_ong/zod-kit",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Zod Kit",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"hy_ong",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"publishConfig": {
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
|
-
"license": "
|
|
22
|
+
"license": "MIT",
|
|
23
23
|
"author": "Ong Hoe Yuan",
|
|
24
24
|
"type": "module",
|
|
25
25
|
"main": "dist/index.cjs",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
".": {
|
|
30
30
|
"import": "./dist/index.js",
|
|
31
31
|
"require": "./dist/index.cjs",
|
|
32
|
-
"
|
|
32
|
+
"default": "./dist/index.js"
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
@@ -37,17 +37,18 @@
|
|
|
37
37
|
"test": "vitest"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"dayjs": "^1.11.
|
|
41
|
-
"zod": "^4.
|
|
40
|
+
"dayjs": "^1.11.14",
|
|
41
|
+
"zod": "^4.1.4"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@eslint/js": "^9.
|
|
45
|
-
"@types/node": "^
|
|
46
|
-
"eslint": "^9.
|
|
44
|
+
"@eslint/js": "^9.34.0",
|
|
45
|
+
"@types/node": "^20.19.11",
|
|
46
|
+
"eslint": "^9.34.0",
|
|
47
|
+
"jiti": "^2.5.1",
|
|
47
48
|
"prettier": "^3.6.2",
|
|
48
49
|
"tsup": "^8.5.0",
|
|
49
50
|
"typescript": "^5.8.3",
|
|
50
|
-
"typescript-eslint": "^8.
|
|
51
|
+
"typescript-eslint": "^8.41.0",
|
|
51
52
|
"vitest": "^3.2.4"
|
|
52
53
|
}
|
|
53
54
|
}
|
package/src/config.ts
CHANGED
package/src/i18n/locales/en.json
CHANGED
|
@@ -1,68 +1,142 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"boolean": {
|
|
4
|
-
"required": "
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
4
|
+
"required": "Required",
|
|
5
|
+
"shouldBeTrue": "Must be True",
|
|
6
|
+
"shouldBeFalse": "Must be False",
|
|
7
|
+
"invalid": "Must be a boolean value"
|
|
9
8
|
},
|
|
10
9
|
"email": {
|
|
11
|
-
"required": "
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"domain": "
|
|
10
|
+
"required": "Required",
|
|
11
|
+
"invalid": "Invalid email format",
|
|
12
|
+
"minLength": "Must be at least ${minLength} characters",
|
|
13
|
+
"maxLength": "Must be at most ${maxLength} characters",
|
|
14
|
+
"includes": "Must include ${includes}",
|
|
15
|
+
"domain": "Must be from domain: ${domain}",
|
|
16
|
+
"domainBlacklist": "Domain ${domain} is not allowed",
|
|
17
|
+
"businessOnly": "Only business email addresses are allowed",
|
|
18
|
+
"noDisposable": "Disposable email addresses are not allowed"
|
|
17
19
|
},
|
|
18
20
|
"url": {
|
|
19
|
-
"required": "
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
21
|
+
"required": "Required",
|
|
22
|
+
"invalid": "Invalid URL format",
|
|
23
|
+
"min": "Must be at least ${min} characters",
|
|
24
|
+
"max": "Must be at most ${max} characters",
|
|
25
|
+
"includes": "Must include ${includes}",
|
|
26
|
+
"excludes": "Must not contain ${excludes}",
|
|
27
|
+
"protocol": "Protocol must be one of: ${protocols}",
|
|
28
|
+
"domain": "Domain must be one of: ${domains}",
|
|
29
|
+
"domainBlacklist": "Domain ${domain} is not allowed",
|
|
30
|
+
"port": "Port must be one of: ${ports}",
|
|
31
|
+
"pathStartsWith": "Path must start with ${path}",
|
|
32
|
+
"pathEndsWith": "Path must end with ${path}",
|
|
33
|
+
"hasQuery": "URL must have query parameters",
|
|
34
|
+
"noQuery": "URL must not have query parameters",
|
|
35
|
+
"hasFragment": "URL must have a fragment",
|
|
36
|
+
"noFragment": "URL must not have a fragment",
|
|
37
|
+
"localhost": "Localhost URLs are not allowed",
|
|
38
|
+
"noLocalhost": "Localhost URLs are not allowed"
|
|
24
39
|
},
|
|
25
40
|
"password": {
|
|
26
|
-
"required": "
|
|
27
|
-
"min": "
|
|
28
|
-
"max": "
|
|
29
|
-
"uppercase": "
|
|
30
|
-
"lowercase": "
|
|
31
|
-
"digits": "
|
|
32
|
-
"special": "
|
|
41
|
+
"required": "Required",
|
|
42
|
+
"min": "Must be at least ${min} characters",
|
|
43
|
+
"max": "Must be at most ${max} characters",
|
|
44
|
+
"uppercase": "Must include at least one uppercase letter",
|
|
45
|
+
"lowercase": "Must include at least one lowercase letter",
|
|
46
|
+
"digits": "Must include at least one digit",
|
|
47
|
+
"special": "Must include at least one special character",
|
|
48
|
+
"noRepeating": "Must not contain repeating characters",
|
|
49
|
+
"noSequential": "Must not contain sequential characters",
|
|
50
|
+
"noCommonWords": "Must not contain common words or patterns",
|
|
51
|
+
"minStrength": "Password strength must be at least ${minStrength}",
|
|
52
|
+
"excludes": "Must not contain ${excludes}",
|
|
53
|
+
"includes": "Must include ${includes}",
|
|
54
|
+
"invalid": "Invalid password format"
|
|
33
55
|
},
|
|
34
56
|
"number": {
|
|
35
|
-
"required": "
|
|
36
|
-
"
|
|
37
|
-
"
|
|
57
|
+
"required": "Required",
|
|
58
|
+
"invalid": "Must be a valid number",
|
|
59
|
+
"integer": "Must be an integer",
|
|
60
|
+
"float": "Must be a decimal number",
|
|
61
|
+
"min": "Must be at least ${min}",
|
|
62
|
+
"max": "Must be at most ${max}",
|
|
63
|
+
"positive": "Must be positive",
|
|
64
|
+
"negative": "Must be negative",
|
|
65
|
+
"nonNegative": "Must be non-negative",
|
|
66
|
+
"nonPositive": "Must be non-positive",
|
|
67
|
+
"multipleOf": "Must be a multiple of ${multipleOf}",
|
|
68
|
+
"finite": "Must be a finite number",
|
|
69
|
+
"precision": "Must have at most ${precision} decimal places"
|
|
38
70
|
},
|
|
39
|
-
"
|
|
40
|
-
"required": "
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
71
|
+
"id": {
|
|
72
|
+
"required": "Required",
|
|
73
|
+
"invalid": "Invalid ID format",
|
|
74
|
+
"minLength": "Must be at least ${minLength} characters",
|
|
75
|
+
"maxLength": "Must be at most ${maxLength} characters",
|
|
76
|
+
"numeric": "Must be a numeric ID",
|
|
77
|
+
"uuid": "Must be a valid UUID",
|
|
78
|
+
"objectId": "Must be a valid MongoDB ObjectId",
|
|
79
|
+
"nanoid": "Must be a valid Nano ID",
|
|
80
|
+
"snowflake": "Must be a valid Snowflake ID",
|
|
81
|
+
"cuid": "Must be a valid CUID",
|
|
82
|
+
"ulid": "Must be a valid ULID",
|
|
83
|
+
"shortid": "Must be a valid Short ID",
|
|
84
|
+
"customFormat": "Invalid ID format",
|
|
85
|
+
"includes": "Must include ${includes}",
|
|
86
|
+
"excludes": "Must not contain ${excludes}",
|
|
87
|
+
"startsWith": "Must start with ${startsWith}",
|
|
88
|
+
"endsWith": "Must end with ${endsWith}"
|
|
50
89
|
},
|
|
51
90
|
"text": {
|
|
52
|
-
"required": "
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
91
|
+
"required": "Required",
|
|
92
|
+
"notEmpty": "Cannot be empty or whitespace only",
|
|
93
|
+
"minLength": "Must be at least ${minLength} characters",
|
|
94
|
+
"maxLength": "Must be at most ${maxLength} characters",
|
|
95
|
+
"startsWith": "Must start with ${startsWith}",
|
|
96
|
+
"endsWith": "Must end with ${endsWith}",
|
|
97
|
+
"includes": "Must include ${includes}",
|
|
98
|
+
"excludes": "Must not contain ${excludes}",
|
|
99
|
+
"invalid": "Invalid format"
|
|
59
100
|
},
|
|
60
101
|
"date": {
|
|
61
|
-
"required": "
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
102
|
+
"required": "Required",
|
|
103
|
+
"invalid": "Invalid date",
|
|
104
|
+
"format": "Must be in ${format} format",
|
|
105
|
+
"min": "Date must be on or after ${min}",
|
|
106
|
+
"max": "Date must be on or before ${max}",
|
|
107
|
+
"includes": "Must include ${includes}",
|
|
108
|
+
"excludes": "Must not contain ${excludes}",
|
|
109
|
+
"past": "Date must be in the past",
|
|
110
|
+
"future": "Date must be in the future",
|
|
111
|
+
"today": "Date must be today",
|
|
112
|
+
"notToday": "Date must not be today",
|
|
113
|
+
"weekday": "Date must be a weekday (Monday-Friday)",
|
|
114
|
+
"weekend": "Date must be a weekend (Saturday-Sunday)"
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"taiwan": {
|
|
118
|
+
"businessId": {
|
|
119
|
+
"required": "Required",
|
|
120
|
+
"invalid": "Invalid Taiwan Business ID"
|
|
121
|
+
},
|
|
122
|
+
"nationalId": {
|
|
123
|
+
"required": "Required",
|
|
124
|
+
"invalid": "Invalid Taiwan National ID"
|
|
125
|
+
},
|
|
126
|
+
"mobile": {
|
|
127
|
+
"required": "Required",
|
|
128
|
+
"invalid": "Invalid Taiwan mobile phone format",
|
|
129
|
+
"notInWhitelist": "Not in allowed mobile phone list"
|
|
130
|
+
},
|
|
131
|
+
"tel": {
|
|
132
|
+
"required": "Required",
|
|
133
|
+
"invalid": "Invalid Taiwan telephone format",
|
|
134
|
+
"notInWhitelist": "Not in allowed telephone list"
|
|
135
|
+
},
|
|
136
|
+
"fax": {
|
|
137
|
+
"required": "Required",
|
|
138
|
+
"invalid": "Invalid Taiwan fax format",
|
|
139
|
+
"notInWhitelist": "Not in allowed fax list"
|
|
66
140
|
}
|
|
67
141
|
}
|
|
68
142
|
}
|
|
@@ -1,65 +1,142 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"boolean": {
|
|
4
|
-
"required": "
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
4
|
+
"required": "必填",
|
|
5
|
+
"shouldBeTrue": "必須為是",
|
|
6
|
+
"shouldBeFalse": "必須為否",
|
|
7
|
+
"invalid": "必須為布林值"
|
|
9
8
|
},
|
|
10
9
|
"email": {
|
|
11
|
-
"required": "
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"domain": "
|
|
10
|
+
"required": "必填",
|
|
11
|
+
"invalid": "電子郵件格式錯誤",
|
|
12
|
+
"minLength": "長度至少 ${minLength} 字元",
|
|
13
|
+
"maxLength": "長度最多 ${maxLength} 字元",
|
|
14
|
+
"includes": "必須包含「${includes}」",
|
|
15
|
+
"domain": "必須為 ${domain} 網域",
|
|
16
|
+
"domainBlacklist": "不允許使用 ${domain} 網域",
|
|
17
|
+
"businessOnly": "僅允許企業郵箱地址",
|
|
18
|
+
"noDisposable": "不允許使用臨時郵箱地址"
|
|
17
19
|
},
|
|
18
20
|
"url": {
|
|
19
|
-
"required": "
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
21
|
+
"required": "必填",
|
|
22
|
+
"invalid": "無效的 URL 格式",
|
|
23
|
+
"min": "長度至少 ${min} 字元",
|
|
24
|
+
"max": "長度最多 ${max} 字元",
|
|
25
|
+
"includes": "必須包含「${includes}」",
|
|
26
|
+
"excludes": "不得包含「${excludes}」",
|
|
27
|
+
"protocol": "協議必須為:${protocols}",
|
|
28
|
+
"domain": "網域必須為:${domains}",
|
|
29
|
+
"domainBlacklist": "不允許使用網域 ${domain}",
|
|
30
|
+
"port": "連接埠必須為:${ports}",
|
|
31
|
+
"pathStartsWith": "路徑必須以「${path}」開頭",
|
|
32
|
+
"pathEndsWith": "路徑必須以「${path}」結尾",
|
|
33
|
+
"hasQuery": "URL 必須包含查詢參數",
|
|
34
|
+
"noQuery": "URL 不得包含查詢參數",
|
|
35
|
+
"hasFragment": "URL 必須包含錨點",
|
|
36
|
+
"noFragment": "URL 不得包含錨點",
|
|
37
|
+
"localhost": "不允許使用本機 URL",
|
|
38
|
+
"noLocalhost": "不允許使用本機 URL"
|
|
24
39
|
},
|
|
25
40
|
"password": {
|
|
26
|
-
"required": "
|
|
27
|
-
"min": "
|
|
28
|
-
"max": "
|
|
29
|
-
"uppercase": "
|
|
30
|
-
"lowercase": "
|
|
31
|
-
"digits": "
|
|
32
|
-
"special": "
|
|
41
|
+
"required": "必填",
|
|
42
|
+
"min": "長度至少 ${min} 字元",
|
|
43
|
+
"max": "長度最多 ${max} 字元",
|
|
44
|
+
"uppercase": "必須包含至少一個大寫字母",
|
|
45
|
+
"lowercase": "必須包含至少一個小寫字母",
|
|
46
|
+
"digits": "必須包含至少一個數字",
|
|
47
|
+
"special": "必須包含至少一個特殊符號",
|
|
48
|
+
"noRepeating": "不可包含重複字元",
|
|
49
|
+
"noSequential": "不可包含連續字元",
|
|
50
|
+
"noCommonWords": "不可包含常見密碼或模式",
|
|
51
|
+
"minStrength": "密碼強度必須至少為 ${minStrength}",
|
|
52
|
+
"excludes": "不得包含「${excludes}」",
|
|
53
|
+
"includes": "必須包含「${includes}」",
|
|
54
|
+
"invalid": "密碼格式錯誤"
|
|
33
55
|
},
|
|
34
56
|
"number": {
|
|
35
|
-
"required": "
|
|
36
|
-
"
|
|
37
|
-
"
|
|
57
|
+
"required": "必填",
|
|
58
|
+
"invalid": "必須為有效數字",
|
|
59
|
+
"integer": "必須為整數",
|
|
60
|
+
"float": "必須為小數",
|
|
61
|
+
"min": "最小值 ${min}",
|
|
62
|
+
"max": "最大值 ${max}",
|
|
63
|
+
"positive": "必須為正數",
|
|
64
|
+
"negative": "必須為負數",
|
|
65
|
+
"nonNegative": "不可為負數",
|
|
66
|
+
"nonPositive": "不可為正數",
|
|
67
|
+
"multipleOf": "必須為 ${multipleOf} 的倍數",
|
|
68
|
+
"finite": "必須為有限數字",
|
|
69
|
+
"precision": "小數位數不可超過 ${precision} 位"
|
|
38
70
|
},
|
|
39
71
|
"id": {
|
|
40
|
-
"required": "
|
|
41
|
-
"invalid": "
|
|
72
|
+
"required": "必填",
|
|
73
|
+
"invalid": "無效的 ID 格式",
|
|
74
|
+
"minLength": "長度至少 ${minLength} 字元",
|
|
75
|
+
"maxLength": "長度最多 ${maxLength} 字元",
|
|
76
|
+
"numeric": "必須為數字 ID",
|
|
77
|
+
"uuid": "必須為有效的 UUID",
|
|
78
|
+
"objectId": "必須為有效的 MongoDB ObjectId",
|
|
79
|
+
"nanoid": "必須為有效的 Nano ID",
|
|
80
|
+
"snowflake": "必須為有效的 Snowflake ID",
|
|
81
|
+
"cuid": "必須為有效的 CUID",
|
|
82
|
+
"ulid": "必須為有效的 ULID",
|
|
83
|
+
"shortid": "必須為有效的 Short ID",
|
|
84
|
+
"customFormat": "無效的 ID 格式",
|
|
85
|
+
"includes": "必須包含「${includes}」",
|
|
86
|
+
"excludes": "不得包含「${excludes}」",
|
|
87
|
+
"startsWith": "必須以「${startsWith}」開頭",
|
|
88
|
+
"endsWith": "必須以「${endsWith}」結尾"
|
|
42
89
|
},
|
|
43
|
-
"
|
|
44
|
-
"required": "
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
90
|
+
"text": {
|
|
91
|
+
"required": "必填",
|
|
92
|
+
"notEmpty": "不可為空白或僅含空格",
|
|
93
|
+
"minLength": "長度至少 ${minLength} 字元",
|
|
94
|
+
"maxLength": "長度最多 ${maxLength} 字元",
|
|
95
|
+
"startsWith": "必須以「${startsWith}」開頭",
|
|
96
|
+
"endsWith": "必須以「${endsWith}」結尾",
|
|
97
|
+
"includes": "必須包含「${includes}」",
|
|
98
|
+
"excludes": "不得包含「${excludes}」",
|
|
99
|
+
"invalid": "格式錯誤"
|
|
48
100
|
},
|
|
49
|
-
"
|
|
50
|
-
"required": "
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
101
|
+
"date": {
|
|
102
|
+
"required": "必填",
|
|
103
|
+
"invalid": "無效日期",
|
|
104
|
+
"format": "必須為 ${format} 格式",
|
|
105
|
+
"min": "日期不得早於 ${min}",
|
|
106
|
+
"max": "日期不得晚於 ${max}",
|
|
107
|
+
"includes": "必須包含「${includes}」",
|
|
108
|
+
"excludes": "不得包含「${excludes}」",
|
|
109
|
+
"past": "必須為過去的日期",
|
|
110
|
+
"future": "必須為未來的日期",
|
|
111
|
+
"today": "必須為今天",
|
|
112
|
+
"notToday": "不得為今天",
|
|
113
|
+
"weekday": "必須為工作日(週一至週五)",
|
|
114
|
+
"weekend": "必須為週末(週六至週日)"
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"taiwan": {
|
|
118
|
+
"businessId": {
|
|
119
|
+
"required": "必填",
|
|
120
|
+
"invalid": "無效的統一編號"
|
|
54
121
|
},
|
|
55
|
-
"
|
|
56
|
-
"required": "
|
|
57
|
-
"
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
122
|
+
"nationalId": {
|
|
123
|
+
"required": "必填",
|
|
124
|
+
"invalid": "無效的身分證字號"
|
|
125
|
+
},
|
|
126
|
+
"mobile": {
|
|
127
|
+
"required": "必填",
|
|
128
|
+
"invalid": "無效的手機號碼格式",
|
|
129
|
+
"notInWhitelist": "不在允許的手機號碼清單中"
|
|
130
|
+
},
|
|
131
|
+
"tel": {
|
|
132
|
+
"required": "必填",
|
|
133
|
+
"invalid": "無效的市話號碼格式",
|
|
134
|
+
"notInWhitelist": "不在允許的市話號碼清單中"
|
|
135
|
+
},
|
|
136
|
+
"fax": {
|
|
137
|
+
"required": "必填",
|
|
138
|
+
"invalid": "無效的傳真號碼格式",
|
|
139
|
+
"notInWhitelist": "不在允許的傳真號碼清單中"
|
|
63
140
|
}
|
|
64
141
|
}
|
|
65
142
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
export * from "./common/boolean"
|
|
2
|
-
export * from "./common/
|
|
3
|
-
export * from "./common/
|
|
4
|
-
export * from "./common/
|
|
5
|
-
export * from "./common/number"
|
|
6
|
-
export * from "./common/password"
|
|
7
|
-
export * from "./common/
|
|
1
|
+
export * from "./validators/common/boolean"
|
|
2
|
+
export * from "./validators/common/date"
|
|
3
|
+
export * from "./validators/common/email"
|
|
4
|
+
export * from "./validators/common/id"
|
|
5
|
+
export * from "./validators/common/number"
|
|
6
|
+
export * from "./validators/common/password"
|
|
7
|
+
export * from "./validators/common/text"
|
|
8
|
+
export * from "./validators/common/url"
|
|
9
|
+
export * from "./validators/taiwan/business-id"
|
|
10
|
+
export * from "./validators/taiwan/national-id"
|
|
11
|
+
export * from "./validators/taiwan/mobile"
|
|
12
|
+
export * from "./validators/taiwan/tel"
|
|
13
|
+
export * from "./validators/taiwan/fax"
|
|
8
14
|
export * from "./config"
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { z, ZodBoolean, ZodNullable, ZodType } from "zod"
|
|
2
|
+
import { t } from "../../i18n"
|
|
3
|
+
import { getLocale, type Locale } from "../../config"
|
|
4
|
+
|
|
5
|
+
export type BooleanMessages = {
|
|
6
|
+
required?: string
|
|
7
|
+
shouldBeTrue?: string
|
|
8
|
+
shouldBeFalse?: string
|
|
9
|
+
invalid?: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type BooleanOptions<IsRequired extends boolean = true> = {
|
|
13
|
+
required?: IsRequired
|
|
14
|
+
defaultValue?: IsRequired extends true ? boolean : boolean | null
|
|
15
|
+
shouldBe?: boolean
|
|
16
|
+
truthyValues?: unknown[]
|
|
17
|
+
falsyValues?: unknown[]
|
|
18
|
+
strict?: boolean
|
|
19
|
+
transform?: (value: boolean) => boolean
|
|
20
|
+
i18n?: Record<Locale, BooleanMessages>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type BooleanSchema<IsRequired extends boolean> = IsRequired extends true ? ZodBoolean : ZodNullable<ZodBoolean>
|
|
24
|
+
|
|
25
|
+
export function boolean<IsRequired extends boolean = true>(options?: BooleanOptions<IsRequired>): BooleanSchema<IsRequired> {
|
|
26
|
+
const {
|
|
27
|
+
required = true,
|
|
28
|
+
defaultValue = null,
|
|
29
|
+
shouldBe,
|
|
30
|
+
truthyValues = [true, "true", 1, "1", "yes", "on"],
|
|
31
|
+
falsyValues = [false, "false", 0, "0", "no", "off"],
|
|
32
|
+
strict = false,
|
|
33
|
+
transform,
|
|
34
|
+
i18n,
|
|
35
|
+
} = options ?? {}
|
|
36
|
+
|
|
37
|
+
// Helper function to get custom message or fallback to default i18n
|
|
38
|
+
const getMessage = (key: keyof BooleanMessages, params?: Record<string, any>) => {
|
|
39
|
+
if (i18n) {
|
|
40
|
+
const currentLocale = getLocale()
|
|
41
|
+
const customMessages = i18n[currentLocale]
|
|
42
|
+
if (customMessages && customMessages[key]) {
|
|
43
|
+
const template = customMessages[key]!
|
|
44
|
+
return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "")
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return t(`common.boolean.${key}`, params)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let result: ZodType = z.preprocess(
|
|
51
|
+
(val) => {
|
|
52
|
+
if (val === "" || val === undefined || val === null) return defaultValue
|
|
53
|
+
|
|
54
|
+
if (strict && typeof val !== "boolean" && val !== null) {
|
|
55
|
+
return val // Let it fail in validation
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Check truthy values
|
|
59
|
+
if (truthyValues.includes(val)) {
|
|
60
|
+
let processed = true
|
|
61
|
+
if (transform) processed = transform(processed)
|
|
62
|
+
return processed
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Check falsy values
|
|
66
|
+
if (falsyValues.includes(val)) {
|
|
67
|
+
let processed = false
|
|
68
|
+
if (transform) processed = transform(processed)
|
|
69
|
+
return processed
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return val
|
|
73
|
+
},
|
|
74
|
+
z.union([z.literal(true), z.literal(false), z.literal(null)])
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
if (required && defaultValue === null) {
|
|
78
|
+
result = result.refine((val) => val !== null, { message: getMessage("required") })
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (shouldBe === true) {
|
|
82
|
+
result = result.refine((val) => val === true, { message: getMessage("shouldBeTrue") })
|
|
83
|
+
} else if (shouldBe === false) {
|
|
84
|
+
result = result.refine((val) => val === false, { message: getMessage("shouldBeFalse") })
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (strict) {
|
|
88
|
+
result = result.refine(
|
|
89
|
+
(val) => {
|
|
90
|
+
return val === null || typeof val === "boolean"
|
|
91
|
+
},
|
|
92
|
+
{ message: getMessage("invalid") }
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return result as IsRequired extends true ? ZodBoolean : ZodNullable<ZodBoolean>
|
|
97
|
+
}
|