@hy_ong/zod-kit 0.0.6 → 0.1.1
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 +4 -1
- package/README.md +134 -68
- package/dist/index.cjs +93 -89
- package/dist/index.d.cts +235 -169
- package/dist/index.d.ts +235 -169
- package/dist/index.js +93 -89
- package/package.json +15 -5
- package/src/validators/common/boolean.ts +17 -14
- package/src/validators/common/date.ts +21 -14
- package/src/validators/common/datetime.ts +21 -14
- package/src/validators/common/email.ts +18 -15
- package/src/validators/common/file.ts +20 -13
- package/src/validators/common/id.ts +14 -14
- package/src/validators/common/number.ts +18 -15
- package/src/validators/common/password.ts +21 -14
- package/src/validators/common/text.ts +21 -17
- package/src/validators/common/time.ts +21 -14
- package/src/validators/common/url.ts +22 -15
- package/src/validators/taiwan/business-id.ts +18 -11
- package/src/validators/taiwan/fax.ts +23 -14
- package/src/validators/taiwan/mobile.ts +23 -14
- package/src/validators/taiwan/national-id.ts +11 -12
- package/src/validators/taiwan/postal-code.ts +16 -17
- package/src/validators/taiwan/tel.ts +23 -14
- package/tests/common/boolean.test.ts +38 -38
- package/tests/common/date.test.ts +65 -65
- package/tests/common/datetime.test.ts +100 -118
- package/tests/common/email.test.ts +24 -28
- package/tests/common/file.test.ts +47 -51
- package/tests/common/id.test.ts +80 -113
- package/tests/common/number.test.ts +24 -25
- package/tests/common/password.test.ts +28 -35
- package/tests/common/text.test.ts +36 -37
- package/tests/common/time.test.ts +64 -82
- package/tests/common/url.test.ts +67 -67
- package/tests/taiwan/business-id.test.ts +22 -22
- package/tests/taiwan/fax.test.ts +33 -42
- package/tests/taiwan/mobile.test.ts +32 -41
- package/tests/taiwan/national-id.test.ts +31 -31
- package/tests/taiwan/postal-code.test.ts +142 -96
- package/tests/taiwan/tel.test.ts +33 -42
- package/debug.js +0 -21
- package/debug.ts +0 -16
|
@@ -6,7 +6,7 @@ describe("postalCode() features", () => {
|
|
|
6
6
|
|
|
7
7
|
describe("3-digit postal code validation", () => {
|
|
8
8
|
it("should accept valid 3-digit postal codes", () => {
|
|
9
|
-
const schema = postalCode({ format: "3" })
|
|
9
|
+
const schema = postalCode(true, { format: "3" })
|
|
10
10
|
expect(schema.parse("100")).toBe("100") // Taipei
|
|
11
11
|
expect(schema.parse("200")).toBe("200") // Keelung
|
|
12
12
|
expect(schema.parse("300")).toBe("300") // Taoyuan/Hsinchu
|
|
@@ -19,20 +19,20 @@ describe("postalCode() features", () => {
|
|
|
19
19
|
})
|
|
20
20
|
|
|
21
21
|
it("should reject invalid 3-digit postal codes", () => {
|
|
22
|
-
const schema = postalCode({ format: "3" })
|
|
22
|
+
const schema = postalCode(true, { format: "3" })
|
|
23
23
|
expect(() => schema.parse("000")).toThrow("Invalid Taiwan postal code")
|
|
24
24
|
expect(() => schema.parse("099")).toThrow("Invalid Taiwan postal code")
|
|
25
25
|
expect(() => schema.parse("999")).toThrow("Invalid Taiwan postal code")
|
|
26
26
|
})
|
|
27
27
|
|
|
28
28
|
it("should reject non-3-digit formats when format is '3'", () => {
|
|
29
|
-
const schema = postalCode({ format: "3" })
|
|
29
|
+
const schema = postalCode(true, { format: "3" })
|
|
30
30
|
expect(() => schema.parse("10001")).toThrow("Only 3-digit postal codes are allowed")
|
|
31
31
|
expect(() => schema.parse("100001")).toThrow("Only 3-digit postal codes are allowed")
|
|
32
32
|
})
|
|
33
33
|
|
|
34
34
|
it("should validate specific Taipei area postal codes", () => {
|
|
35
|
-
const schema = postalCode({ format: "3" })
|
|
35
|
+
const schema = postalCode(true, { format: "3" })
|
|
36
36
|
expect(schema.parse("100")).toBe("100") // Zhongzheng
|
|
37
37
|
expect(schema.parse("103")).toBe("103") // Datong
|
|
38
38
|
expect(schema.parse("104")).toBe("104") // Zhongshan
|
|
@@ -50,7 +50,7 @@ describe("postalCode() features", () => {
|
|
|
50
50
|
|
|
51
51
|
describe("5-digit postal code validation", () => {
|
|
52
52
|
it("should accept valid 5-digit postal codes", () => {
|
|
53
|
-
const schema = postalCode({ format: "5" })
|
|
53
|
+
const schema = postalCode(true, { format: "5" })
|
|
54
54
|
expect(schema.parse("10001")).toBe("10001")
|
|
55
55
|
expect(schema.parse("20001")).toBe("20001")
|
|
56
56
|
expect(schema.parse("30001")).toBe("30001")
|
|
@@ -59,20 +59,20 @@ describe("postalCode() features", () => {
|
|
|
59
59
|
})
|
|
60
60
|
|
|
61
61
|
it("should reject invalid 5-digit postal codes", () => {
|
|
62
|
-
const schema = postalCode({ format: "5" })
|
|
62
|
+
const schema = postalCode(true, { format: "5" })
|
|
63
63
|
expect(() => schema.parse("00001")).toThrow("Invalid Taiwan postal code")
|
|
64
64
|
expect(() => schema.parse("09901")).toThrow("Invalid Taiwan postal code")
|
|
65
65
|
expect(() => schema.parse("99901")).toThrow("Invalid Taiwan postal code")
|
|
66
66
|
})
|
|
67
67
|
|
|
68
68
|
it("should reject non-5-digit formats when format is '5'", () => {
|
|
69
|
-
const schema = postalCode({ format: "5" })
|
|
69
|
+
const schema = postalCode(true, { format: "5" })
|
|
70
70
|
expect(() => schema.parse("100")).toThrow("Only 5-digit postal codes are allowed")
|
|
71
71
|
expect(() => schema.parse("100001")).toThrow("Only 5-digit postal codes are allowed")
|
|
72
72
|
})
|
|
73
73
|
|
|
74
74
|
it("should validate 5-digit postal codes with valid prefixes", () => {
|
|
75
|
-
const schema = postalCode({ format: "5" })
|
|
75
|
+
const schema = postalCode(true, { format: "5" })
|
|
76
76
|
expect(schema.parse("10099")).toBe("10099") // Valid Taipei prefix
|
|
77
77
|
expect(schema.parse("20099")).toBe("20099") // Valid Keelung prefix
|
|
78
78
|
expect(schema.parse("88099")).toBe("88099") // Valid Penghu prefix
|
|
@@ -81,7 +81,7 @@ describe("postalCode() features", () => {
|
|
|
81
81
|
|
|
82
82
|
describe("6-digit postal code validation", () => {
|
|
83
83
|
it("should accept valid 6-digit postal codes", () => {
|
|
84
|
-
const schema = postalCode({ format: "6" })
|
|
84
|
+
const schema = postalCode(true, { format: "6" })
|
|
85
85
|
expect(schema.parse("100001")).toBe("100001")
|
|
86
86
|
expect(schema.parse("200001")).toBe("200001")
|
|
87
87
|
expect(schema.parse("300001")).toBe("300001")
|
|
@@ -90,20 +90,20 @@ describe("postalCode() features", () => {
|
|
|
90
90
|
})
|
|
91
91
|
|
|
92
92
|
it("should reject invalid 6-digit postal codes", () => {
|
|
93
|
-
const schema = postalCode({ format: "6" })
|
|
93
|
+
const schema = postalCode(true, { format: "6" })
|
|
94
94
|
expect(() => schema.parse("000001")).toThrow("Invalid Taiwan postal code")
|
|
95
95
|
expect(() => schema.parse("099001")).toThrow("Invalid Taiwan postal code")
|
|
96
96
|
expect(() => schema.parse("999001")).toThrow("Invalid Taiwan postal code")
|
|
97
97
|
})
|
|
98
98
|
|
|
99
99
|
it("should reject non-6-digit formats when format is '6'", () => {
|
|
100
|
-
const schema = postalCode({ format: "6" })
|
|
100
|
+
const schema = postalCode(true, { format: "6" })
|
|
101
101
|
expect(() => schema.parse("100")).toThrow("Only 6-digit postal codes are allowed")
|
|
102
102
|
expect(() => schema.parse("10001")).toThrow("Only 6-digit postal codes are allowed")
|
|
103
103
|
})
|
|
104
104
|
|
|
105
105
|
it("should validate 6-digit postal codes with all valid prefixes", () => {
|
|
106
|
-
const schema = postalCode({ format: "6" })
|
|
106
|
+
const schema = postalCode(true, { format: "6" })
|
|
107
107
|
expect(schema.parse("100999")).toBe("100999") // Taipei
|
|
108
108
|
expect(schema.parse("880999")).toBe("880999") // Penghu
|
|
109
109
|
expect(schema.parse("890999")).toBe("890999") // Kinmen
|
|
@@ -113,7 +113,7 @@ describe("postalCode() features", () => {
|
|
|
113
113
|
|
|
114
114
|
describe("combined format validation", () => {
|
|
115
115
|
it("should accept both 3 and 5 digit formats with '3+5'", () => {
|
|
116
|
-
const schema = postalCode({ format: "3+5" })
|
|
116
|
+
const schema = postalCode(true, { format: "3+5" })
|
|
117
117
|
expect(schema.parse("100")).toBe("100")
|
|
118
118
|
expect(schema.parse("10001")).toBe("10001")
|
|
119
119
|
expect(() => schema.parse("100001")).toThrow("Invalid Taiwan postal code")
|
|
@@ -127,14 +127,14 @@ describe("postalCode() features", () => {
|
|
|
127
127
|
})
|
|
128
128
|
|
|
129
129
|
it("should accept both 5 and 6 digit formats with '5+6'", () => {
|
|
130
|
-
const schema = postalCode({ format: "5+6" })
|
|
130
|
+
const schema = postalCode(true, { format: "5+6" })
|
|
131
131
|
expect(schema.parse("10001")).toBe("10001")
|
|
132
132
|
expect(schema.parse("100001")).toBe("100001")
|
|
133
133
|
expect(() => schema.parse("100")).toThrow("Invalid Taiwan postal code")
|
|
134
134
|
})
|
|
135
135
|
|
|
136
136
|
it("should accept all formats with 'all'", () => {
|
|
137
|
-
const schema = postalCode({ format: "all" })
|
|
137
|
+
const schema = postalCode(true, { format: "all" })
|
|
138
138
|
expect(schema.parse("100")).toBe("100")
|
|
139
139
|
expect(schema.parse("10001")).toBe("10001")
|
|
140
140
|
expect(schema.parse("100001")).toBe("100001")
|
|
@@ -143,7 +143,7 @@ describe("postalCode() features", () => {
|
|
|
143
143
|
|
|
144
144
|
describe("dash and space handling", () => {
|
|
145
145
|
it("should handle dashes in postal codes when allowDashes is true", () => {
|
|
146
|
-
const schema = postalCode({ format: "all", allowDashes: true })
|
|
146
|
+
const schema = postalCode(true, { format: "all", allowDashes: true })
|
|
147
147
|
expect(schema.parse("100")).toBe("100")
|
|
148
148
|
expect(schema.parse("100-01")).toBe("10001")
|
|
149
149
|
expect(schema.parse("100-001")).toBe("100001")
|
|
@@ -151,14 +151,14 @@ describe("postalCode() features", () => {
|
|
|
151
151
|
})
|
|
152
152
|
|
|
153
153
|
it("should reject dashes when allowDashes is false", () => {
|
|
154
|
-
const schema = postalCode({ format: "all", allowDashes: false })
|
|
154
|
+
const schema = postalCode(true, { format: "all", allowDashes: false })
|
|
155
155
|
expect(schema.parse("100")).toBe("100")
|
|
156
156
|
expect(() => schema.parse("100-01")).toThrow("Invalid Taiwan postal code")
|
|
157
157
|
expect(() => schema.parse("100-001")).toThrow("Invalid Taiwan postal code")
|
|
158
158
|
})
|
|
159
159
|
|
|
160
160
|
it("should normalize various dash and space formats", () => {
|
|
161
|
-
const schema = postalCode({ format: "6", allowDashes: true })
|
|
161
|
+
const schema = postalCode(true, { format: "6", allowDashes: true })
|
|
162
162
|
expect(schema.parse("100-001")).toBe("100001")
|
|
163
163
|
expect(schema.parse("100 001")).toBe("100001")
|
|
164
164
|
expect(schema.parse("100 001")).toBe("100001")
|
|
@@ -168,9 +168,9 @@ describe("postalCode() features", () => {
|
|
|
168
168
|
|
|
169
169
|
describe("prefix filtering", () => {
|
|
170
170
|
it("should only allow specified prefixes", () => {
|
|
171
|
-
const schema = postalCode({
|
|
171
|
+
const schema = postalCode(true, {
|
|
172
172
|
format: "all",
|
|
173
|
-
allowedPrefixes: ["100", "200", "300"]
|
|
173
|
+
allowedPrefixes: ["100", "200", "300"],
|
|
174
174
|
})
|
|
175
175
|
expect(schema.parse("100")).toBe("100")
|
|
176
176
|
expect(schema.parse("10001")).toBe("10001")
|
|
@@ -181,9 +181,9 @@ describe("postalCode() features", () => {
|
|
|
181
181
|
})
|
|
182
182
|
|
|
183
183
|
it("should block specified prefixes", () => {
|
|
184
|
-
const schema = postalCode({
|
|
184
|
+
const schema = postalCode(true, {
|
|
185
185
|
format: "all",
|
|
186
|
-
blockedPrefixes: ["999", "000"]
|
|
186
|
+
blockedPrefixes: ["999", "000"],
|
|
187
187
|
})
|
|
188
188
|
expect(schema.parse("100")).toBe("100")
|
|
189
189
|
expect(() => schema.parse("999")).toThrow("Invalid Taiwan postal code")
|
|
@@ -192,19 +192,19 @@ describe("postalCode() features", () => {
|
|
|
192
192
|
})
|
|
193
193
|
|
|
194
194
|
it("should prioritize allowedPrefixes over strict validation", () => {
|
|
195
|
-
const schema = postalCode({
|
|
195
|
+
const schema = postalCode(true, {
|
|
196
196
|
format: "3",
|
|
197
197
|
allowedPrefixes: ["999"], // Not in official list
|
|
198
|
-
strictValidation: true
|
|
198
|
+
strictValidation: true,
|
|
199
199
|
})
|
|
200
200
|
expect(schema.parse("999")).toBe("999")
|
|
201
201
|
})
|
|
202
202
|
|
|
203
203
|
it("should respect blockedPrefixes even with allowedPrefixes", () => {
|
|
204
|
-
const schema = postalCode({
|
|
204
|
+
const schema = postalCode(true, {
|
|
205
205
|
format: "3",
|
|
206
206
|
allowedPrefixes: ["100", "200", "999"],
|
|
207
|
-
blockedPrefixes: ["999"]
|
|
207
|
+
blockedPrefixes: ["999"],
|
|
208
208
|
})
|
|
209
209
|
expect(schema.parse("100")).toBe("100")
|
|
210
210
|
expect(schema.parse("200")).toBe("200")
|
|
@@ -214,20 +214,20 @@ describe("postalCode() features", () => {
|
|
|
214
214
|
|
|
215
215
|
describe("strict validation", () => {
|
|
216
216
|
it("should validate against official postal code list when strict", () => {
|
|
217
|
-
const schema = postalCode({ format: "3", strictValidation: true })
|
|
217
|
+
const schema = postalCode(true, { format: "3", strictValidation: true })
|
|
218
218
|
expect(schema.parse("100")).toBe("100") // Valid official code
|
|
219
219
|
expect(() => schema.parse("199")).toThrow("Invalid Taiwan postal code") // Not in official list
|
|
220
220
|
})
|
|
221
221
|
|
|
222
222
|
it("should allow broader range when not strict", () => {
|
|
223
|
-
const schema = postalCode({ format: "3", strictValidation: false })
|
|
223
|
+
const schema = postalCode(true, { format: "3", strictValidation: false })
|
|
224
224
|
expect(schema.parse("100")).toBe("100") // Valid official code
|
|
225
225
|
expect(schema.parse("199")).toBe("199") // Not in official list but in range 100-999
|
|
226
226
|
expect(() => schema.parse("099")).toThrow("Invalid Taiwan postal code") // Still below 100
|
|
227
227
|
})
|
|
228
228
|
|
|
229
229
|
it("should validate all Taiwan regions with strict validation", () => {
|
|
230
|
-
const schema = postalCode({ format: "3", strictValidation: true })
|
|
230
|
+
const schema = postalCode(true, { format: "3", strictValidation: true })
|
|
231
231
|
|
|
232
232
|
// Major cities
|
|
233
233
|
expect(schema.parse("100")).toBe("100") // Taipei City
|
|
@@ -254,28 +254,28 @@ describe("postalCode() features", () => {
|
|
|
254
254
|
|
|
255
255
|
describe("required and optional validation", () => {
|
|
256
256
|
it("should handle required validation", () => {
|
|
257
|
-
const schema = postalCode()
|
|
257
|
+
const schema = postalCode(true)
|
|
258
258
|
expect(() => schema.parse(null)).toThrow("Required")
|
|
259
259
|
expect(() => schema.parse(undefined)).toThrow("Required")
|
|
260
260
|
expect(() => schema.parse("")).toThrow("Required")
|
|
261
261
|
})
|
|
262
262
|
|
|
263
263
|
it("should allow null when not required", () => {
|
|
264
|
-
const schema = postalCode(
|
|
264
|
+
const schema = postalCode(false)
|
|
265
265
|
expect(schema.parse(null)).toBe(null)
|
|
266
266
|
expect(schema.parse(undefined)).toBe(null)
|
|
267
267
|
expect(schema.parse("")).toBe(null)
|
|
268
268
|
})
|
|
269
269
|
|
|
270
270
|
it("should use default value when provided", () => {
|
|
271
|
-
const schema = postalCode({ defaultValue: "100001" })
|
|
271
|
+
const schema = postalCode(true, { defaultValue: "100001" })
|
|
272
272
|
expect(schema.parse("")).toBe("100001")
|
|
273
273
|
expect(schema.parse(null)).toBe("100001")
|
|
274
274
|
expect(schema.parse(undefined)).toBe("100001")
|
|
275
275
|
})
|
|
276
276
|
|
|
277
277
|
it("should use default value for optional fields", () => {
|
|
278
|
-
const schema = postalCode(
|
|
278
|
+
const schema = postalCode(false, { defaultValue: "100001" })
|
|
279
279
|
expect(schema.parse("")).toBe("100001")
|
|
280
280
|
expect(schema.parse(null)).toBe("100001")
|
|
281
281
|
expect(schema.parse(undefined)).toBe("100001")
|
|
@@ -284,9 +284,9 @@ describe("postalCode() features", () => {
|
|
|
284
284
|
|
|
285
285
|
describe("transform functionality", () => {
|
|
286
286
|
it("should apply transform function", () => {
|
|
287
|
-
const schema = postalCode({
|
|
287
|
+
const schema = postalCode(true, {
|
|
288
288
|
format: "6",
|
|
289
|
-
transform: (val) => val.replace(/\D/g, "") // Remove non-digits
|
|
289
|
+
transform: (val) => val.replace(/\D/g, ""), // Remove non-digits
|
|
290
290
|
})
|
|
291
291
|
expect(schema.parse("100-001")).toBe("100001")
|
|
292
292
|
expect(schema.parse("100.001")).toBe("100001")
|
|
@@ -294,10 +294,10 @@ describe("postalCode() features", () => {
|
|
|
294
294
|
})
|
|
295
295
|
|
|
296
296
|
it("should apply transform after dash removal", () => {
|
|
297
|
-
const schema = postalCode({
|
|
297
|
+
const schema = postalCode(true, {
|
|
298
298
|
format: "3",
|
|
299
299
|
allowDashes: true,
|
|
300
|
-
transform: (val) => val.padEnd(3, "0") // Pad to 3 digits
|
|
300
|
+
transform: (val) => val.padEnd(3, "0"), // Pad to 3 digits
|
|
301
301
|
})
|
|
302
302
|
expect(schema.parse("10")).toBe("100")
|
|
303
303
|
expect(schema.parse("1")).toBe("100")
|
|
@@ -306,8 +306,8 @@ describe("postalCode() features", () => {
|
|
|
306
306
|
|
|
307
307
|
describe("legacy 5-digit warning", () => {
|
|
308
308
|
it("should emit warning for 5-digit codes when warn5Digit is true", () => {
|
|
309
|
-
const consoleSpy = vi.spyOn(console,
|
|
310
|
-
const schema = postalCode({ format: "all", warn5Digit: true })
|
|
309
|
+
const consoleSpy = vi.spyOn(console, "warn").mockImplementation(() => {})
|
|
310
|
+
const schema = postalCode(true, { format: "all", warn5Digit: true })
|
|
311
311
|
|
|
312
312
|
schema.parse("10001") // Should emit warning
|
|
313
313
|
expect(consoleSpy).toHaveBeenCalledWith("5-digit postal codes are legacy format, consider using 6-digit format")
|
|
@@ -319,8 +319,8 @@ describe("postalCode() features", () => {
|
|
|
319
319
|
})
|
|
320
320
|
|
|
321
321
|
it("should not emit warning when warn5Digit is false", () => {
|
|
322
|
-
const consoleSpy = vi.spyOn(console,
|
|
323
|
-
const schema = postalCode({ format: "all", warn5Digit: false })
|
|
322
|
+
const consoleSpy = vi.spyOn(console, "warn").mockImplementation(() => {})
|
|
323
|
+
const schema = postalCode(true, { format: "all", warn5Digit: false })
|
|
324
324
|
|
|
325
325
|
schema.parse("10001") // Should not emit warning
|
|
326
326
|
expect(consoleSpy).not.toHaveBeenCalled()
|
|
@@ -329,8 +329,8 @@ describe("postalCode() features", () => {
|
|
|
329
329
|
})
|
|
330
330
|
|
|
331
331
|
it("should not emit warning for 5-digit only format", () => {
|
|
332
|
-
const consoleSpy = vi.spyOn(console,
|
|
333
|
-
const schema = postalCode({ format: "5", warn5Digit: true })
|
|
332
|
+
const consoleSpy = vi.spyOn(console, "warn").mockImplementation(() => {})
|
|
333
|
+
const schema = postalCode(true, { format: "5", warn5Digit: true })
|
|
334
334
|
|
|
335
335
|
schema.parse("10001") // Should not emit warning for 5-digit only format
|
|
336
336
|
expect(consoleSpy).not.toHaveBeenCalled()
|
|
@@ -341,7 +341,7 @@ describe("postalCode() features", () => {
|
|
|
341
341
|
|
|
342
342
|
describe("custom i18n messages", () => {
|
|
343
343
|
it("should use custom messages when provided", () => {
|
|
344
|
-
const schema = postalCode({
|
|
344
|
+
const schema = postalCode(true, {
|
|
345
345
|
format: "3",
|
|
346
346
|
i18n: {
|
|
347
347
|
en: {
|
|
@@ -363,7 +363,7 @@ describe("postalCode() features", () => {
|
|
|
363
363
|
})
|
|
364
364
|
|
|
365
365
|
it("should fallback to default messages when custom not provided", () => {
|
|
366
|
-
const schema = postalCode({
|
|
366
|
+
const schema = postalCode(true, {
|
|
367
367
|
format: "6",
|
|
368
368
|
i18n: {
|
|
369
369
|
en: {
|
|
@@ -381,7 +381,7 @@ describe("postalCode() features", () => {
|
|
|
381
381
|
|
|
382
382
|
it("should use correct locale for custom messages", () => {
|
|
383
383
|
setLocale("en")
|
|
384
|
-
const schemaEn = postalCode({
|
|
384
|
+
const schemaEn = postalCode(true, {
|
|
385
385
|
format: "3",
|
|
386
386
|
i18n: {
|
|
387
387
|
en: {
|
|
@@ -395,7 +395,7 @@ describe("postalCode() features", () => {
|
|
|
395
395
|
expect(() => schemaEn.parse("999")).toThrow("English invalid message")
|
|
396
396
|
|
|
397
397
|
setLocale("zh-TW")
|
|
398
|
-
const schemaZh = postalCode({
|
|
398
|
+
const schemaZh = postalCode(true, {
|
|
399
399
|
format: "3",
|
|
400
400
|
i18n: {
|
|
401
401
|
en: {
|
|
@@ -412,12 +412,12 @@ describe("postalCode() features", () => {
|
|
|
412
412
|
|
|
413
413
|
describe("complex scenarios", () => {
|
|
414
414
|
it("should work with multiple validations", () => {
|
|
415
|
-
const schema = postalCode({
|
|
415
|
+
const schema = postalCode(true, {
|
|
416
416
|
format: "6",
|
|
417
417
|
allowDashes: true,
|
|
418
418
|
strictValidation: true,
|
|
419
419
|
allowedPrefixes: ["100", "200", "300"],
|
|
420
|
-
transform: (val) => val.replace(/\D/g, "").padEnd(6, "0")
|
|
420
|
+
transform: (val) => val.replace(/\D/g, "").padEnd(6, "0"),
|
|
421
421
|
})
|
|
422
422
|
|
|
423
423
|
expect(schema.parse("100-001")).toBe("100001")
|
|
@@ -429,10 +429,10 @@ describe("postalCode() features", () => {
|
|
|
429
429
|
})
|
|
430
430
|
|
|
431
431
|
it("should handle edge cases with transforms and dashes", () => {
|
|
432
|
-
const schema = postalCode({
|
|
432
|
+
const schema = postalCode(true, {
|
|
433
433
|
format: "all",
|
|
434
434
|
allowDashes: true,
|
|
435
|
-
transform: (val) => val.toUpperCase().replace(/[^0-9-]/g, "")
|
|
435
|
+
transform: (val) => val.toUpperCase().replace(/[^0-9-]/g, ""),
|
|
436
436
|
})
|
|
437
437
|
|
|
438
438
|
expect(schema.parse("100ABC-001DEF")).toBe("100001")
|
|
@@ -441,57 +441,103 @@ describe("postalCode() features", () => {
|
|
|
441
441
|
})
|
|
442
442
|
|
|
443
443
|
it("should validate comprehensive Taiwan postal code coverage", () => {
|
|
444
|
-
const schema = postalCode({ format: "all", strictValidation: true })
|
|
444
|
+
const schema = postalCode(true, { format: "all", strictValidation: true })
|
|
445
445
|
|
|
446
446
|
// Test various regions
|
|
447
447
|
const validCodes = [
|
|
448
448
|
// Taipei area
|
|
449
|
-
"100",
|
|
450
|
-
"
|
|
449
|
+
"100",
|
|
450
|
+
"103",
|
|
451
|
+
"104",
|
|
452
|
+
"105",
|
|
453
|
+
"106",
|
|
454
|
+
"108",
|
|
455
|
+
"110",
|
|
456
|
+
"111",
|
|
457
|
+
"112",
|
|
458
|
+
"114",
|
|
459
|
+
"115",
|
|
460
|
+
"116",
|
|
461
|
+
"10001",
|
|
462
|
+
"10301",
|
|
463
|
+
"100001",
|
|
464
|
+
"103001",
|
|
451
465
|
|
|
452
466
|
// New Taipei area
|
|
453
|
-
"220",
|
|
454
|
-
"
|
|
467
|
+
"220",
|
|
468
|
+
"221",
|
|
469
|
+
"222",
|
|
470
|
+
"223",
|
|
471
|
+
"224",
|
|
472
|
+
"226",
|
|
473
|
+
"227",
|
|
474
|
+
"228",
|
|
475
|
+
"22001",
|
|
476
|
+
"221001",
|
|
455
477
|
|
|
456
478
|
// Taoyuan area
|
|
457
|
-
"320",
|
|
458
|
-
"
|
|
479
|
+
"320",
|
|
480
|
+
"324",
|
|
481
|
+
"325",
|
|
482
|
+
"326",
|
|
483
|
+
"327",
|
|
484
|
+
"328",
|
|
485
|
+
"330",
|
|
486
|
+
"333",
|
|
487
|
+
"32001",
|
|
488
|
+
"320001",
|
|
459
489
|
|
|
460
490
|
// Offshore islands
|
|
461
|
-
"880",
|
|
462
|
-
"
|
|
463
|
-
"
|
|
464
|
-
"
|
|
491
|
+
"880",
|
|
492
|
+
"881",
|
|
493
|
+
"882",
|
|
494
|
+
"883",
|
|
495
|
+
"884",
|
|
496
|
+
"885", // Penghu
|
|
497
|
+
"890",
|
|
498
|
+
"891",
|
|
499
|
+
"892",
|
|
500
|
+
"893",
|
|
501
|
+
"894",
|
|
502
|
+
"895",
|
|
503
|
+
"896", // Kinmen
|
|
504
|
+
"209",
|
|
505
|
+
"210",
|
|
506
|
+
"211",
|
|
507
|
+
"212", // Lienchiang (Matsu)
|
|
508
|
+
"88001",
|
|
509
|
+
"890001",
|
|
510
|
+
"209001",
|
|
465
511
|
]
|
|
466
512
|
|
|
467
|
-
validCodes.forEach(code => {
|
|
513
|
+
validCodes.forEach((code) => {
|
|
468
514
|
expect(schema.parse(code)).toBe(code)
|
|
469
515
|
})
|
|
470
516
|
})
|
|
471
517
|
|
|
472
518
|
it("should work with real-world postal codes", () => {
|
|
473
|
-
const schema = postalCode({ format: "all", allowDashes: true })
|
|
519
|
+
const schema = postalCode(true, { format: "all", allowDashes: true })
|
|
474
520
|
|
|
475
521
|
// Real Taiwan postal codes
|
|
476
|
-
expect(schema.parse("100")).toBe("100")
|
|
477
|
-
expect(schema.parse("110")).toBe("110")
|
|
478
|
-
expect(schema.parse("220")).toBe("220")
|
|
479
|
-
expect(schema.parse("300")).toBe("300")
|
|
480
|
-
expect(schema.parse("400")).toBe("400")
|
|
481
|
-
expect(schema.parse("700")).toBe("700")
|
|
482
|
-
expect(schema.parse("800")).toBe("800")
|
|
483
|
-
expect(schema.parse("880")).toBe("880")
|
|
484
|
-
expect(schema.parse("890")).toBe("890")
|
|
522
|
+
expect(schema.parse("100")).toBe("100") // Taipei Main Post Office
|
|
523
|
+
expect(schema.parse("110")).toBe("110") // Xinyi District, Taipei
|
|
524
|
+
expect(schema.parse("220")).toBe("220") // Banqiao District, New Taipei
|
|
525
|
+
expect(schema.parse("300")).toBe("300") // East District, Hsinchu City
|
|
526
|
+
expect(schema.parse("400")).toBe("400") // Central District, Taichung
|
|
527
|
+
expect(schema.parse("700")).toBe("700") // Central District, Tainan
|
|
528
|
+
expect(schema.parse("800")).toBe("800") // Xinxing District, Kaohsiung
|
|
529
|
+
expect(schema.parse("880")).toBe("880") // Magong City, Penghu
|
|
530
|
+
expect(schema.parse("890")).toBe("890") // Jincheng Township, Kinmen
|
|
485
531
|
|
|
486
532
|
// With dashes
|
|
487
|
-
expect(schema.parse("100-01")).toBe("10001")
|
|
533
|
+
expect(schema.parse("100-01")).toBe("10001") // 5-digit format
|
|
488
534
|
expect(schema.parse("100-001")).toBe("100001") // 6-digit format
|
|
489
535
|
})
|
|
490
536
|
})
|
|
491
537
|
|
|
492
538
|
describe("strict suffix validation with regional ranges", () => {
|
|
493
539
|
it("should validate 5-digit suffix ranges for major cities", () => {
|
|
494
|
-
const schema = postalCode({ format: "5", strictSuffixValidation: true })
|
|
540
|
+
const schema = postalCode(true, { format: "5", strictSuffixValidation: true })
|
|
495
541
|
// Taipei areas (full range 01-99)
|
|
496
542
|
expect(schema.parse("10001")).toBe("10001") // Valid suffix 01
|
|
497
543
|
expect(schema.parse("10099")).toBe("10099") // Valid suffix 99
|
|
@@ -500,7 +546,7 @@ describe("postalCode() features", () => {
|
|
|
500
546
|
})
|
|
501
547
|
|
|
502
548
|
it("should validate 6-digit suffix ranges for major cities", () => {
|
|
503
|
-
const schema = postalCode({ format: "6", strictSuffixValidation: true })
|
|
549
|
+
const schema = postalCode(true, { format: "6", strictSuffixValidation: true })
|
|
504
550
|
// Taipei areas (full range 001-999)
|
|
505
551
|
expect(schema.parse("100001")).toBe("100001") // Valid suffix 001
|
|
506
552
|
expect(schema.parse("100999")).toBe("100999") // Valid suffix 999
|
|
@@ -509,7 +555,7 @@ describe("postalCode() features", () => {
|
|
|
509
555
|
})
|
|
510
556
|
|
|
511
557
|
it("should validate restricted ranges for smaller areas", () => {
|
|
512
|
-
const schema = postalCode({ format: "all", strictSuffixValidation: true })
|
|
558
|
+
const schema = postalCode(true, { format: "all", strictSuffixValidation: true })
|
|
513
559
|
|
|
514
560
|
// Penghu (limited range)
|
|
515
561
|
expect(schema.parse("88001")).toBe("88001") // Valid for Penghu
|
|
@@ -531,7 +577,7 @@ describe("postalCode() features", () => {
|
|
|
531
577
|
})
|
|
532
578
|
|
|
533
579
|
it("should allow any suffix when strictSuffixValidation is disabled", () => {
|
|
534
|
-
const schema = postalCode({ format: "all", strictSuffixValidation: false })
|
|
580
|
+
const schema = postalCode(true, { format: "all", strictSuffixValidation: false })
|
|
535
581
|
expect(schema.parse("10000")).toBe("10000") // Suffix 00 allowed
|
|
536
582
|
expect(schema.parse("100000")).toBe("100000") // Suffix 000 allowed
|
|
537
583
|
expect(schema.parse("10099")).toBe("10099") // Normal suffix
|
|
@@ -540,24 +586,24 @@ describe("postalCode() features", () => {
|
|
|
540
586
|
|
|
541
587
|
describe("5-digit deprecation", () => {
|
|
542
588
|
it("should reject 5-digit codes when deprecate5Digit is enabled", () => {
|
|
543
|
-
const schema = postalCode({ format: "all", deprecate5Digit: true })
|
|
589
|
+
const schema = postalCode(true, { format: "all", deprecate5Digit: true })
|
|
544
590
|
expect(schema.parse("100")).toBe("100") // 3-digit still allowed
|
|
545
591
|
expect(schema.parse("100001")).toBe("100001") // 6-digit still allowed
|
|
546
592
|
expect(() => schema.parse("10001")).toThrow("5-digit postal codes are deprecated") // 5-digit rejected
|
|
547
593
|
})
|
|
548
594
|
|
|
549
595
|
it("should allow 5-digit codes when deprecate5Digit is disabled", () => {
|
|
550
|
-
const schema = postalCode({ format: "all", deprecate5Digit: false })
|
|
596
|
+
const schema = postalCode(true, { format: "all", deprecate5Digit: false })
|
|
551
597
|
expect(schema.parse("10001")).toBe("10001") // 5-digit allowed
|
|
552
598
|
})
|
|
553
599
|
})
|
|
554
600
|
|
|
555
601
|
describe("combined strict validation scenarios", () => {
|
|
556
602
|
it("should work with both strictSuffixValidation and deprecate5Digit", () => {
|
|
557
|
-
const schema = postalCode({
|
|
603
|
+
const schema = postalCode(true, {
|
|
558
604
|
format: "6",
|
|
559
605
|
strictSuffixValidation: true,
|
|
560
|
-
deprecate5Digit: true
|
|
606
|
+
deprecate5Digit: true,
|
|
561
607
|
})
|
|
562
608
|
expect(schema.parse("100001")).toBe("100001") // Valid 6-digit
|
|
563
609
|
expect(() => schema.parse("100000")).toThrow("Invalid postal code suffix") // Invalid suffix
|
|
@@ -565,10 +611,10 @@ describe("postalCode() features", () => {
|
|
|
565
611
|
})
|
|
566
612
|
|
|
567
613
|
it("should provide specific error for real-world validation scenarios", () => {
|
|
568
|
-
const realWorldSchema = postalCode({
|
|
614
|
+
const realWorldSchema = postalCode(true, {
|
|
569
615
|
format: "6",
|
|
570
616
|
strictSuffixValidation: true,
|
|
571
|
-
strictValidation: true
|
|
617
|
+
strictValidation: true,
|
|
572
618
|
})
|
|
573
619
|
|
|
574
620
|
// Valid real postal codes from major cities
|
|
@@ -598,11 +644,11 @@ describe("postalCode() features", () => {
|
|
|
598
644
|
|
|
599
645
|
describe("regional-specific validation", () => {
|
|
600
646
|
it("should validate major cities with full ranges", () => {
|
|
601
|
-
const schema = postalCode({ format: "all", strictSuffixValidation: true })
|
|
647
|
+
const schema = postalCode(true, { format: "all", strictSuffixValidation: true })
|
|
602
648
|
|
|
603
649
|
// Taipei City areas - should have full 01-99 and 001-999 ranges
|
|
604
650
|
const taipeiAreas = ["100", "103", "104", "105", "106", "108", "110", "111", "112", "114", "115", "116"]
|
|
605
|
-
taipeiAreas.forEach(area => {
|
|
651
|
+
taipeiAreas.forEach((area) => {
|
|
606
652
|
expect(schema.parse(`${area}01`)).toBe(`${area}01`) // Min 5-digit
|
|
607
653
|
expect(schema.parse(`${area}99`)).toBe(`${area}99`) // Max 5-digit
|
|
608
654
|
expect(schema.parse(`${area}001`)).toBe(`${area}001`) // Min 6-digit
|
|
@@ -617,7 +663,7 @@ describe("postalCode() features", () => {
|
|
|
617
663
|
})
|
|
618
664
|
|
|
619
665
|
it("should enforce restricted ranges for offshore islands", () => {
|
|
620
|
-
const schema = postalCode({ format: "all", strictSuffixValidation: true })
|
|
666
|
+
const schema = postalCode(true, { format: "all", strictSuffixValidation: true })
|
|
621
667
|
|
|
622
668
|
// Penghu County (880) - limited to 01-50 and 001-500
|
|
623
669
|
expect(schema.parse("88001")).toBe("88001")
|
|
@@ -645,7 +691,7 @@ describe("postalCode() features", () => {
|
|
|
645
691
|
})
|
|
646
692
|
|
|
647
693
|
it("should use default ranges for areas not in specific mapping", () => {
|
|
648
|
-
const schema = postalCode({ format: "all", strictSuffixValidation: true })
|
|
694
|
+
const schema = postalCode(true, { format: "all", strictSuffixValidation: true })
|
|
649
695
|
|
|
650
696
|
// Areas not specifically mapped should use default ranges (01-99, 001-999)
|
|
651
697
|
expect(schema.parse("26001")).toBe("26001") // Yilan - uses default
|
|
@@ -659,7 +705,7 @@ describe("postalCode() features", () => {
|
|
|
659
705
|
|
|
660
706
|
describe("edge cases", () => {
|
|
661
707
|
it("should handle empty and whitespace inputs", () => {
|
|
662
|
-
const schema = postalCode(
|
|
708
|
+
const schema = postalCode(false)
|
|
663
709
|
expect(schema.parse("")).toBe(null)
|
|
664
710
|
expect(schema.parse(" ")).toBe(null)
|
|
665
711
|
expect(schema.parse("\t")).toBe(null)
|
|
@@ -667,22 +713,22 @@ describe("postalCode() features", () => {
|
|
|
667
713
|
})
|
|
668
714
|
|
|
669
715
|
it("should handle numeric inputs", () => {
|
|
670
|
-
const schema = postalCode({ format: "3" })
|
|
716
|
+
const schema = postalCode(true, { format: "3" })
|
|
671
717
|
expect(schema.parse(100)).toBe("100")
|
|
672
718
|
expect(schema.parse(200)).toBe("200")
|
|
673
719
|
})
|
|
674
720
|
|
|
675
721
|
it("should reject codes with letters when not using transform", () => {
|
|
676
|
-
const schema = postalCode({ format: "3", allowDashes: false })
|
|
722
|
+
const schema = postalCode(true, { format: "3", allowDashes: false })
|
|
677
723
|
expect(() => schema.parse("10A")).toThrow("Invalid Taiwan postal code")
|
|
678
724
|
expect(() => schema.parse("ABC")).toThrow("Invalid Taiwan postal code")
|
|
679
725
|
})
|
|
680
726
|
|
|
681
727
|
it("should handle very specific area restrictions", () => {
|
|
682
728
|
// Only allow Taipei city areas
|
|
683
|
-
const taipeiOnlySchema = postalCode({
|
|
729
|
+
const taipeiOnlySchema = postalCode(true, {
|
|
684
730
|
format: "all",
|
|
685
|
-
allowedPrefixes: ["100", "103", "104", "105", "106", "108", "110", "111", "112", "114", "115", "116"]
|
|
731
|
+
allowedPrefixes: ["100", "103", "104", "105", "106", "108", "110", "111", "112", "114", "115", "116"],
|
|
686
732
|
})
|
|
687
733
|
|
|
688
734
|
expect(taipeiOnlySchema.parse("100")).toBe("100")
|
|
@@ -691,15 +737,15 @@ describe("postalCode() features", () => {
|
|
|
691
737
|
})
|
|
692
738
|
|
|
693
739
|
it("should handle format combinations correctly", () => {
|
|
694
|
-
const schema35 = postalCode({ format: "3+5" })
|
|
740
|
+
const schema35 = postalCode(true, { format: "3+5" })
|
|
695
741
|
expect(schema35.parse("100")).toBe("100")
|
|
696
742
|
expect(schema35.parse("10001")).toBe("10001")
|
|
697
743
|
expect(() => schema35.parse("100001")).toThrow("Invalid Taiwan postal code")
|
|
698
744
|
|
|
699
|
-
const schema56 = postalCode({ format: "5+6" })
|
|
745
|
+
const schema56 = postalCode(true, { format: "5+6" })
|
|
700
746
|
expect(schema56.parse("10001")).toBe("10001")
|
|
701
747
|
expect(schema56.parse("100001")).toBe("100001")
|
|
702
748
|
expect(() => schema56.parse("100")).toThrow("Invalid Taiwan postal code")
|
|
703
749
|
})
|
|
704
750
|
})
|
|
705
|
-
})
|
|
751
|
+
})
|