@hy_ong/zod-kit 0.1.4 → 0.1.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/dist/index.cjs CHANGED
@@ -3326,36 +3326,58 @@ var validateTaiwanTel = (value) => {
3326
3326
  return false;
3327
3327
  }
3328
3328
  const areaCode4 = cleanValue.substring(0, 4);
3329
- if (areaCode4 === "0826") {
3330
- return cleanValue.length === 9 && /^0826[6]\d{4}$/.test(cleanValue);
3331
- }
3332
3329
  if (areaCode4 === "0836") {
3333
- return cleanValue.length === 9 && /^0836[2-9]\d{4}$/.test(cleanValue);
3330
+ return cleanValue.length === 9 && /^0836\d{5}$/.test(cleanValue);
3334
3331
  }
3335
3332
  const areaCode3 = cleanValue.substring(0, 3);
3336
3333
  if (areaCode3 === "037") {
3337
- return cleanValue.length === 9 && /^037[2-9]\d{5}$/.test(cleanValue);
3334
+ const firstDigit = cleanValue[3];
3335
+ if (firstDigit === "0" || firstDigit === "1") {
3336
+ return false;
3337
+ }
3338
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^037[2-9]\d{5,6}$/.test(cleanValue);
3338
3339
  }
3339
3340
  if (areaCode3 === "049") {
3340
- return cleanValue.length === 10 && /^049[2-9]\d{6}$/.test(cleanValue);
3341
+ return cleanValue.length === 10 && /^049\d{7}$/.test(cleanValue);
3341
3342
  }
3342
3343
  if (areaCode3 === "082") {
3343
- return cleanValue.length === 9 && /^082[2-57-9]\d{5}$/.test(cleanValue);
3344
+ return cleanValue.length === 9 && /^082\d{6}$/.test(cleanValue);
3344
3345
  }
3345
3346
  if (areaCode3 === "089") {
3346
- return cleanValue.length === 9 && /^089[2-9]\d{5}$/.test(cleanValue);
3347
+ return cleanValue.length === 9 && /^089\d{6}$/.test(cleanValue);
3347
3348
  }
3348
3349
  const areaCode2 = cleanValue.substring(0, 2);
3349
3350
  if (areaCode2 === "02") {
3350
- return cleanValue.length === 10 && /^02[235-8]\d{7}$/.test(cleanValue);
3351
+ const firstDigit = cleanValue[2];
3352
+ if (firstDigit === "0" || firstDigit === "1") {
3353
+ return false;
3354
+ }
3355
+ return cleanValue.length === 10 && /^02[2-9]\d{7}$/.test(cleanValue);
3356
+ }
3357
+ if (areaCode2 === "03") {
3358
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^03\d{7,8}$/.test(cleanValue);
3351
3359
  }
3352
- if (["03", "04", "05", "06"].includes(areaCode2)) {
3353
- return cleanValue.length === 9;
3360
+ if (areaCode2 === "04") {
3361
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^04\d{7,8}$/.test(cleanValue);
3362
+ }
3363
+ if (areaCode2 === "05") {
3364
+ return cleanValue.length === 9 && /^05\d{7}$/.test(cleanValue);
3365
+ }
3366
+ if (areaCode2 === "06") {
3367
+ return cleanValue.length === 9 && /^06\d{7}$/.test(cleanValue);
3354
3368
  }
3355
3369
  if (areaCode2 === "07") {
3370
+ const firstDigit = cleanValue[2];
3371
+ if (firstDigit === "0" || firstDigit === "1") {
3372
+ return false;
3373
+ }
3356
3374
  return cleanValue.length === 9 && /^07[2-9]\d{6}$/.test(cleanValue);
3357
3375
  }
3358
3376
  if (areaCode2 === "08") {
3377
+ const firstDigit = cleanValue[2];
3378
+ if (firstDigit !== "4" && firstDigit !== "7" && firstDigit !== "8") {
3379
+ return false;
3380
+ }
3359
3381
  return cleanValue.length === 9 && /^08[478]\d{6}$/.test(cleanValue);
3360
3382
  }
3361
3383
  return false;
@@ -3426,36 +3448,58 @@ var validateTaiwanFax = (value) => {
3426
3448
  return false;
3427
3449
  }
3428
3450
  const areaCode4 = cleanValue.substring(0, 4);
3429
- if (areaCode4 === "0826") {
3430
- return cleanValue.length === 9 && /^0826[6]\d{4}$/.test(cleanValue);
3431
- }
3432
3451
  if (areaCode4 === "0836") {
3433
- return cleanValue.length === 9 && /^0836[2-9]\d{4}$/.test(cleanValue);
3452
+ return cleanValue.length === 9 && /^0836\d{5}$/.test(cleanValue);
3434
3453
  }
3435
3454
  const areaCode3 = cleanValue.substring(0, 3);
3436
3455
  if (areaCode3 === "037") {
3437
- return cleanValue.length === 9 && /^037[2-9]\d{5}$/.test(cleanValue);
3456
+ const firstDigit = cleanValue[3];
3457
+ if (firstDigit === "0" || firstDigit === "1") {
3458
+ return false;
3459
+ }
3460
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^037[2-9]\d{5,6}$/.test(cleanValue);
3438
3461
  }
3439
3462
  if (areaCode3 === "049") {
3440
- return cleanValue.length === 10 && /^049[2-9]\d{6}$/.test(cleanValue);
3463
+ return cleanValue.length === 10 && /^049\d{7}$/.test(cleanValue);
3441
3464
  }
3442
3465
  if (areaCode3 === "082") {
3443
- return cleanValue.length === 9 && /^082[2-57-9]\d{5}$/.test(cleanValue);
3466
+ return cleanValue.length === 9 && /^082\d{6}$/.test(cleanValue);
3444
3467
  }
3445
3468
  if (areaCode3 === "089") {
3446
- return cleanValue.length === 9 && /^089[2-9]\d{5}$/.test(cleanValue);
3469
+ return cleanValue.length === 9 && /^089\d{6}$/.test(cleanValue);
3447
3470
  }
3448
3471
  const areaCode2 = cleanValue.substring(0, 2);
3449
3472
  if (areaCode2 === "02") {
3450
- return cleanValue.length === 10 && /^02[235-8]\d{7}$/.test(cleanValue);
3473
+ const firstDigit = cleanValue[2];
3474
+ if (firstDigit === "0" || firstDigit === "1") {
3475
+ return false;
3476
+ }
3477
+ return cleanValue.length === 10 && /^02[2-9]\d{7}$/.test(cleanValue);
3478
+ }
3479
+ if (areaCode2 === "03") {
3480
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^03\d{7,8}$/.test(cleanValue);
3451
3481
  }
3452
- if (["03", "04", "05", "06"].includes(areaCode2)) {
3453
- return cleanValue.length === 9;
3482
+ if (areaCode2 === "04") {
3483
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^04\d{7,8}$/.test(cleanValue);
3484
+ }
3485
+ if (areaCode2 === "05") {
3486
+ return cleanValue.length === 9 && /^05\d{7}$/.test(cleanValue);
3487
+ }
3488
+ if (areaCode2 === "06") {
3489
+ return cleanValue.length === 9 && /^06\d{7}$/.test(cleanValue);
3454
3490
  }
3455
3491
  if (areaCode2 === "07") {
3492
+ const firstDigit = cleanValue[2];
3493
+ if (firstDigit === "0" || firstDigit === "1") {
3494
+ return false;
3495
+ }
3456
3496
  return cleanValue.length === 9 && /^07[2-9]\d{6}$/.test(cleanValue);
3457
3497
  }
3458
3498
  if (areaCode2 === "08") {
3499
+ const firstDigit = cleanValue[2];
3500
+ if (firstDigit !== "4" && firstDigit !== "7" && firstDigit !== "8") {
3501
+ return false;
3502
+ }
3459
3503
  return cleanValue.length === 9 && /^08[478]\d{6}$/.test(cleanValue);
3460
3504
  }
3461
3505
  return false;
package/dist/index.d.cts CHANGED
@@ -2898,28 +2898,26 @@ type TwTelSchema<IsRequired extends boolean> = IsRequired extends true ? ZodStri
2898
2898
  * number patterns.
2899
2899
  *
2900
2900
  * Supported area codes and formats:
2901
- * - 02: Taipei, New Taipei, Keelung - 8 digits (2&3&5~8+7D)
2902
- * - 03: Taoyuan, Hsinchu, Yilan, Hualien - 7 digits
2903
- * - 037: Miaoli - 6 digits (2~9+5D)
2904
- * - 04: Taichung, Changhua - 7 digits
2905
- * - 049: Nantou - 7 digits (2~9+6D)
2901
+ * - 02: Taipei, New Taipei, Keelung - 8 digits
2902
+ * - 03: Taoyuan, Hsinchu, Yilan, Hualien - 7-8 digits
2903
+ * - 037: Miaoli - 6-7 digits
2904
+ * - 04: Taichung, Changhua, Nantou - 7-8 digits
2905
+ * - 049: Nantou - 7 digits
2906
2906
  * - 05: Yunlin, Chiayi - 7 digits
2907
2907
  * - 06: Tainan - 7 digits
2908
- * - 07: Kaohsiung - 7 digits (2~9+6D)
2909
- * - 08: Pingtung - 7 digits (4&7&8+6D)
2910
- * - 082: Kinmen - 6 digits (2~5&7~9+5D)
2911
- * - 0826: Wuqiu - 5 digits (6+4D)
2912
- * - 0836: Matsu - 5 digits (2~9+4D)
2913
- * - 089: Taitung - 6 digits (2~9+5D)
2908
+ * - 07: Kaohsiung - 7 digits
2909
+ * - 08: Pingtung - 7 digits
2910
+ * - 082: Kinmen - 6 digits
2911
+ * - 0836: Matsu - 5 digits
2912
+ * - 089: Taitung - 6 digits
2914
2913
  *
2915
2914
  * @example
2916
2915
  * ```typescript
2917
2916
  * validateTaiwanTel("0223456789") // true (Taipei area)
2918
- * validateTaiwanTel("0312345678") // true (Taoyuan area)
2917
+ * validateTaiwanTel("0423288882") // true (Taichung area, 8 digits)
2919
2918
  * validateTaiwanTel("037234567") // true (Miaoli area)
2920
2919
  * validateTaiwanTel("082234567") // true (Kinmen area)
2921
2920
  * validateTaiwanTel("02-2345-6789") // true (with separators)
2922
- * validateTaiwanTel("0812345678") // false (invalid for 08 area)
2923
2921
  * ```
2924
2922
  */
2925
2923
  declare const validateTaiwanTel: (value: string) => boolean;
@@ -3055,27 +3053,25 @@ type TwFaxSchema<IsRequired extends boolean> = IsRequired extends true ? ZodStri
3055
3053
  * Fax numbers follow the same format as landline telephone numbers in Taiwan.
3056
3054
  *
3057
3055
  * Supported area codes and formats (same as landline):
3058
- * - 02: Taipei, New Taipei, Keelung - 8 digits (2&3&5~8+7D)
3059
- * - 03: Taoyuan, Hsinchu, Yilan, Hualien - 7 digits
3060
- * - 037: Miaoli - 6 digits (2~9+5D)
3061
- * - 04: Taichung, Changhua - 7 digits
3062
- * - 049: Nantou - 7 digits (2~9+6D)
3056
+ * - 02: Taipei, New Taipei, Keelung - 8 digits
3057
+ * - 03: Taoyuan, Hsinchu, Yilan, Hualien - 7-8 digits
3058
+ * - 037: Miaoli - 6-7 digits
3059
+ * - 04: Taichung, Changhua, Nantou - 7-8 digits
3060
+ * - 049: Nantou - 7 digits
3063
3061
  * - 05: Yunlin, Chiayi - 7 digits
3064
3062
  * - 06: Tainan - 7 digits
3065
- * - 07: Kaohsiung - 7 digits (2~9+6D)
3066
- * - 08: Pingtung - 7 digits (4&7&8+6D)
3067
- * - 082: Kinmen - 6 digits (2~5&7~9+5D)
3068
- * - 0826: Wuqiu - 5 digits (6+4D)
3069
- * - 0836: Matsu - 5 digits (2~9+4D)
3070
- * - 089: Taitung - 6 digits (2~9+5D)
3063
+ * - 07: Kaohsiung - 7 digits
3064
+ * - 08: Pingtung - 7 digits
3065
+ * - 082: Kinmen - 6 digits
3066
+ * - 0836: Matsu - 5 digits
3067
+ * - 089: Taitung - 6 digits
3071
3068
  *
3072
3069
  * @example
3073
3070
  * ```typescript
3074
3071
  * validateTaiwanFax("0223456789") // true (Taipei area)
3075
- * validateTaiwanFax("0312345678") // true (Taoyuan area)
3072
+ * validateTaiwanFax("0423288882") // true (Taichung area, 8 digits)
3076
3073
  * validateTaiwanFax("037234567") // true (Miaoli area)
3077
3074
  * validateTaiwanFax("02-2345-6789") // true (with separators)
3078
- * validateTaiwanFax("0812345678") // false (invalid for 08 area)
3079
3075
  * ```
3080
3076
  */
3081
3077
  declare const validateTaiwanFax: (value: string) => boolean;
package/dist/index.d.ts CHANGED
@@ -2898,28 +2898,26 @@ type TwTelSchema<IsRequired extends boolean> = IsRequired extends true ? ZodStri
2898
2898
  * number patterns.
2899
2899
  *
2900
2900
  * Supported area codes and formats:
2901
- * - 02: Taipei, New Taipei, Keelung - 8 digits (2&3&5~8+7D)
2902
- * - 03: Taoyuan, Hsinchu, Yilan, Hualien - 7 digits
2903
- * - 037: Miaoli - 6 digits (2~9+5D)
2904
- * - 04: Taichung, Changhua - 7 digits
2905
- * - 049: Nantou - 7 digits (2~9+6D)
2901
+ * - 02: Taipei, New Taipei, Keelung - 8 digits
2902
+ * - 03: Taoyuan, Hsinchu, Yilan, Hualien - 7-8 digits
2903
+ * - 037: Miaoli - 6-7 digits
2904
+ * - 04: Taichung, Changhua, Nantou - 7-8 digits
2905
+ * - 049: Nantou - 7 digits
2906
2906
  * - 05: Yunlin, Chiayi - 7 digits
2907
2907
  * - 06: Tainan - 7 digits
2908
- * - 07: Kaohsiung - 7 digits (2~9+6D)
2909
- * - 08: Pingtung - 7 digits (4&7&8+6D)
2910
- * - 082: Kinmen - 6 digits (2~5&7~9+5D)
2911
- * - 0826: Wuqiu - 5 digits (6+4D)
2912
- * - 0836: Matsu - 5 digits (2~9+4D)
2913
- * - 089: Taitung - 6 digits (2~9+5D)
2908
+ * - 07: Kaohsiung - 7 digits
2909
+ * - 08: Pingtung - 7 digits
2910
+ * - 082: Kinmen - 6 digits
2911
+ * - 0836: Matsu - 5 digits
2912
+ * - 089: Taitung - 6 digits
2914
2913
  *
2915
2914
  * @example
2916
2915
  * ```typescript
2917
2916
  * validateTaiwanTel("0223456789") // true (Taipei area)
2918
- * validateTaiwanTel("0312345678") // true (Taoyuan area)
2917
+ * validateTaiwanTel("0423288882") // true (Taichung area, 8 digits)
2919
2918
  * validateTaiwanTel("037234567") // true (Miaoli area)
2920
2919
  * validateTaiwanTel("082234567") // true (Kinmen area)
2921
2920
  * validateTaiwanTel("02-2345-6789") // true (with separators)
2922
- * validateTaiwanTel("0812345678") // false (invalid for 08 area)
2923
2921
  * ```
2924
2922
  */
2925
2923
  declare const validateTaiwanTel: (value: string) => boolean;
@@ -3055,27 +3053,25 @@ type TwFaxSchema<IsRequired extends boolean> = IsRequired extends true ? ZodStri
3055
3053
  * Fax numbers follow the same format as landline telephone numbers in Taiwan.
3056
3054
  *
3057
3055
  * Supported area codes and formats (same as landline):
3058
- * - 02: Taipei, New Taipei, Keelung - 8 digits (2&3&5~8+7D)
3059
- * - 03: Taoyuan, Hsinchu, Yilan, Hualien - 7 digits
3060
- * - 037: Miaoli - 6 digits (2~9+5D)
3061
- * - 04: Taichung, Changhua - 7 digits
3062
- * - 049: Nantou - 7 digits (2~9+6D)
3056
+ * - 02: Taipei, New Taipei, Keelung - 8 digits
3057
+ * - 03: Taoyuan, Hsinchu, Yilan, Hualien - 7-8 digits
3058
+ * - 037: Miaoli - 6-7 digits
3059
+ * - 04: Taichung, Changhua, Nantou - 7-8 digits
3060
+ * - 049: Nantou - 7 digits
3063
3061
  * - 05: Yunlin, Chiayi - 7 digits
3064
3062
  * - 06: Tainan - 7 digits
3065
- * - 07: Kaohsiung - 7 digits (2~9+6D)
3066
- * - 08: Pingtung - 7 digits (4&7&8+6D)
3067
- * - 082: Kinmen - 6 digits (2~5&7~9+5D)
3068
- * - 0826: Wuqiu - 5 digits (6+4D)
3069
- * - 0836: Matsu - 5 digits (2~9+4D)
3070
- * - 089: Taitung - 6 digits (2~9+5D)
3063
+ * - 07: Kaohsiung - 7 digits
3064
+ * - 08: Pingtung - 7 digits
3065
+ * - 082: Kinmen - 6 digits
3066
+ * - 0836: Matsu - 5 digits
3067
+ * - 089: Taitung - 6 digits
3071
3068
  *
3072
3069
  * @example
3073
3070
  * ```typescript
3074
3071
  * validateTaiwanFax("0223456789") // true (Taipei area)
3075
- * validateTaiwanFax("0312345678") // true (Taoyuan area)
3072
+ * validateTaiwanFax("0423288882") // true (Taichung area, 8 digits)
3076
3073
  * validateTaiwanFax("037234567") // true (Miaoli area)
3077
3074
  * validateTaiwanFax("02-2345-6789") // true (with separators)
3078
- * validateTaiwanFax("0812345678") // false (invalid for 08 area)
3079
3075
  * ```
3080
3076
  */
3081
3077
  declare const validateTaiwanFax: (value: string) => boolean;
package/dist/index.js CHANGED
@@ -3248,36 +3248,58 @@ var validateTaiwanTel = (value) => {
3248
3248
  return false;
3249
3249
  }
3250
3250
  const areaCode4 = cleanValue.substring(0, 4);
3251
- if (areaCode4 === "0826") {
3252
- return cleanValue.length === 9 && /^0826[6]\d{4}$/.test(cleanValue);
3253
- }
3254
3251
  if (areaCode4 === "0836") {
3255
- return cleanValue.length === 9 && /^0836[2-9]\d{4}$/.test(cleanValue);
3252
+ return cleanValue.length === 9 && /^0836\d{5}$/.test(cleanValue);
3256
3253
  }
3257
3254
  const areaCode3 = cleanValue.substring(0, 3);
3258
3255
  if (areaCode3 === "037") {
3259
- return cleanValue.length === 9 && /^037[2-9]\d{5}$/.test(cleanValue);
3256
+ const firstDigit = cleanValue[3];
3257
+ if (firstDigit === "0" || firstDigit === "1") {
3258
+ return false;
3259
+ }
3260
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^037[2-9]\d{5,6}$/.test(cleanValue);
3260
3261
  }
3261
3262
  if (areaCode3 === "049") {
3262
- return cleanValue.length === 10 && /^049[2-9]\d{6}$/.test(cleanValue);
3263
+ return cleanValue.length === 10 && /^049\d{7}$/.test(cleanValue);
3263
3264
  }
3264
3265
  if (areaCode3 === "082") {
3265
- return cleanValue.length === 9 && /^082[2-57-9]\d{5}$/.test(cleanValue);
3266
+ return cleanValue.length === 9 && /^082\d{6}$/.test(cleanValue);
3266
3267
  }
3267
3268
  if (areaCode3 === "089") {
3268
- return cleanValue.length === 9 && /^089[2-9]\d{5}$/.test(cleanValue);
3269
+ return cleanValue.length === 9 && /^089\d{6}$/.test(cleanValue);
3269
3270
  }
3270
3271
  const areaCode2 = cleanValue.substring(0, 2);
3271
3272
  if (areaCode2 === "02") {
3272
- return cleanValue.length === 10 && /^02[235-8]\d{7}$/.test(cleanValue);
3273
+ const firstDigit = cleanValue[2];
3274
+ if (firstDigit === "0" || firstDigit === "1") {
3275
+ return false;
3276
+ }
3277
+ return cleanValue.length === 10 && /^02[2-9]\d{7}$/.test(cleanValue);
3278
+ }
3279
+ if (areaCode2 === "03") {
3280
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^03\d{7,8}$/.test(cleanValue);
3273
3281
  }
3274
- if (["03", "04", "05", "06"].includes(areaCode2)) {
3275
- return cleanValue.length === 9;
3282
+ if (areaCode2 === "04") {
3283
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^04\d{7,8}$/.test(cleanValue);
3284
+ }
3285
+ if (areaCode2 === "05") {
3286
+ return cleanValue.length === 9 && /^05\d{7}$/.test(cleanValue);
3287
+ }
3288
+ if (areaCode2 === "06") {
3289
+ return cleanValue.length === 9 && /^06\d{7}$/.test(cleanValue);
3276
3290
  }
3277
3291
  if (areaCode2 === "07") {
3292
+ const firstDigit = cleanValue[2];
3293
+ if (firstDigit === "0" || firstDigit === "1") {
3294
+ return false;
3295
+ }
3278
3296
  return cleanValue.length === 9 && /^07[2-9]\d{6}$/.test(cleanValue);
3279
3297
  }
3280
3298
  if (areaCode2 === "08") {
3299
+ const firstDigit = cleanValue[2];
3300
+ if (firstDigit !== "4" && firstDigit !== "7" && firstDigit !== "8") {
3301
+ return false;
3302
+ }
3281
3303
  return cleanValue.length === 9 && /^08[478]\d{6}$/.test(cleanValue);
3282
3304
  }
3283
3305
  return false;
@@ -3348,36 +3370,58 @@ var validateTaiwanFax = (value) => {
3348
3370
  return false;
3349
3371
  }
3350
3372
  const areaCode4 = cleanValue.substring(0, 4);
3351
- if (areaCode4 === "0826") {
3352
- return cleanValue.length === 9 && /^0826[6]\d{4}$/.test(cleanValue);
3353
- }
3354
3373
  if (areaCode4 === "0836") {
3355
- return cleanValue.length === 9 && /^0836[2-9]\d{4}$/.test(cleanValue);
3374
+ return cleanValue.length === 9 && /^0836\d{5}$/.test(cleanValue);
3356
3375
  }
3357
3376
  const areaCode3 = cleanValue.substring(0, 3);
3358
3377
  if (areaCode3 === "037") {
3359
- return cleanValue.length === 9 && /^037[2-9]\d{5}$/.test(cleanValue);
3378
+ const firstDigit = cleanValue[3];
3379
+ if (firstDigit === "0" || firstDigit === "1") {
3380
+ return false;
3381
+ }
3382
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^037[2-9]\d{5,6}$/.test(cleanValue);
3360
3383
  }
3361
3384
  if (areaCode3 === "049") {
3362
- return cleanValue.length === 10 && /^049[2-9]\d{6}$/.test(cleanValue);
3385
+ return cleanValue.length === 10 && /^049\d{7}$/.test(cleanValue);
3363
3386
  }
3364
3387
  if (areaCode3 === "082") {
3365
- return cleanValue.length === 9 && /^082[2-57-9]\d{5}$/.test(cleanValue);
3388
+ return cleanValue.length === 9 && /^082\d{6}$/.test(cleanValue);
3366
3389
  }
3367
3390
  if (areaCode3 === "089") {
3368
- return cleanValue.length === 9 && /^089[2-9]\d{5}$/.test(cleanValue);
3391
+ return cleanValue.length === 9 && /^089\d{6}$/.test(cleanValue);
3369
3392
  }
3370
3393
  const areaCode2 = cleanValue.substring(0, 2);
3371
3394
  if (areaCode2 === "02") {
3372
- return cleanValue.length === 10 && /^02[235-8]\d{7}$/.test(cleanValue);
3395
+ const firstDigit = cleanValue[2];
3396
+ if (firstDigit === "0" || firstDigit === "1") {
3397
+ return false;
3398
+ }
3399
+ return cleanValue.length === 10 && /^02[2-9]\d{7}$/.test(cleanValue);
3400
+ }
3401
+ if (areaCode2 === "03") {
3402
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^03\d{7,8}$/.test(cleanValue);
3373
3403
  }
3374
- if (["03", "04", "05", "06"].includes(areaCode2)) {
3375
- return cleanValue.length === 9;
3404
+ if (areaCode2 === "04") {
3405
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^04\d{7,8}$/.test(cleanValue);
3406
+ }
3407
+ if (areaCode2 === "05") {
3408
+ return cleanValue.length === 9 && /^05\d{7}$/.test(cleanValue);
3409
+ }
3410
+ if (areaCode2 === "06") {
3411
+ return cleanValue.length === 9 && /^06\d{7}$/.test(cleanValue);
3376
3412
  }
3377
3413
  if (areaCode2 === "07") {
3414
+ const firstDigit = cleanValue[2];
3415
+ if (firstDigit === "0" || firstDigit === "1") {
3416
+ return false;
3417
+ }
3378
3418
  return cleanValue.length === 9 && /^07[2-9]\d{6}$/.test(cleanValue);
3379
3419
  }
3380
3420
  if (areaCode2 === "08") {
3421
+ const firstDigit = cleanValue[2];
3422
+ if (firstDigit !== "4" && firstDigit !== "7" && firstDigit !== "8") {
3423
+ return false;
3424
+ }
3381
3425
  return cleanValue.length === 9 && /^08[478]\d{6}$/.test(cleanValue);
3382
3426
  }
3383
3427
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hy_ong/zod-kit",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "A comprehensive TypeScript library providing pre-built Zod validation schemas with full internationalization support for common data types and Taiwan-specific formats",
5
5
  "keywords": [
6
6
  "zod",
@@ -65,44 +65,41 @@ export type TwFaxSchema<IsRequired extends boolean> = IsRequired extends true ?
65
65
  * Fax numbers follow the same format as landline telephone numbers in Taiwan.
66
66
  *
67
67
  * Supported area codes and formats (same as landline):
68
- * - 02: Taipei, New Taipei, Keelung - 8 digits (2&3&5~8+7D)
69
- * - 03: Taoyuan, Hsinchu, Yilan, Hualien - 7 digits
70
- * - 037: Miaoli - 6 digits (2~9+5D)
71
- * - 04: Taichung, Changhua - 7 digits
72
- * - 049: Nantou - 7 digits (2~9+6D)
68
+ * - 02: Taipei, New Taipei, Keelung - 8 digits
69
+ * - 03: Taoyuan, Hsinchu, Yilan, Hualien - 7-8 digits
70
+ * - 037: Miaoli - 6-7 digits
71
+ * - 04: Taichung, Changhua, Nantou - 7-8 digits
72
+ * - 049: Nantou - 7 digits
73
73
  * - 05: Yunlin, Chiayi - 7 digits
74
74
  * - 06: Tainan - 7 digits
75
- * - 07: Kaohsiung - 7 digits (2~9+6D)
76
- * - 08: Pingtung - 7 digits (4&7&8+6D)
77
- * - 082: Kinmen - 6 digits (2~5&7~9+5D)
78
- * - 0826: Wuqiu - 5 digits (6+4D)
79
- * - 0836: Matsu - 5 digits (2~9+4D)
80
- * - 089: Taitung - 6 digits (2~9+5D)
75
+ * - 07: Kaohsiung - 7 digits
76
+ * - 08: Pingtung - 7 digits
77
+ * - 082: Kinmen - 6 digits
78
+ * - 0836: Matsu - 5 digits
79
+ * - 089: Taitung - 6 digits
81
80
  *
82
81
  * @example
83
82
  * ```typescript
84
83
  * validateTaiwanFax("0223456789") // true (Taipei area)
85
- * validateTaiwanFax("0312345678") // true (Taoyuan area)
84
+ * validateTaiwanFax("0423288882") // true (Taichung area, 8 digits)
86
85
  * validateTaiwanFax("037234567") // true (Miaoli area)
87
86
  * validateTaiwanFax("02-2345-6789") // true (with separators)
88
- * validateTaiwanFax("0812345678") // false (invalid for 08 area)
89
87
  * ```
90
88
  */
91
89
  const validateTaiwanFax = (value: string): boolean => {
92
90
  // Official Taiwan fax formats according to telecom numbering plan (same as landline):
93
- // 02: Taipei, New Taipei, Keelung - 8 digits (2&3&5~8+7D)
94
- // 03: Taoyuan, Hsinchu, Yilan, Hualien - 7 digits
95
- // 037: Miaoli - 6 digits (2~9+5D)
96
- // 04: Taichung, Changhua - 7 digits
97
- // 049: Nantou - 7 digits (2~9+6D)
91
+ // 02: Taipei, New Taipei, Keelung - 8 digits
92
+ // 03: Taoyuan, Hsinchu, Yilan, Hualien - 7-8 digits
93
+ // 037: Miaoli - 6-7 digits
94
+ // 04: Taichung, Changhua, Nantou - 7-8 digits
95
+ // 049: Nantou - 7 digits
98
96
  // 05: Yunlin, Chiayi - 7 digits
99
97
  // 06: Tainan - 7 digits
100
- // 07: Kaohsiung - 7 digits (2~9+6D)
101
- // 08: Pingtung - 7 digits (4&7&8+6D)
102
- // 082: Kinmen - 6 digits (2~5&7~9+5D)
103
- // 0826: Wuqiu - 5 digits (6+4D)
104
- // 0836: Matsu - 5 digits (2~9+4D)
105
- // 089: Taitung - 6 digits (2~9+5D)
98
+ // 07: Kaohsiung - 7 digits
99
+ // 08: Pingtung - 7 digits
100
+ // 082: Kinmen - 6 digits
101
+ // 0836: Matsu - 5 digits
102
+ // 089: Taitung - 6 digits
106
103
 
107
104
  // Remove common separators for validation
108
105
  const cleanValue = value.replace(/[-\s]/g, "")
@@ -114,52 +111,79 @@ const validateTaiwanFax = (value: string): boolean => {
114
111
 
115
112
  // Check 4-digit area codes first
116
113
  const areaCode4 = cleanValue.substring(0, 4)
117
- if (areaCode4 === '0826') {
118
- // Wuqiu: 0826 + 5 digits (6+4D), total 9 digits
119
- return cleanValue.length === 9 && /^0826[6]\d{4}$/.test(cleanValue)
120
- }
121
114
  if (areaCode4 === '0836') {
122
- // Matsu: 0836 + 5 digits (2~9+4D), total 9 digits
123
- return cleanValue.length === 9 && /^0836[2-9]\d{4}$/.test(cleanValue)
115
+ // Matsu: 0836 + 5 digits, total 9 digits
116
+ return cleanValue.length === 9 && /^0836\d{5}$/.test(cleanValue)
124
117
  }
125
118
 
126
119
  // Check 3-digit area codes
127
120
  const areaCode3 = cleanValue.substring(0, 3)
128
121
  if (areaCode3 === '037') {
129
- // Miaoli: 037 + 6 digits (2~9+5D), total 9 digits
130
- return cleanValue.length === 9 && /^037[2-9]\d{5}$/.test(cleanValue)
122
+ // Miaoli: 037 + 6-7 digits, total 9-10 digits
123
+ // User number must start with 2-9 (not 0 or 1)
124
+ const firstDigit = cleanValue[3]
125
+ if (firstDigit === "0" || firstDigit === "1") {
126
+ return false
127
+ }
128
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^037[2-9]\d{5,6}$/.test(cleanValue)
131
129
  }
132
130
  if (areaCode3 === '049') {
133
- // Nantou: 049 + 7 digits (2~9+6D), total 10 digits
134
- return cleanValue.length === 10 && /^049[2-9]\d{6}$/.test(cleanValue)
131
+ // Nantou: 049 + 7 digits, total 10 digits
132
+ return cleanValue.length === 10 && /^049\d{7}$/.test(cleanValue)
135
133
  }
136
134
  if (areaCode3 === '082') {
137
- // Kinmen: 082 + 6 digits (2~5&7~9+5D), total 9 digits
138
- return cleanValue.length === 9 && /^082[2-57-9]\d{5}$/.test(cleanValue)
135
+ // Kinmen: 082 + 6 digits, total 9 digits
136
+ return cleanValue.length === 9 && /^082\d{6}$/.test(cleanValue)
139
137
  }
140
138
  if (areaCode3 === '089') {
141
- // Taitung: 089 + 6 digits (2~9+5D), total 9 digits
142
- return cleanValue.length === 9 && /^089[2-9]\d{5}$/.test(cleanValue)
139
+ // Taitung: 089 + 6 digits, total 9 digits
140
+ return cleanValue.length === 9 && /^089\d{6}$/.test(cleanValue)
143
141
  }
144
142
 
145
143
  // Check 2-digit area codes
146
144
  const areaCode2 = cleanValue.substring(0, 2)
147
145
 
148
146
  if (areaCode2 === '02') {
149
- // Taipei, New Taipei, Keelung: 02 + 8 digits (2&3&5~8+7D), total 10 digits
150
- return cleanValue.length === 10 && /^02[235-8]\d{7}$/.test(cleanValue)
147
+ // Taipei, New Taipei, Keelung: 02 + 8 digits, total 10 digits
148
+ // User number must start with 2-9 (not 0 or 1)
149
+ const firstDigit = cleanValue[2]
150
+ if (firstDigit === "0" || firstDigit === "1") {
151
+ return false
152
+ }
153
+ return cleanValue.length === 10 && /^02[2-9]\d{7}$/.test(cleanValue)
154
+ }
155
+ if (areaCode2 === '03') {
156
+ // Taoyuan, Hsinchu, Yilan, Hualien: 03 + 7-8 digits, total 9-10 digits
157
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^03\d{7,8}$/.test(cleanValue)
151
158
  }
152
- if (['03', '04', '05', '06'].includes(areaCode2)) {
153
- // Taoyuan/Hsinchu/Yilan/Hualien (03), Taichung/Changhua (04),
154
- // Yunlin/Chiayi (05), Tainan (06): 7 digits, total 9 digits
155
- return cleanValue.length === 9
159
+ if (areaCode2 === '04') {
160
+ // Taichung, Changhua, Nantou: 04 + 7-8 digits, total 9-10 digits
161
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^04\d{7,8}$/.test(cleanValue)
162
+ }
163
+ if (areaCode2 === '05') {
164
+ // Yunlin, Chiayi: 05 + 7 digits, total 9 digits
165
+ return cleanValue.length === 9 && /^05\d{7}$/.test(cleanValue)
166
+ }
167
+ if (areaCode2 === '06') {
168
+ // Tainan: 06 + 7 digits, total 9 digits
169
+ return cleanValue.length === 9 && /^06\d{7}$/.test(cleanValue)
156
170
  }
157
171
  if (areaCode2 === '07') {
158
- // Kaohsiung: 07 + 7 digits (2~9+6D), total 9 digits
172
+ // Kaohsiung: 07 + 7 digits, total 9 digits
173
+ // User number must start with 2-9 (not 0 or 1)
174
+ const firstDigit = cleanValue[2]
175
+ if (firstDigit === "0" || firstDigit === "1") {
176
+ return false
177
+ }
159
178
  return cleanValue.length === 9 && /^07[2-9]\d{6}$/.test(cleanValue)
160
179
  }
161
180
  if (areaCode2 === '08') {
162
- // Pingtung: 08 + 7 digits (4&7&8+6D), total 9 digits
181
+ // Pingtung: 08 + 7 digits, total 9 digits
182
+ // User number must start with 4, 7, or 8 (format: 4&7&8+6D)
183
+ const firstDigit = cleanValue[2]
184
+ if (firstDigit !== "4" && firstDigit !== "7" && firstDigit !== "8") {
185
+ return false // Invalid first digit for 08 area code
186
+ }
163
187
  return cleanValue.length === 9 && /^08[478]\d{6}$/.test(cleanValue)
164
188
  }
165
189
 
@@ -66,45 +66,42 @@ export type TwTelSchema<IsRequired extends boolean> = IsRequired extends true ?
66
66
  * number patterns.
67
67
  *
68
68
  * Supported area codes and formats:
69
- * - 02: Taipei, New Taipei, Keelung - 8 digits (2&3&5~8+7D)
70
- * - 03: Taoyuan, Hsinchu, Yilan, Hualien - 7 digits
71
- * - 037: Miaoli - 6 digits (2~9+5D)
72
- * - 04: Taichung, Changhua - 7 digits
73
- * - 049: Nantou - 7 digits (2~9+6D)
69
+ * - 02: Taipei, New Taipei, Keelung - 8 digits
70
+ * - 03: Taoyuan, Hsinchu, Yilan, Hualien - 7-8 digits
71
+ * - 037: Miaoli - 6-7 digits
72
+ * - 04: Taichung, Changhua, Nantou - 7-8 digits
73
+ * - 049: Nantou - 7 digits
74
74
  * - 05: Yunlin, Chiayi - 7 digits
75
75
  * - 06: Tainan - 7 digits
76
- * - 07: Kaohsiung - 7 digits (2~9+6D)
77
- * - 08: Pingtung - 7 digits (4&7&8+6D)
78
- * - 082: Kinmen - 6 digits (2~5&7~9+5D)
79
- * - 0826: Wuqiu - 5 digits (6+4D)
80
- * - 0836: Matsu - 5 digits (2~9+4D)
81
- * - 089: Taitung - 6 digits (2~9+5D)
76
+ * - 07: Kaohsiung - 7 digits
77
+ * - 08: Pingtung - 7 digits
78
+ * - 082: Kinmen - 6 digits
79
+ * - 0836: Matsu - 5 digits
80
+ * - 089: Taitung - 6 digits
82
81
  *
83
82
  * @example
84
83
  * ```typescript
85
84
  * validateTaiwanTel("0223456789") // true (Taipei area)
86
- * validateTaiwanTel("0312345678") // true (Taoyuan area)
85
+ * validateTaiwanTel("0423288882") // true (Taichung area, 8 digits)
87
86
  * validateTaiwanTel("037234567") // true (Miaoli area)
88
87
  * validateTaiwanTel("082234567") // true (Kinmen area)
89
88
  * validateTaiwanTel("02-2345-6789") // true (with separators)
90
- * validateTaiwanTel("0812345678") // false (invalid for 08 area)
91
89
  * ```
92
90
  */
93
91
  const validateTaiwanTel = (value: string): boolean => {
94
92
  // Official Taiwan landline formats according to telecom numbering plan:
95
- // 02: Taipei, New Taipei, Keelung - 8 digits (2&3&5~8+7D)
96
- // 03: Taoyuan, Hsinchu, Yilan, Hualien - 7 digits
97
- // 037: Miaoli - 6 digits (2~9+5D)
98
- // 04: Taichung, Changhua - 7 digits
99
- // 049: Nantou - 7 digits (2~9+6D)
93
+ // 02: Taipei, New Taipei, Keelung - 8 digits
94
+ // 03: Taoyuan, Hsinchu, Yilan, Hualien - 7-8 digits
95
+ // 037: Miaoli - 6-7 digits
96
+ // 04: Taichung, Changhua, Nantou - 7-8 digits
97
+ // 049: Nantou - 7 digits
100
98
  // 05: Yunlin, Chiayi - 7 digits
101
99
  // 06: Tainan - 7 digits
102
- // 07: Kaohsiung - 7 digits (2~9+6D)
103
- // 08: Pingtung - 7 digits (4&7&8+6D)
104
- // 082: Kinmen - 6 digits (2~5&7~9+5D)
105
- // 0826: Wuqiu - 5 digits (6+4D)
106
- // 0836: Matsu - 5 digits (2~9+4D)
107
- // 089: Taitung - 6 digits (2~9+5D)
100
+ // 07: Kaohsiung - 7 digits
101
+ // 08: Pingtung - 7 digits
102
+ // 082: Kinmen - 6 digits
103
+ // 0836: Matsu - 5 digits
104
+ // 089: Taitung - 6 digits
108
105
 
109
106
  // Remove common separators for validation
110
107
  const cleanValue = value.replace(/[-\s]/g, "")
@@ -116,52 +113,79 @@ const validateTaiwanTel = (value: string): boolean => {
116
113
 
117
114
  // Check 4-digit area codes first
118
115
  const areaCode4 = cleanValue.substring(0, 4)
119
- if (areaCode4 === "0826") {
120
- // Wuqiu: 0826 + 5 digits (6+4D), total 9 digits
121
- return cleanValue.length === 9 && /^0826[6]\d{4}$/.test(cleanValue)
122
- }
123
116
  if (areaCode4 === "0836") {
124
- // Matsu: 0836 + 5 digits (2~9+4D), total 9 digits
125
- return cleanValue.length === 9 && /^0836[2-9]\d{4}$/.test(cleanValue)
117
+ // Matsu: 0836 + 5 digits, total 9 digits
118
+ return cleanValue.length === 9 && /^0836\d{5}$/.test(cleanValue)
126
119
  }
127
120
 
128
121
  // Check 3-digit area codes
129
122
  const areaCode3 = cleanValue.substring(0, 3)
130
123
  if (areaCode3 === "037") {
131
- // Miaoli: 037 + 6 digits (2~9+5D), total 9 digits
132
- return cleanValue.length === 9 && /^037[2-9]\d{5}$/.test(cleanValue)
124
+ // Miaoli: 037 + 6-7 digits, total 9-10 digits
125
+ // User number must start with 2-9 (not 0 or 1)
126
+ const firstDigit = cleanValue[3]
127
+ if (firstDigit === "0" || firstDigit === "1") {
128
+ return false
129
+ }
130
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^037[2-9]\d{5,6}$/.test(cleanValue)
133
131
  }
134
132
  if (areaCode3 === "049") {
135
- // Nantou: 049 + 7 digits (2~9+6D), total 10 digits
136
- return cleanValue.length === 10 && /^049[2-9]\d{6}$/.test(cleanValue)
133
+ // Nantou: 049 + 7 digits, total 10 digits
134
+ return cleanValue.length === 10 && /^049\d{7}$/.test(cleanValue)
137
135
  }
138
136
  if (areaCode3 === "082") {
139
- // Kinmen: 082 + 6 digits (2~5&7~9+5D), total 9 digits
140
- return cleanValue.length === 9 && /^082[2-57-9]\d{5}$/.test(cleanValue)
137
+ // Kinmen: 082 + 6 digits, total 9 digits
138
+ return cleanValue.length === 9 && /^082\d{6}$/.test(cleanValue)
141
139
  }
142
140
  if (areaCode3 === "089") {
143
- // Taitung: 089 + 6 digits (2~9+5D), total 9 digits
144
- return cleanValue.length === 9 && /^089[2-9]\d{5}$/.test(cleanValue)
141
+ // Taitung: 089 + 6 digits, total 9 digits
142
+ return cleanValue.length === 9 && /^089\d{6}$/.test(cleanValue)
145
143
  }
146
144
 
147
145
  // Check 2-digit area codes
148
146
  const areaCode2 = cleanValue.substring(0, 2)
149
147
 
150
148
  if (areaCode2 === "02") {
151
- // Taipei, New Taipei, Keelung: 02 + 8 digits (2&3&5~8+7D), total 10 digits
152
- return cleanValue.length === 10 && /^02[235-8]\d{7}$/.test(cleanValue)
149
+ // Taipei, New Taipei, Keelung: 02 + 8 digits, total 10 digits
150
+ // User number must start with 2-9 (not 0 or 1)
151
+ const firstDigit = cleanValue[2]
152
+ if (firstDigit === "0" || firstDigit === "1") {
153
+ return false
154
+ }
155
+ return cleanValue.length === 10 && /^02[2-9]\d{7}$/.test(cleanValue)
156
+ }
157
+ if (areaCode2 === "03") {
158
+ // Taoyuan, Hsinchu, Yilan, Hualien: 03 + 7-8 digits, total 9-10 digits
159
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^03\d{7,8}$/.test(cleanValue)
153
160
  }
154
- if (["03", "04", "05", "06"].includes(areaCode2)) {
155
- // Taoyuan/Hsinchu/Yilan/Hualien (03), Taichung/Changhua (04),
156
- // Yunlin/Chiayi (05), Tainan (06): 7 digits, total 9 digits
157
- return cleanValue.length === 9
161
+ if (areaCode2 === "04") {
162
+ // Taichung, Changhua, Nantou: 04 + 7-8 digits, total 9-10 digits
163
+ return (cleanValue.length === 9 || cleanValue.length === 10) && /^04\d{7,8}$/.test(cleanValue)
164
+ }
165
+ if (areaCode2 === "05") {
166
+ // Yunlin, Chiayi: 05 + 7 digits, total 9 digits
167
+ return cleanValue.length === 9 && /^05\d{7}$/.test(cleanValue)
168
+ }
169
+ if (areaCode2 === "06") {
170
+ // Tainan: 06 + 7 digits, total 9 digits
171
+ return cleanValue.length === 9 && /^06\d{7}$/.test(cleanValue)
158
172
  }
159
173
  if (areaCode2 === "07") {
160
- // Kaohsiung: 07 + 7 digits (2~9+6D), total 9 digits
174
+ // Kaohsiung: 07 + 7 digits, total 9 digits
175
+ // User number must start with 2-9 (not 0 or 1)
176
+ const firstDigit = cleanValue[2]
177
+ if (firstDigit === "0" || firstDigit === "1") {
178
+ return false
179
+ }
161
180
  return cleanValue.length === 9 && /^07[2-9]\d{6}$/.test(cleanValue)
162
181
  }
163
182
  if (areaCode2 === "08") {
164
- // Pingtung: 08 + 7 digits (4&7&8+6D), total 9 digits
183
+ // Pingtung: 08 + 7 digits, total 9 digits
184
+ // User number must start with 4, 7, or 8 (format: 4&7&8+6D)
185
+ const firstDigit = cleanValue[2]
186
+ if (firstDigit !== "4" && firstDigit !== "7" && firstDigit !== "8") {
187
+ return false // Invalid first digit for 08 area code
188
+ }
165
189
  return cleanValue.length === 9 && /^08[478]\d{6}$/.test(cleanValue)
166
190
  }
167
191
 
@@ -20,6 +20,7 @@ describe("Taiwan twTel(true) validator", () => {
20
20
  // Taichung (04) - requires 9 digits total
21
21
  expect(schema.parse("041234567")).toBe("041234567") // 04-123-4567 (9 digits)
22
22
  expect(schema.parse("043456789")).toBe("043456789") // 04-345-6789 (9 digits)
23
+ expect(schema.parse("0423288882")).toBe("0423288882") // 04-232-88882 (10 digits)
23
24
 
24
25
  // Tainan (06) - requires 9 digits total
25
26
  expect(schema.parse("061234567")).toBe("061234567") // 06-123-4567 (9 digits)