@hy_ong/zod-kit 0.0.4 → 0.0.6
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 +28 -0
- package/LICENSE +21 -0
- package/README.md +465 -97
- package/debug.js +21 -0
- package/debug.ts +16 -0
- package/dist/index.cjs +3127 -146
- package/dist/index.d.cts +3021 -25
- package/dist/index.d.ts +3021 -25
- package/dist/index.js +3081 -144
- package/eslint.config.mts +8 -0
- package/package.json +10 -9
- package/src/config.ts +1 -1
- package/src/i18n/locales/en.json +161 -25
- package/src/i18n/locales/zh-TW.json +165 -26
- package/src/index.ts +17 -7
- package/src/validators/common/boolean.ts +191 -0
- package/src/validators/common/date.ts +299 -0
- package/src/validators/common/datetime.ts +673 -0
- package/src/validators/common/email.ts +313 -0
- package/src/validators/common/file.ts +384 -0
- package/src/validators/common/id.ts +471 -0
- package/src/validators/common/number.ts +319 -0
- package/src/validators/common/password.ts +386 -0
- package/src/validators/common/text.ts +271 -0
- package/src/validators/common/time.ts +600 -0
- package/src/validators/common/url.ts +347 -0
- package/src/validators/taiwan/business-id.ts +262 -0
- package/src/validators/taiwan/fax.ts +327 -0
- package/src/validators/taiwan/mobile.ts +242 -0
- package/src/validators/taiwan/national-id.ts +425 -0
- package/src/validators/taiwan/postal-code.ts +1049 -0
- package/src/validators/taiwan/tel.ts +330 -0
- package/tests/common/boolean.test.ts +340 -92
- package/tests/common/date.test.ts +458 -0
- package/tests/common/datetime.test.ts +693 -0
- package/tests/common/email.test.ts +232 -60
- package/tests/common/file.test.ts +479 -0
- 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/time.test.ts +528 -0
- 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/postal-code.test.ts +705 -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
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from "vitest"
|
|
2
|
+
import { businessId, setLocale, validateTaiwanBusinessId } from "../../src"
|
|
3
|
+
|
|
4
|
+
describe("Taiwan businessId() validator", () => {
|
|
5
|
+
beforeEach(() => setLocale("en"))
|
|
6
|
+
|
|
7
|
+
describe("basic functionality", () => {
|
|
8
|
+
it("should validate correct Taiwan business IDs", () => {
|
|
9
|
+
const schema = businessId()
|
|
10
|
+
|
|
11
|
+
// Valid Taiwan business IDs (統一編號) - using calculation based on new/old rules
|
|
12
|
+
expect(schema.parse("22550077")).toBe("22550077") // Sum = 50, 50 % 5 = 0 (new rule)
|
|
13
|
+
expect(schema.parse("12345675")).toBe("12345675") // Should be valid with our algorithm
|
|
14
|
+
expect(schema.parse("04595257")).toBe("04595257") // Should be valid
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it("should reject invalid Taiwan business IDs", () => {
|
|
18
|
+
const schema = businessId()
|
|
19
|
+
|
|
20
|
+
// Invalid checksums
|
|
21
|
+
expect(() => schema.parse("12345672")).toThrow("Invalid Taiwan Business ID")
|
|
22
|
+
expect(() => schema.parse("12345673")).toThrow("Invalid Taiwan Business ID")
|
|
23
|
+
expect(() => schema.parse("12345674")).toThrow("Invalid Taiwan Business ID")
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it("should reject non-numeric inputs", () => {
|
|
27
|
+
const schema = businessId()
|
|
28
|
+
|
|
29
|
+
expect(() => schema.parse("1234567A")).toThrow("Invalid Taiwan Business ID")
|
|
30
|
+
expect(() => schema.parse("abcdefgh")).toThrow("Invalid Taiwan Business ID")
|
|
31
|
+
expect(() => schema.parse("123-45-67")).toThrow("Invalid Taiwan Business ID")
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it("should reject wrong length inputs", () => {
|
|
35
|
+
const schema = businessId()
|
|
36
|
+
|
|
37
|
+
expect(() => schema.parse("1234567")).toThrow("Invalid Taiwan Business ID")
|
|
38
|
+
expect(() => schema.parse("123456789")).toThrow("Invalid Taiwan Business ID")
|
|
39
|
+
expect(() => schema.parse("12")).toThrow("Invalid Taiwan Business ID")
|
|
40
|
+
expect(() => schema.parse("")).toThrow("Required")
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe("special case validation (7th digit = 7)", () => {
|
|
45
|
+
it("should handle special case where 7th digit is 7", () => {
|
|
46
|
+
const schema = businessId()
|
|
47
|
+
|
|
48
|
+
// Valid number with 7th digit = 7 for testing special case
|
|
49
|
+
expect(schema.parse("12345670")).toBe("12345670") // Should be valid with special case
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
describe("utility function validateTaiwanBusinessId", () => {
|
|
54
|
+
it("should correctly validate business IDs", () => {
|
|
55
|
+
// Valid IDs (confirmed by our algorithm)
|
|
56
|
+
expect(validateTaiwanBusinessId("12345675")).toBe(true)
|
|
57
|
+
expect(validateTaiwanBusinessId("22550077")).toBe(true)
|
|
58
|
+
expect(validateTaiwanBusinessId("04595257")).toBe(true)
|
|
59
|
+
expect(validateTaiwanBusinessId("53885486")).toBe(true)
|
|
60
|
+
|
|
61
|
+
// Invalid IDs
|
|
62
|
+
expect(validateTaiwanBusinessId("12345672")).toBe(false)
|
|
63
|
+
expect(validateTaiwanBusinessId("12345673")).toBe(false)
|
|
64
|
+
expect(validateTaiwanBusinessId("12345674")).toBe(false)
|
|
65
|
+
expect(validateTaiwanBusinessId("1234567")).toBe(false)
|
|
66
|
+
expect(validateTaiwanBusinessId("123456789")).toBe(false)
|
|
67
|
+
expect(validateTaiwanBusinessId("abcdefgh")).toBe(false)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it("should handle special case for 7th digit = 7", () => {
|
|
71
|
+
// Test with 7th digit = 7 (requires special calculation)
|
|
72
|
+
expect(validateTaiwanBusinessId("12345670")).toBe(true) // Should be valid with special case
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
describe("required/optional behavior", () => {
|
|
77
|
+
it("should handle required=true (default)", () => {
|
|
78
|
+
const schema = businessId()
|
|
79
|
+
|
|
80
|
+
expect(() => schema.parse("")).toThrow("Required")
|
|
81
|
+
expect(() => schema.parse(null)).toThrow()
|
|
82
|
+
expect(() => schema.parse(undefined)).toThrow()
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it("should handle required=false", () => {
|
|
86
|
+
const schema = businessId({ required: false })
|
|
87
|
+
|
|
88
|
+
expect(schema.parse("")).toBe(null)
|
|
89
|
+
expect(schema.parse(null)).toBe(null)
|
|
90
|
+
expect(schema.parse(undefined)).toBe(null)
|
|
91
|
+
expect(schema.parse("12345675")).toBe("12345675")
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it("should use default values", () => {
|
|
95
|
+
const requiredSchema = businessId({ defaultValue: "12345675" })
|
|
96
|
+
const optionalSchema = businessId({ required: false, defaultValue: "12345675" })
|
|
97
|
+
|
|
98
|
+
expect(requiredSchema.parse("")).toBe("12345675")
|
|
99
|
+
expect(optionalSchema.parse("")).toBe("12345675")
|
|
100
|
+
})
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
describe("transform function", () => {
|
|
104
|
+
it("should apply custom transform", () => {
|
|
105
|
+
const schema = businessId({
|
|
106
|
+
transform: (val) => val.replace(/[-\s]/g, ""),
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
expect(schema.parse("1234-5675")).toBe("12345675")
|
|
110
|
+
// Note: This will fail validation since the cleaned value has wrong checksum
|
|
111
|
+
expect(() => schema.parse("1234-5672")).toThrow("Invalid Taiwan Business ID")
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it("should apply transform before validation", () => {
|
|
115
|
+
const schema = businessId({
|
|
116
|
+
transform: (val) => val.replace(/\s+/g, ""),
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
expect(schema.parse(" 12345675 ")).toBe("12345675")
|
|
120
|
+
expect(() => schema.parse(" 1234567 2 ")).toThrow("Invalid Taiwan Business ID")
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
describe("input preprocessing", () => {
|
|
125
|
+
it("should handle string conversion", () => {
|
|
126
|
+
const schema = businessId()
|
|
127
|
+
|
|
128
|
+
expect(schema.parse(12345675)).toBe("12345675")
|
|
129
|
+
expect(() => schema.parse(12345672)).toThrow("Invalid Taiwan Business ID")
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it("should trim whitespace", () => {
|
|
133
|
+
const schema = businessId()
|
|
134
|
+
|
|
135
|
+
expect(schema.parse(" 12345675 ")).toBe("12345675")
|
|
136
|
+
expect(schema.parse("\t12345675\n")).toBe("12345675")
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
describe("i18n support", () => {
|
|
141
|
+
it("should use English messages by default", () => {
|
|
142
|
+
setLocale("en")
|
|
143
|
+
const schema = businessId()
|
|
144
|
+
|
|
145
|
+
expect(() => schema.parse("")).toThrow("Required")
|
|
146
|
+
expect(() => schema.parse("1234567")).toThrow("Invalid Taiwan Business ID")
|
|
147
|
+
expect(() => schema.parse("12345672")).toThrow("Invalid Taiwan Business ID")
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it("should use Chinese messages when locale is zh-TW", () => {
|
|
151
|
+
setLocale("zh-TW")
|
|
152
|
+
const schema = businessId()
|
|
153
|
+
|
|
154
|
+
expect(() => schema.parse("")).toThrow("必填")
|
|
155
|
+
expect(() => schema.parse("1234567")).toThrow("無效的統一編號")
|
|
156
|
+
expect(() => schema.parse("12345672")).toThrow("無效的統一編號")
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it("should support custom i18n messages", () => {
|
|
160
|
+
const schema = businessId({
|
|
161
|
+
i18n: {
|
|
162
|
+
en: {
|
|
163
|
+
required: "Business ID is required",
|
|
164
|
+
invalid: "Business ID is invalid",
|
|
165
|
+
},
|
|
166
|
+
"zh-TW": {
|
|
167
|
+
required: "請輸入統一編號",
|
|
168
|
+
invalid: "統一編號格式錯誤",
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
setLocale("en")
|
|
174
|
+
expect(() => schema.parse("")).toThrow("Business ID is required")
|
|
175
|
+
expect(() => schema.parse("12345672")).toThrow("Business ID is invalid")
|
|
176
|
+
|
|
177
|
+
setLocale("zh-TW")
|
|
178
|
+
expect(() => schema.parse("")).toThrow("請輸入統一編號")
|
|
179
|
+
expect(() => schema.parse("12345672")).toThrow("統一編號格式錯誤")
|
|
180
|
+
})
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
describe("real world Taiwan business IDs", () => {
|
|
184
|
+
it("should validate known real business IDs", () => {
|
|
185
|
+
const schema = businessId()
|
|
186
|
+
|
|
187
|
+
// These are example valid Taiwan business IDs for testing
|
|
188
|
+
const validIds = [
|
|
189
|
+
"12345675", // Calculated valid example
|
|
190
|
+
"22550077", // Calculated valid example
|
|
191
|
+
"04595257", // Calculated valid example
|
|
192
|
+
"53885486", // Calculated valid example
|
|
193
|
+
]
|
|
194
|
+
|
|
195
|
+
validIds.forEach((id) => {
|
|
196
|
+
expect(schema.parse(id)).toBe(id)
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
it("should reject common invalid patterns", () => {
|
|
201
|
+
const schema = businessId()
|
|
202
|
+
|
|
203
|
+
const invalidIds = [
|
|
204
|
+
"00000001", // All zeros with bad checksum
|
|
205
|
+
"11111111", // All ones
|
|
206
|
+
"12345672", // Sequential but wrong checksum
|
|
207
|
+
"12345673", // Almost valid but wrong checksum
|
|
208
|
+
"12345674", // Almost valid but wrong checksum
|
|
209
|
+
"98765432", // Reverse sequential but wrong checksum
|
|
210
|
+
"87654321", // Another invalid pattern
|
|
211
|
+
]
|
|
212
|
+
|
|
213
|
+
invalidIds.forEach((id) => {
|
|
214
|
+
expect(() => schema.parse(id)).toThrow()
|
|
215
|
+
})
|
|
216
|
+
})
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
describe("edge cases", () => {
|
|
220
|
+
it("should handle leading zeros", () => {
|
|
221
|
+
const schema = businessId()
|
|
222
|
+
|
|
223
|
+
expect(schema.parse("04595257")).toBe("04595257")
|
|
224
|
+
expect(() => schema.parse("00123456")).toThrow("Invalid Taiwan Business ID")
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
it("should handle empty and whitespace inputs", () => {
|
|
228
|
+
const schema = businessId()
|
|
229
|
+
const optionalSchema = businessId({ required: false })
|
|
230
|
+
|
|
231
|
+
expect(() => schema.parse("")).toThrow("Required")
|
|
232
|
+
expect(() => schema.parse(" ")).toThrow("Required")
|
|
233
|
+
expect(() => schema.parse("\t\n")).toThrow("Required")
|
|
234
|
+
|
|
235
|
+
expect(optionalSchema.parse("")).toBe(null)
|
|
236
|
+
expect(optionalSchema.parse(" ")).toBe(null)
|
|
237
|
+
expect(optionalSchema.parse("\t\n")).toBe(null)
|
|
238
|
+
})
|
|
239
|
+
})
|
|
240
|
+
})
|