@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.
Files changed (191) hide show
  1. package/.github/workflows/ci.yml +24 -0
  2. package/CLAUDE.md +64 -22
  3. package/dist/chunk-2SWEVDFZ.js +134 -0
  4. package/dist/chunk-32JI34CV.cjs +146 -0
  5. package/dist/chunk-42C5OHRK.js +71 -0
  6. package/dist/chunk-46VAH2BJ.js +160 -0
  7. package/dist/chunk-5JGTDL3Y.js +87 -0
  8. package/dist/chunk-5LEXCVLX.js +257 -0
  9. package/dist/chunk-6AAP4LPF.js +2606 -0
  10. package/dist/chunk-B4EZYZOK.cjs +215 -0
  11. package/dist/chunk-COYKBWTI.js +161 -0
  12. package/dist/chunk-DFJZ3NS2.cjs +151 -0
  13. package/dist/chunk-EDHT4LPO.js +118 -0
  14. package/dist/chunk-EGHL277K.cjs +165 -0
  15. package/dist/chunk-ERH4NIMU.cjs +69 -0
  16. package/dist/chunk-FM3EZ72O.js +165 -0
  17. package/dist/chunk-GJIRDBZJ.cjs +90 -0
  18. package/dist/chunk-H2XTEM4M.js +696 -0
  19. package/dist/chunk-HMSM6FFA.cjs +181 -0
  20. package/dist/chunk-HTEHINI7.cjs +177 -0
  21. package/dist/chunk-JOLSGZGN.cjs +696 -0
  22. package/dist/chunk-JXY7APBU.js +69 -0
  23. package/dist/chunk-K2UOY6TB.js +136 -0
  24. package/dist/chunk-KFOHKTFD.js +61 -0
  25. package/dist/chunk-L4HSIKTU.cjs +135 -0
  26. package/dist/chunk-LH7ZB4BK.js +124 -0
  27. package/dist/chunk-LL4ZWLGO.js +90 -0
  28. package/dist/chunk-M6MTP3NY.cjs +99 -0
  29. package/dist/chunk-MHJFYYGV.js +215 -0
  30. package/dist/chunk-MINMXGW3.js +135 -0
  31. package/dist/chunk-MM7IL2RG.js +181 -0
  32. package/dist/chunk-OPQJWHXN.cjs +301 -0
  33. package/dist/chunk-ORFHDJII.cjs +136 -0
  34. package/dist/chunk-ORVV4MCF.cjs +87 -0
  35. package/dist/chunk-QICQ6YEY.js +75 -0
  36. package/dist/chunk-RKUQREMW.js +127 -0
  37. package/dist/chunk-RO47DKQG.js +146 -0
  38. package/dist/chunk-RRPXIRTQ.cjs +257 -0
  39. package/dist/chunk-RYFG2GKM.cjs +118 -0
  40. package/dist/chunk-STNHTRG7.cjs +124 -0
  41. package/dist/chunk-TFGS34VD.cjs +71 -0
  42. package/dist/chunk-TQXDUMML.cjs +61 -0
  43. package/dist/chunk-UBK3VCVH.cjs +134 -0
  44. package/dist/chunk-UCOXAZJF.cjs +2606 -0
  45. package/dist/chunk-UQZKFAFX.js +130 -0
  46. package/dist/chunk-VB2KV2ZM.cjs +130 -0
  47. package/dist/chunk-WABKPFPK.js +151 -0
  48. package/dist/chunk-WDI4QJMQ.js +177 -0
  49. package/dist/chunk-YDH3L27K.cjs +127 -0
  50. package/dist/chunk-YIM3D2AD.js +99 -0
  51. package/dist/chunk-YPSEIDUR.cjs +160 -0
  52. package/dist/chunk-ZNJLWJX3.cjs +75 -0
  53. package/dist/chunk-ZTFCJCPO.cjs +161 -0
  54. package/dist/chunk-ZXUMK2RR.js +301 -0
  55. package/dist/common/boolean.cjs +7 -0
  56. package/dist/common/boolean.d.cts +119 -0
  57. package/dist/common/boolean.d.ts +119 -0
  58. package/dist/common/boolean.js +7 -0
  59. package/dist/common/color.cjs +9 -0
  60. package/dist/common/color.d.cts +26 -0
  61. package/dist/common/color.d.ts +26 -0
  62. package/dist/common/color.js +9 -0
  63. package/dist/common/coordinate.cjs +11 -0
  64. package/dist/common/coordinate.d.cts +23 -0
  65. package/dist/common/coordinate.d.ts +23 -0
  66. package/dist/common/coordinate.js +11 -0
  67. package/dist/common/credit-card.cjs +11 -0
  68. package/dist/common/credit-card.d.cts +22 -0
  69. package/dist/common/credit-card.d.ts +22 -0
  70. package/dist/common/credit-card.js +11 -0
  71. package/dist/common/date.cjs +7 -0
  72. package/dist/common/date.d.cts +174 -0
  73. package/dist/common/date.d.ts +174 -0
  74. package/dist/common/date.js +7 -0
  75. package/dist/common/datetime.cjs +15 -0
  76. package/dist/common/datetime.d.cts +301 -0
  77. package/dist/common/datetime.d.ts +301 -0
  78. package/dist/common/datetime.js +15 -0
  79. package/dist/common/email.cjs +7 -0
  80. package/dist/common/email.d.cts +149 -0
  81. package/dist/common/email.d.ts +149 -0
  82. package/dist/common/email.js +7 -0
  83. package/dist/common/file.cjs +7 -0
  84. package/dist/common/file.d.cts +178 -0
  85. package/dist/common/file.d.ts +178 -0
  86. package/dist/common/file.js +7 -0
  87. package/dist/common/id.cjs +13 -0
  88. package/dist/common/id.d.cts +288 -0
  89. package/dist/common/id.d.ts +288 -0
  90. package/dist/common/id.js +13 -0
  91. package/dist/common/ip.cjs +11 -0
  92. package/dist/common/ip.d.cts +25 -0
  93. package/dist/common/ip.d.ts +25 -0
  94. package/dist/common/ip.js +11 -0
  95. package/dist/common/number.cjs +7 -0
  96. package/dist/common/number.d.cts +167 -0
  97. package/dist/common/number.d.ts +167 -0
  98. package/dist/common/number.js +7 -0
  99. package/dist/common/password.cjs +7 -0
  100. package/dist/common/password.d.cts +192 -0
  101. package/dist/common/password.d.ts +192 -0
  102. package/dist/common/password.js +7 -0
  103. package/dist/common/text.cjs +7 -0
  104. package/dist/common/text.d.cts +156 -0
  105. package/dist/common/text.d.ts +156 -0
  106. package/dist/common/text.js +7 -0
  107. package/dist/common/time.cjs +15 -0
  108. package/dist/common/time.d.cts +268 -0
  109. package/dist/common/time.d.ts +268 -0
  110. package/dist/common/time.js +15 -0
  111. package/dist/common/url.cjs +7 -0
  112. package/dist/common/url.d.cts +196 -0
  113. package/dist/common/url.d.ts +196 -0
  114. package/dist/common/url.js +7 -0
  115. package/dist/config-CABSSvAp.d.cts +5 -0
  116. package/dist/config-CABSSvAp.d.ts +5 -0
  117. package/dist/index.cjs +180 -5255
  118. package/dist/index.d.cts +28 -3150
  119. package/dist/index.d.ts +28 -3150
  120. package/dist/index.js +135 -5131
  121. package/dist/taiwan/bank-account.cjs +11 -0
  122. package/dist/taiwan/bank-account.d.cts +22 -0
  123. package/dist/taiwan/bank-account.d.ts +22 -0
  124. package/dist/taiwan/bank-account.js +11 -0
  125. package/dist/taiwan/business-id.cjs +9 -0
  126. package/dist/taiwan/business-id.d.cts +133 -0
  127. package/dist/taiwan/business-id.d.ts +133 -0
  128. package/dist/taiwan/business-id.js +9 -0
  129. package/dist/taiwan/fax.cjs +9 -0
  130. package/dist/taiwan/fax.d.cts +157 -0
  131. package/dist/taiwan/fax.d.ts +157 -0
  132. package/dist/taiwan/fax.js +9 -0
  133. package/dist/taiwan/invoice.cjs +9 -0
  134. package/dist/taiwan/invoice.d.cts +17 -0
  135. package/dist/taiwan/invoice.d.ts +17 -0
  136. package/dist/taiwan/invoice.js +9 -0
  137. package/dist/taiwan/license-plate.cjs +9 -0
  138. package/dist/taiwan/license-plate.d.cts +19 -0
  139. package/dist/taiwan/license-plate.d.ts +19 -0
  140. package/dist/taiwan/license-plate.js +9 -0
  141. package/dist/taiwan/mobile.cjs +9 -0
  142. package/dist/taiwan/mobile.d.cts +146 -0
  143. package/dist/taiwan/mobile.d.ts +146 -0
  144. package/dist/taiwan/mobile.js +9 -0
  145. package/dist/taiwan/national-id.cjs +15 -0
  146. package/dist/taiwan/national-id.d.cts +214 -0
  147. package/dist/taiwan/national-id.d.ts +214 -0
  148. package/dist/taiwan/national-id.js +15 -0
  149. package/dist/taiwan/passport.cjs +9 -0
  150. package/dist/taiwan/passport.d.cts +19 -0
  151. package/dist/taiwan/passport.d.ts +19 -0
  152. package/dist/taiwan/passport.js +9 -0
  153. package/dist/taiwan/postal-code.cjs +17 -0
  154. package/dist/taiwan/postal-code.d.cts +237 -0
  155. package/dist/taiwan/postal-code.d.ts +237 -0
  156. package/dist/taiwan/postal-code.js +17 -0
  157. package/dist/taiwan/tel.cjs +9 -0
  158. package/dist/taiwan/tel.d.cts +162 -0
  159. package/dist/taiwan/tel.d.ts +162 -0
  160. package/dist/taiwan/tel.js +9 -0
  161. package/package.json +132 -6
  162. package/src/i18n/locales/en-GB.json +51 -0
  163. package/src/i18n/locales/en-US.json +52 -1
  164. package/src/i18n/locales/id-ID.json +51 -0
  165. package/src/i18n/locales/ja-JP.json +51 -0
  166. package/src/i18n/locales/ko-KR.json +51 -0
  167. package/src/i18n/locales/ms-MY.json +51 -0
  168. package/src/i18n/locales/th-TH.json +51 -0
  169. package/src/i18n/locales/vi-VN.json +51 -0
  170. package/src/i18n/locales/zh-CN.json +51 -0
  171. package/src/i18n/locales/zh-TW.json +51 -0
  172. package/src/index.ts +10 -2
  173. package/src/validators/common/color.ts +192 -0
  174. package/src/validators/common/coordinate.ts +159 -0
  175. package/src/validators/common/credit-card.ts +134 -0
  176. package/src/validators/common/id.ts +45 -3
  177. package/src/validators/common/ip.ts +210 -0
  178. package/src/validators/taiwan/bank-account.ts +176 -0
  179. package/src/validators/taiwan/invoice.ts +84 -0
  180. package/src/validators/taiwan/license-plate.ts +110 -0
  181. package/src/validators/taiwan/passport.ts +103 -0
  182. package/tests/common/color.test.ts +587 -0
  183. package/tests/common/coordinate.test.ts +345 -0
  184. package/tests/common/credit-card.test.ts +378 -0
  185. package/tests/common/id.test.ts +68 -3
  186. package/tests/common/ip.test.ts +419 -0
  187. package/tests/taiwan/bank-account.test.ts +286 -0
  188. package/tests/taiwan/invoice.test.ts +227 -0
  189. package/tests/taiwan/license-plate.test.ts +280 -0
  190. package/tests/taiwan/passport.test.ts +277 -0
  191. package/tsup.config.ts +36 -0
@@ -0,0 +1,215 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+ var _chunkUCOXAZJFcjs = require('./chunk-UCOXAZJF.cjs');
5
+
6
+ // src/validators/common/id.ts
7
+ var _zod = require('zod');
8
+ var UUID_BASE = (version) => new RegExp(`^[0-9a-f]{8}-[0-9a-f]{4}-${version}[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`, "i");
9
+ var ID_PATTERNS = {
10
+ numeric: /^\d+$/,
11
+ uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
12
+ uuidv1: UUID_BASE("1"),
13
+ uuidv2: UUID_BASE("2"),
14
+ uuidv3: UUID_BASE("3"),
15
+ uuidv4: UUID_BASE("4"),
16
+ uuidv5: UUID_BASE("5"),
17
+ uuidv6: UUID_BASE("6"),
18
+ uuidv7: UUID_BASE("7"),
19
+ uuidv8: UUID_BASE("8"),
20
+ objectId: /^[0-9a-f]{24}$/i,
21
+ nanoid: /^[A-Za-z0-9_-]{21}$/,
22
+ snowflake: /^\d{19}$/,
23
+ cuid: /^c[a-z0-9]{24}$/,
24
+ ulid: /^[0-9A-HJKMNP-TV-Z]{26}$/,
25
+ shortid: /^[A-Za-z0-9_-]{7,14}$/
26
+ };
27
+ var detectIdType = (value) => {
28
+ const orderedTypes = [
29
+ ["uuid", ID_PATTERNS.uuid],
30
+ ["objectId", ID_PATTERNS.objectId],
31
+ ["snowflake", ID_PATTERNS.snowflake],
32
+ ["cuid", ID_PATTERNS.cuid],
33
+ ["ulid", ID_PATTERNS.ulid],
34
+ ["nanoid", ID_PATTERNS.nanoid],
35
+ ["numeric", ID_PATTERNS.numeric],
36
+ ["shortid", ID_PATTERNS.shortid]
37
+ // 放最後,因為最通用
38
+ ];
39
+ for (const [type, pattern] of orderedTypes) {
40
+ if (pattern.test(value)) {
41
+ return type;
42
+ }
43
+ }
44
+ return null;
45
+ };
46
+ var validateIdType = (value, type) => {
47
+ if (type === "auto") {
48
+ return detectIdType(value) !== null;
49
+ }
50
+ const pattern = ID_PATTERNS[type];
51
+ return pattern ? pattern.test(value) : false;
52
+ };
53
+ function id(required, options) {
54
+ const { type = "auto", minLength, maxLength, allowedTypes, customRegex, includes, excludes, startsWith, endsWith, caseSensitive = true, transform, defaultValue, i18n } = _nullishCoalesce(options, () => ( {}));
55
+ const isRequired = _nullishCoalesce(required, () => ( false));
56
+ const isNumericType = type === "numeric";
57
+ const actualDefaultValue = defaultValue !== void 0 ? defaultValue : isRequired ? isNumericType ? NaN : "" : null;
58
+ const getMessage = (key, params) => {
59
+ if (i18n) {
60
+ const currentLocale = _chunkUCOXAZJFcjs.getLocale.call(void 0, );
61
+ const customMessages = i18n[currentLocale];
62
+ if (customMessages && customMessages[key]) {
63
+ const template = customMessages[key];
64
+ return template.replace(/\$\{(\w+)}/g, (_match, k) => _nullishCoalesce(_optionalChain([params, 'optionalAccess', _ => _[k]]), () => ( "")));
65
+ }
66
+ }
67
+ return _chunkUCOXAZJFcjs.t.call(void 0, `common.id.${key}`, params);
68
+ };
69
+ const preprocessNumericFn = (val) => {
70
+ if (val === "" || val === null || val === void 0) {
71
+ if (isRequired && defaultValue === void 0) {
72
+ return void 0;
73
+ }
74
+ return actualDefaultValue;
75
+ }
76
+ return Number(val);
77
+ };
78
+ const preprocessStringFn = (val) => {
79
+ if (val === "" || val === null || val === void 0) {
80
+ return actualDefaultValue;
81
+ }
82
+ let processed = String(val);
83
+ if (transform) {
84
+ processed = transform(processed);
85
+ }
86
+ return processed;
87
+ };
88
+ if (isNumericType) {
89
+ const numericSchema = _zod.z.preprocess(preprocessNumericFn, _zod.z.any()).superRefine((val, ctx) => {
90
+ if (!isRequired && val === null) return;
91
+ if (val === void 0 || isRequired && val === null) {
92
+ ctx.addIssue({ code: "custom", message: getMessage("required") });
93
+ return;
94
+ }
95
+ if (typeof val !== "number" || isNaN(val)) {
96
+ ctx.addIssue({ code: "custom", message: getMessage("numeric") });
97
+ return;
98
+ }
99
+ const strVal = String(val);
100
+ if (!ID_PATTERNS.numeric.test(strVal)) {
101
+ ctx.addIssue({ code: "custom", message: getMessage("numeric") });
102
+ return;
103
+ }
104
+ if (minLength !== void 0 && strVal.length < minLength) {
105
+ ctx.addIssue({ code: "custom", message: getMessage("minLength", { minLength }) });
106
+ return;
107
+ }
108
+ if (maxLength !== void 0 && strVal.length > maxLength) {
109
+ ctx.addIssue({ code: "custom", message: getMessage("maxLength", { maxLength }) });
110
+ return;
111
+ }
112
+ });
113
+ return numericSchema;
114
+ }
115
+ const baseSchema = isRequired ? _zod.z.preprocess(preprocessStringFn, _zod.z.string()) : _zod.z.preprocess(preprocessStringFn, _zod.z.string().nullable());
116
+ const schema = baseSchema.superRefine((val, ctx) => {
117
+ if (val === null) return;
118
+ if (isRequired && (val === "" || val === "null" || val === "undefined")) {
119
+ ctx.addIssue({ code: "custom", message: getMessage("required") });
120
+ return;
121
+ }
122
+ const comparisonVal = !caseSensitive ? val.toLowerCase() : val;
123
+ if (val !== null && minLength !== void 0 && val.length < minLength) {
124
+ ctx.addIssue({ code: "custom", message: getMessage("minLength", { minLength }) });
125
+ return;
126
+ }
127
+ if (val !== null && maxLength !== void 0 && val.length > maxLength) {
128
+ ctx.addIssue({ code: "custom", message: getMessage("maxLength", { maxLength }) });
129
+ return;
130
+ }
131
+ const hasContentValidations = customRegex !== void 0 || startsWith !== void 0 || endsWith !== void 0 || includes !== void 0 || excludes !== void 0;
132
+ if (val !== null && customRegex !== void 0) {
133
+ if (!customRegex.test(val)) {
134
+ ctx.addIssue({ code: "custom", message: getMessage("customFormat") });
135
+ return;
136
+ }
137
+ } else if (val !== null && !hasContentValidations) {
138
+ let isValidId;
139
+ if (allowedTypes && allowedTypes.length > 0) {
140
+ isValidId = allowedTypes.some((allowedType) => validateIdType(val, allowedType));
141
+ if (!isValidId) {
142
+ const typeNames = allowedTypes.join(", ");
143
+ ctx.addIssue({ code: "custom", message: getMessage("invalid") + ` (allowed types: ${typeNames})` });
144
+ return;
145
+ }
146
+ } else if (type && type !== "auto") {
147
+ isValidId = validateIdType(val, type);
148
+ if (!isValidId) {
149
+ ctx.addIssue({ code: "custom", message: getMessage(type) || getMessage("invalid") });
150
+ return;
151
+ }
152
+ } else {
153
+ isValidId = detectIdType(val) !== null;
154
+ if (!isValidId) {
155
+ ctx.addIssue({ code: "custom", message: getMessage("invalid") });
156
+ return;
157
+ }
158
+ }
159
+ } else if (val !== null && hasContentValidations && type && type !== "auto" && !customRegex) {
160
+ if (allowedTypes && allowedTypes.length > 0) {
161
+ const isValidType = allowedTypes.some((allowedType) => validateIdType(val, allowedType));
162
+ if (!isValidType) {
163
+ const typeNames = allowedTypes.join(", ");
164
+ ctx.addIssue({ code: "custom", message: getMessage("invalid") + ` (allowed types: ${typeNames})` });
165
+ return;
166
+ }
167
+ } else {
168
+ if (!validateIdType(val, type)) {
169
+ ctx.addIssue({ code: "custom", message: getMessage(type) || getMessage("invalid") });
170
+ return;
171
+ }
172
+ }
173
+ }
174
+ const searchStartsWith = !caseSensitive && startsWith ? startsWith.toLowerCase() : startsWith;
175
+ const searchEndsWith = !caseSensitive && endsWith ? endsWith.toLowerCase() : endsWith;
176
+ const searchIncludes = !caseSensitive && includes ? includes.toLowerCase() : includes;
177
+ if (val !== null && startsWith !== void 0 && !comparisonVal.startsWith(searchStartsWith)) {
178
+ ctx.addIssue({ code: "custom", message: getMessage("startsWith", { startsWith }) });
179
+ return;
180
+ }
181
+ if (val !== null && endsWith !== void 0 && !comparisonVal.endsWith(searchEndsWith)) {
182
+ ctx.addIssue({ code: "custom", message: getMessage("endsWith", { endsWith }) });
183
+ return;
184
+ }
185
+ if (val !== null && includes !== void 0 && !comparisonVal.includes(searchIncludes)) {
186
+ ctx.addIssue({ code: "custom", message: getMessage("includes", { includes }) });
187
+ return;
188
+ }
189
+ if (val !== null && excludes !== void 0) {
190
+ const excludeList = Array.isArray(excludes) ? excludes : [excludes];
191
+ for (const exclude of excludeList) {
192
+ const searchExclude = !caseSensitive ? exclude.toLowerCase() : exclude;
193
+ if (comparisonVal.includes(searchExclude)) {
194
+ ctx.addIssue({ code: "custom", message: getMessage("excludes", { excludes: exclude }) });
195
+ return;
196
+ }
197
+ }
198
+ }
199
+ }).transform((val) => {
200
+ if (val === null) return val;
201
+ const shouldPreserveCase = type === "uuid" || type === "objectId";
202
+ if (!caseSensitive && !shouldPreserveCase) {
203
+ return val.toLowerCase();
204
+ }
205
+ return val;
206
+ });
207
+ return schema;
208
+ }
209
+
210
+
211
+
212
+
213
+
214
+
215
+ exports.ID_PATTERNS = ID_PATTERNS; exports.detectIdType = detectIdType; exports.validateIdType = validateIdType; exports.id = id;
@@ -0,0 +1,161 @@
1
+ import {
2
+ getLocale,
3
+ t
4
+ } from "./chunk-6AAP4LPF.js";
5
+
6
+ // src/validators/taiwan/national-id.ts
7
+ import { z } from "zod";
8
+ var CITY_CODES = {
9
+ "A": 10,
10
+ "B": 11,
11
+ "C": 12,
12
+ "D": 13,
13
+ "E": 14,
14
+ "F": 15,
15
+ "G": 16,
16
+ "H": 17,
17
+ "I": 34,
18
+ "J": 18,
19
+ "K": 19,
20
+ "L": 20,
21
+ "M": 21,
22
+ "N": 22,
23
+ "O": 35,
24
+ "P": 23,
25
+ "Q": 24,
26
+ "R": 25,
27
+ "S": 26,
28
+ "T": 27,
29
+ "U": 28,
30
+ "V": 29,
31
+ "W": 32,
32
+ "X": 30,
33
+ "Y": 31,
34
+ "Z": 33
35
+ };
36
+ var validateCitizenId = (value) => {
37
+ if (!/^[A-Z][1-2]\d{8}$/.test(value)) {
38
+ return false;
39
+ }
40
+ const letter = value[0];
41
+ const digits = value.slice(1).split("").map(Number);
42
+ const cityCode = CITY_CODES[letter];
43
+ if (!cityCode) return false;
44
+ const cityDigits = [Math.floor(cityCode / 10), cityCode % 10];
45
+ const coefficients = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1];
46
+ let sum = cityDigits[0] * coefficients[0] + cityDigits[1] * coefficients[1];
47
+ for (let i = 0; i < 8; i++) {
48
+ sum += digits[i] * coefficients[i + 2];
49
+ }
50
+ const checksum = (10 - sum % 10) % 10;
51
+ return checksum === digits[8];
52
+ };
53
+ var validateOldResidentId = (value) => {
54
+ if (!/^[A-Z][ABCD]\d{8}$/.test(value)) {
55
+ return false;
56
+ }
57
+ const letter = value[0];
58
+ const genderCode = value[1];
59
+ const digits = value.slice(2).split("").map(Number);
60
+ const cityCode = CITY_CODES[letter];
61
+ if (!cityCode) return false;
62
+ const genderValue = genderCode === "A" || genderCode === "C" ? 1 : 0;
63
+ const cityDigits = [Math.floor(cityCode / 10), cityCode % 10];
64
+ const coefficients = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1];
65
+ let sum = cityDigits[0] * coefficients[0] + cityDigits[1] * coefficients[1] + genderValue * coefficients[2];
66
+ for (let i = 0; i < 7; i++) {
67
+ sum += digits[i] * coefficients[i + 3];
68
+ }
69
+ const checksum = (10 - sum % 10) % 10;
70
+ return checksum === digits[7];
71
+ };
72
+ var validateNewResidentId = (value) => {
73
+ if (!/^[A-Z][89]\d{8}$/.test(value)) {
74
+ return false;
75
+ }
76
+ const letter = value[0];
77
+ const digits = value.slice(1).split("").map(Number);
78
+ const cityCode = CITY_CODES[letter];
79
+ if (!cityCode) return false;
80
+ const cityDigits = [Math.floor(cityCode / 10), cityCode % 10];
81
+ const coefficients = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1];
82
+ let sum = cityDigits[0] * coefficients[0] + cityDigits[1] * coefficients[1];
83
+ for (let i = 0; i < 8; i++) {
84
+ sum += digits[i] * coefficients[i + 2];
85
+ }
86
+ const checksum = (10 - sum % 10) % 10;
87
+ return checksum === digits[8];
88
+ };
89
+ var validateTaiwanNationalId = (value, type = "both", allowOldResident = true) => {
90
+ if (!/^[A-Z].{9}$/.test(value)) {
91
+ return false;
92
+ }
93
+ switch (type) {
94
+ case "citizen":
95
+ return validateCitizenId(value);
96
+ case "resident":
97
+ return (allowOldResident ? validateOldResidentId(value) : false) || validateNewResidentId(value);
98
+ case "both":
99
+ return validateCitizenId(value) || (allowOldResident ? validateOldResidentId(value) : false) || validateNewResidentId(value);
100
+ default:
101
+ return false;
102
+ }
103
+ };
104
+ function twNationalId(required, options) {
105
+ const {
106
+ type = "both",
107
+ allowOldResident = true,
108
+ transform,
109
+ defaultValue,
110
+ i18n
111
+ } = options ?? {};
112
+ const isRequired = required ?? false;
113
+ const actualDefaultValue = defaultValue ?? (isRequired ? "" : null);
114
+ const getMessage = (key, params) => {
115
+ if (i18n) {
116
+ const currentLocale = getLocale();
117
+ const customMessages = i18n[currentLocale];
118
+ if (customMessages && customMessages[key]) {
119
+ const template = customMessages[key];
120
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
121
+ }
122
+ }
123
+ return t(`taiwan.nationalId.${key}`, params);
124
+ };
125
+ const preprocessFn = (val) => {
126
+ if (val === "" || val === null || val === void 0) {
127
+ return actualDefaultValue;
128
+ }
129
+ let processed = String(val).trim().toUpperCase();
130
+ if (processed === "" && !required) {
131
+ return null;
132
+ }
133
+ if (transform) {
134
+ processed = transform(processed);
135
+ }
136
+ return processed;
137
+ };
138
+ const baseSchema = isRequired ? z.preprocess(preprocessFn, z.string()) : z.preprocess(preprocessFn, z.string().nullable());
139
+ const schema = baseSchema.superRefine((val, ctx) => {
140
+ if (val === null) return;
141
+ if (isRequired && (val === "" || val === "null" || val === "undefined")) {
142
+ ctx.addIssue({ code: "custom", message: getMessage("required") });
143
+ return;
144
+ }
145
+ if (val === null) return;
146
+ if (!isRequired && val === "") return;
147
+ if (!validateTaiwanNationalId(val, type, allowOldResident)) {
148
+ ctx.addIssue({ code: "custom", message: getMessage("invalid") });
149
+ return;
150
+ }
151
+ });
152
+ return schema;
153
+ }
154
+
155
+ export {
156
+ validateCitizenId,
157
+ validateOldResidentId,
158
+ validateNewResidentId,
159
+ validateTaiwanNationalId,
160
+ twNationalId
161
+ };
@@ -0,0 +1,151 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+ var _chunkUCOXAZJFcjs = require('./chunk-UCOXAZJF.cjs');
5
+
6
+ // src/validators/common/url.ts
7
+ var _zod = require('zod');
8
+ function url(required, options) {
9
+ const {
10
+ min,
11
+ max,
12
+ includes,
13
+ excludes,
14
+ protocols,
15
+ allowedDomains,
16
+ blockedDomains,
17
+ allowedPorts,
18
+ blockedPorts,
19
+ pathStartsWith,
20
+ pathEndsWith,
21
+ mustHaveQuery,
22
+ mustNotHaveQuery,
23
+ mustHaveFragment,
24
+ mustNotHaveFragment,
25
+ allowLocalhost = true,
26
+ blockLocalhost,
27
+ transform,
28
+ defaultValue = null,
29
+ i18n
30
+ } = _nullishCoalesce(options, () => ( {}));
31
+ const isRequired = _nullishCoalesce(required, () => ( false));
32
+ const actualDefaultValue = _nullishCoalesce(defaultValue, () => ( (isRequired ? "" : null)));
33
+ const getMessage = (key, params) => {
34
+ if (i18n) {
35
+ const currentLocale = _chunkUCOXAZJFcjs.getLocale.call(void 0, );
36
+ const customMessages = i18n[currentLocale];
37
+ if (customMessages && customMessages[key]) {
38
+ const template = customMessages[key];
39
+ return template.replace(/\$\{(\w+)}/g, (_, k) => _nullishCoalesce(_optionalChain([params, 'optionalAccess', _2 => _2[k]]), () => ( "")));
40
+ }
41
+ }
42
+ return _chunkUCOXAZJFcjs.t.call(void 0, `common.url.${key}`, params);
43
+ };
44
+ const preprocessFn = (val) => {
45
+ if (val === "" || val === null || val === void 0) {
46
+ return actualDefaultValue;
47
+ }
48
+ let processed = String(val).trim();
49
+ if (transform) {
50
+ processed = transform(processed);
51
+ }
52
+ return processed;
53
+ };
54
+ const baseSchema = isRequired ? _zod.z.preprocess(preprocessFn, _zod.z.string()) : _zod.z.preprocess(preprocessFn, _zod.z.string().nullable());
55
+ const schema = baseSchema.superRefine((val, ctx) => {
56
+ if (val === null) return;
57
+ if (isRequired && (val === "" || val === "null" || val === "undefined")) {
58
+ ctx.addIssue({ code: "custom", message: getMessage("required") });
59
+ return;
60
+ }
61
+ let urlObj;
62
+ try {
63
+ urlObj = new URL(val);
64
+ } catch (e) {
65
+ ctx.addIssue({ code: "custom", message: getMessage("invalid") });
66
+ return;
67
+ }
68
+ if (val !== null && min !== void 0 && val.length < min) {
69
+ ctx.addIssue({ code: "custom", message: getMessage("min", { min }) });
70
+ return;
71
+ }
72
+ if (val !== null && max !== void 0 && val.length > max) {
73
+ ctx.addIssue({ code: "custom", message: getMessage("max", { max }) });
74
+ return;
75
+ }
76
+ if (val !== null && includes !== void 0 && !val.includes(includes)) {
77
+ ctx.addIssue({ code: "custom", message: getMessage("includes", { includes }) });
78
+ return;
79
+ }
80
+ if (val !== null && excludes !== void 0) {
81
+ const excludeList = Array.isArray(excludes) ? excludes : [excludes];
82
+ for (const exclude of excludeList) {
83
+ if (val.includes(exclude)) {
84
+ ctx.addIssue({ code: "custom", message: getMessage("excludes", { excludes: exclude }) });
85
+ return;
86
+ }
87
+ }
88
+ }
89
+ if (protocols && !protocols.includes(urlObj.protocol.slice(0, -1))) {
90
+ ctx.addIssue({ code: "custom", message: getMessage("protocol", { protocols: protocols.join(", ") }) });
91
+ return;
92
+ }
93
+ const hostname = urlObj.hostname.toLowerCase();
94
+ if (allowedDomains && !allowedDomains.some((domain) => hostname === domain || hostname.endsWith(`.${domain}`))) {
95
+ ctx.addIssue({ code: "custom", message: getMessage("domain", { domains: allowedDomains.join(", ") }) });
96
+ return;
97
+ }
98
+ if (blockedDomains && blockedDomains.some((domain) => hostname === domain || hostname.endsWith(`.${domain}`))) {
99
+ const blockedDomain = blockedDomains.find((domain) => hostname === domain || hostname.endsWith(`.${domain}`));
100
+ ctx.addIssue({ code: "custom", message: getMessage("domainBlacklist", { domain: blockedDomain }) });
101
+ return;
102
+ }
103
+ const port = urlObj.port ? parseInt(urlObj.port) : urlObj.protocol === "https:" ? 443 : 80;
104
+ if (allowedPorts && !allowedPorts.includes(port)) {
105
+ ctx.addIssue({ code: "custom", message: getMessage("port", { ports: allowedPorts.join(", ") }) });
106
+ return;
107
+ }
108
+ if (blockedPorts && blockedPorts.includes(port)) {
109
+ ctx.addIssue({ code: "custom", message: getMessage("port", { port }) });
110
+ return;
111
+ }
112
+ if (pathStartsWith && !urlObj.pathname.startsWith(pathStartsWith)) {
113
+ ctx.addIssue({ code: "custom", message: getMessage("pathStartsWith", { path: pathStartsWith }) });
114
+ return;
115
+ }
116
+ if (pathEndsWith && !urlObj.pathname.endsWith(pathEndsWith)) {
117
+ ctx.addIssue({ code: "custom", message: getMessage("pathEndsWith", { path: pathEndsWith }) });
118
+ return;
119
+ }
120
+ if (mustHaveQuery && !urlObj.search) {
121
+ ctx.addIssue({ code: "custom", message: getMessage("hasQuery") });
122
+ return;
123
+ }
124
+ if (mustNotHaveQuery && urlObj.search) {
125
+ ctx.addIssue({ code: "custom", message: getMessage("noQuery") });
126
+ return;
127
+ }
128
+ if (mustHaveFragment && !urlObj.hash) {
129
+ ctx.addIssue({ code: "custom", message: getMessage("hasFragment") });
130
+ return;
131
+ }
132
+ if (mustNotHaveFragment && urlObj.hash) {
133
+ ctx.addIssue({ code: "custom", message: getMessage("noFragment") });
134
+ return;
135
+ }
136
+ const isLocalhost = hostname === "localhost" || hostname === "127.0.0.1" || hostname.startsWith("192.168.") || hostname.startsWith("10.") || hostname.match(/^172\.(1[6-9]|2[0-9]|3[0-1])\./);
137
+ if (blockLocalhost && isLocalhost) {
138
+ ctx.addIssue({ code: "custom", message: getMessage("noLocalhost") });
139
+ return;
140
+ }
141
+ if (!allowLocalhost && isLocalhost) {
142
+ ctx.addIssue({ code: "custom", message: getMessage("localhost") });
143
+ return;
144
+ }
145
+ });
146
+ return schema;
147
+ }
148
+
149
+
150
+
151
+ exports.url = url;
@@ -0,0 +1,118 @@
1
+ import {
2
+ getLocale,
3
+ t
4
+ } from "./chunk-6AAP4LPF.js";
5
+
6
+ // src/validators/common/coordinate.ts
7
+ import { z } from "zod";
8
+ function validateLatitude(value) {
9
+ return Number.isFinite(value) && value >= -90 && value <= 90;
10
+ }
11
+ function validateLongitude(value) {
12
+ return Number.isFinite(value) && value >= -180 && value <= 180;
13
+ }
14
+ function validatePrecision(value, precision) {
15
+ const decimalPart = value.toString().split(".")[1];
16
+ if (!decimalPart) return true;
17
+ return decimalPart.length <= precision;
18
+ }
19
+ function coordinate(required, options) {
20
+ const { type = "pair", precision, transform, defaultValue, i18n } = options ?? {};
21
+ const isRequired = required ?? false;
22
+ const actualDefaultValue = defaultValue ?? (isRequired ? "" : null);
23
+ const getMessage = (key, params) => {
24
+ if (i18n) {
25
+ const currentLocale = getLocale();
26
+ const customMessages = i18n[currentLocale];
27
+ if (customMessages && customMessages[key]) {
28
+ const template = customMessages[key];
29
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
30
+ }
31
+ }
32
+ return t(`common.coordinate.${key}`, params);
33
+ };
34
+ const preprocessFn = (val) => {
35
+ if (val === "" || val === null || val === void 0) {
36
+ return actualDefaultValue;
37
+ }
38
+ let processed = String(val).trim();
39
+ if (processed === "" && !required) {
40
+ return null;
41
+ }
42
+ if (transform) {
43
+ processed = transform(processed);
44
+ }
45
+ return processed;
46
+ };
47
+ const baseSchema = isRequired ? z.preprocess(preprocessFn, z.string()) : z.preprocess(preprocessFn, z.string().nullable());
48
+ const schema = baseSchema.superRefine((val, ctx) => {
49
+ if (val === null) return;
50
+ if (isRequired && (val === "" || val === "null" || val === "undefined")) {
51
+ ctx.addIssue({ code: "custom", message: getMessage("required") });
52
+ return;
53
+ }
54
+ if (!isRequired && val === "") return;
55
+ if (type === "pair") {
56
+ const parts = val.split(",");
57
+ if (parts.length !== 2) {
58
+ ctx.addIssue({ code: "custom", message: getMessage("invalid") });
59
+ return;
60
+ }
61
+ const lat = Number(parts[0].trim());
62
+ const lng = Number(parts[1].trim());
63
+ if (isNaN(lat) || isNaN(lng)) {
64
+ ctx.addIssue({ code: "custom", message: getMessage("invalid") });
65
+ return;
66
+ }
67
+ if (!validateLatitude(lat)) {
68
+ ctx.addIssue({ code: "custom", message: getMessage("invalidLatitude") });
69
+ return;
70
+ }
71
+ if (!validateLongitude(lng)) {
72
+ ctx.addIssue({ code: "custom", message: getMessage("invalidLongitude") });
73
+ return;
74
+ }
75
+ if (precision !== void 0) {
76
+ if (!validatePrecision(lat, precision) || !validatePrecision(lng, precision)) {
77
+ ctx.addIssue({ code: "custom", message: getMessage("invalid") });
78
+ return;
79
+ }
80
+ }
81
+ } else if (type === "latitude") {
82
+ const num = Number(val);
83
+ if (isNaN(num)) {
84
+ ctx.addIssue({ code: "custom", message: getMessage("invalidLatitude") });
85
+ return;
86
+ }
87
+ if (!validateLatitude(num)) {
88
+ ctx.addIssue({ code: "custom", message: getMessage("invalidLatitude") });
89
+ return;
90
+ }
91
+ if (precision !== void 0 && !validatePrecision(num, precision)) {
92
+ ctx.addIssue({ code: "custom", message: getMessage("invalid") });
93
+ return;
94
+ }
95
+ } else if (type === "longitude") {
96
+ const num = Number(val);
97
+ if (isNaN(num)) {
98
+ ctx.addIssue({ code: "custom", message: getMessage("invalidLongitude") });
99
+ return;
100
+ }
101
+ if (!validateLongitude(num)) {
102
+ ctx.addIssue({ code: "custom", message: getMessage("invalidLongitude") });
103
+ return;
104
+ }
105
+ if (precision !== void 0 && !validatePrecision(num, precision)) {
106
+ ctx.addIssue({ code: "custom", message: getMessage("invalid") });
107
+ return;
108
+ }
109
+ }
110
+ });
111
+ return schema;
112
+ }
113
+
114
+ export {
115
+ validateLatitude,
116
+ validateLongitude,
117
+ coordinate
118
+ };