@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,99 @@
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/credit-card.ts
7
+ var _zod = require('zod');
8
+ function detectCardType(value) {
9
+ const digits = value.replace(/[\s-]/g, "");
10
+ if (/^4/.test(digits)) return "visa";
11
+ if (/^5[1-5]/.test(digits) || /^2[2-7]/.test(digits)) return "mastercard";
12
+ if (/^3[47]/.test(digits)) return "amex";
13
+ if (/^35/.test(digits)) return "jcb";
14
+ if (/^6011/.test(digits) || /^65/.test(digits) || /^64[4-9]/.test(digits)) return "discover";
15
+ if (/^62/.test(digits)) return "unionpay";
16
+ return "any";
17
+ }
18
+ function validateCreditCard(value) {
19
+ const digits = value.replace(/[\s-]/g, "");
20
+ if (!/^\d{13,19}$/.test(digits)) return false;
21
+ let sum = 0;
22
+ let alternate = false;
23
+ for (let i = digits.length - 1; i >= 0; i--) {
24
+ let n = parseInt(digits[i], 10);
25
+ if (alternate) {
26
+ n *= 2;
27
+ if (n > 9) n -= 9;
28
+ }
29
+ sum += n;
30
+ alternate = !alternate;
31
+ }
32
+ return sum % 10 === 0;
33
+ }
34
+ function creditCard(required, options) {
35
+ const { cardType, whitelist, transform, defaultValue, i18n } = _nullishCoalesce(options, () => ( {}));
36
+ const isRequired = _nullishCoalesce(required, () => ( false));
37
+ const actualDefaultValue = _nullishCoalesce(defaultValue, () => ( (isRequired ? "" : null)));
38
+ const getMessage = (key, params) => {
39
+ if (i18n) {
40
+ const currentLocale = _chunkUCOXAZJFcjs.getLocale.call(void 0, );
41
+ const customMessages = i18n[currentLocale];
42
+ if (customMessages && customMessages[key]) {
43
+ const template = customMessages[key];
44
+ return template.replace(/\$\{(\w+)}/g, (_, k) => _nullishCoalesce(_optionalChain([params, 'optionalAccess', _2 => _2[k]]), () => ( "")));
45
+ }
46
+ }
47
+ return _chunkUCOXAZJFcjs.t.call(void 0, `common.creditCard.${key}`, params);
48
+ };
49
+ const preprocessFn = (val) => {
50
+ if (val === "" || val === null || val === void 0) {
51
+ return actualDefaultValue;
52
+ }
53
+ let processed = String(val).trim().replace(/[\s-]/g, "");
54
+ if (processed === "" && !required) {
55
+ return null;
56
+ }
57
+ if (transform) {
58
+ processed = transform(processed);
59
+ }
60
+ return processed;
61
+ };
62
+ const baseSchema = isRequired ? _zod.z.preprocess(preprocessFn, _zod.z.string()) : _zod.z.preprocess(preprocessFn, _zod.z.string().nullable());
63
+ const schema = baseSchema.superRefine((val, ctx) => {
64
+ if (val === null) return;
65
+ if (isRequired && (val === "" || val === "null" || val === "undefined")) {
66
+ ctx.addIssue({ code: "custom", message: getMessage("required") });
67
+ return;
68
+ }
69
+ if (!isRequired && val === "") return;
70
+ if (!validateCreditCard(val)) {
71
+ ctx.addIssue({ code: "custom", message: getMessage("invalid") });
72
+ return;
73
+ }
74
+ if (cardType) {
75
+ const allowedTypes = Array.isArray(cardType) ? cardType : [cardType];
76
+ if (!allowedTypes.includes("any")) {
77
+ const detected = detectCardType(val);
78
+ if (!allowedTypes.includes(detected)) {
79
+ ctx.addIssue({ code: "custom", message: getMessage("invalid") });
80
+ return;
81
+ }
82
+ }
83
+ }
84
+ if (whitelist && whitelist.length > 0) {
85
+ const normalized = whitelist.map((w) => w.replace(/[\s-]/g, ""));
86
+ if (!normalized.includes(val)) {
87
+ ctx.addIssue({ code: "custom", message: getMessage("notInWhitelist") });
88
+ return;
89
+ }
90
+ }
91
+ });
92
+ return schema;
93
+ }
94
+
95
+
96
+
97
+
98
+
99
+ exports.detectCardType = detectCardType; exports.validateCreditCard = validateCreditCard; exports.creditCard = creditCard;
@@ -0,0 +1,215 @@
1
+ import {
2
+ getLocale,
3
+ t
4
+ } from "./chunk-6AAP4LPF.js";
5
+
6
+ // src/validators/common/id.ts
7
+ import { z } from "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 } = options ?? {};
55
+ const isRequired = 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 = getLocale();
61
+ const customMessages = i18n[currentLocale];
62
+ if (customMessages && customMessages[key]) {
63
+ const template = customMessages[key];
64
+ return template.replace(/\$\{(\w+)}/g, (_match, k) => params?.[k] ?? "");
65
+ }
66
+ }
67
+ return t(`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 = z.preprocess(preprocessNumericFn, 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 ? z.preprocess(preprocessStringFn, z.string()) : z.preprocess(preprocessStringFn, 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
+ export {
211
+ ID_PATTERNS,
212
+ detectIdType,
213
+ validateIdType,
214
+ id
215
+ };
@@ -0,0 +1,135 @@
1
+ import {
2
+ getLocale,
3
+ t
4
+ } from "./chunk-6AAP4LPF.js";
5
+
6
+ // src/validators/taiwan/bank-account.ts
7
+ import { z } from "zod";
8
+ var TAIWAN_BANK_CODES = {
9
+ "004": "\u53F0\u7063\u9280\u884C",
10
+ "005": "\u571F\u5730\u9280\u884C",
11
+ "006": "\u5408\u5EAB",
12
+ "007": "\u7B2C\u4E00\u9280\u884C",
13
+ "008": "\u83EF\u5357",
14
+ "009": "\u5F70\u5316",
15
+ "011": "\u4E0A\u6D77",
16
+ "012": "\u53F0\u5317\u5BCC\u90A6",
17
+ "013": "\u570B\u6CF0\u4E16\u83EF",
18
+ "017": "\u5146\u8C50",
19
+ "021": "\u82B1\u65D7",
20
+ "048": "\u738B\u9053",
21
+ "050": "\u53F0\u7063\u4F01\u9280",
22
+ "052": "\u6E23\u6253",
23
+ "053": "\u53F0\u4E2D\u9280\u884C",
24
+ "054": "\u4EAC\u57CE",
25
+ "081": "\u6ED9\u8C50",
26
+ "103": "\u65B0\u5149",
27
+ "108": "\u967D\u4FE1",
28
+ "118": "\u677F\u4FE1",
29
+ "147": "\u4E09\u4FE1",
30
+ "700": "\u4E2D\u83EF\u90F5\u653F",
31
+ "803": "\u806F\u90A6",
32
+ "805": "\u9060\u6771",
33
+ "806": "\u5143\u5927",
34
+ "807": "\u6C38\u8C50",
35
+ "808": "\u7389\u5C71",
36
+ "809": "\u51F1\u57FA",
37
+ "810": "\u661F\u5C55",
38
+ "812": "\u53F0\u65B0",
39
+ "816": "\u5B89\u6CF0",
40
+ "822": "\u4E2D\u4FE1"
41
+ };
42
+ var validateTaiwanBankAccount = (value, validateBankCode = true) => {
43
+ let bankCode;
44
+ let accountNumber;
45
+ if (value.includes("-")) {
46
+ const parts = value.split("-");
47
+ if (parts.length !== 2) return false;
48
+ bankCode = parts[0];
49
+ accountNumber = parts[1];
50
+ } else {
51
+ accountNumber = value;
52
+ }
53
+ if (bankCode !== void 0) {
54
+ if (!/^\d{3}$/.test(bankCode)) return false;
55
+ if (validateBankCode && !(bankCode in TAIWAN_BANK_CODES)) return false;
56
+ }
57
+ if (!/^\d{10,16}$/.test(accountNumber)) return false;
58
+ return true;
59
+ };
60
+ function twBankAccount(required, options) {
61
+ const { validateBankCode = true, bankCode, transform, defaultValue, i18n } = options ?? {};
62
+ const isRequired = required ?? false;
63
+ const actualDefaultValue = defaultValue ?? (isRequired ? "" : null);
64
+ const getMessage = (key, params) => {
65
+ if (i18n) {
66
+ const currentLocale = getLocale();
67
+ const customMessages = i18n[currentLocale];
68
+ if (customMessages && customMessages[key]) {
69
+ const template = customMessages[key];
70
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
71
+ }
72
+ }
73
+ return t(`taiwan.bankAccount.${key}`, params);
74
+ };
75
+ const preprocessFn = (val) => {
76
+ if (val === "" || val === null || val === void 0) {
77
+ return actualDefaultValue;
78
+ }
79
+ let processed = String(val).trim().replace(/\s/g, "");
80
+ if (processed === "" && !required) {
81
+ return null;
82
+ }
83
+ if (transform) {
84
+ processed = transform(processed);
85
+ }
86
+ if (bankCode && !processed.includes("-")) {
87
+ processed = `${bankCode}-${processed}`;
88
+ }
89
+ return processed;
90
+ };
91
+ const baseSchema = isRequired ? z.preprocess(preprocessFn, z.string()) : z.preprocess(preprocessFn, z.string().nullable());
92
+ const schema = baseSchema.superRefine((val, ctx) => {
93
+ if (val === null) return;
94
+ if (isRequired && (val === "" || val === "null" || val === "undefined")) {
95
+ ctx.addIssue({ code: "custom", message: getMessage("required") });
96
+ return;
97
+ }
98
+ if (val === null) return;
99
+ if (!isRequired && val === "") return;
100
+ let parsedBankCode;
101
+ let accountNumber;
102
+ if (val.includes("-")) {
103
+ const parts = val.split("-");
104
+ if (parts.length !== 2) {
105
+ ctx.addIssue({ code: "custom", message: getMessage("invalid") });
106
+ return;
107
+ }
108
+ parsedBankCode = parts[0];
109
+ accountNumber = parts[1];
110
+ } else {
111
+ accountNumber = val;
112
+ }
113
+ if (parsedBankCode !== void 0) {
114
+ if (!/^\d{3}$/.test(parsedBankCode)) {
115
+ ctx.addIssue({ code: "custom", message: getMessage("invalidBankCode") });
116
+ return;
117
+ }
118
+ if (validateBankCode && !(parsedBankCode in TAIWAN_BANK_CODES)) {
119
+ ctx.addIssue({ code: "custom", message: getMessage("invalidBankCode") });
120
+ return;
121
+ }
122
+ }
123
+ if (!/^\d{10,16}$/.test(accountNumber)) {
124
+ ctx.addIssue({ code: "custom", message: getMessage("invalidAccountNumber") });
125
+ return;
126
+ }
127
+ });
128
+ return schema;
129
+ }
130
+
131
+ export {
132
+ TAIWAN_BANK_CODES,
133
+ validateTaiwanBankAccount,
134
+ twBankAccount
135
+ };
@@ -0,0 +1,181 @@
1
+ import {
2
+ getLocale,
3
+ t
4
+ } from "./chunk-6AAP4LPF.js";
5
+
6
+ // src/validators/common/email.ts
7
+ import { z } from "zod";
8
+ function email(required, options) {
9
+ const {
10
+ domain,
11
+ domainBlacklist,
12
+ minLength,
13
+ maxLength,
14
+ includes,
15
+ excludes,
16
+ allowSubdomains = true,
17
+ businessOnly = false,
18
+ noDisposable = false,
19
+ lowercase = true,
20
+ transform,
21
+ defaultValue,
22
+ i18n
23
+ } = options ?? {};
24
+ const isRequired = required ?? false;
25
+ const getMessage = (key, params) => {
26
+ if (i18n) {
27
+ const currentLocale = getLocale();
28
+ const customMessages = i18n[currentLocale];
29
+ if (customMessages && customMessages[key]) {
30
+ const template = customMessages[key];
31
+ return template.replace(/\$\{(\w+)}/g, (_, k) => params?.[k] ?? "");
32
+ }
33
+ }
34
+ return t(`common.email.${key}`, params);
35
+ };
36
+ const disposableDomains = ["10minutemail.com", "tempmail.org", "guerrillamail.com", "mailinator.com", "yopmail.com", "temp-mail.org", "throwaway.email", "getnada.com", "maildrop.cc"];
37
+ const freeEmailDomains = ["gmail.com", "yahoo.com", "hotmail.com", "outlook.com", "icloud.com", "aol.com", "protonmail.com", "zoho.com"];
38
+ const actualDefaultValue = defaultValue ?? null;
39
+ const baseSchema = z.preprocess(
40
+ (val) => {
41
+ if (val === "" || val === null || val === void 0) {
42
+ return actualDefaultValue;
43
+ }
44
+ let processed = String(val).trim();
45
+ if (lowercase) {
46
+ processed = processed.toLowerCase();
47
+ }
48
+ if (transform) {
49
+ processed = transform(processed);
50
+ }
51
+ return processed;
52
+ },
53
+ z.union([z.string().email(), z.null()])
54
+ );
55
+ const schema = baseSchema.superRefine((val, ctx) => {
56
+ if (isRequired && val === null) {
57
+ ctx.addIssue({
58
+ code: "custom",
59
+ message: getMessage("required")
60
+ });
61
+ return;
62
+ }
63
+ if (val === null) return;
64
+ if (typeof val !== "string") {
65
+ ctx.addIssue({
66
+ code: "custom",
67
+ message: getMessage("invalid")
68
+ });
69
+ return;
70
+ }
71
+ if (minLength !== void 0 && val.length < minLength) {
72
+ ctx.addIssue({
73
+ code: "custom",
74
+ message: getMessage("minLength", { minLength })
75
+ });
76
+ return;
77
+ }
78
+ if (maxLength !== void 0 && val.length > maxLength) {
79
+ ctx.addIssue({
80
+ code: "custom",
81
+ message: getMessage("maxLength", { maxLength })
82
+ });
83
+ return;
84
+ }
85
+ if (includes !== void 0 && !val.includes(includes)) {
86
+ ctx.addIssue({
87
+ code: "custom",
88
+ message: getMessage("includes", { includes })
89
+ });
90
+ return;
91
+ }
92
+ if (excludes !== void 0) {
93
+ const excludeList = Array.isArray(excludes) ? excludes : [excludes];
94
+ for (const exclude of excludeList) {
95
+ if (val.includes(exclude)) {
96
+ ctx.addIssue({
97
+ code: "custom",
98
+ message: getMessage("includes", { includes: exclude })
99
+ });
100
+ return;
101
+ }
102
+ }
103
+ }
104
+ const emailDomain = val.split("@")[1]?.toLowerCase();
105
+ if (!emailDomain) {
106
+ ctx.addIssue({
107
+ code: "custom",
108
+ message: getMessage("invalid")
109
+ });
110
+ return;
111
+ }
112
+ if (businessOnly) {
113
+ const isFreeProvider = freeEmailDomains.some((freeDomain) => {
114
+ if (allowSubdomains) {
115
+ return emailDomain === freeDomain || emailDomain.endsWith("." + freeDomain);
116
+ }
117
+ return emailDomain === freeDomain;
118
+ });
119
+ if (isFreeProvider) {
120
+ ctx.addIssue({
121
+ code: "custom",
122
+ message: getMessage("businessOnly")
123
+ });
124
+ return;
125
+ }
126
+ }
127
+ if (domainBlacklist && domainBlacklist.length > 0) {
128
+ const isBlacklisted = domainBlacklist.some((blacklistedDomain) => {
129
+ const lowerDomain = blacklistedDomain.toLowerCase();
130
+ if (allowSubdomains) {
131
+ return emailDomain === lowerDomain || emailDomain.endsWith("." + lowerDomain);
132
+ }
133
+ return emailDomain === lowerDomain;
134
+ });
135
+ if (isBlacklisted) {
136
+ ctx.addIssue({
137
+ code: "custom",
138
+ message: getMessage("domainBlacklist", { domain: emailDomain })
139
+ });
140
+ return;
141
+ }
142
+ }
143
+ if (domain !== void 0) {
144
+ const allowedDomains = Array.isArray(domain) ? domain : [domain];
145
+ const isAllowed = allowedDomains.some((allowedDomain) => {
146
+ const lowerDomain = allowedDomain.toLowerCase();
147
+ if (allowSubdomains) {
148
+ return emailDomain === lowerDomain || emailDomain.endsWith("." + lowerDomain);
149
+ }
150
+ return emailDomain === lowerDomain;
151
+ });
152
+ if (!isAllowed) {
153
+ ctx.addIssue({
154
+ code: "custom",
155
+ message: getMessage("domain", { domain: Array.isArray(domain) ? domain.join(", ") : domain })
156
+ });
157
+ return;
158
+ }
159
+ }
160
+ if (noDisposable) {
161
+ const isDisposable = disposableDomains.some((disposableDomain) => {
162
+ if (allowSubdomains) {
163
+ return emailDomain === disposableDomain || emailDomain.endsWith("." + disposableDomain);
164
+ }
165
+ return emailDomain === disposableDomain;
166
+ });
167
+ if (isDisposable) {
168
+ ctx.addIssue({
169
+ code: "custom",
170
+ message: getMessage("noDisposable")
171
+ });
172
+ return;
173
+ }
174
+ }
175
+ });
176
+ return schema;
177
+ }
178
+
179
+ export {
180
+ email
181
+ };