@hy_ong/zod-kit 0.0.5 β 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 +6 -1
- package/README.md +465 -97
- package/dist/index.cjs +1628 -121
- package/dist/index.d.cts +2699 -2
- package/dist/index.d.ts +2699 -2
- package/dist/index.js +1610 -120
- package/package.json +1 -1
- package/src/i18n/locales/en.json +62 -0
- package/src/i18n/locales/zh-TW.json +62 -0
- package/src/index.ts +4 -0
- package/src/validators/common/boolean.ts +94 -0
- package/src/validators/common/date.ts +128 -0
- package/src/validators/common/datetime.ts +673 -0
- package/src/validators/common/email.ts +113 -0
- package/src/validators/common/file.ts +384 -0
- package/src/validators/common/id.ts +224 -12
- package/src/validators/common/number.ts +125 -0
- package/src/validators/common/password.ts +174 -2
- package/src/validators/common/text.ts +120 -0
- package/src/validators/common/time.ts +600 -0
- package/src/validators/common/url.ts +140 -0
- package/src/validators/taiwan/business-id.ts +124 -2
- package/src/validators/taiwan/fax.ts +147 -2
- package/src/validators/taiwan/mobile.ts +134 -2
- package/src/validators/taiwan/national-id.ts +227 -10
- package/src/validators/taiwan/postal-code.ts +1049 -0
- package/src/validators/taiwan/tel.ts +150 -2
- package/tests/common/datetime.test.ts +693 -0
- package/tests/common/file.test.ts +479 -0
- package/tests/common/time.test.ts +528 -0
- package/tests/taiwan/postal-code.test.ts +705 -0
|
@@ -15,7 +15,12 @@
|
|
|
15
15
|
"Bash(npx tsc:*)",
|
|
16
16
|
"WebFetch(domain:www.motc.gov.tw)",
|
|
17
17
|
"WebFetch(domain:zh.wikipedia.org)",
|
|
18
|
-
"Bash(npx ts-node:*)"
|
|
18
|
+
"Bash(npx ts-node:*)",
|
|
19
|
+
"WebFetch(domain:www.post.gov.tw)",
|
|
20
|
+
"WebFetch(domain:foundi.tw)",
|
|
21
|
+
"WebFetch(domain:data.gov.tw)",
|
|
22
|
+
"WebFetch(domain:gist.github.com)",
|
|
23
|
+
"WebFetch(domain:zip5.5432.tw)"
|
|
19
24
|
],
|
|
20
25
|
"deny": [],
|
|
21
26
|
"ask": []
|
package/README.md
CHANGED
|
@@ -1,169 +1,495 @@
|
|
|
1
1
|
# Zod Kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://badge.fury.io/js/%40hy_ong%2Fzod-kit)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
A comprehensive TypeScript library that provides pre-built validation schemas on top of [Zod](https://github.com/colinhacks/zod) with full internationalization support. Streamline your form validation with battle-tested schemas for common data types and Taiwan-specific formats.
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
- π Internationalization support (English and Traditional Chinese)
|
|
9
|
-
- π TypeScript-first with full type safety
|
|
10
|
-
- β‘ Built on top of Zod for robust validation
|
|
11
|
-
- π― Configurable validation options
|
|
9
|
+
## β¨ Features
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
- π **Pre-built schemas** - Common validation patterns ready to use
|
|
12
|
+
- π **i18n support** - English and Traditional Chinese localization
|
|
13
|
+
- π **TypeScript-first** - Full type safety and IntelliSense support
|
|
14
|
+
- β‘ **Zero dependencies** - Built on top of Zod (peer dependency)
|
|
15
|
+
- π― **Highly configurable** - Flexible options for every use case
|
|
16
|
+
- πΉπΌ **Taiwan-specific** - National ID, business ID, phone numbers, postal codes, etc.
|
|
17
|
+
- β° **Date/Time support** - Comprehensive datetime, time, and date validation
|
|
18
|
+
- π **File validation** - MIME type filtering, size constraints, and file type checking
|
|
19
|
+
- π§ͺ **Battle-tested** - Comprehensive test suite with 500+ tests
|
|
20
|
+
|
|
21
|
+
## π¦ Installation
|
|
14
22
|
|
|
15
23
|
```bash
|
|
16
|
-
npm install zod-kit
|
|
24
|
+
npm install @hy_ong/zod-kit zod
|
|
17
25
|
```
|
|
18
26
|
|
|
19
|
-
|
|
27
|
+
```bash
|
|
28
|
+
yarn add @hy_ong/zod-kit zod
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pnpm add @hy_ong/zod-kit zod
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
> **Note**: Zod is a peer dependency and must be installed separately.
|
|
36
|
+
|
|
37
|
+
## π Quick Start
|
|
20
38
|
|
|
21
39
|
```typescript
|
|
22
|
-
import { email, password, text,
|
|
40
|
+
import { email, password, text, mobile, datetime, time, postalCode } from '@hy_ong/zod-kit'
|
|
23
41
|
|
|
24
|
-
//
|
|
25
|
-
const emailSchema = email(
|
|
26
|
-
emailSchema.parse('user@example.com') // β
|
|
42
|
+
// Simple email validation
|
|
43
|
+
const emailSchema = email()
|
|
44
|
+
emailSchema.parse('user@example.com') // β
"user@example.com"
|
|
27
45
|
|
|
28
|
-
// Password
|
|
46
|
+
// Password with complexity requirements
|
|
29
47
|
const passwordSchema = password({
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
digits: true,
|
|
35
|
-
special: true
|
|
48
|
+
minLength: 8,
|
|
49
|
+
requireUppercase: true,
|
|
50
|
+
requireDigits: true,
|
|
51
|
+
requireSpecialChars: true
|
|
36
52
|
})
|
|
37
53
|
|
|
38
|
-
//
|
|
54
|
+
// Taiwan mobile phone validation
|
|
55
|
+
const phoneSchema = mobile()
|
|
56
|
+
phoneSchema.parse('0912345678') // β
"0912345678"
|
|
57
|
+
|
|
58
|
+
// DateTime validation
|
|
59
|
+
const datetimeSchema = datetime()
|
|
60
|
+
datetimeSchema.parse('2024-03-15 14:30') // β
"2024-03-15 14:30"
|
|
61
|
+
|
|
62
|
+
// Time validation
|
|
63
|
+
const timeSchema = time()
|
|
64
|
+
timeSchema.parse('14:30') // β
"14:30"
|
|
65
|
+
|
|
66
|
+
// Taiwan postal code validation
|
|
67
|
+
const postalSchema = postalCode()
|
|
68
|
+
postalSchema.parse('100001') // β
"100001"
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## π API Reference
|
|
72
|
+
|
|
73
|
+
### Common Validators
|
|
74
|
+
|
|
75
|
+
#### `email(options?)`
|
|
76
|
+
|
|
77
|
+
Validates email addresses with comprehensive format checking.
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { email } from '@hy_ong/zod-kit'
|
|
81
|
+
|
|
82
|
+
// Basic usage
|
|
83
|
+
const basicEmail = email()
|
|
84
|
+
|
|
85
|
+
// With options
|
|
86
|
+
const advancedEmail = email({
|
|
87
|
+
required: true, // Default: true
|
|
88
|
+
allowedDomains: ['gmail.com', 'company.com'],
|
|
89
|
+
minLength: 5,
|
|
90
|
+
maxLength: 100,
|
|
91
|
+
transform: (val) => val.toLowerCase(),
|
|
92
|
+
i18n: {
|
|
93
|
+
en: { invalid: 'Please enter a valid email' }
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### `password(options?)`
|
|
99
|
+
|
|
100
|
+
Validates passwords with customizable complexity requirements.
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import { password } from '@hy_ong/zod-kit'
|
|
104
|
+
|
|
105
|
+
const passwordSchema = password({
|
|
106
|
+
minLength: 8, // Minimum length
|
|
107
|
+
maxLength: 128, // Maximum length
|
|
108
|
+
requireUppercase: true, // Require A-Z
|
|
109
|
+
requireLowercase: true, // Require a-z
|
|
110
|
+
requireDigits: true, // Require 0-9
|
|
111
|
+
requireSpecialChars: true,// Require !@#$%^&*
|
|
112
|
+
customPatterns: [
|
|
113
|
+
{ pattern: /[A-Z]/, message: 'Need uppercase' }
|
|
114
|
+
]
|
|
115
|
+
})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### `text(options?)`
|
|
119
|
+
|
|
120
|
+
General text validation with length and pattern constraints.
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import { text } from '@hy_ong/zod-kit'
|
|
124
|
+
|
|
39
125
|
const nameSchema = text({
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
126
|
+
minLength: 2,
|
|
127
|
+
maxLength: 50,
|
|
128
|
+
pattern: /^[a-zA-Z\s]+$/,
|
|
129
|
+
transform: (val) => val.trim()
|
|
130
|
+
})
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
#### `number(options?)`
|
|
134
|
+
|
|
135
|
+
Validates numeric values with range and type constraints.
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { number } from '@hy_ong/zod-kit'
|
|
139
|
+
|
|
140
|
+
const ageSchema = number({
|
|
141
|
+
min: 0,
|
|
142
|
+
max: 150,
|
|
143
|
+
integer: true,
|
|
144
|
+
positive: true
|
|
145
|
+
})
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### `url(options?)`
|
|
149
|
+
|
|
150
|
+
URL validation with protocol and domain restrictions.
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { url } from '@hy_ong/zod-kit'
|
|
154
|
+
|
|
155
|
+
const urlSchema = url({
|
|
156
|
+
protocols: ['https'], // Only HTTPS allowed
|
|
157
|
+
allowedDomains: ['safe.com'], // Domain whitelist
|
|
158
|
+
requireTLD: true // Require top-level domain
|
|
159
|
+
})
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### `boolean(options?)`
|
|
163
|
+
|
|
164
|
+
Boolean validation with flexible input handling.
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import { boolean } from '@hy_ong/zod-kit'
|
|
168
|
+
|
|
169
|
+
const consentSchema = boolean({
|
|
170
|
+
required: true,
|
|
171
|
+
trueValues: ['yes', '1', 'true'], // Custom truthy values
|
|
172
|
+
falseValues: ['no', '0', 'false'] // Custom falsy values
|
|
173
|
+
})
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
#### `datetime(options?)`
|
|
177
|
+
|
|
178
|
+
Validates datetime with comprehensive format support and timezone handling.
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
import { datetime } from '@hy_ong/zod-kit'
|
|
182
|
+
|
|
183
|
+
// Basic datetime validation
|
|
184
|
+
const basicSchema = datetime()
|
|
185
|
+
basicSchema.parse('2024-03-15 14:30') // β Valid
|
|
186
|
+
|
|
187
|
+
// Business hours validation
|
|
188
|
+
const businessHours = datetime({
|
|
189
|
+
format: 'YYYY-MM-DD HH:mm',
|
|
190
|
+
minHour: 9,
|
|
191
|
+
maxHour: 17,
|
|
192
|
+
weekdaysOnly: true
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
// Timezone-aware validation
|
|
196
|
+
const timezoneSchema = datetime({
|
|
197
|
+
timezone: 'Asia/Taipei',
|
|
198
|
+
mustBeFuture: true
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
// Multiple format support
|
|
202
|
+
const flexibleSchema = datetime({
|
|
203
|
+
format: 'DD/MM/YYYY HH:mm'
|
|
204
|
+
})
|
|
205
|
+
flexibleSchema.parse('15/03/2024 14:30') // β Valid
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### `time(options?)`
|
|
209
|
+
|
|
210
|
+
Time validation with multiple formats and constraints.
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
import { time } from '@hy_ong/zod-kit'
|
|
214
|
+
|
|
215
|
+
// Basic time validation (24-hour format)
|
|
216
|
+
const basicSchema = time()
|
|
217
|
+
basicSchema.parse('14:30') // β Valid
|
|
218
|
+
|
|
219
|
+
// 12-hour format with AM/PM
|
|
220
|
+
const ampmSchema = time({ format: 'hh:mm A' })
|
|
221
|
+
ampmSchema.parse('02:30 PM') // β Valid
|
|
222
|
+
|
|
223
|
+
// Business hours validation
|
|
224
|
+
const businessHours = time({
|
|
225
|
+
format: 'HH:mm',
|
|
226
|
+
minHour: 9,
|
|
227
|
+
maxHour: 17,
|
|
228
|
+
minuteStep: 15 // Only :00, :15, :30, :45
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
// Time range validation
|
|
232
|
+
const timeRangeSchema = time({
|
|
233
|
+
min: '09:00',
|
|
234
|
+
max: '17:00'
|
|
43
235
|
})
|
|
44
236
|
```
|
|
45
237
|
|
|
46
|
-
|
|
238
|
+
#### `date(options?)`
|
|
47
239
|
|
|
48
|
-
|
|
240
|
+
Date validation with range and format constraints.
|
|
49
241
|
|
|
50
242
|
```typescript
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
243
|
+
import { date } from '@hy_ong/zod-kit'
|
|
244
|
+
|
|
245
|
+
const birthdateSchema = date({
|
|
246
|
+
format: 'YYYY-MM-DD',
|
|
247
|
+
minDate: '1900-01-01',
|
|
248
|
+
maxDate: new Date(),
|
|
249
|
+
timezone: 'Asia/Taipei'
|
|
58
250
|
})
|
|
59
251
|
```
|
|
60
252
|
|
|
61
|
-
|
|
253
|
+
#### `file(options?)`
|
|
254
|
+
|
|
255
|
+
File validation with MIME type filtering and size constraints.
|
|
62
256
|
|
|
63
257
|
```typescript
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
258
|
+
import { file } from '@hy_ong/zod-kit'
|
|
259
|
+
|
|
260
|
+
// Basic file validation
|
|
261
|
+
const basicSchema = file()
|
|
262
|
+
basicSchema.parse(new File(['content'], 'test.txt'))
|
|
263
|
+
|
|
264
|
+
// Size restrictions
|
|
265
|
+
const sizeSchema = file({
|
|
266
|
+
maxSize: 1024 * 1024, // 1MB
|
|
267
|
+
minSize: 1024 // 1KB
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
// Extension restrictions
|
|
271
|
+
const imageSchema = file({
|
|
272
|
+
extension: ['.jpg', '.png', '.gif'],
|
|
273
|
+
maxSize: 5 * 1024 * 1024 // 5MB
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
// MIME type restrictions
|
|
277
|
+
const documentSchema = file({
|
|
278
|
+
type: ['application/pdf', 'application/msword'],
|
|
279
|
+
maxSize: 10 * 1024 * 1024 // 10MB
|
|
73
280
|
})
|
|
281
|
+
|
|
282
|
+
// Image files only
|
|
283
|
+
const imageOnlySchema = file({ imageOnly: true })
|
|
74
284
|
```
|
|
75
285
|
|
|
76
|
-
|
|
286
|
+
#### `id(options?)`
|
|
287
|
+
|
|
288
|
+
Flexible ID validation supporting multiple formats.
|
|
77
289
|
|
|
78
290
|
```typescript
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
regex? : RegExp // Custom regex pattern
|
|
291
|
+
import { id } from '@hy_ong/zod-kit'
|
|
292
|
+
|
|
293
|
+
const userIdSchema = id({
|
|
294
|
+
type: 'uuid', // 'uuid', 'nanoid', 'objectId', 'auto', etc.
|
|
295
|
+
allowedTypes: ['uuid', 'nanoid'], // Multiple allowed types
|
|
296
|
+
customRegex: /^USR_[A-Z0-9]+$/ // Custom pattern
|
|
86
297
|
})
|
|
87
298
|
```
|
|
88
299
|
|
|
89
|
-
###
|
|
300
|
+
### Taiwan-Specific Validators
|
|
301
|
+
|
|
302
|
+
#### `nationalId(options?)`
|
|
303
|
+
|
|
304
|
+
Validates Taiwan National ID (θΊ«δ»½θεθ).
|
|
90
305
|
|
|
91
306
|
```typescript
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
negative? : boolean, // Must be negative
|
|
99
|
-
finite? : boolean // Must be finite
|
|
307
|
+
import { nationalId } from '@hy_ong/zod-kit'
|
|
308
|
+
|
|
309
|
+
const idSchema = nationalId({
|
|
310
|
+
required: true,
|
|
311
|
+
normalize: true, // Convert to uppercase
|
|
312
|
+
whitelist: ['A123456789'] // Allow specific IDs
|
|
100
313
|
})
|
|
314
|
+
|
|
315
|
+
idSchema.parse('A123456789') // β
Valid Taiwan National ID
|
|
101
316
|
```
|
|
102
317
|
|
|
103
|
-
|
|
318
|
+
#### `businessId(options?)`
|
|
319
|
+
|
|
320
|
+
Validates Taiwan Business ID (η΅±δΈη·¨θ).
|
|
104
321
|
|
|
105
322
|
```typescript
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
323
|
+
import { businessId } from '@hy_ong/zod-kit'
|
|
324
|
+
|
|
325
|
+
const bizSchema = businessId()
|
|
326
|
+
bizSchema.parse('12345675') // β
Valid business ID with checksum
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
#### `mobile(options?)`
|
|
330
|
+
|
|
331
|
+
Validates Taiwan mobile phone numbers.
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
import { mobile } from '@hy_ong/zod-kit'
|
|
335
|
+
|
|
336
|
+
const phoneSchema = mobile({
|
|
337
|
+
allowInternational: true, // Allow +886 prefix
|
|
338
|
+
allowSeparators: true, // Allow 0912-345-678
|
|
339
|
+
operators: ['09'] // Restrict to specific operators
|
|
113
340
|
})
|
|
114
341
|
```
|
|
115
342
|
|
|
116
|
-
|
|
343
|
+
#### `tel(options?)`
|
|
344
|
+
|
|
345
|
+
Validates Taiwan landline telephone numbers.
|
|
117
346
|
|
|
118
347
|
```typescript
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
348
|
+
import { tel } from '@hy_ong/zod-kit'
|
|
349
|
+
|
|
350
|
+
const landlineSchema = tel({
|
|
351
|
+
allowSeparators: true, // Allow 02-1234-5678
|
|
352
|
+
areaCodes: ['02', '03'] // Restrict to specific areas
|
|
123
353
|
})
|
|
124
354
|
```
|
|
125
355
|
|
|
126
|
-
|
|
356
|
+
#### `fax(options?)`
|
|
357
|
+
|
|
358
|
+
Validates Taiwan fax numbers (same format as landline).
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
import { fax } from '@hy_ong/zod-kit'
|
|
362
|
+
|
|
363
|
+
const faxSchema = fax()
|
|
364
|
+
faxSchema.parse('02-2345-6789') // β
Valid fax number
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
#### `postalCode(options?)`
|
|
368
|
+
|
|
369
|
+
Validates Taiwan postal codes with support for 3-digit, 5-digit, and 6-digit formats.
|
|
127
370
|
|
|
128
371
|
```typescript
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
372
|
+
import { postalCode } from '@hy_ong/zod-kit'
|
|
373
|
+
|
|
374
|
+
// Accept 3-digit or 6-digit formats (recommended)
|
|
375
|
+
const modernSchema = postalCode()
|
|
376
|
+
modernSchema.parse('100') // β
Valid 3-digit
|
|
377
|
+
modernSchema.parse('100001') // β
Valid 6-digit
|
|
378
|
+
|
|
379
|
+
// Accept all formats
|
|
380
|
+
const flexibleSchema = postalCode({ format: 'all' })
|
|
381
|
+
flexibleSchema.parse('100') // β
Valid
|
|
382
|
+
flexibleSchema.parse('10001') // β
Valid (5-digit legacy)
|
|
383
|
+
flexibleSchema.parse('100001') // β
Valid
|
|
384
|
+
|
|
385
|
+
// Only 6-digit format (current standard)
|
|
386
|
+
const modernOnlySchema = postalCode({ format: '6' })
|
|
387
|
+
modernOnlySchema.parse('100001') // β
Valid
|
|
388
|
+
modernOnlySchema.parse('100') // β Invalid
|
|
389
|
+
|
|
390
|
+
// With dashes allowed
|
|
391
|
+
const dashSchema = postalCode({ allowDashes: true })
|
|
392
|
+
dashSchema.parse('100-001') // β
Valid (normalized to '100001')
|
|
393
|
+
|
|
394
|
+
// Specific areas only
|
|
395
|
+
const taipeiSchema = postalCode({
|
|
396
|
+
allowedPrefixes: ['100', '103', '104', '105', '106']
|
|
132
397
|
})
|
|
398
|
+
taipeiSchema.parse('100001') // β
Valid (Taipei area)
|
|
399
|
+
taipeiSchema.parse('200001') // β Invalid (not in allowlist)
|
|
133
400
|
```
|
|
134
401
|
|
|
135
|
-
## Internationalization
|
|
402
|
+
## π Internationalization
|
|
136
403
|
|
|
137
|
-
|
|
404
|
+
Zod Kit supports multiple languages for error messages:
|
|
138
405
|
|
|
139
406
|
```typescript
|
|
140
407
|
import { setLocale } from '@hy_ong/zod-kit'
|
|
141
408
|
|
|
142
|
-
// Set
|
|
143
|
-
setLocale('zh-TW')
|
|
409
|
+
// Set global locale
|
|
410
|
+
setLocale('zh-TW') // Traditional Chinese
|
|
411
|
+
setLocale('en') // English (default)
|
|
412
|
+
|
|
413
|
+
// Or use custom messages per validator
|
|
414
|
+
const emailSchema = email({
|
|
415
|
+
i18n: {
|
|
416
|
+
en: {
|
|
417
|
+
required: 'Email is required',
|
|
418
|
+
invalid: 'Please enter a valid email address'
|
|
419
|
+
},
|
|
420
|
+
'zh-TW': {
|
|
421
|
+
required: 'θ«θΌΈε
₯ι»ει΅δ»Ά',
|
|
422
|
+
invalid: 'θ«θΌΈε
₯ζζηι»ει΅δ»Άζ ΌεΌ'
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
})
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
## π¨ Advanced Usage
|
|
429
|
+
|
|
430
|
+
### Optional Fields
|
|
431
|
+
|
|
432
|
+
Make any field optional by setting `required: false`:
|
|
433
|
+
|
|
434
|
+
```typescript
|
|
435
|
+
const optionalEmail = email({ required: false })
|
|
436
|
+
|
|
437
|
+
optionalEmail.parse(null) // β
null
|
|
438
|
+
optionalEmail.parse('') // β
null
|
|
439
|
+
optionalEmail.parse('test@example.com') // β
"test@example.com"
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Custom Transformations
|
|
144
443
|
|
|
145
|
-
|
|
146
|
-
|
|
444
|
+
Transform values during validation:
|
|
445
|
+
|
|
446
|
+
```typescript
|
|
447
|
+
const trimmedText = text({
|
|
448
|
+
transform: (val) => val.trim().toLowerCase(),
|
|
449
|
+
minLength: 1
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
trimmedText.parse(' HELLO ') // β
"hello"
|
|
147
453
|
```
|
|
148
454
|
|
|
149
|
-
|
|
455
|
+
### Whitelist Validation
|
|
150
456
|
|
|
151
|
-
|
|
457
|
+
Allow specific values regardless of format:
|
|
152
458
|
|
|
153
459
|
```typescript
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
460
|
+
const flexibleId = id({
|
|
461
|
+
type: 'uuid',
|
|
462
|
+
whitelist: ['admin', 'system', 'test-user']
|
|
157
463
|
})
|
|
158
464
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
optionalEmail.parse('user@example.com') // β
'user@example.com'
|
|
465
|
+
flexibleId.parse('admin') // β
"admin"
|
|
466
|
+
flexibleId.parse('550e8400-e29b-41d4-a716-446655440000') // β
Valid UUID
|
|
162
467
|
```
|
|
163
468
|
|
|
164
|
-
|
|
469
|
+
### Combining Validators
|
|
470
|
+
|
|
471
|
+
Use with Zod's composition features:
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
import { z } from 'zod'
|
|
475
|
+
import { email, password } from '@hy_ong/zod-kit'
|
|
476
|
+
|
|
477
|
+
const userSchema = z.object({
|
|
478
|
+
email: email(),
|
|
479
|
+
password: password({ minLength: 8 }),
|
|
480
|
+
confirmPassword: z.string()
|
|
481
|
+
}).refine(data => data.password === data.confirmPassword, {
|
|
482
|
+
message: "Passwords don't match"
|
|
483
|
+
})
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
## π οΈ Development
|
|
165
487
|
|
|
166
488
|
```bash
|
|
489
|
+
# Clone the repository
|
|
490
|
+
git clone https://github.com/hy-ong/zod-kit.git
|
|
491
|
+
cd zod-kit
|
|
492
|
+
|
|
167
493
|
# Install dependencies
|
|
168
494
|
npm install
|
|
169
495
|
|
|
@@ -172,12 +498,54 @@ npm test
|
|
|
172
498
|
|
|
173
499
|
# Build the package
|
|
174
500
|
npm run build
|
|
501
|
+
|
|
502
|
+
# Run tests in watch mode
|
|
503
|
+
npm run test:watch
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
## π§ͺ Testing
|
|
507
|
+
|
|
508
|
+
The library includes comprehensive tests covering:
|
|
509
|
+
|
|
510
|
+
- β
All validator functions
|
|
511
|
+
- β
Edge cases and error conditions
|
|
512
|
+
- β
Internationalization
|
|
513
|
+
- β
TypeScript type safety
|
|
514
|
+
- β
Taiwan-specific format validation
|
|
515
|
+
|
|
516
|
+
```bash
|
|
517
|
+
npm test # Run all tests
|
|
518
|
+
npm run test:coverage # Run with coverage report
|
|
175
519
|
```
|
|
176
520
|
|
|
177
|
-
## License
|
|
521
|
+
## π License
|
|
522
|
+
|
|
523
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
524
|
+
|
|
525
|
+
## π€ Contributing
|
|
526
|
+
|
|
527
|
+
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
|
|
528
|
+
|
|
529
|
+
1. Fork the repository
|
|
530
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
531
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
532
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
533
|
+
5. Open a Pull Request
|
|
534
|
+
|
|
535
|
+
## π Project Stats
|
|
536
|
+
|
|
537
|
+

|
|
538
|
+

|
|
539
|
+

|
|
540
|
+
|
|
541
|
+
## π Acknowledgments
|
|
542
|
+
|
|
543
|
+
- Built on top of the amazing [Zod](https://github.com/colinhacks/zod) library
|
|
544
|
+
- Inspired by real-world validation needs in Taiwan's tech ecosystem
|
|
545
|
+
- Thanks to all contributors and users
|
|
178
546
|
|
|
179
|
-
|
|
547
|
+
---
|
|
180
548
|
|
|
181
|
-
|
|
549
|
+
**Made with β€οΈ by [Ong Hoe Yuan](https://github.com/hy-ong)**
|
|
182
550
|
|
|
183
|
-
|
|
551
|
+
For questions or support, please [open an issue](https://github.com/hy-ong/zod-kit/issues) on GitHub.
|