@hy_ong/zod-kit 0.2.0 → 0.2.2
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/.github/workflows/ci.yml +24 -0
- package/CLAUDE.md +64 -22
- package/dist/chunk-2SWEVDFZ.js +134 -0
- package/dist/chunk-32JI34CV.cjs +146 -0
- package/dist/chunk-42C5OHRK.js +71 -0
- package/dist/chunk-46VAH2BJ.js +160 -0
- package/dist/chunk-5JGTDL3Y.js +87 -0
- package/dist/chunk-5LEXCVLX.js +257 -0
- package/dist/chunk-6AAP4LPF.js +2606 -0
- package/dist/chunk-B4EZYZOK.cjs +215 -0
- package/dist/chunk-COYKBWTI.js +161 -0
- package/dist/chunk-DFJZ3NS2.cjs +151 -0
- package/dist/chunk-EDHT4LPO.js +118 -0
- package/dist/chunk-EGHL277K.cjs +165 -0
- package/dist/chunk-ERH4NIMU.cjs +69 -0
- package/dist/chunk-FM3EZ72O.js +165 -0
- package/dist/chunk-GJIRDBZJ.cjs +90 -0
- package/dist/chunk-H2XTEM4M.js +696 -0
- package/dist/chunk-HMSM6FFA.cjs +181 -0
- package/dist/chunk-HTEHINI7.cjs +177 -0
- package/dist/chunk-JOLSGZGN.cjs +696 -0
- package/dist/chunk-JXY7APBU.js +69 -0
- package/dist/chunk-K2UOY6TB.js +136 -0
- package/dist/chunk-KFOHKTFD.js +61 -0
- package/dist/chunk-L4HSIKTU.cjs +135 -0
- package/dist/chunk-LH7ZB4BK.js +124 -0
- package/dist/chunk-LL4ZWLGO.js +90 -0
- package/dist/chunk-M6MTP3NY.cjs +99 -0
- package/dist/chunk-MHJFYYGV.js +215 -0
- package/dist/chunk-MINMXGW3.js +135 -0
- package/dist/chunk-MM7IL2RG.js +181 -0
- package/dist/chunk-OPQJWHXN.cjs +301 -0
- package/dist/chunk-ORFHDJII.cjs +136 -0
- package/dist/chunk-ORVV4MCF.cjs +87 -0
- package/dist/chunk-QICQ6YEY.js +75 -0
- package/dist/chunk-RKUQREMW.js +127 -0
- package/dist/chunk-RO47DKQG.js +146 -0
- package/dist/chunk-RRPXIRTQ.cjs +257 -0
- package/dist/chunk-RYFG2GKM.cjs +118 -0
- package/dist/chunk-STNHTRG7.cjs +124 -0
- package/dist/chunk-TFGS34VD.cjs +71 -0
- package/dist/chunk-TQXDUMML.cjs +61 -0
- package/dist/chunk-UBK3VCVH.cjs +134 -0
- package/dist/chunk-UCOXAZJF.cjs +2606 -0
- package/dist/chunk-UQZKFAFX.js +130 -0
- package/dist/chunk-VB2KV2ZM.cjs +130 -0
- package/dist/chunk-WABKPFPK.js +151 -0
- package/dist/chunk-WDI4QJMQ.js +177 -0
- package/dist/chunk-YDH3L27K.cjs +127 -0
- package/dist/chunk-YIM3D2AD.js +99 -0
- package/dist/chunk-YPSEIDUR.cjs +160 -0
- package/dist/chunk-ZNJLWJX3.cjs +75 -0
- package/dist/chunk-ZTFCJCPO.cjs +161 -0
- package/dist/chunk-ZXUMK2RR.js +301 -0
- package/dist/common/boolean.cjs +7 -0
- package/dist/common/boolean.d.cts +119 -0
- package/dist/common/boolean.d.ts +119 -0
- package/dist/common/boolean.js +7 -0
- package/dist/common/color.cjs +9 -0
- package/dist/common/color.d.cts +26 -0
- package/dist/common/color.d.ts +26 -0
- package/dist/common/color.js +9 -0
- package/dist/common/coordinate.cjs +11 -0
- package/dist/common/coordinate.d.cts +23 -0
- package/dist/common/coordinate.d.ts +23 -0
- package/dist/common/coordinate.js +11 -0
- package/dist/common/credit-card.cjs +11 -0
- package/dist/common/credit-card.d.cts +22 -0
- package/dist/common/credit-card.d.ts +22 -0
- package/dist/common/credit-card.js +11 -0
- package/dist/common/date.cjs +7 -0
- package/dist/common/date.d.cts +174 -0
- package/dist/common/date.d.ts +174 -0
- package/dist/common/date.js +7 -0
- package/dist/common/datetime.cjs +15 -0
- package/dist/common/datetime.d.cts +301 -0
- package/dist/common/datetime.d.ts +301 -0
- package/dist/common/datetime.js +15 -0
- package/dist/common/email.cjs +7 -0
- package/dist/common/email.d.cts +149 -0
- package/dist/common/email.d.ts +149 -0
- package/dist/common/email.js +7 -0
- package/dist/common/file.cjs +7 -0
- package/dist/common/file.d.cts +178 -0
- package/dist/common/file.d.ts +178 -0
- package/dist/common/file.js +7 -0
- package/dist/common/id.cjs +13 -0
- package/dist/common/id.d.cts +288 -0
- package/dist/common/id.d.ts +288 -0
- package/dist/common/id.js +13 -0
- package/dist/common/ip.cjs +11 -0
- package/dist/common/ip.d.cts +25 -0
- package/dist/common/ip.d.ts +25 -0
- package/dist/common/ip.js +11 -0
- package/dist/common/number.cjs +7 -0
- package/dist/common/number.d.cts +167 -0
- package/dist/common/number.d.ts +167 -0
- package/dist/common/number.js +7 -0
- package/dist/common/password.cjs +7 -0
- package/dist/common/password.d.cts +192 -0
- package/dist/common/password.d.ts +192 -0
- package/dist/common/password.js +7 -0
- package/dist/common/text.cjs +7 -0
- package/dist/common/text.d.cts +156 -0
- package/dist/common/text.d.ts +156 -0
- package/dist/common/text.js +7 -0
- package/dist/common/time.cjs +15 -0
- package/dist/common/time.d.cts +268 -0
- package/dist/common/time.d.ts +268 -0
- package/dist/common/time.js +15 -0
- package/dist/common/url.cjs +7 -0
- package/dist/common/url.d.cts +196 -0
- package/dist/common/url.d.ts +196 -0
- package/dist/common/url.js +7 -0
- package/dist/config-CABSSvAp.d.cts +5 -0
- package/dist/config-CABSSvAp.d.ts +5 -0
- package/dist/index.cjs +180 -5255
- package/dist/index.d.cts +28 -3150
- package/dist/index.d.ts +28 -3150
- package/dist/index.js +135 -5131
- package/dist/taiwan/bank-account.cjs +11 -0
- package/dist/taiwan/bank-account.d.cts +22 -0
- package/dist/taiwan/bank-account.d.ts +22 -0
- package/dist/taiwan/bank-account.js +11 -0
- package/dist/taiwan/business-id.cjs +9 -0
- package/dist/taiwan/business-id.d.cts +133 -0
- package/dist/taiwan/business-id.d.ts +133 -0
- package/dist/taiwan/business-id.js +9 -0
- package/dist/taiwan/fax.cjs +9 -0
- package/dist/taiwan/fax.d.cts +157 -0
- package/dist/taiwan/fax.d.ts +157 -0
- package/dist/taiwan/fax.js +9 -0
- package/dist/taiwan/invoice.cjs +9 -0
- package/dist/taiwan/invoice.d.cts +17 -0
- package/dist/taiwan/invoice.d.ts +17 -0
- package/dist/taiwan/invoice.js +9 -0
- package/dist/taiwan/license-plate.cjs +9 -0
- package/dist/taiwan/license-plate.d.cts +19 -0
- package/dist/taiwan/license-plate.d.ts +19 -0
- package/dist/taiwan/license-plate.js +9 -0
- package/dist/taiwan/mobile.cjs +9 -0
- package/dist/taiwan/mobile.d.cts +146 -0
- package/dist/taiwan/mobile.d.ts +146 -0
- package/dist/taiwan/mobile.js +9 -0
- package/dist/taiwan/national-id.cjs +15 -0
- package/dist/taiwan/national-id.d.cts +214 -0
- package/dist/taiwan/national-id.d.ts +214 -0
- package/dist/taiwan/national-id.js +15 -0
- package/dist/taiwan/passport.cjs +9 -0
- package/dist/taiwan/passport.d.cts +19 -0
- package/dist/taiwan/passport.d.ts +19 -0
- package/dist/taiwan/passport.js +9 -0
- package/dist/taiwan/postal-code.cjs +17 -0
- package/dist/taiwan/postal-code.d.cts +237 -0
- package/dist/taiwan/postal-code.d.ts +237 -0
- package/dist/taiwan/postal-code.js +17 -0
- package/dist/taiwan/tel.cjs +9 -0
- package/dist/taiwan/tel.d.cts +162 -0
- package/dist/taiwan/tel.d.ts +162 -0
- package/dist/taiwan/tel.js +9 -0
- package/package.json +132 -6
- package/src/i18n/locales/en-GB.json +51 -0
- package/src/i18n/locales/en-US.json +52 -1
- package/src/i18n/locales/id-ID.json +51 -0
- package/src/i18n/locales/ja-JP.json +51 -0
- package/src/i18n/locales/ko-KR.json +51 -0
- package/src/i18n/locales/ms-MY.json +51 -0
- package/src/i18n/locales/th-TH.json +51 -0
- package/src/i18n/locales/vi-VN.json +51 -0
- package/src/i18n/locales/zh-CN.json +51 -0
- package/src/i18n/locales/zh-TW.json +51 -0
- package/src/index.ts +10 -2
- package/src/validators/common/color.ts +192 -0
- package/src/validators/common/coordinate.ts +159 -0
- package/src/validators/common/credit-card.ts +134 -0
- package/src/validators/common/id.ts +45 -3
- package/src/validators/common/ip.ts +210 -0
- package/src/validators/taiwan/bank-account.ts +176 -0
- package/src/validators/taiwan/invoice.ts +84 -0
- package/src/validators/taiwan/license-plate.ts +110 -0
- package/src/validators/taiwan/passport.ts +103 -0
- package/tests/common/color.test.ts +587 -0
- package/tests/common/coordinate.test.ts +345 -0
- package/tests/common/credit-card.test.ts +378 -0
- package/tests/common/id.test.ts +68 -3
- package/tests/common/ip.test.ts +419 -0
- package/tests/taiwan/bank-account.test.ts +286 -0
- package/tests/taiwan/invoice.test.ts +227 -0
- package/tests/taiwan/license-plate.test.ts +280 -0
- package/tests/taiwan/passport.test.ts +277 -0
- package/tsup.config.ts +36 -0
|
@@ -75,6 +75,14 @@
|
|
|
75
75
|
"maxLength": "ต้องไม่เกิน ${maxLength} ตัวอักษร",
|
|
76
76
|
"numeric": "ต้องเป็น ID ตัวเลข",
|
|
77
77
|
"uuid": "ต้องเป็น UUID ที่ถูกต้อง",
|
|
78
|
+
"uuidv1": "ต้องเป็น UUID v1 ที่ถูกต้อง",
|
|
79
|
+
"uuidv2": "ต้องเป็น UUID v2 ที่ถูกต้อง",
|
|
80
|
+
"uuidv3": "ต้องเป็น UUID v3 ที่ถูกต้อง",
|
|
81
|
+
"uuidv4": "ต้องเป็น UUID v4 ที่ถูกต้อง",
|
|
82
|
+
"uuidv5": "ต้องเป็น UUID v5 ที่ถูกต้อง",
|
|
83
|
+
"uuidv6": "ต้องเป็น UUID v6 ที่ถูกต้อง",
|
|
84
|
+
"uuidv7": "ต้องเป็น UUID v7 ที่ถูกต้อง",
|
|
85
|
+
"uuidv8": "ต้องเป็น UUID v8 ที่ถูกต้อง",
|
|
78
86
|
"objectId": "ต้องเป็น MongoDB ObjectId ที่ถูกต้อง",
|
|
79
87
|
"nanoid": "ต้องเป็น Nano ID ที่ถูกต้อง",
|
|
80
88
|
"snowflake": "ต้องเป็น Snowflake ID ที่ถูกต้อง",
|
|
@@ -162,6 +170,31 @@
|
|
|
162
170
|
"videoOnly": "อนุญาตเฉพาะไฟล์วิดีโอ",
|
|
163
171
|
"audioOnly": "อนุญาตเฉพาะไฟล์เสียง",
|
|
164
172
|
"archiveOnly": "อนุญาตเฉพาะไฟล์บีบอัด"
|
|
173
|
+
},
|
|
174
|
+
"creditCard": {
|
|
175
|
+
"required": "จำเป็นต้องกรอก",
|
|
176
|
+
"invalid": "หมายเลขบัตรเครดิตไม่ถูกต้อง",
|
|
177
|
+
"notInWhitelist": "หมายเลขบัตรเครดิตไม่อยู่ในรายการที่อนุญาต"
|
|
178
|
+
},
|
|
179
|
+
"ip": {
|
|
180
|
+
"required": "จำเป็นต้องกรอก",
|
|
181
|
+
"invalid": "ที่อยู่ IP ไม่ถูกต้อง",
|
|
182
|
+
"notIPv4": "ต้องเป็นที่อยู่ IPv4 ที่ถูกต้อง",
|
|
183
|
+
"notIPv6": "ต้องเป็นที่อยู่ IPv6 ที่ถูกต้อง",
|
|
184
|
+
"notInWhitelist": "ที่อยู่ IP ไม่อยู่ในรายการที่อนุญาต"
|
|
185
|
+
},
|
|
186
|
+
"color": {
|
|
187
|
+
"required": "จำเป็นต้องกรอก",
|
|
188
|
+
"invalid": "รูปแบบสีไม่ถูกต้อง",
|
|
189
|
+
"notHex": "ต้องเป็นสี hex ที่ถูกต้อง",
|
|
190
|
+
"notRgb": "ต้องเป็นสี RGB ที่ถูกต้อง",
|
|
191
|
+
"notHsl": "ต้องเป็นสี HSL ที่ถูกต้อง"
|
|
192
|
+
},
|
|
193
|
+
"coordinate": {
|
|
194
|
+
"required": "จำเป็นต้องกรอก",
|
|
195
|
+
"invalid": "พิกัดไม่ถูกต้อง",
|
|
196
|
+
"invalidLatitude": "ละติจูดต้องอยู่ระหว่าง -90 ถึง 90",
|
|
197
|
+
"invalidLongitude": "ลองจิจูดต้องอยู่ระหว่าง -180 ถึง 180"
|
|
165
198
|
}
|
|
166
199
|
},
|
|
167
200
|
"taiwan": {
|
|
@@ -199,6 +232,24 @@
|
|
|
199
232
|
"format6Only": "อนุญาตเฉพาะรหัสไปรษณีย์ 6 หลัก",
|
|
200
233
|
"invalidSuffix": "ส่วนท้ายรหัสไปรษณีย์ไม่ถูกต้อง - 5 หลักต้องเป็น 01-99 หรือ 6 หลักต้องเป็น 001-999",
|
|
201
234
|
"deprecated5Digit": "รหัสไปรษณีย์ 5 หลักถูกยกเลิกและไม่รองรับอีกต่อไป"
|
|
235
|
+
},
|
|
236
|
+
"invoice": {
|
|
237
|
+
"required": "จำเป็นต้องกรอก",
|
|
238
|
+
"invalid": "หมายเลขใบกำกับภาษีไต้หวันไม่ถูกต้อง"
|
|
239
|
+
},
|
|
240
|
+
"licensePlate": {
|
|
241
|
+
"required": "จำเป็นต้องกรอก",
|
|
242
|
+
"invalid": "หมายเลขทะเบียนรถไต้หวันไม่ถูกต้อง"
|
|
243
|
+
},
|
|
244
|
+
"bankAccount": {
|
|
245
|
+
"required": "จำเป็นต้องกรอก",
|
|
246
|
+
"invalid": "บัญชีธนาคารไต้หวันไม่ถูกต้อง",
|
|
247
|
+
"invalidBankCode": "รหัสธนาคารไม่ถูกต้อง",
|
|
248
|
+
"invalidAccountNumber": "หมายเลขบัญชีไม่ถูกต้อง"
|
|
249
|
+
},
|
|
250
|
+
"passport": {
|
|
251
|
+
"required": "จำเป็นต้องกรอก",
|
|
252
|
+
"invalid": "หมายเลขหนังสือเดินทางไต้หวันไม่ถูกต้อง"
|
|
202
253
|
}
|
|
203
254
|
}
|
|
204
255
|
}
|
|
@@ -75,6 +75,14 @@
|
|
|
75
75
|
"maxLength": "Phải có tối đa ${maxLength} ký tự",
|
|
76
76
|
"numeric": "Phải là ID dạng số",
|
|
77
77
|
"uuid": "Phải là UUID hợp lệ",
|
|
78
|
+
"uuidv1": "Phải là UUID v1 hợp lệ",
|
|
79
|
+
"uuidv2": "Phải là UUID v2 hợp lệ",
|
|
80
|
+
"uuidv3": "Phải là UUID v3 hợp lệ",
|
|
81
|
+
"uuidv4": "Phải là UUID v4 hợp lệ",
|
|
82
|
+
"uuidv5": "Phải là UUID v5 hợp lệ",
|
|
83
|
+
"uuidv6": "Phải là UUID v6 hợp lệ",
|
|
84
|
+
"uuidv7": "Phải là UUID v7 hợp lệ",
|
|
85
|
+
"uuidv8": "Phải là UUID v8 hợp lệ",
|
|
78
86
|
"objectId": "Phải là MongoDB ObjectId hợp lệ",
|
|
79
87
|
"nanoid": "Phải là Nano ID hợp lệ",
|
|
80
88
|
"snowflake": "Phải là Snowflake ID hợp lệ",
|
|
@@ -162,6 +170,31 @@
|
|
|
162
170
|
"videoOnly": "Chỉ cho phép tệp video",
|
|
163
171
|
"audioOnly": "Chỉ cho phép tệp âm thanh",
|
|
164
172
|
"archiveOnly": "Chỉ cho phép tệp nén"
|
|
173
|
+
},
|
|
174
|
+
"creditCard": {
|
|
175
|
+
"required": "Bắt buộc",
|
|
176
|
+
"invalid": "Số thẻ tín dụng không hợp lệ",
|
|
177
|
+
"notInWhitelist": "Số thẻ tín dụng không nằm trong danh sách cho phép"
|
|
178
|
+
},
|
|
179
|
+
"ip": {
|
|
180
|
+
"required": "Bắt buộc",
|
|
181
|
+
"invalid": "Địa chỉ IP không hợp lệ",
|
|
182
|
+
"notIPv4": "Phải là địa chỉ IPv4 hợp lệ",
|
|
183
|
+
"notIPv6": "Phải là địa chỉ IPv6 hợp lệ",
|
|
184
|
+
"notInWhitelist": "Địa chỉ IP không nằm trong danh sách cho phép"
|
|
185
|
+
},
|
|
186
|
+
"color": {
|
|
187
|
+
"required": "Bắt buộc",
|
|
188
|
+
"invalid": "Định dạng màu không hợp lệ",
|
|
189
|
+
"notHex": "Phải là màu hex hợp lệ",
|
|
190
|
+
"notRgb": "Phải là màu RGB hợp lệ",
|
|
191
|
+
"notHsl": "Phải là màu HSL hợp lệ"
|
|
192
|
+
},
|
|
193
|
+
"coordinate": {
|
|
194
|
+
"required": "Bắt buộc",
|
|
195
|
+
"invalid": "Tọa độ không hợp lệ",
|
|
196
|
+
"invalidLatitude": "Vĩ độ phải từ -90 đến 90",
|
|
197
|
+
"invalidLongitude": "Kinh độ phải từ -180 đến 180"
|
|
165
198
|
}
|
|
166
199
|
},
|
|
167
200
|
"taiwan": {
|
|
@@ -199,6 +232,24 @@
|
|
|
199
232
|
"format6Only": "Chỉ cho phép mã bưu chính 6 chữ số",
|
|
200
233
|
"invalidSuffix": "Hậu tố mã bưu chính không hợp lệ - 5 chữ số phải là 01-99 hoặc 6 chữ số phải là 001-999",
|
|
201
234
|
"deprecated5Digit": "Mã bưu chính 5 chữ số đã ngừng sử dụng và không còn được hỗ trợ"
|
|
235
|
+
},
|
|
236
|
+
"invoice": {
|
|
237
|
+
"required": "Bắt buộc",
|
|
238
|
+
"invalid": "Số hóa đơn thống nhất Đài Loan không hợp lệ"
|
|
239
|
+
},
|
|
240
|
+
"licensePlate": {
|
|
241
|
+
"required": "Bắt buộc",
|
|
242
|
+
"invalid": "Số biển số xe Đài Loan không hợp lệ"
|
|
243
|
+
},
|
|
244
|
+
"bankAccount": {
|
|
245
|
+
"required": "Bắt buộc",
|
|
246
|
+
"invalid": "Tài khoản ngân hàng Đài Loan không hợp lệ",
|
|
247
|
+
"invalidBankCode": "Mã ngân hàng không hợp lệ",
|
|
248
|
+
"invalidAccountNumber": "Số tài khoản không hợp lệ"
|
|
249
|
+
},
|
|
250
|
+
"passport": {
|
|
251
|
+
"required": "Bắt buộc",
|
|
252
|
+
"invalid": "Số hộ chiếu Đài Loan không hợp lệ"
|
|
202
253
|
}
|
|
203
254
|
}
|
|
204
255
|
}
|
|
@@ -75,6 +75,14 @@
|
|
|
75
75
|
"maxLength": "长度最多 ${maxLength} 个字符",
|
|
76
76
|
"numeric": "必须为数字 ID",
|
|
77
77
|
"uuid": "必须为有效的 UUID",
|
|
78
|
+
"uuidv1": "必须为有效的 UUID v1",
|
|
79
|
+
"uuidv2": "必须为有效的 UUID v2",
|
|
80
|
+
"uuidv3": "必须为有效的 UUID v3",
|
|
81
|
+
"uuidv4": "必须为有效的 UUID v4",
|
|
82
|
+
"uuidv5": "必须为有效的 UUID v5",
|
|
83
|
+
"uuidv6": "必须为有效的 UUID v6",
|
|
84
|
+
"uuidv7": "必须为有效的 UUID v7",
|
|
85
|
+
"uuidv8": "必须为有效的 UUID v8",
|
|
78
86
|
"objectId": "必须为有效的 MongoDB ObjectId",
|
|
79
87
|
"nanoid": "必须为有效的 Nano ID",
|
|
80
88
|
"snowflake": "必须为有效的 Snowflake ID",
|
|
@@ -162,6 +170,31 @@
|
|
|
162
170
|
"videoOnly": "仅允许视频文件",
|
|
163
171
|
"audioOnly": "仅允许音频文件",
|
|
164
172
|
"archiveOnly": "仅允许压缩文件"
|
|
173
|
+
},
|
|
174
|
+
"creditCard": {
|
|
175
|
+
"required": "必填",
|
|
176
|
+
"invalid": "无效的信用卡号码",
|
|
177
|
+
"notInWhitelist": "信用卡号码不在允许的列表中"
|
|
178
|
+
},
|
|
179
|
+
"ip": {
|
|
180
|
+
"required": "必填",
|
|
181
|
+
"invalid": "无效的 IP 地址",
|
|
182
|
+
"notIPv4": "必须为有效的 IPv4 地址",
|
|
183
|
+
"notIPv6": "必须为有效的 IPv6 地址",
|
|
184
|
+
"notInWhitelist": "IP 地址不在允许的列表中"
|
|
185
|
+
},
|
|
186
|
+
"color": {
|
|
187
|
+
"required": "必填",
|
|
188
|
+
"invalid": "无效的颜色格式",
|
|
189
|
+
"notHex": "必须为有效的十六进制颜色",
|
|
190
|
+
"notRgb": "必须为有效的 RGB 颜色",
|
|
191
|
+
"notHsl": "必须为有效的 HSL 颜色"
|
|
192
|
+
},
|
|
193
|
+
"coordinate": {
|
|
194
|
+
"required": "必填",
|
|
195
|
+
"invalid": "无效的坐标",
|
|
196
|
+
"invalidLatitude": "纬度必须介于 -90 与 90 之间",
|
|
197
|
+
"invalidLongitude": "经度必须介于 -180 与 180 之间"
|
|
165
198
|
}
|
|
166
199
|
},
|
|
167
200
|
"taiwan": {
|
|
@@ -199,6 +232,24 @@
|
|
|
199
232
|
"format6Only": "仅允许 6 位邮政编码",
|
|
200
233
|
"invalidSuffix": "无效的邮政编码后缀 - 5 位格式须为 01-99,6 位格式须为 001-999",
|
|
201
234
|
"deprecated5Digit": "5 位邮政编码已弃用且不再支持"
|
|
235
|
+
},
|
|
236
|
+
"invoice": {
|
|
237
|
+
"required": "必填",
|
|
238
|
+
"invalid": "无效的统一发票号码"
|
|
239
|
+
},
|
|
240
|
+
"licensePlate": {
|
|
241
|
+
"required": "必填",
|
|
242
|
+
"invalid": "无效的车牌号码"
|
|
243
|
+
},
|
|
244
|
+
"bankAccount": {
|
|
245
|
+
"required": "必填",
|
|
246
|
+
"invalid": "无效的银行账号",
|
|
247
|
+
"invalidBankCode": "无效的银行代码",
|
|
248
|
+
"invalidAccountNumber": "无效的账号号码"
|
|
249
|
+
},
|
|
250
|
+
"passport": {
|
|
251
|
+
"required": "必填",
|
|
252
|
+
"invalid": "无效的护照号码"
|
|
202
253
|
}
|
|
203
254
|
}
|
|
204
255
|
}
|
|
@@ -75,6 +75,14 @@
|
|
|
75
75
|
"maxLength": "長度最多 ${maxLength} 字元",
|
|
76
76
|
"numeric": "必須為數字 ID",
|
|
77
77
|
"uuid": "必須為有效的 UUID",
|
|
78
|
+
"uuidv1": "必須為有效的 UUID v1",
|
|
79
|
+
"uuidv2": "必須為有效的 UUID v2",
|
|
80
|
+
"uuidv3": "必須為有效的 UUID v3",
|
|
81
|
+
"uuidv4": "必須為有效的 UUID v4",
|
|
82
|
+
"uuidv5": "必須為有效的 UUID v5",
|
|
83
|
+
"uuidv6": "必須為有效的 UUID v6",
|
|
84
|
+
"uuidv7": "必須為有效的 UUID v7",
|
|
85
|
+
"uuidv8": "必須為有效的 UUID v8",
|
|
78
86
|
"objectId": "必須為有效的 MongoDB ObjectId",
|
|
79
87
|
"nanoid": "必須為有效的 Nano ID",
|
|
80
88
|
"snowflake": "必須為有效的 Snowflake ID",
|
|
@@ -162,6 +170,31 @@
|
|
|
162
170
|
"videoOnly": "僅允許影片檔案",
|
|
163
171
|
"audioOnly": "僅允許音訊檔案",
|
|
164
172
|
"archiveOnly": "僅允許壓縮檔案"
|
|
173
|
+
},
|
|
174
|
+
"creditCard": {
|
|
175
|
+
"required": "必填",
|
|
176
|
+
"invalid": "無效的信用卡號碼",
|
|
177
|
+
"notInWhitelist": "信用卡號碼不在允許的清單中"
|
|
178
|
+
},
|
|
179
|
+
"ip": {
|
|
180
|
+
"required": "必填",
|
|
181
|
+
"invalid": "無效的 IP 位址",
|
|
182
|
+
"notIPv4": "必須為有效的 IPv4 位址",
|
|
183
|
+
"notIPv6": "必須為有效的 IPv6 位址",
|
|
184
|
+
"notInWhitelist": "IP 位址不在允許的清單中"
|
|
185
|
+
},
|
|
186
|
+
"color": {
|
|
187
|
+
"required": "必填",
|
|
188
|
+
"invalid": "無效的顏色格式",
|
|
189
|
+
"notHex": "必須為有效的十六進位顏色",
|
|
190
|
+
"notRgb": "必須為有效的 RGB 顏色",
|
|
191
|
+
"notHsl": "必須為有效的 HSL 顏色"
|
|
192
|
+
},
|
|
193
|
+
"coordinate": {
|
|
194
|
+
"required": "必填",
|
|
195
|
+
"invalid": "無效的座標",
|
|
196
|
+
"invalidLatitude": "緯度必須介於 -90 與 90 之間",
|
|
197
|
+
"invalidLongitude": "經度必須介於 -180 與 180 之間"
|
|
165
198
|
}
|
|
166
199
|
},
|
|
167
200
|
"taiwan": {
|
|
@@ -199,6 +232,24 @@
|
|
|
199
232
|
"format6Only": "僅允許 6 碼郵遞區號",
|
|
200
233
|
"invalidSuffix": "無效的郵遞區號後碼 - 5 碼格式須為 01-99,6 碼格式須為 001-999",
|
|
201
234
|
"deprecated5Digit": "5 碼郵遞區號已棄用且不再支援"
|
|
235
|
+
},
|
|
236
|
+
"invoice": {
|
|
237
|
+
"required": "必填",
|
|
238
|
+
"invalid": "無效的統一發票號碼"
|
|
239
|
+
},
|
|
240
|
+
"licensePlate": {
|
|
241
|
+
"required": "必填",
|
|
242
|
+
"invalid": "無效的車牌號碼"
|
|
243
|
+
},
|
|
244
|
+
"bankAccount": {
|
|
245
|
+
"required": "必填",
|
|
246
|
+
"invalid": "無效的銀行帳號",
|
|
247
|
+
"invalidBankCode": "無效的銀行代碼",
|
|
248
|
+
"invalidAccountNumber": "無效的帳號號碼"
|
|
249
|
+
},
|
|
250
|
+
"passport": {
|
|
251
|
+
"required": "必填",
|
|
252
|
+
"invalid": "無效的護照號碼"
|
|
202
253
|
}
|
|
203
254
|
}
|
|
204
255
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
export * from "./validators/common/boolean"
|
|
2
|
+
export * from "./validators/common/color"
|
|
3
|
+
export * from "./validators/common/coordinate"
|
|
4
|
+
export * from "./validators/common/credit-card"
|
|
2
5
|
export * from "./validators/common/date"
|
|
3
6
|
export * from "./validators/common/datetime"
|
|
4
7
|
export * from "./validators/common/email"
|
|
5
8
|
export * from "./validators/common/file"
|
|
6
9
|
export * from "./validators/common/id"
|
|
10
|
+
export * from "./validators/common/ip"
|
|
7
11
|
export * from "./validators/common/number"
|
|
8
12
|
export * from "./validators/common/password"
|
|
9
13
|
export * from "./validators/common/text"
|
|
10
14
|
export * from "./validators/common/time"
|
|
11
15
|
export * from "./validators/common/url"
|
|
16
|
+
export * from "./validators/taiwan/bank-account"
|
|
12
17
|
export * from "./validators/taiwan/business-id"
|
|
13
|
-
export * from "./validators/taiwan/
|
|
18
|
+
export * from "./validators/taiwan/fax"
|
|
19
|
+
export * from "./validators/taiwan/invoice"
|
|
20
|
+
export * from "./validators/taiwan/license-plate"
|
|
14
21
|
export * from "./validators/taiwan/mobile"
|
|
22
|
+
export * from "./validators/taiwan/national-id"
|
|
23
|
+
export * from "./validators/taiwan/passport"
|
|
15
24
|
export * from "./validators/taiwan/postal-code"
|
|
16
25
|
export * from "./validators/taiwan/tel"
|
|
17
|
-
export * from "./validators/taiwan/fax"
|
|
18
26
|
export * from "./config"
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { z, ZodNullable, ZodString } from "zod"
|
|
2
|
+
import { t } from "../../i18n"
|
|
3
|
+
import { getLocale, type Locale } from "../../config"
|
|
4
|
+
|
|
5
|
+
export type ColorFormat = "hex" | "rgb" | "hsl" | "any"
|
|
6
|
+
|
|
7
|
+
export type ColorMessages = {
|
|
8
|
+
required?: string
|
|
9
|
+
invalid?: string
|
|
10
|
+
notHex?: string
|
|
11
|
+
notRgb?: string
|
|
12
|
+
notHsl?: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type ColorOptions<IsRequired extends boolean = true> = {
|
|
16
|
+
format?: ColorFormat | ColorFormat[]
|
|
17
|
+
allowAlpha?: boolean
|
|
18
|
+
transform?: (value: string) => string
|
|
19
|
+
defaultValue?: IsRequired extends true ? string : string | null
|
|
20
|
+
i18n?: Partial<Record<Locale, Partial<ColorMessages>>>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type ColorSchema<IsRequired extends boolean> = IsRequired extends true ? ZodString : ZodNullable<ZodString>
|
|
24
|
+
|
|
25
|
+
const HEX_RGB = /^#[0-9a-f]{3}$/i
|
|
26
|
+
const HEX_RRGGBB = /^#[0-9a-f]{6}$/i
|
|
27
|
+
const HEX_RRGGBBAA = /^#[0-9a-f]{8}$/i
|
|
28
|
+
|
|
29
|
+
function isValidByte(n: number): boolean {
|
|
30
|
+
return Number.isInteger(n) && n >= 0 && n <= 255
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function isValidAlpha(n: number): boolean {
|
|
34
|
+
return n >= 0 && n <= 1
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function isValidHue(n: number): boolean {
|
|
38
|
+
return n >= 0 && n <= 360
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function isValidPercentage(n: number): boolean {
|
|
42
|
+
return n >= 0 && n <= 100
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function validateHex(value: string, allowAlpha: boolean): boolean {
|
|
46
|
+
if (HEX_RGB.test(value) || HEX_RRGGBB.test(value)) return true
|
|
47
|
+
if (allowAlpha && HEX_RRGGBBAA.test(value)) return true
|
|
48
|
+
return false
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function validateRgb(value: string, allowAlpha: boolean): boolean {
|
|
52
|
+
const rgbaMatch = value.match(/^rgba?\(\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)\s*(?:,\s*(-?\d+(?:\.\d+)?))?\s*\)$/)
|
|
53
|
+
if (!rgbaMatch) return false
|
|
54
|
+
|
|
55
|
+
const r = Number(rgbaMatch[1])
|
|
56
|
+
const g = Number(rgbaMatch[2])
|
|
57
|
+
const b = Number(rgbaMatch[3])
|
|
58
|
+
const a = rgbaMatch[4] !== undefined ? Number(rgbaMatch[4]) : undefined
|
|
59
|
+
|
|
60
|
+
if (!isValidByte(r) || !isValidByte(g) || !isValidByte(b)) return false
|
|
61
|
+
|
|
62
|
+
if (a !== undefined) {
|
|
63
|
+
if (!allowAlpha) return false
|
|
64
|
+
if (!isValidAlpha(a)) return false
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// If function name is "rgba", alpha must be present
|
|
68
|
+
if (value.startsWith("rgba(") && a === undefined) return false
|
|
69
|
+
// If function name is "rgb", alpha must not be present
|
|
70
|
+
if (value.startsWith("rgb(") && a !== undefined) return false
|
|
71
|
+
|
|
72
|
+
return true
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function validateHsl(value: string, allowAlpha: boolean): boolean {
|
|
76
|
+
const hslaMatch = value.match(/^hsla?\(\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*(?:,\s*(-?\d+(?:\.\d+)?))?\s*\)$/)
|
|
77
|
+
if (!hslaMatch) return false
|
|
78
|
+
|
|
79
|
+
const h = Number(hslaMatch[1])
|
|
80
|
+
const s = Number(hslaMatch[2])
|
|
81
|
+
const l = Number(hslaMatch[3])
|
|
82
|
+
const a = hslaMatch[4] !== undefined ? Number(hslaMatch[4]) : undefined
|
|
83
|
+
|
|
84
|
+
if (!isValidHue(h) || !isValidPercentage(s) || !isValidPercentage(l)) return false
|
|
85
|
+
|
|
86
|
+
if (a !== undefined) {
|
|
87
|
+
if (!allowAlpha) return false
|
|
88
|
+
if (!isValidAlpha(a)) return false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// If function name is "hsla", alpha must be present
|
|
92
|
+
if (value.startsWith("hsla(") && a === undefined) return false
|
|
93
|
+
// If function name is "hsl", alpha must not be present
|
|
94
|
+
if (value.startsWith("hsl(") && a !== undefined) return false
|
|
95
|
+
|
|
96
|
+
return true
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function validateColor(value: string, formats: ColorFormat[], allowAlpha: boolean): { valid: boolean; failedFormat?: ColorFormat } {
|
|
100
|
+
const hasAny = formats.includes("any")
|
|
101
|
+
|
|
102
|
+
if (hasAny) {
|
|
103
|
+
if (validateHex(value, allowAlpha)) return { valid: true }
|
|
104
|
+
if (validateRgb(value, allowAlpha)) return { valid: true }
|
|
105
|
+
if (validateHsl(value, allowAlpha)) return { valid: true }
|
|
106
|
+
return { valid: false }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
for (const format of formats) {
|
|
110
|
+
if (format === "hex" && validateHex(value, allowAlpha)) return { valid: true }
|
|
111
|
+
if (format === "rgb" && validateRgb(value, allowAlpha)) return { valid: true }
|
|
112
|
+
if (format === "hsl" && validateHsl(value, allowAlpha)) return { valid: true }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (formats.length === 1) {
|
|
116
|
+
return { valid: false, failedFormat: formats[0] }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return { valid: false }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function color<IsRequired extends boolean = false>(required?: IsRequired, options?: Omit<ColorOptions<IsRequired>, "required">): ColorSchema<IsRequired> {
|
|
123
|
+
const { format = "any", allowAlpha = true, transform, defaultValue, i18n } = options ?? {}
|
|
124
|
+
|
|
125
|
+
const isRequired = required ?? (false as IsRequired)
|
|
126
|
+
|
|
127
|
+
const actualDefaultValue = defaultValue ?? (isRequired ? "" : null)
|
|
128
|
+
|
|
129
|
+
const formats: ColorFormat[] = Array.isArray(format) ? format : [format]
|
|
130
|
+
|
|
131
|
+
const getMessage = (key: keyof ColorMessages, params?: Record<string, any>) => {
|
|
132
|
+
if (i18n) {
|
|
133
|
+
const currentLocale = getLocale()
|
|
134
|
+
const customMessages = i18n[currentLocale]
|
|
135
|
+
if (customMessages && customMessages[key]) {
|
|
136
|
+
const template = customMessages[key]!
|
|
137
|
+
return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "")
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return t(`common.color.${key}`, params)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const preprocessFn = (val: unknown) => {
|
|
144
|
+
if (val === "" || val === null || val === undefined) {
|
|
145
|
+
return actualDefaultValue
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let processed = String(val).trim()
|
|
149
|
+
|
|
150
|
+
if (processed === "" && !required) {
|
|
151
|
+
return null
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (transform) {
|
|
155
|
+
processed = transform(processed)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return processed
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const baseSchema = isRequired ? z.preprocess(preprocessFn, z.string()) : z.preprocess(preprocessFn, z.string().nullable())
|
|
162
|
+
|
|
163
|
+
const schema = baseSchema.superRefine((val, ctx) => {
|
|
164
|
+
if (val === null) return
|
|
165
|
+
|
|
166
|
+
if (isRequired && (val === "" || val === "null" || val === "undefined")) {
|
|
167
|
+
ctx.addIssue({ code: "custom", message: getMessage("required") })
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!isRequired && val === "") return
|
|
172
|
+
|
|
173
|
+
const result = validateColor(val, formats, allowAlpha)
|
|
174
|
+
|
|
175
|
+
if (!result.valid) {
|
|
176
|
+
const formatMessageMap: Record<ColorFormat, keyof ColorMessages> = {
|
|
177
|
+
hex: "notHex",
|
|
178
|
+
rgb: "notRgb",
|
|
179
|
+
hsl: "notHsl",
|
|
180
|
+
any: "invalid",
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const messageKey = result.failedFormat ? formatMessageMap[result.failedFormat] : "invalid"
|
|
184
|
+
ctx.addIssue({ code: "custom", message: getMessage(messageKey) })
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
return schema as unknown as ColorSchema<IsRequired>
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export { validateColor }
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { z, ZodNullable, ZodString } from "zod"
|
|
2
|
+
import { t } from "../../i18n"
|
|
3
|
+
import { getLocale, type Locale } from "../../config"
|
|
4
|
+
|
|
5
|
+
export type CoordinateType = "latitude" | "longitude" | "pair"
|
|
6
|
+
|
|
7
|
+
export type CoordinateMessages = {
|
|
8
|
+
required?: string
|
|
9
|
+
invalid?: string
|
|
10
|
+
invalidLatitude?: string
|
|
11
|
+
invalidLongitude?: string
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type CoordinateOptions<IsRequired extends boolean = true> = {
|
|
15
|
+
type?: CoordinateType
|
|
16
|
+
precision?: number
|
|
17
|
+
transform?: (value: string) => string
|
|
18
|
+
defaultValue?: IsRequired extends true ? string : string | null
|
|
19
|
+
i18n?: Partial<Record<Locale, Partial<CoordinateMessages>>>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type CoordinateSchema<IsRequired extends boolean> = IsRequired extends true ? ZodString : ZodNullable<ZodString>
|
|
23
|
+
|
|
24
|
+
export function validateLatitude(value: number): boolean {
|
|
25
|
+
return Number.isFinite(value) && value >= -90 && value <= 90
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function validateLongitude(value: number): boolean {
|
|
29
|
+
return Number.isFinite(value) && value >= -180 && value <= 180
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function validatePrecision(value: number, precision: number): boolean {
|
|
33
|
+
const decimalPart = value.toString().split(".")[1]
|
|
34
|
+
if (!decimalPart) return true
|
|
35
|
+
return decimalPart.length <= precision
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function coordinate<IsRequired extends boolean = false>(
|
|
39
|
+
required?: IsRequired,
|
|
40
|
+
options?: Omit<CoordinateOptions<IsRequired>, "required">,
|
|
41
|
+
): CoordinateSchema<IsRequired> {
|
|
42
|
+
const { type = "pair", precision, transform, defaultValue, i18n } = options ?? {}
|
|
43
|
+
|
|
44
|
+
const isRequired = required ?? (false as IsRequired)
|
|
45
|
+
|
|
46
|
+
const actualDefaultValue = defaultValue ?? (isRequired ? "" : null)
|
|
47
|
+
|
|
48
|
+
const getMessage = (key: keyof CoordinateMessages, params?: Record<string, any>) => {
|
|
49
|
+
if (i18n) {
|
|
50
|
+
const currentLocale = getLocale()
|
|
51
|
+
const customMessages = i18n[currentLocale]
|
|
52
|
+
if (customMessages && customMessages[key]) {
|
|
53
|
+
const template = customMessages[key]!
|
|
54
|
+
return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "")
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return t(`common.coordinate.${key}`, params)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const preprocessFn = (val: unknown) => {
|
|
61
|
+
if (val === "" || val === null || val === undefined) {
|
|
62
|
+
return actualDefaultValue
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let processed = String(val).trim()
|
|
66
|
+
|
|
67
|
+
if (processed === "" && !required) {
|
|
68
|
+
return null
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (transform) {
|
|
72
|
+
processed = transform(processed)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return processed
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const baseSchema = isRequired ? z.preprocess(preprocessFn, z.string()) : z.preprocess(preprocessFn, z.string().nullable())
|
|
79
|
+
|
|
80
|
+
const schema = baseSchema.superRefine((val, ctx) => {
|
|
81
|
+
if (val === null) return
|
|
82
|
+
|
|
83
|
+
if (isRequired && (val === "" || val === "null" || val === "undefined")) {
|
|
84
|
+
ctx.addIssue({ code: "custom", message: getMessage("required") })
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!isRequired && val === "") return
|
|
89
|
+
|
|
90
|
+
if (type === "pair") {
|
|
91
|
+
const parts = val.split(",")
|
|
92
|
+
if (parts.length !== 2) {
|
|
93
|
+
ctx.addIssue({ code: "custom", message: getMessage("invalid") })
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const lat = Number(parts[0].trim())
|
|
98
|
+
const lng = Number(parts[1].trim())
|
|
99
|
+
|
|
100
|
+
if (isNaN(lat) || isNaN(lng)) {
|
|
101
|
+
ctx.addIssue({ code: "custom", message: getMessage("invalid") })
|
|
102
|
+
return
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!validateLatitude(lat)) {
|
|
106
|
+
ctx.addIssue({ code: "custom", message: getMessage("invalidLatitude") })
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!validateLongitude(lng)) {
|
|
111
|
+
ctx.addIssue({ code: "custom", message: getMessage("invalidLongitude") })
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (precision !== undefined) {
|
|
116
|
+
if (!validatePrecision(lat, precision) || !validatePrecision(lng, precision)) {
|
|
117
|
+
ctx.addIssue({ code: "custom", message: getMessage("invalid") })
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
} else if (type === "latitude") {
|
|
122
|
+
const num = Number(val)
|
|
123
|
+
|
|
124
|
+
if (isNaN(num)) {
|
|
125
|
+
ctx.addIssue({ code: "custom", message: getMessage("invalidLatitude") })
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (!validateLatitude(num)) {
|
|
130
|
+
ctx.addIssue({ code: "custom", message: getMessage("invalidLatitude") })
|
|
131
|
+
return
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (precision !== undefined && !validatePrecision(num, precision)) {
|
|
135
|
+
ctx.addIssue({ code: "custom", message: getMessage("invalid") })
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
} else if (type === "longitude") {
|
|
139
|
+
const num = Number(val)
|
|
140
|
+
|
|
141
|
+
if (isNaN(num)) {
|
|
142
|
+
ctx.addIssue({ code: "custom", message: getMessage("invalidLongitude") })
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (!validateLongitude(num)) {
|
|
147
|
+
ctx.addIssue({ code: "custom", message: getMessage("invalidLongitude") })
|
|
148
|
+
return
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (precision !== undefined && !validatePrecision(num, precision)) {
|
|
152
|
+
ctx.addIssue({ code: "custom", message: getMessage("invalid") })
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
return schema as unknown as CoordinateSchema<IsRequired>
|
|
159
|
+
}
|