schema-dsl 1.2.4 → 2.0.0

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 (242) hide show
  1. package/CHANGELOG.md +87 -210
  2. package/README.md +391 -2249
  3. package/dist/DslBuilder-DQDN0ZxZ.d.cts +341 -0
  4. package/dist/DslBuilder-DkLaOo9Q.d.ts +341 -0
  5. package/dist/Validator-C7GsVQOH.d.cts +192 -0
  6. package/dist/Validator-hFWKGxir.d.ts +192 -0
  7. package/dist/index.cjs +6594 -0
  8. package/dist/index.d.cts +1145 -0
  9. package/dist/index.d.ts +1145 -0
  10. package/dist/index.js +6528 -0
  11. package/dist/plugin-CIKtTMtS.d.cts +246 -0
  12. package/dist/plugin-CIKtTMtS.d.ts +246 -0
  13. package/dist/plugins/custom-format.cjs +3802 -0
  14. package/dist/plugins/custom-format.d.cts +12 -0
  15. package/dist/plugins/custom-format.d.ts +12 -0
  16. package/dist/plugins/custom-format.js +3772 -0
  17. package/dist/plugins/custom-type-example.cjs +3795 -0
  18. package/dist/plugins/custom-type-example.d.cts +8 -0
  19. package/dist/plugins/custom-type-example.d.ts +8 -0
  20. package/dist/plugins/custom-type-example.js +3765 -0
  21. package/dist/plugins/custom-validator.cjs +146 -0
  22. package/dist/plugins/custom-validator.d.cts +10 -0
  23. package/dist/plugins/custom-validator.d.ts +10 -0
  24. package/dist/plugins/custom-validator.js +121 -0
  25. package/docs/FEATURE-INDEX.md +102 -68
  26. package/docs/add-custom-locale.md +48 -35
  27. package/docs/add-keyword.md +24 -0
  28. package/docs/api-reference.md +396 -154
  29. package/docs/api.md +13 -0
  30. package/docs/best-practices-project-structure.md +19 -10
  31. package/docs/best-practices.md +93 -53
  32. package/docs/cache-manager.md +23 -15
  33. package/docs/compile.md +45 -0
  34. package/docs/conditional-api.md +40 -11
  35. package/docs/custom-extensions-guide.md +80 -152
  36. package/docs/design-philosophy.md +76 -71
  37. package/docs/doc-index.md +324 -0
  38. package/docs/dsl-syntax.md +69 -19
  39. package/docs/dynamic-locale.md +24 -14
  40. package/docs/enum.md +12 -5
  41. package/docs/error-handling.md +53 -44
  42. package/docs/export-guide.md +47 -8
  43. package/docs/export-limitations.md +27 -11
  44. package/docs/faq.md +86 -67
  45. package/docs/frontend-i18n-guide.md +26 -12
  46. package/docs/i18n-user-guide.md +60 -47
  47. package/docs/i18n.md +51 -32
  48. package/docs/index.md +48 -0
  49. package/docs/json-schema-basics.md +40 -0
  50. package/docs/label-vs-description.md +12 -3
  51. package/docs/markdown-exporter.md +15 -6
  52. package/docs/mongodb-exporter.md +11 -4
  53. package/docs/multi-language.md +26 -0
  54. package/docs/multi-type-support.md +26 -33
  55. package/docs/mysql-exporter.md +9 -2
  56. package/docs/number-operators.md +12 -5
  57. package/docs/optional-marker-guide.md +28 -23
  58. package/docs/performance-guide.md +49 -0
  59. package/docs/plugin-system.md +205 -366
  60. package/docs/plugin-type-registration.md +34 -0
  61. package/docs/postgresql-exporter.md +9 -2
  62. package/docs/public/favicon.svg +5 -0
  63. package/docs/quick-start.md +37 -363
  64. package/docs/runtime-locale-support.md +20 -9
  65. package/docs/schema-helper.md +10 -5
  66. package/docs/schema-utils-advanced-issues.md +23 -0
  67. package/docs/schema-utils-best-practices.md +20 -0
  68. package/docs/schema-utils-chaining.md +7 -0
  69. package/docs/schema-utils.md +76 -42
  70. package/docs/security-checklist.md +20 -0
  71. package/docs/string-extensions.md +17 -9
  72. package/docs/troubleshooting.md +36 -21
  73. package/docs/type-converter.md +41 -50
  74. package/docs/type-reference.md +38 -15
  75. package/docs/typescript-guide.md +53 -42
  76. package/docs/union-type-guide.md +11 -1
  77. package/docs/union-types.md +10 -3
  78. package/docs/validate-async.md +36 -25
  79. package/docs/validate-batch.md +49 -0
  80. package/docs/validate-dsl-object-support.md +33 -28
  81. package/docs/validate.md +36 -16
  82. package/docs/validation-guide.md +25 -7
  83. package/docs/validator.md +39 -0
  84. package/package.json +85 -27
  85. package/plugins/custom-format.cjs +8 -0
  86. package/plugins/custom-type-example.cjs +8 -0
  87. package/plugins/custom-validator.cjs +8 -0
  88. package/src/adapters/DslAdapter.ts +111 -0
  89. package/src/adapters/index.ts +1 -0
  90. package/src/config/constants.ts +83 -0
  91. package/src/config/index.ts +2 -0
  92. package/src/config/patterns.ts +77 -0
  93. package/src/core/CacheManager.ts +159 -0
  94. package/src/core/ConditionalBuilder.ts +382 -0
  95. package/src/core/ConditionalRuntime.ts +28 -0
  96. package/src/core/ConditionalValidator.ts +255 -0
  97. package/src/core/DslBuilder.ts +677 -0
  98. package/src/core/ErrorCodes.ts +38 -0
  99. package/src/core/ErrorFormatter.ts +271 -0
  100. package/src/core/JSONSchemaCore.ts +65 -0
  101. package/src/core/Locale.ts +187 -0
  102. package/src/core/MessageTemplate.ts +42 -0
  103. package/src/core/ObjectDslBuilder.ts +64 -0
  104. package/src/core/PluginManager.ts +326 -0
  105. package/src/core/StringExtensions.ts +140 -0
  106. package/src/core/TemplateEngine.ts +44 -0
  107. package/src/core/Validator.ts +448 -0
  108. package/src/errors/I18nError.ts +159 -0
  109. package/src/errors/ValidationError.ts +105 -0
  110. package/src/exporters/BaseExporter.ts +60 -0
  111. package/src/exporters/MarkdownExporter.ts +305 -0
  112. package/src/exporters/MongoDBExporter.ts +126 -0
  113. package/src/exporters/MySQLExporter.ts +155 -0
  114. package/src/exporters/PostgreSQLExporter.ts +222 -0
  115. package/src/exporters/index.ts +18 -0
  116. package/src/index.ts +633 -0
  117. package/{lib/locales/en-US.js → src/locales/en-US.ts} +21 -37
  118. package/{lib/locales/es-ES.js → src/locales/es-ES.ts} +63 -16
  119. package/{lib/locales/fr-FR.js → src/locales/fr-FR.ts} +74 -27
  120. package/src/locales/index.ts +103 -0
  121. package/{lib/locales/ja-JP.js → src/locales/ja-JP.ts} +59 -17
  122. package/src/locales/types.ts +156 -0
  123. package/{lib/locales/zh-CN.js → src/locales/zh-CN.ts} +21 -38
  124. package/src/parser/ConstraintParser.ts +101 -0
  125. package/src/parser/DslParser.ts +470 -0
  126. package/src/parser/SchemaCompiler.ts +66 -0
  127. package/src/parser/TypeRegistry.ts +250 -0
  128. package/src/parser/index.ts +6 -0
  129. package/src/plugins/custom-format.ts +126 -0
  130. package/src/plugins/custom-type-example.ts +108 -0
  131. package/src/plugins/custom-validator.ts +140 -0
  132. package/src/types/conditional.ts +28 -0
  133. package/src/types/config.ts +59 -0
  134. package/src/types/dsl.ts +131 -0
  135. package/src/types/error.ts +60 -0
  136. package/src/types/index.ts +17 -0
  137. package/src/types/infer.ts +128 -0
  138. package/src/types/plugin.ts +58 -0
  139. package/src/types/safe-regex.d.ts +9 -0
  140. package/src/types/schema.ts +66 -0
  141. package/src/types/validate.ts +71 -0
  142. package/src/utils/SchemaHelper.ts +196 -0
  143. package/src/utils/SchemaUtils.ts +346 -0
  144. package/src/utils/TypeConverter.ts +215 -0
  145. package/src/utils/index.ts +10 -0
  146. package/src/validators/CustomKeywords.ts +477 -0
  147. package/.eslintignore +0 -11
  148. package/.eslintrc.json +0 -27
  149. package/CONTRIBUTING.md +0 -368
  150. package/STATUS.md +0 -491
  151. package/changelogs/v1.0.0.md +0 -328
  152. package/changelogs/v1.0.9.md +0 -367
  153. package/changelogs/v1.1.0.md +0 -389
  154. package/changelogs/v1.1.1.md +0 -308
  155. package/changelogs/v1.1.2.md +0 -183
  156. package/changelogs/v1.1.3.md +0 -161
  157. package/changelogs/v1.1.4.md +0 -432
  158. package/changelogs/v1.1.5.md +0 -493
  159. package/changelogs/v1.1.6.md +0 -211
  160. package/changelogs/v1.1.8.md +0 -376
  161. package/changelogs/v1.2.3.md +0 -124
  162. package/docs/INDEX.md +0 -252
  163. package/docs/issues-resolved-summary.md +0 -196
  164. package/docs/performance-benchmark-report.md +0 -179
  165. package/docs/performance-quick-reference.md +0 -123
  166. package/docs/user-questions-answered.md +0 -353
  167. package/docs/validation-rules-v1.0.2.md +0 -1608
  168. package/examples/README.md +0 -81
  169. package/examples/array-dsl-example.js +0 -227
  170. package/examples/conditional-example.js +0 -288
  171. package/examples/conditional-non-object.js +0 -129
  172. package/examples/conditional-validate-example.js +0 -321
  173. package/examples/custom-extension.js +0 -85
  174. package/examples/dsl-match-example.js +0 -74
  175. package/examples/dsl-style.js +0 -118
  176. package/examples/dynamic-locale-configuration.js +0 -348
  177. package/examples/dynamic-locale-example.js +0 -287
  178. package/examples/enum.examples.js +0 -324
  179. package/examples/export-demo.js +0 -130
  180. package/examples/express-integration.js +0 -376
  181. package/examples/i18n-error-handling-complete.js +0 -381
  182. package/examples/i18n-error-handling-quickstart.md +0 -0
  183. package/examples/i18n-error.examples.js +0 -181
  184. package/examples/i18n-full-demo.js +0 -301
  185. package/examples/i18n-memory-safety.examples.js +0 -268
  186. package/examples/markdown-export.js +0 -71
  187. package/examples/middleware-usage.js +0 -93
  188. package/examples/new-features-comparison.js +0 -315
  189. package/examples/password-reset/README.md +0 -153
  190. package/examples/password-reset/schema.js +0 -26
  191. package/examples/password-reset/test.js +0 -101
  192. package/examples/plugin-system.examples.js +0 -205
  193. package/examples/schema-utils-chaining.examples.js +0 -250
  194. package/examples/simple-example.js +0 -122
  195. package/examples/slug.examples.js +0 -179
  196. package/examples/string-extensions.js +0 -297
  197. package/examples/union-type-example.js +0 -127
  198. package/examples/union-types-example.js +0 -77
  199. package/examples/user-registration/README.md +0 -156
  200. package/examples/user-registration/routes.js +0 -92
  201. package/examples/user-registration/schema.js +0 -150
  202. package/examples/user-registration/server.js +0 -74
  203. package/index.d.ts +0 -3540
  204. package/index.js +0 -457
  205. package/index.mjs +0 -60
  206. package/lib/adapters/DslAdapter.js +0 -871
  207. package/lib/adapters/index.js +0 -20
  208. package/lib/config/constants.js +0 -286
  209. package/lib/config/patterns/common.js +0 -47
  210. package/lib/config/patterns/creditCard.js +0 -9
  211. package/lib/config/patterns/idCard.js +0 -9
  212. package/lib/config/patterns/index.js +0 -9
  213. package/lib/config/patterns/licensePlate.js +0 -4
  214. package/lib/config/patterns/passport.js +0 -4
  215. package/lib/config/patterns/phone.js +0 -9
  216. package/lib/config/patterns/postalCode.js +0 -5
  217. package/lib/core/CacheManager.js +0 -376
  218. package/lib/core/ConditionalBuilder.js +0 -503
  219. package/lib/core/DslBuilder.js +0 -1400
  220. package/lib/core/ErrorCodes.js +0 -233
  221. package/lib/core/ErrorFormatter.js +0 -445
  222. package/lib/core/JSONSchemaCore.js +0 -347
  223. package/lib/core/Locale.js +0 -130
  224. package/lib/core/MessageTemplate.js +0 -98
  225. package/lib/core/PluginManager.js +0 -448
  226. package/lib/core/StringExtensions.js +0 -240
  227. package/lib/core/Validator.js +0 -654
  228. package/lib/errors/I18nError.js +0 -328
  229. package/lib/errors/ValidationError.js +0 -191
  230. package/lib/exporters/MarkdownExporter.js +0 -420
  231. package/lib/exporters/MongoDBExporter.js +0 -162
  232. package/lib/exporters/MySQLExporter.js +0 -212
  233. package/lib/exporters/PostgreSQLExporter.js +0 -289
  234. package/lib/exporters/index.js +0 -24
  235. package/lib/locales/index.js +0 -8
  236. package/lib/utils/LRUCache.js +0 -174
  237. package/lib/utils/SchemaHelper.js +0 -240
  238. package/lib/utils/SchemaUtils.js +0 -445
  239. package/lib/utils/TypeConverter.js +0 -245
  240. package/lib/utils/index.js +0 -13
  241. package/lib/validators/CustomKeywords.js +0 -616
  242. package/lib/validators/index.js +0 -11
@@ -0,0 +1,3772 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+
11
+ // src/parser/TypeRegistry.ts
12
+ var INTERNAL_KEYS, BUILTIN_TYPES, CUSTOM_TYPES, DYNAMIC_TYPES, _strictMode, TypeRegistry;
13
+ var init_TypeRegistry = __esm({
14
+ "src/parser/TypeRegistry.ts"() {
15
+ "use strict";
16
+ INTERNAL_KEYS = /* @__PURE__ */ new Set([
17
+ "_label",
18
+ "_customMessages",
19
+ "_description",
20
+ "_required",
21
+ "_isConditional",
22
+ "_runtimeOnlyConditional",
23
+ "conditions",
24
+ "_evaluateCondition",
25
+ // Custom AJV keywords (non-standard JSON Schema fields, stripped on output)
26
+ "exactLength",
27
+ "alphanum",
28
+ "lowercase",
29
+ "uppercase",
30
+ "trim",
31
+ "jsonString",
32
+ "port",
33
+ "requiredAll",
34
+ "strictSchema",
35
+ "noSparse",
36
+ "includesRequired",
37
+ "dateFormat",
38
+ "dateGreater",
39
+ "dateLess",
40
+ "precision"
41
+ // ⚠️ multipleOf is a standard JSON Schema field and is NOT in this list (fix DB-01)
42
+ ]);
43
+ BUILTIN_TYPES = /* @__PURE__ */ new Map([
44
+ // --- Primitive types ---
45
+ ["string", { baseSchema: { type: "string" } }],
46
+ ["number", { baseSchema: { type: "number" } }],
47
+ ["integer", { baseSchema: { type: "integer" } }],
48
+ ["boolean", { baseSchema: { type: "boolean" } }],
49
+ ["object", { baseSchema: { type: "object" } }],
50
+ ["array", { baseSchema: { type: "array" } }],
51
+ ["null", { baseSchema: { type: "null" } }],
52
+ ["any", { baseSchema: {} }],
53
+ // --- Format types ---
54
+ ["email", { baseSchema: { type: "string", format: "email" } }],
55
+ ["url", { baseSchema: { type: "string", format: "uri" } }],
56
+ ["uri", { baseSchema: { type: "string", format: "uri" } }],
57
+ ["uuid", { baseSchema: { type: "string", format: "uuid" } }],
58
+ ["ipv4", { baseSchema: { type: "string", format: "ipv4" } }],
59
+ ["ipv6", { baseSchema: { type: "string", format: "ipv6" } }],
60
+ ["ip", { baseSchema: { anyOf: [{ type: "string", format: "ipv4" }, { type: "string", format: "ipv6" }] } }],
61
+ ["hostname", { baseSchema: { type: "string", format: "hostname" } }],
62
+ ["date", { baseSchema: { type: "string", format: "date" } }],
63
+ ["datetime", { baseSchema: { type: "string", format: "date-time" } }],
64
+ ["time", { baseSchema: { type: "string", format: "time" } }],
65
+ // --- Special string types ---
66
+ ["binary", { baseSchema: { type: "string", contentEncoding: "base64" } }],
67
+ ["objectId", { baseSchema: { type: "string", pattern: "^[0-9a-fA-F]{24}$" }, customMessages: { pattern: "pattern.objectId" } }],
68
+ ["hexColor", { baseSchema: { type: "string", pattern: "^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$" }, customMessages: { pattern: "pattern.hexColor" } }],
69
+ ["macAddress", {
70
+ baseSchema: { type: "string", pattern: "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$" },
71
+ customMessages: { pattern: "pattern.macAddress" }
72
+ }],
73
+ ["cron", {
74
+ baseSchema: {
75
+ type: "string",
76
+ pattern: "^(\\*|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\\*\\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])) (\\*|([0-9]|1[0-9]|2[0-3])|\\*\\/([0-9]|1[0-9]|2[0-3])) (\\*|([1-9]|1[0-9]|2[0-9]|3[0-1])|\\*\\/([1-9]|1[0-9]|2[0-9]|3[0-1])) (\\*|([1-9]|1[0-2])|\\*\\/([1-9]|1[0-2])) (\\*|([0-6])|\\*\\/([0-6]))$"
77
+ },
78
+ customMessages: { pattern: "pattern.cron" }
79
+ }],
80
+ // --- slug (fix DB-02: v1 DslAdapter was missing slug type definition) ---
81
+ ["slug", {
82
+ baseSchema: { type: "string", pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*$" },
83
+ customMessages: { pattern: "pattern.slug" }
84
+ }],
85
+ // --- CJK / Chinese ---
86
+ ["chineseName", {
87
+ baseSchema: { type: "string", pattern: "^[\\u4e00-\\u9fa5]{2,10}$" },
88
+ customMessages: { pattern: "chineseName" }
89
+ }],
90
+ ["chinese", {
91
+ baseSchema: { type: "string", pattern: "^[\\u4e00-\\u9fa5]+$" }
92
+ }],
93
+ // --- Domain-related (handled by CustomKeywords; only baseSchema registered here) ---
94
+ ["emailDomain", { baseSchema: { type: "string", format: "email" } }],
95
+ // --- v1 extension types (DslBuilder v1.0.2) ---
96
+ ["alphanum", { baseSchema: { type: "string", alphanum: true } }],
97
+ ["lower", { baseSchema: { type: "string", lowercase: true } }],
98
+ ["upper", { baseSchema: { type: "string", uppercase: true } }],
99
+ ["json", { baseSchema: { type: "string", jsonString: true } }],
100
+ ["port", { baseSchema: { type: "integer", port: true } }]
101
+ ]);
102
+ CUSTOM_TYPES = /* @__PURE__ */ new Map();
103
+ DYNAMIC_TYPES = /* @__PURE__ */ new Map();
104
+ _strictMode = false;
105
+ TypeRegistry = {
106
+ /**
107
+ * Resolve a type name to its TypeDefinition.
108
+ * Built-in types take priority; custom types may override non-primitive built-ins.
109
+ */
110
+ resolve(typeName) {
111
+ const dynamicFn = DYNAMIC_TYPES.get(typeName);
112
+ if (dynamicFn) {
113
+ return { baseSchema: dynamicFn() };
114
+ }
115
+ const custom = CUSTOM_TYPES.get(typeName);
116
+ if (custom) return custom;
117
+ const builtin = BUILTIN_TYPES.get(typeName);
118
+ if (builtin) return builtin;
119
+ if (_strictMode) {
120
+ throw new Error(`[schema-dsl] Unknown type "${typeName}"`);
121
+ }
122
+ console.warn(`[schema-dsl] Unknown type "${typeName}", falling back to string`);
123
+ return { baseSchema: { type: "string" } };
124
+ },
125
+ /**
126
+ * Register a custom type (delegated from DslBuilder.registerType)
127
+ */
128
+ register(name, def) {
129
+ if (!name || typeof name !== "string") {
130
+ throw new Error("[schema-dsl] TypeRegistry.register: name must be a non-empty string");
131
+ }
132
+ const normalized = "baseSchema" in def ? def : { baseSchema: def };
133
+ CUSTOM_TYPES.set(name, normalized);
134
+ },
135
+ /**
136
+ * Register a dynamic type (factory function invoked on every resolve call)
137
+ */
138
+ registerDynamic(name, factory) {
139
+ if (!name || typeof name !== "string") {
140
+ throw new Error("[schema-dsl] TypeRegistry.registerDynamic: name must be a non-empty string");
141
+ }
142
+ DYNAMIC_TYPES.set(name, factory);
143
+ },
144
+ /**
145
+ * Unregister a custom type
146
+ */
147
+ unregister(name) {
148
+ CUSTOM_TYPES.delete(name);
149
+ DYNAMIC_TYPES.delete(name);
150
+ },
151
+ /**
152
+ * Clear all custom and dynamic types (primarily for testing; called by DslBuilder.clearCustomTypes).
153
+ * Built-in types are unaffected.
154
+ */
155
+ clearCustomTypes() {
156
+ CUSTOM_TYPES.clear();
157
+ DYNAMIC_TYPES.clear();
158
+ },
159
+ /**
160
+ * Enable or disable strict mode for type resolution.
161
+ * In strict mode, resolving an unknown type throws instead of warning and falling back to string.
162
+ */
163
+ setStrict(flag) {
164
+ _strictMode = flag;
165
+ },
166
+ /**
167
+ * Check whether a type is registered (built-in or custom)
168
+ */
169
+ has(typeName) {
170
+ return BUILTIN_TYPES.has(typeName) || CUSTOM_TYPES.has(typeName) || DYNAMIC_TYPES.has(typeName);
171
+ },
172
+ /**
173
+ * Return an iterator over all registered types (built-in + custom; custom overrides same-name built-in)
174
+ * BC-4 compat: consumed by the DslAdapter.typeMap getter
175
+ */
176
+ entries() {
177
+ const merged = new Map([...BUILTIN_TYPES, ...CUSTOM_TYPES]);
178
+ return merged.entries();
179
+ },
180
+ /**
181
+ * Return the internal key set (used to strip non-standard fields during toJsonSchema)
182
+ */
183
+ getInternalKeys() {
184
+ return INTERNAL_KEYS;
185
+ },
186
+ /**
187
+ * Strip internal keys from a schema and return a clean JSON Schema.
188
+ *
189
+ * Special case for exactLength: translated to standard minLength + maxLength
190
+ * instead of being stripped. This preserves v1 DslBuilder string:N behavior
191
+ * (output {minLength:N, maxLength:N}) while keeping AJV's exactLength Unicode
192
+ * code-point counting advantage internally (CK-Y04).
193
+ */
194
+ toJsonSchema(schema) {
195
+ const result = {};
196
+ for (const [k, v] of Object.entries(schema)) {
197
+ if (k === "exactLength" && typeof v === "number") {
198
+ result.minLength = v;
199
+ result.maxLength = v;
200
+ } else if (!INTERNAL_KEYS.has(k)) {
201
+ result[k] = v;
202
+ }
203
+ }
204
+ return result;
205
+ }
206
+ };
207
+ }
208
+ });
209
+
210
+ // src/parser/ConstraintParser.ts
211
+ var ConstraintParser;
212
+ var init_ConstraintParser = __esm({
213
+ "src/parser/ConstraintParser.ts"() {
214
+ "use strict";
215
+ ConstraintParser = {
216
+ /**
217
+ * Parse a constraint string
218
+ * @param constraintStr - The constraint portion (type name and '!' already stripped)
219
+ * @param baseType - Base type name ('string' | 'number' | 'integer' | 'array' | ...)
220
+ * @returns Partial<JSONSchema>; returns {} when unparseable (avoids polluting the target schema)
221
+ */
222
+ parse(constraintStr, baseType) {
223
+ if (!constraintStr) return {};
224
+ const s = constraintStr.trim();
225
+ if (!s) return {};
226
+ if (baseType === "number" || baseType === "integer") {
227
+ const gteMatch = /^>=(-?\d+(?:\.\d+)?)$/.exec(s);
228
+ if (gteMatch) return { minimum: parseFloat(gteMatch[1]) };
229
+ const lteMatch = /^<=(-?\d+(?:\.\d+)?)$/.exec(s);
230
+ if (lteMatch) return { maximum: parseFloat(lteMatch[1]) };
231
+ const gtMatch = /^>(-?\d+(?:\.\d+)?)$/.exec(s);
232
+ if (gtMatch) return { exclusiveMinimum: parseFloat(gtMatch[1]) };
233
+ const ltMatch = /^<(-?\d+(?:\.\d+)?)$/.exec(s);
234
+ if (ltMatch) return { exclusiveMaximum: parseFloat(ltMatch[1]) };
235
+ const eqMatch = /^=(-?\d+(?:\.\d+)?)$/.exec(s);
236
+ if (eqMatch) return { enum: [parseFloat(eqMatch[1])] };
237
+ }
238
+ if (s.includes("|") && !/^-?\d*\.?\d*--?\d*\.?\d*$/.test(s)) {
239
+ return { enum: s.split("|").map((v) => v.trim()) };
240
+ }
241
+ const rangeMatch = /^(-?\d*\.?\d*)-(-?\d*\.?\d*)$/.exec(s);
242
+ if (rangeMatch) {
243
+ const [, rawMin, rawMax] = rangeMatch;
244
+ const result = {};
245
+ if (baseType === "string") {
246
+ if (rawMin) result.minLength = Math.max(0, parseInt(rawMin, 10));
247
+ if (rawMax) result.maxLength = Math.abs(parseInt(rawMax, 10));
248
+ } else if (baseType === "array") {
249
+ if (rawMin) result.minItems = Math.max(0, parseInt(rawMin, 10));
250
+ if (rawMax) result.maxItems = Math.abs(parseInt(rawMax, 10));
251
+ } else {
252
+ if (rawMin) result.minimum = parseFloat(rawMin);
253
+ if (rawMax) result.maximum = parseFloat(rawMax);
254
+ }
255
+ return result;
256
+ }
257
+ const singleMatch = /^(\d+(?:\.\d+)?)$/.exec(s);
258
+ if (singleMatch) {
259
+ const value = parseFloat(singleMatch[1]);
260
+ if (baseType === "string") {
261
+ return { exactLength: Math.floor(value) };
262
+ } else if (baseType === "array") {
263
+ return { maxItems: Math.floor(value) };
264
+ } else {
265
+ return { maximum: value };
266
+ }
267
+ }
268
+ console.warn(`[schema-dsl] ConstraintParser: unrecognized constraint "${constraintStr}" for type "${baseType}" \u2014 ignored`);
269
+ return {};
270
+ }
271
+ };
272
+ }
273
+ });
274
+
275
+ // src/parser/SchemaCompiler.ts
276
+ var SchemaCompiler;
277
+ var init_SchemaCompiler = __esm({
278
+ "src/parser/SchemaCompiler.ts"() {
279
+ "use strict";
280
+ SchemaCompiler = {
281
+ /**
282
+ * Compile and return a JSONSchema (including internal keys; stripped by toJsonSchema).
283
+ */
284
+ compile(typeDef, constraints, meta) {
285
+ const schema = {
286
+ ...typeDef.baseSchema,
287
+ ...constraints
288
+ };
289
+ if (typeDef.customMessages) {
290
+ schema["_customMessages"] = {
291
+ ...schema["_customMessages"],
292
+ ...typeDef.customMessages
293
+ };
294
+ }
295
+ if (meta?.label) schema["_label"] = meta.label;
296
+ if (meta?.required) schema["_required"] = true;
297
+ if (meta?.afterCompileHook) {
298
+ meta.afterCompileHook(schema);
299
+ }
300
+ return schema;
301
+ },
302
+ /**
303
+ * Strip internal keys and return a clean JSON Schema (used by toJsonSchema() output).
304
+ */
305
+ toJsonSchema(schema, internalKeys) {
306
+ const result = {};
307
+ for (const [k, v] of Object.entries(schema)) {
308
+ if (!internalKeys.has(k)) {
309
+ result[k] = v;
310
+ }
311
+ }
312
+ return result;
313
+ }
314
+ };
315
+ }
316
+ });
317
+
318
+ // src/config/patterns.ts
319
+ var phone, idCard, creditCard, licensePlate, postalCode, passport, common, PATTERNS;
320
+ var init_patterns = __esm({
321
+ "src/config/patterns.ts"() {
322
+ "use strict";
323
+ phone = {
324
+ cn: { pattern: /^1[3-9]\d{9}$/, min: 11, max: 11, key: "pattern.phone.cn" },
325
+ us: { pattern: /^\d{10}$/, min: 10, max: 10, key: "pattern.phone.us" },
326
+ uk: { pattern: /^(\+44\s?)?0?\d{10}$/, min: 10, max: 15, key: "pattern.phone.uk" },
327
+ hk: { pattern: /^[5-9]\d{7}$/, min: 8, max: 8, key: "pattern.phone.hk" },
328
+ tw: { pattern: /^09\d{8}$/, min: 10, max: 10, key: "pattern.phone.tw" },
329
+ international: { pattern: /^\+[1-9]\d{1,14}$/, min: 8, max: 15, key: "pattern.phone.international" }
330
+ };
331
+ idCard = {
332
+ cn: {
333
+ pattern: /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/,
334
+ min: 18,
335
+ max: 18,
336
+ key: "pattern.idCard.cn"
337
+ }
338
+ };
339
+ creditCard = {
340
+ visa: { pattern: /^4[0-9]{12}(?:[0-9]{3})?$/, key: "pattern.creditCard.visa" },
341
+ mastercard: { pattern: /^5[1-5][0-9]{14}$/, key: "pattern.creditCard.mastercard" },
342
+ amex: { pattern: /^3[47][0-9]{13}$/, key: "pattern.creditCard.amex" },
343
+ discover: { pattern: /^6(?:011|5[0-9]{2})[0-9]{12}$/, key: "pattern.creditCard.discover" },
344
+ jcb: { pattern: /^(?:2131|1800|35\d{3})\d{11}$/, key: "pattern.creditCard.jcb" },
345
+ unionpay: { pattern: /^62[0-9]{14,17}$/, key: "pattern.creditCard.unionpay" }
346
+ };
347
+ licensePlate = {
348
+ cn: {
349
+ pattern: /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]$/,
350
+ key: "pattern.licensePlate.cn"
351
+ }
352
+ };
353
+ postalCode = {
354
+ cn: { pattern: /^[1-9]\d{5}$/, key: "pattern.postalCode.cn" },
355
+ us: { pattern: /^\d{5}(-\d{4})?$/, key: "pattern.postalCode.us" }
356
+ };
357
+ passport = {
358
+ cn: {
359
+ pattern: /(^[EeKkGgDdHhMQqSs][0-9]{8}$)|(^(([Ee][a-fA-F])|([DdSPp][Ee])|([Kk][Jj])|([Mm][Aa])|(1[45]))[0-9]{7}$)/,
360
+ key: "pattern.passport.cn"
361
+ }
362
+ };
363
+ common = {
364
+ domain: {
365
+ pattern: /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$/i,
366
+ key: "pattern.domain",
367
+ min: 3,
368
+ max: 253
369
+ },
370
+ ip: {
371
+ // Composite IPv4 + IPv6 pattern (same as v1)
372
+ pattern: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$|^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/,
373
+ key: "pattern.ip"
374
+ },
375
+ base64: {
376
+ pattern: /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/,
377
+ key: "pattern.base64"
378
+ },
379
+ jwt: {
380
+ pattern: /^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]*$/,
381
+ key: "pattern.jwt"
382
+ }
383
+ };
384
+ PATTERNS = { phone, idCard, creditCard, licensePlate, postalCode, passport, common };
385
+ }
386
+ });
387
+
388
+ // src/parser/DslParser.ts
389
+ function _isRawJsonSchema(obj) {
390
+ if (typeof obj["type"] === "string" && JSON_SCHEMA_TYPES.has(obj["type"])) return true;
391
+ if ("anyOf" in obj || "oneOf" in obj || "allOf" in obj || "$ref" in obj) return true;
392
+ return false;
393
+ }
394
+ function _cleanRequiredMarks(schema) {
395
+ if (!schema || typeof schema !== "object") return;
396
+ delete schema["_required"];
397
+ const obj = schema;
398
+ if (obj.properties) {
399
+ for (const prop of Object.values(obj.properties)) _cleanRequiredMarks(prop);
400
+ }
401
+ if (obj.items) _cleanRequiredMarks(obj.items);
402
+ }
403
+ function _copyHiddenSchemaProperties(source, target) {
404
+ for (const symbol of Object.getOwnPropertySymbols(source)) {
405
+ const descriptor = Object.getOwnPropertyDescriptor(source, symbol);
406
+ if (descriptor) Object.defineProperty(target, symbol, descriptor);
407
+ }
408
+ }
409
+ function _resolveDsl(value) {
410
+ if (value === null || value === void 0) return {};
411
+ if (typeof value === "string") return DslParser.parseString(value);
412
+ if (typeof value === "object" && !Array.isArray(value)) {
413
+ const obj = value;
414
+ if (typeof obj["toSchema"] === "function") return obj["toSchema"]();
415
+ if (_isRawJsonSchema(obj)) return value;
416
+ return DslParser.parseObject(value);
417
+ }
418
+ return value;
419
+ }
420
+ function _schemaForTarget(targetField, dslValue) {
421
+ const s = _resolveDsl(dslValue);
422
+ const isRequired = s._required;
423
+ _cleanRequiredMarks(s);
424
+ const result = { properties: { [targetField]: s } };
425
+ if (isRequired) result.required = [targetField];
426
+ return result;
427
+ }
428
+ function _buildMatchSchema(conditionField, targetField, map) {
429
+ const entries = Object.entries(map).filter(([k]) => k !== "_default");
430
+ const defaultDsl = map["_default"];
431
+ const build = (index) => {
432
+ if (index >= entries.length) {
433
+ if (defaultDsl === null || defaultDsl === void 0) return {};
434
+ const defaultObj = defaultDsl;
435
+ if (defaultObj && defaultObj["_isMatch"]) {
436
+ return _buildMatchSchema(String(defaultObj["field"]), targetField, defaultObj["map"]);
437
+ }
438
+ if (defaultObj && defaultObj["_isIf"]) {
439
+ return _buildIfSchema(String(defaultObj["condition"]), targetField, defaultObj["then"], defaultObj["else"]);
440
+ }
441
+ return _schemaForTarget(targetField, defaultDsl);
442
+ }
443
+ const [val, dslValue] = entries[index];
444
+ if (dslValue === null || dslValue === void 0) return build(index + 1);
445
+ const branchObj = dslValue;
446
+ let thenSchema;
447
+ if (branchObj && branchObj["_isMatch"]) {
448
+ thenSchema = _buildMatchSchema(String(branchObj["field"]), targetField, branchObj["map"]);
449
+ } else if (branchObj && branchObj["_isIf"]) {
450
+ thenSchema = _buildIfSchema(String(branchObj["condition"]), targetField, branchObj["then"], branchObj["else"]);
451
+ } else {
452
+ thenSchema = _schemaForTarget(targetField, dslValue);
453
+ }
454
+ return {
455
+ if: { properties: { [conditionField]: { const: val } } },
456
+ then: thenSchema,
457
+ else: build(index + 1)
458
+ };
459
+ };
460
+ return build(0);
461
+ }
462
+ function _buildIfSchema(conditionField, targetField, thenDsl, elseDsl) {
463
+ const thenObj = thenDsl;
464
+ const elseObj = elseDsl;
465
+ let thenResult;
466
+ if (thenObj && thenObj["_isMatch"]) {
467
+ thenResult = _buildMatchSchema(String(thenObj["field"]), targetField, thenObj["map"]);
468
+ } else if (thenObj && thenObj["_isIf"]) {
469
+ thenResult = _buildIfSchema(String(thenObj["condition"]), targetField, thenObj["then"], thenObj["else"]);
470
+ } else {
471
+ thenResult = _schemaForTarget(targetField, thenDsl);
472
+ }
473
+ let elseResult = {};
474
+ if (elseDsl !== null && elseDsl !== void 0) {
475
+ if (elseObj && elseObj["_isMatch"]) {
476
+ elseResult = _buildMatchSchema(String(elseObj["field"]), targetField, elseObj["map"]);
477
+ } else if (elseObj && elseObj["_isIf"]) {
478
+ elseResult = _buildIfSchema(String(elseObj["condition"]), targetField, elseObj["then"], elseObj["else"]);
479
+ } else {
480
+ elseResult = _schemaForTarget(targetField, elseDsl);
481
+ }
482
+ }
483
+ return {
484
+ if: { properties: { [conditionField]: { const: true } } },
485
+ then: thenResult,
486
+ else: elseResult
487
+ };
488
+ }
489
+ var JSON_SCHEMA_TYPES, DslParser;
490
+ var init_DslParser = __esm({
491
+ "src/parser/DslParser.ts"() {
492
+ "use strict";
493
+ init_TypeRegistry();
494
+ init_ConstraintParser();
495
+ init_SchemaCompiler();
496
+ init_patterns();
497
+ JSON_SCHEMA_TYPES = /* @__PURE__ */ new Set(["string", "number", "integer", "boolean", "array", "object", "null"]);
498
+ DslParser = {
499
+ /**
500
+ * Parse a DSL string → JSONSchema
501
+ *
502
+ * Supported formats:
503
+ * - 'string' → { type: 'string' }
504
+ * - 'string!' → { type: 'string', _required: true }
505
+ * - 'string:6' → { type: 'string', exactLength: 6 } (DA-03 fix)
506
+ * - 'string:3-32' → { type: 'string', minLength: 3, maxLength: 32 }
507
+ * - 'number:0-100' → { type: 'number', minimum: 0, maximum: 100 }
508
+ * - 'number:-100-0' → { type: 'number', minimum: -100, maximum: 0 } (DB-03 fix)
509
+ * - 'enum:a,b,c' → { type: 'string', enum: ['a','b','c'] }
510
+ * - 'a|b|c' → { type: 'string', enum: ['a','b','c'] }
511
+ * - 'array!1-10' → { type: 'array', minItems:1, maxItems:10, _required:true }
512
+ */
513
+ parseString(dslStr) {
514
+ if (!dslStr || typeof dslStr !== "string") {
515
+ return { type: "string" };
516
+ }
517
+ let s = dslStr.trim();
518
+ let required = false;
519
+ const arrayBangMatch = /^array!([\d-]+)$/.exec(s);
520
+ if (arrayBangMatch) {
521
+ s = `array:${arrayBangMatch[1]}`;
522
+ required = true;
523
+ }
524
+ if (s.endsWith("!")) {
525
+ required = true;
526
+ s = s.slice(0, -1);
527
+ } else if (s.endsWith("?")) {
528
+ s = s.slice(0, -1);
529
+ }
530
+ if (s.includes("|") && !s.includes(":")) {
531
+ const rawValues = s.split("|").map((v) => v.trim());
532
+ if (rawValues.every((v) => v === "true" || v === "false")) {
533
+ return {
534
+ type: "boolean",
535
+ enum: rawValues.map((v) => v === "true"),
536
+ ...required ? { _required: true } : {}
537
+ };
538
+ }
539
+ const numericValues = rawValues.map((v) => Number(v));
540
+ if (rawValues.every((v, i) => v !== "" && !isNaN(numericValues[i]))) {
541
+ return {
542
+ type: "number",
543
+ enum: numericValues,
544
+ ...required ? { _required: true } : {}
545
+ };
546
+ }
547
+ return {
548
+ type: "string",
549
+ enum: rawValues,
550
+ ...required ? { _required: true } : {}
551
+ };
552
+ }
553
+ if (s.startsWith("enum:")) {
554
+ return DslParser._parseEnumSyntax(s, required);
555
+ }
556
+ if (s.startsWith("types:")) {
557
+ return DslParser._parseUnionTypes(s.slice(6), required);
558
+ }
559
+ const arrayAngleWithConstraintMatch = /^array:([^<]+)<(.+)>$/.exec(s);
560
+ if (arrayAngleWithConstraintMatch) {
561
+ const arrayConstraint = ConstraintParser.parse(arrayAngleWithConstraintMatch[1], "array");
562
+ const itemSchema = DslParser.parseString(arrayAngleWithConstraintMatch[2]);
563
+ return {
564
+ type: "array",
565
+ ...arrayConstraint,
566
+ items: itemSchema,
567
+ ...required ? { _required: true } : {}
568
+ };
569
+ }
570
+ const arrayAngleMatch = /^array<(.+)>$/.exec(s);
571
+ if (arrayAngleMatch) {
572
+ const itemSchema = DslParser.parseString(arrayAngleMatch[1]);
573
+ return {
574
+ type: "array",
575
+ items: itemSchema,
576
+ ...required ? { _required: true } : {}
577
+ };
578
+ }
579
+ const colonIdx = s.indexOf(":");
580
+ let typeName;
581
+ let constraintStr;
582
+ if (colonIdx === -1) {
583
+ typeName = s;
584
+ constraintStr = "";
585
+ } else {
586
+ typeName = s.slice(0, colonIdx);
587
+ constraintStr = s.slice(colonIdx + 1);
588
+ }
589
+ const PATTERN_TYPES = ["phone", "idCard", "creditCard", "licensePlate", "postalCode", "passport"];
590
+ if (PATTERN_TYPES.includes(typeName)) {
591
+ const patternGroup = PATTERNS[typeName];
592
+ if (patternGroup) {
593
+ const arg = constraintStr || (typeName === "creditCard" ? "visa" : "cn");
594
+ const cfg = patternGroup[arg.toLowerCase()];
595
+ if (cfg) {
596
+ return {
597
+ type: "string",
598
+ pattern: cfg.pattern.source,
599
+ ...cfg.min !== void 0 ? { minLength: cfg.min } : {},
600
+ ...cfg.max !== void 0 ? { maxLength: cfg.max } : {},
601
+ _customMessages: { pattern: cfg.key },
602
+ ...required ? { _required: true } : {}
603
+ };
604
+ }
605
+ throw new Error(`[schema-dsl] Unsupported country/variant "${arg}" for type "${typeName}"`);
606
+ }
607
+ }
608
+ const typeDef = TypeRegistry.resolve(typeName);
609
+ const resolvedBaseType = typeDef.baseSchema.type ?? typeName;
610
+ const constraints = ConstraintParser.parse(constraintStr, resolvedBaseType);
611
+ const schema = SchemaCompiler.compile(typeDef, constraints, {
612
+ required
613
+ });
614
+ return schema;
615
+ },
616
+ /**
617
+ * Parse an object DSL definition → JSONSchema (type:object + properties + required[])
618
+ */
619
+ parseObject(dslObj) {
620
+ const schema = {
621
+ type: "object",
622
+ properties: {},
623
+ required: []
624
+ };
625
+ for (const [rawKey, value] of Object.entries(dslObj)) {
626
+ let fieldKey = rawKey;
627
+ let isKeyRequired = false;
628
+ if (rawKey.endsWith("!")) {
629
+ fieldKey = rawKey.slice(0, -1);
630
+ isKeyRequired = true;
631
+ }
632
+ let fieldSchema;
633
+ if (typeof value === "string") {
634
+ fieldSchema = DslParser.parseString(value);
635
+ } else if (typeof value === "object" && value !== null && !Array.isArray(value)) {
636
+ const obj = value;
637
+ if (obj["_isMatch"]) {
638
+ if (!schema.allOf) schema.allOf = [];
639
+ schema.allOf.push(_buildMatchSchema(String(obj["field"]), fieldKey, obj["map"]));
640
+ fieldSchema = { description: `Depends on ${String(obj["field"])}` };
641
+ } else if (obj["_isIf"]) {
642
+ if (!schema.allOf) schema.allOf = [];
643
+ schema.allOf.push(_buildIfSchema(String(obj["condition"]), fieldKey, obj["then"], obj["else"]));
644
+ fieldSchema = { description: `Conditional field based on ${String(obj["condition"])}` };
645
+ } else if (typeof obj["toSchema"] === "function") {
646
+ fieldSchema = obj["toSchema"]();
647
+ } else if (_isRawJsonSchema(obj)) {
648
+ fieldSchema = value;
649
+ } else {
650
+ fieldSchema = DslParser.parseObject(value);
651
+ }
652
+ } else {
653
+ fieldSchema = value;
654
+ }
655
+ if (isKeyRequired) {
656
+ ;
657
+ schema.required.push(fieldKey);
658
+ } else if (fieldSchema._required) {
659
+ ;
660
+ schema.required.push(fieldKey);
661
+ }
662
+ const { _required: _r, ...cleanSchema } = fieldSchema;
663
+ void _r;
664
+ _copyHiddenSchemaProperties(fieldSchema, cleanSchema);
665
+ _cleanRequiredMarks(cleanSchema);
666
+ schema.properties[fieldKey] = cleanSchema;
667
+ }
668
+ if (schema.required.length === 0) {
669
+ delete schema.required;
670
+ }
671
+ return schema;
672
+ },
673
+ // --------------- Private helpers ---------------
674
+ /** Parse enum: prefix syntax */
675
+ _parseEnumSyntax(s, required) {
676
+ const rest = s.slice("enum:".length);
677
+ const typedEnumMatch = /^(string|number|integer|boolean):(.+)$/.exec(rest);
678
+ if (typedEnumMatch) {
679
+ const enumType = typedEnumMatch[1];
680
+ const rawStr = typedEnumMatch[2];
681
+ const rawValues = (rawStr.includes("|") ? rawStr.split("|") : rawStr.split(",")).map((v) => v.trim());
682
+ const values = DslParser._coerceEnumValues(rawValues, enumType);
683
+ return {
684
+ type: enumType,
685
+ enum: values,
686
+ ...required ? { _required: true } : {}
687
+ };
688
+ }
689
+ return {
690
+ type: "string",
691
+ enum: (rest.includes("|") ? rest.split("|") : rest.split(",")).map((v) => v.trim()),
692
+ ...required ? { _required: true } : {}
693
+ };
694
+ },
695
+ /** Convert a string array to enum values of the specified type */
696
+ _coerceEnumValues(values, type) {
697
+ if (type === "number" || type === "integer") {
698
+ return values.map((v) => {
699
+ const n = parseFloat(v);
700
+ if (isNaN(n)) throw new Error(`[schema-dsl] Invalid number enum value: "${v}"`);
701
+ return n;
702
+ });
703
+ }
704
+ if (type === "boolean") {
705
+ return values.map((v) => {
706
+ if (v !== "true" && v !== "false")
707
+ throw new Error(`[schema-dsl] Invalid boolean enum value: "${v}"`);
708
+ return v === "true";
709
+ });
710
+ }
711
+ return values;
712
+ },
713
+ /**
714
+ * Parse types: union type syntax (v1 compatible)
715
+ *
716
+ * Splits 'string|number' into a oneOf array, parsing each segment independently.
717
+ * Uses smart splitting: 'string:3-10|number:0-100' → ['string:3-10', 'number:0-100']
718
+ * When only a single type is present, emits a plain schema instead of a oneOf wrapper.
719
+ */
720
+ _parseUnionTypes(typesStr, required) {
721
+ const segments = [];
722
+ let current = "";
723
+ let depth = 0;
724
+ for (let i = 0; i < typesStr.length; i++) {
725
+ const ch = typesStr[i];
726
+ if (ch === "<") {
727
+ depth++;
728
+ current += ch;
729
+ } else if (ch === ">") {
730
+ depth--;
731
+ current += ch;
732
+ } else if (ch === "|" && depth === 0) {
733
+ if (current.trim()) segments.push(current.trim());
734
+ current = "";
735
+ } else {
736
+ current += ch;
737
+ }
738
+ }
739
+ if (current.trim()) segments.push(current.trim());
740
+ if (segments.length === 0) {
741
+ throw new Error("[schema-dsl] types: requires at least one type");
742
+ }
743
+ if (segments.length === 1) {
744
+ const schema = DslParser.parseString(segments[0]);
745
+ if (required) schema._required = true;
746
+ return schema;
747
+ }
748
+ const oneOf = segments.map((seg) => DslParser.parseString(seg));
749
+ return {
750
+ oneOf,
751
+ ...required ? { _required: true } : {}
752
+ };
753
+ }
754
+ };
755
+ }
756
+ });
757
+
758
+ // src/config/constants.ts
759
+ var CACHE, IPV4_OCTET, PATTERN_IPV4, HEX4, IPV6_FULL, IPV6_COMPRESS, PATTERN_IPV6;
760
+ var init_constants = __esm({
761
+ "src/config/constants.ts"() {
762
+ "use strict";
763
+ CACHE = {
764
+ ENABLED: true,
765
+ SCHEMA_CACHE: {
766
+ MAX_SIZE: 5e3,
767
+ TTL: 36e5,
768
+ // 1 hour
769
+ STRATEGY: "LRU"
770
+ },
771
+ STATS_ENABLED: true
772
+ };
773
+ IPV4_OCTET = "(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d?)";
774
+ PATTERN_IPV4 = new RegExp(`^(?:${IPV4_OCTET}\\.){3}${IPV4_OCTET}$`);
775
+ HEX4 = "[0-9a-fA-F]{1,4}";
776
+ IPV6_FULL = `(?:${HEX4}:){7}${HEX4}`;
777
+ IPV6_COMPRESS = [
778
+ `(?:${HEX4}:){1,7}:`,
779
+ // n:...:
780
+ `(?:${HEX4}:){1,6}:${HEX4}`,
781
+ // n:...:n
782
+ `(?:${HEX4}:){1,5}(?::${HEX4}){1,2}`,
783
+ `(?:${HEX4}:){1,4}(?::${HEX4}){1,3}`,
784
+ `(?:${HEX4}:){1,3}(?::${HEX4}){1,4}`,
785
+ `(?:${HEX4}:){1,2}(?::${HEX4}){1,5}`,
786
+ `${HEX4}:(?::${HEX4}){1,6}`,
787
+ `:(?::${HEX4}){1,7}`,
788
+ // ::n...
789
+ `::`
790
+ // standalone :: (all-zeros)
791
+ ].join("|");
792
+ PATTERN_IPV6 = new RegExp(`^(?:${IPV6_FULL}|${IPV6_COMPRESS})$`);
793
+ }
794
+ });
795
+
796
+ // src/core/CacheManager.ts
797
+ import { MemoryCache } from "cache-hub";
798
+ var CacheManager;
799
+ var init_CacheManager = __esm({
800
+ "src/core/CacheManager.ts"() {
801
+ "use strict";
802
+ init_constants();
803
+ CacheManager = class {
804
+ _enabled;
805
+ _maxSize;
806
+ _ttl;
807
+ _cache;
808
+ _statsEnabled = true;
809
+ _clears = 0;
810
+ constructor(options = {}) {
811
+ this._maxSize = options.maxSize ?? CACHE.SCHEMA_CACHE.MAX_SIZE;
812
+ this._ttl = options.ttl ?? CACHE.SCHEMA_CACHE.TTL;
813
+ this._enabled = options.enabled !== false;
814
+ this._cache = new MemoryCache({ maxEntries: this._maxSize });
815
+ this._statsEnabled = options.statsEnabled !== false;
816
+ }
817
+ get options() {
818
+ return {
819
+ maxSize: this._maxSize,
820
+ ttl: this._ttl,
821
+ enabled: this._enabled,
822
+ statsEnabled: this._statsEnabled
823
+ };
824
+ }
825
+ set options(opts) {
826
+ if (opts.maxSize !== void 0) this._maxSize = opts.maxSize;
827
+ if (opts.ttl !== void 0) this._ttl = opts.ttl;
828
+ if (opts.enabled !== void 0) this._enabled = opts.enabled;
829
+ if (opts.statsEnabled !== void 0) this._statsEnabled = opts.statsEnabled;
830
+ }
831
+ /**
832
+ * Retrieve a cached AJV compile function.
833
+ * @returns cached compile function, or null on miss (BD-04: undefined → null)
834
+ */
835
+ get(key) {
836
+ if (!this._enabled || key == null) return null;
837
+ try {
838
+ const result = this._cache.get(String(key));
839
+ return result !== void 0 ? result : null;
840
+ } catch {
841
+ return null;
842
+ }
843
+ }
844
+ /**
845
+ * Write a value to the cache.
846
+ */
847
+ set(key, value, ttl) {
848
+ if (!this._enabled || key == null) return;
849
+ try {
850
+ this._cache.set(String(key), value, ttl ?? this._ttl);
851
+ } catch {
852
+ }
853
+ }
854
+ /**
855
+ * Delete a single cache entry.
856
+ */
857
+ delete(key) {
858
+ return this._cache.del(key);
859
+ }
860
+ /**
861
+ * Check whether a key exists in the cache.
862
+ */
863
+ has(key) {
864
+ if (!this._enabled) return false;
865
+ return this._cache.has(key);
866
+ }
867
+ /**
868
+ * Clear all cache entries.
869
+ */
870
+ clear() {
871
+ this._cache.clear();
872
+ this._clears++;
873
+ }
874
+ /**
875
+ * Return the current number of cache entries.
876
+ */
877
+ size() {
878
+ return this._cache.keys().length;
879
+ }
880
+ /**
881
+ * Return cache statistics.
882
+ */
883
+ getStats() {
884
+ if (!this._statsEnabled) {
885
+ return {
886
+ hits: 0,
887
+ misses: 0,
888
+ sets: 0,
889
+ deletes: 0,
890
+ evictions: 0,
891
+ clears: 0,
892
+ hitRate: "0.00",
893
+ size: 0,
894
+ maxSize: this._maxSize,
895
+ enabled: this._enabled
896
+ };
897
+ }
898
+ const inner = this._cache.getStats();
899
+ const total = inner.hits + inner.misses;
900
+ return {
901
+ hits: inner.hits,
902
+ misses: inner.misses,
903
+ sets: inner.sets,
904
+ deletes: inner.deletes,
905
+ evictions: inner.evictions ?? 0,
906
+ clears: this._clears,
907
+ hitRate: total > 0 ? (inner.hits / total * 100).toFixed(2) : "0.00",
908
+ size: inner.entries,
909
+ maxSize: this._maxSize,
910
+ enabled: this._enabled
911
+ };
912
+ }
913
+ /**
914
+ * Reset all hit/miss/eviction counters.
915
+ */
916
+ resetStats() {
917
+ this._cache.resetStats();
918
+ this._clears = 0;
919
+ }
920
+ };
921
+ }
922
+ });
923
+
924
+ // src/core/TemplateEngine.ts
925
+ function renderTemplate(template, params) {
926
+ return template.replace(/\{\{#([^}]+)\}\}|\{([^}]+)\}/g, (match, k1, k2) => {
927
+ const key = k1 ?? k2;
928
+ if (key !== void 0 && key in params) {
929
+ const val = params[key];
930
+ if (val === null) return "null";
931
+ if (val === void 0) return match;
932
+ if (Array.isArray(val)) return val.join(", ");
933
+ if (val instanceof RegExp) return val.toString();
934
+ if (val instanceof Date) return val.toISOString();
935
+ return String(val);
936
+ }
937
+ return match;
938
+ });
939
+ }
940
+ var init_TemplateEngine = __esm({
941
+ "src/core/TemplateEngine.ts"() {
942
+ "use strict";
943
+ }
944
+ });
945
+
946
+ // src/core/ErrorCodes.ts
947
+ var KEYWORD_MAP;
948
+ var init_ErrorCodes = __esm({
949
+ "src/core/ErrorCodes.ts"() {
950
+ "use strict";
951
+ KEYWORD_MAP = {
952
+ minLength: "min",
953
+ maxLength: "max",
954
+ minimum: "min",
955
+ maximum: "max",
956
+ minItems: "min",
957
+ maxItems: "max",
958
+ exclusiveMinimum: "min",
959
+ exclusiveMaximum: "max",
960
+ pattern: "pattern",
961
+ format: "format",
962
+ required: "required",
963
+ enum: "enum",
964
+ type: "type",
965
+ uniqueItems: "uniqueItems",
966
+ additionalProperties: "additionalProperties"
967
+ };
968
+ }
969
+ });
970
+
971
+ // src/locales/zh-CN.ts
972
+ var zhCN, zh_CN_default;
973
+ var init_zh_CN = __esm({
974
+ "src/locales/zh-CN.ts"() {
975
+ "use strict";
976
+ zhCN = {
977
+ // Generic
978
+ required: "{{#label}}\u4E0D\u80FD\u4E3A\u7A7A",
979
+ type: "{{#label}}\u5E94\u8BE5\u662F {{#expected}} \u7C7B\u578B",
980
+ min: "{{#label}}\u957F\u5EA6\u4E0D\u80FD\u5C11\u4E8E{{#limit}}\u4E2A\u5B57\u7B26",
981
+ max: "{{#label}}\u957F\u5EA6\u4E0D\u80FD\u8D85\u8FC7{{#limit}}\u4E2A\u5B57\u7B26",
982
+ length: "{{#label}}\u957F\u5EA6\u5FC5\u987B\u662F{{#limit}}\u4E2A\u5B57\u7B26",
983
+ pattern: "{{#label}}\u683C\u5F0F\u4E0D\u6B63\u786E",
984
+ enum: "{{#label}}\u5FC5\u987B\u662F\u4EE5\u4E0B\u503C\u4E4B\u4E00: {{#allowed}}",
985
+ custom: "{{#label}}\u9A8C\u8BC1\u5931\u8D25: {{#message}}",
986
+ circular: "{{#label}}\u68C0\u6D4B\u5230\u5FAA\u73AF\u5F15\u7528",
987
+ "max-depth": "\u8D85\u8FC7\u6700\u5927\u9012\u5F52\u6DF1\u5EA6 ({{#depth}}) at {{#label}}",
988
+ exception: "{{#label}}\u9A8C\u8BC1\u5F02\u5E38: {{#message}}",
989
+ // Conditional
990
+ "conditional.underAge": "\u672A\u6210\u5E74\u7528\u6237\u4E0D\u80FD\u6CE8\u518C",
991
+ "conditional.blocked": "\u8D26\u53F7\u5DF2\u88AB\u5C01\u7981",
992
+ "conditional.notAllowed": "\u4E0D\u5141\u8BB8\u6CE8\u518C",
993
+ // I18nError — generic
994
+ "error.notFound": "\u627E\u4E0D\u5230{{#resource}}",
995
+ "error.forbidden": "\u6CA1\u6709\u6743\u9650\u8BBF\u95EE{{#resource}}",
996
+ "error.unauthorized": "\u672A\u6388\u6743\uFF0C\u8BF7\u5148\u767B\u5F55",
997
+ "error.invalid": "{{#field}}\u65E0\u6548",
998
+ "error.duplicate": "{{#resource}}\u5DF2\u5B58\u5728",
999
+ "error.conflict": "\u64CD\u4F5C\u51B2\u7A81: {{#reason}}",
1000
+ // Account
1001
+ "account.notFound": { code: "ACCOUNT_NOT_FOUND", message: "\u8D26\u6237\u4E0D\u5B58\u5728" },
1002
+ "account.inactive": "\u8D26\u6237\u672A\u6FC0\u6D3B",
1003
+ "account.banned": "\u8D26\u6237\u5DF2\u88AB\u5C01\u7981",
1004
+ "account.insufficientBalance": {
1005
+ code: "INSUFFICIENT_BALANCE",
1006
+ message: "\u4F59\u989D\u4E0D\u8DB3\uFF0C\u5F53\u524D\u4F59\u989D{{#balance}}\uFF0C\u9700\u8981{{#required}}"
1007
+ },
1008
+ "account.insufficientCredits": "\u79EF\u5206\u4E0D\u8DB3\uFF0C\u5F53\u524D\u79EF\u5206{{#credits}}\uFF0C\u9700\u8981{{#required}}",
1009
+ // User
1010
+ "user.notFound": "\u7528\u6237\u4E0D\u5B58\u5728",
1011
+ "user.notVerified": "\u7528\u6237\u672A\u9A8C\u8BC1",
1012
+ "user.noPermission": "\u6CA1\u6709\u7BA1\u7406\u5458\u6743\u9650",
1013
+ // Order
1014
+ "order.notPaid": { code: "ORDER_NOT_PAID", message: "\u8BA2\u5355\u672A\u652F\u4ED8" },
1015
+ "order.paymentMissing": "\u7F3A\u5C11\u652F\u4ED8\u4FE1\u606F",
1016
+ "order.addressMissing": "\u7F3A\u5C11\u6536\u8D27\u5730\u5740",
1017
+ // Format
1018
+ "format.email": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684\u90AE\u7BB1\u5730\u5740",
1019
+ "format.url": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684URL\u5730\u5740",
1020
+ "format.uuid": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684UUID",
1021
+ "format.date": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684\u65E5\u671F\u683C\u5F0F (YYYY-MM-DD)",
1022
+ "format.datetime": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684\u65E5\u671F\u65F6\u95F4\u683C\u5F0F (ISO 8601)",
1023
+ "format.time": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684\u65F6\u95F4\u683C\u5F0F (HH:mm:ss)",
1024
+ "format.ipv4": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684IPv4\u5730\u5740",
1025
+ "format.ipv6": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684IPv6\u5730\u5740",
1026
+ "format.binary": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684Base64\u7F16\u7801",
1027
+ // String
1028
+ "string.hostname": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684\u4E3B\u673A\u540D",
1029
+ "string.pattern": "{{#label}}\u683C\u5F0F\u4E0D\u7B26\u5408\u8981\u6C42",
1030
+ "string.enum": "{{#label}}\u5FC5\u987B\u662F\u4EE5\u4E0B\u503C\u4E4B\u4E00: {{#valids}}",
1031
+ "string.length": "{{#label}}\u957F\u5EA6\u5FC5\u987B\u662F{{#limit}}\u4E2A\u5B57\u7B26",
1032
+ "string.alphanum": "{{#label}}\u53EA\u80FD\u5305\u542B\u5B57\u6BCD\u548C\u6570\u5B57",
1033
+ "string.trim": "{{#label}}\u4E0D\u80FD\u5305\u542B\u524D\u540E\u7A7A\u683C",
1034
+ "string.lowercase": "{{#label}}\u5FC5\u987B\u662F\u5C0F\u5199",
1035
+ "string.uppercase": "{{#label}}\u5FC5\u987B\u662F\u5927\u5199",
1036
+ // Number
1037
+ "number.base": "{{#label}}\u5FC5\u987B\u662F\u6570\u5B57\u7C7B\u578B",
1038
+ "number.min": "{{#label}}\u4E0D\u80FD\u5C0F\u4E8E{{#limit}}",
1039
+ "number.max": "{{#label}}\u4E0D\u80FD\u5927\u4E8E{{#limit}}",
1040
+ "number.integer": "{{#label}}\u5FC5\u987B\u662F\u6574\u6570",
1041
+ "number.positive": "{{#label}}\u5FC5\u987B\u662F\u6B63\u6570",
1042
+ "number.negative": "{{#label}}\u5FC5\u987B\u662F\u8D1F\u6570",
1043
+ "number.precision": "{{#label}}\u5C0F\u6570\u4F4D\u6570\u4E0D\u80FD\u8D85\u8FC7{{#limit}}\u4F4D",
1044
+ "number.port": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684\u7AEF\u53E3\u53F7(1-65535)",
1045
+ // Boolean
1046
+ "boolean.base": "{{#label}}\u5FC5\u987B\u662F\u5E03\u5C14\u7C7B\u578B",
1047
+ // Object
1048
+ "object.base": "{{#label}}\u5FC5\u987B\u662F\u5BF9\u8C61\u7C7B\u578B",
1049
+ "object.min": "{{#label}}\u81F3\u5C11\u9700\u8981{{#limit}}\u4E2A\u5C5E\u6027",
1050
+ "object.max": "{{#label}}\u6700\u591A\u53EA\u80FD\u6709{{#limit}}\u4E2A\u5C5E\u6027",
1051
+ "object.unknown": "{{#label}}\u5305\u542B\u672A\u77E5\u5C5E\u6027: {{#key}}",
1052
+ "object.missing": "{{#label}}\u7F3A\u5C11\u5FC5\u9700\u5C5E\u6027",
1053
+ "object.schema": "{{#label}}\u5305\u542B\u989D\u5916\u5C5E\u6027",
1054
+ "additionalProperties": "{{#label}}\u4E0D\u5141\u8BB8\u6709\u989D\u5916\u5C5E\u6027: {{#key}}",
1055
+ // Array
1056
+ "array.base": "{{#label}}\u5FC5\u987B\u662F\u6570\u7EC4\u7C7B\u578B",
1057
+ "array.min": "{{#label}}\u81F3\u5C11\u9700\u8981{{#limit}}\u4E2A\u5143\u7D20",
1058
+ "array.max": "{{#label}}\u6700\u591A\u53EA\u80FD\u6709{{#limit}}\u4E2A\u5143\u7D20",
1059
+ "array.length": "{{#label}}\u5FC5\u987B\u6709{{#limit}}\u4E2A\u5143\u7D20",
1060
+ "array.unique": "{{#label}}\u4E0D\u80FD\u5305\u542B\u91CD\u590D\u5143\u7D20",
1061
+ "array.sparse": "{{#label}}\u4E0D\u80FD\u662F\u7A00\u758F\u6570\u7EC4",
1062
+ "array.includesRequired": "{{#label}}\u5FC5\u987B\u5305\u542B\u6307\u5B9A\u5143\u7D20",
1063
+ // Date
1064
+ "date.base": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684\u65E5\u671F",
1065
+ "date.min": "{{#label}}\u4E0D\u80FD\u65E9\u4E8E{{#limit}}",
1066
+ "date.max": "{{#label}}\u4E0D\u80FD\u665A\u4E8E{{#limit}}",
1067
+ "date.format": "{{#label}}\u65E5\u671F\u683C\u5F0F\u4E0D\u6B63\u786E",
1068
+ "date.greater": "{{#label}}\u5FC5\u987B\u665A\u4E8E{{#limit}}",
1069
+ "date.less": "{{#label}}\u5FC5\u987B\u65E9\u4E8E{{#limit}}",
1070
+ // Any
1071
+ "any.required": "{{#label}}\u662F\u5FC5\u586B\u9879",
1072
+ "any.invalid": "{{#label}}\u5305\u542B\u65E0\u6548\u503C",
1073
+ "any.only": "{{#label}}\u5FC5\u987B\u5339\u914D{{#valids}}",
1074
+ "any.unknown": "\u4E0D\u5141\u8BB8\u5B57\u6BB5{{#key}}",
1075
+ // Patterns
1076
+ "pattern.phone": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u624B\u673A\u53F7",
1077
+ "pattern.phone.international": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u56FD\u9645\u624B\u673A\u53F7",
1078
+ "pattern.idCard": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u8EAB\u4EFD\u8BC1\u53F7\u7801",
1079
+ "pattern.creditCard": "\u65E0\u6548\u7684\u4FE1\u7528\u5361\u53F7",
1080
+ "pattern.creditCard.visa": "\u65E0\u6548\u7684Visa\u5361\u53F7",
1081
+ "pattern.creditCard.mastercard": "\u65E0\u6548\u7684\u4E07\u4E8B\u8FBE\u5361\u53F7",
1082
+ "pattern.creditCard.amex": "\u65E0\u6548\u7684\u7F8E\u56FD\u8FD0\u901A\u5361\u53F7",
1083
+ "pattern.creditCard.discover": "\u65E0\u6548\u7684Discover\u5361\u53F7",
1084
+ "pattern.creditCard.jcb": "\u65E0\u6548\u7684JCB\u5361\u53F7",
1085
+ "pattern.creditCard.unionpay": "\u65E0\u6548\u7684\u94F6\u8054\u5361\u53F7",
1086
+ "pattern.licensePlate": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u8F66\u724C\u53F7",
1087
+ "pattern.postalCode": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u90AE\u653F\u7F16\u7801",
1088
+ "pattern.passport": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u62A4\u7167\u53F7\u7801",
1089
+ "pattern.objectId": "\u65E0\u6548\u7684 ObjectId",
1090
+ "pattern.hexColor": "\u65E0\u6548\u7684\u5341\u516D\u8FDB\u5236\u989C\u8272\u503C",
1091
+ "pattern.macAddress": "\u65E0\u6548\u7684 MAC \u5730\u5740",
1092
+ "pattern.cron": "\u65E0\u6548\u7684 Cron \u8868\u8FBE\u5F0F",
1093
+ "pattern.slug": "URL\u522B\u540D\u53EA\u80FD\u5305\u542B\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u8FDE\u5B57\u7B26",
1094
+ "pattern.domain": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684\u57DF\u540D",
1095
+ "pattern.ip": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684IP\u5730\u5740",
1096
+ "pattern.base64": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684Base64\u7F16\u7801",
1097
+ "pattern.jwt": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684JWT\u4EE4\u724C",
1098
+ "pattern.json": "{{#label}}\u5FC5\u987B\u662F\u6709\u6548\u7684JSON\u5B57\u7B26\u4E32",
1099
+ "pattern.username": "\u7528\u6237\u540D\u5FC5\u987B\u4EE5\u5B57\u6BCD\u5F00\u5934\uFF0C\u53EA\u80FD\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u4E0B\u5212\u7EBF",
1100
+ "pattern.password.weak": "\u5BC6\u7801\u81F3\u5C116\u4F4D",
1101
+ "pattern.password.medium": "\u5BC6\u7801\u81F3\u5C118\u4F4D\uFF0C\u9700\u5305\u542B\u5B57\u6BCD\u548C\u6570\u5B57",
1102
+ "pattern.password.strong": "\u5BC6\u7801\u81F3\u5C118\u4F4D\uFF0C\u9700\u5305\u542B\u5927\u5C0F\u5199\u5B57\u6BCD\u548C\u6570\u5B57",
1103
+ "pattern.password.veryStrong": "\u5BC6\u7801\u81F3\u5C1110\u4F4D\uFF0C\u9700\u5305\u542B\u5927\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u7279\u6B8A\u5B57\u7B26",
1104
+ "pattern.emailOrPhone": "\u5FC5\u987B\u662F\u90AE\u7BB1\u6216\u624B\u673A\u53F7",
1105
+ "pattern.usernameOrEmail": "\u5FC5\u987B\u662F\u7528\u6237\u540D\u6216\u90AE\u7BB1",
1106
+ "pattern.httpOrHttps": "\u5FC5\u987B\u662F http \u6216 https \u5F00\u5934\u7684 URL",
1107
+ // oneOf
1108
+ oneOf: "{{#label}}\u5FC5\u987B\u5339\u914D\u4EE5\u4E0B\u7C7B\u578B\u4E4B\u4E00",
1109
+ "oneOf.invalid": "{{#label}}\u7684\u503C\u4E0D\u5339\u914D\u4EFB\u4F55\u5141\u8BB8\u7684\u7C7B\u578B",
1110
+ // Error fallback
1111
+ UNKNOWN_ERROR: "\u672A\u77E5\u7684\u9A8C\u8BC1\u9519\u8BEF",
1112
+ CUSTOM_VALIDATION_FAILED: "\u81EA\u5B9A\u4E49\u9A8C\u8BC1\u5931\u8D25",
1113
+ ASYNC_VALIDATION_NOT_SUPPORTED: "\u540C\u6B65\u9A8C\u8BC1\u4E0D\u652F\u6301\u5F02\u6B65\u64CD\u4F5C",
1114
+ VALIDATE_MUST_BE_FUNCTION: "validate \u5FC5\u987B\u662F\u4E00\u4E2A\u51FD\u6570"
1115
+ };
1116
+ zh_CN_default = zhCN;
1117
+ }
1118
+ });
1119
+
1120
+ // src/locales/en-US.ts
1121
+ var enUS, en_US_default;
1122
+ var init_en_US = __esm({
1123
+ "src/locales/en-US.ts"() {
1124
+ "use strict";
1125
+ enUS = {
1126
+ // Generic
1127
+ required: "{{#label}} is required",
1128
+ type: "{{#label}} should be {{#expected}}, got {{#actual}}",
1129
+ min: "{{#label}} length must be at least {{#limit}}",
1130
+ max: "{{#label}} length must be at most {{#limit}}",
1131
+ length: "{{#label}} length must be exactly {{#expected}}",
1132
+ pattern: "{{#label}} format is invalid",
1133
+ enum: "{{#label}} must be one of: {{#allowed}}",
1134
+ custom: "{{#label}} validation failed: {{#message}}",
1135
+ circular: "Circular reference detected at {{#label}}",
1136
+ "max-depth": "Maximum recursion depth ({{#depth}}) exceeded at {{#label}}",
1137
+ exception: "{{#label}} validation exception: {{#message}}",
1138
+ // Conditional
1139
+ "conditional.underAge": "Minors cannot register",
1140
+ "conditional.blocked": "Account has been blocked",
1141
+ "conditional.notAllowed": "Registration not allowed",
1142
+ // I18nError — generic
1143
+ "error.notFound": "{{#resource}} not found",
1144
+ "error.forbidden": "Access to {{#resource}} is forbidden",
1145
+ "error.unauthorized": "Unauthorized, please log in",
1146
+ "error.invalid": "Invalid {{#field}}",
1147
+ "error.duplicate": "{{#resource}} already exists",
1148
+ "error.conflict": "Operation conflict: {{#reason}}",
1149
+ // Account
1150
+ "account.notFound": { code: "ACCOUNT_NOT_FOUND", message: "Account not found" },
1151
+ "account.inactive": "Account is inactive",
1152
+ "account.banned": "Account has been banned",
1153
+ "account.insufficientBalance": {
1154
+ code: "INSUFFICIENT_BALANCE",
1155
+ message: "Insufficient balance, current: {{#balance}}, required: {{#required}}"
1156
+ },
1157
+ "account.insufficientCredits": "Insufficient credits, current: {{#credits}}, required: {{#required}}",
1158
+ // User
1159
+ "user.notFound": "User not found",
1160
+ "user.notVerified": "User is not verified",
1161
+ "user.noPermission": "No admin permission",
1162
+ // Order
1163
+ "order.notPaid": { code: "ORDER_NOT_PAID", message: "Order not paid" },
1164
+ "order.paymentMissing": "Payment information missing",
1165
+ "order.addressMissing": "Shipping address missing",
1166
+ // Format
1167
+ "format.email": "{{#label}} must be a valid email address",
1168
+ "format.url": "{{#label}} must be a valid URL",
1169
+ "format.uuid": "{{#label}} must be a valid UUID",
1170
+ "format.date": "{{#label}} must be a valid date (YYYY-MM-DD)",
1171
+ "format.datetime": "{{#label}} must be a valid date-time (ISO 8601)",
1172
+ "format.time": "{{#label}} must be a valid time (HH:mm:ss)",
1173
+ "format.ipv4": "{{#label}} must be a valid IPv4 address",
1174
+ "format.ipv6": "{{#label}} must be a valid IPv6 address",
1175
+ "format.binary": "{{#label}} must be a valid base64 string",
1176
+ // String
1177
+ "string.hostname": "{{#label}} must be a valid hostname",
1178
+ "string.pattern": "{{#label}} format does not match required pattern",
1179
+ "string.enum": "{{#label}} must be one of: {{#valids}}",
1180
+ "string.length": "{{#label}} length must be exactly {{#limit}} characters",
1181
+ "string.alphanum": "{{#label}} must only contain alphanumeric characters",
1182
+ "string.trim": "{{#label}} must not have leading or trailing whitespace",
1183
+ "string.lowercase": "{{#label}} must be lowercase",
1184
+ "string.uppercase": "{{#label}} must be uppercase",
1185
+ // Number
1186
+ "number.base": "{{#label}} must be a number",
1187
+ "number.min": "{{#label}} must be greater than or equal to {{#limit}}",
1188
+ "number.max": "{{#label}} must be less than or equal to {{#limit}}",
1189
+ "number.integer": "{{#label}} must be an integer",
1190
+ "number.positive": "{{#label}} must be a positive number",
1191
+ "number.negative": "{{#label}} must be a negative number",
1192
+ "number.precision": "{{#label}} must have at most {{#limit}} decimal places",
1193
+ "number.port": "{{#label}} must be a valid port number (1-65535)",
1194
+ // Boolean
1195
+ "boolean.base": "{{#label}} must be a boolean",
1196
+ // Object
1197
+ "object.base": "{{#label}} must be an object",
1198
+ "object.min": "{{#label}} must have at least {{#limit}} properties",
1199
+ "object.max": "{{#label}} must have at most {{#limit}} properties",
1200
+ "object.unknown": "{{#label}} contains unknown property: {{#key}}",
1201
+ "object.missing": "{{#label}} is missing required properties",
1202
+ "object.schema": "{{#label}} contains additional properties",
1203
+ "additionalProperties": "{{#label}} must NOT have additional properties: {{#key}}",
1204
+ // Array
1205
+ "array.base": "{{#label}} must be an array",
1206
+ "array.min": "{{#label}} must have at least {{#limit}} items",
1207
+ "array.max": "{{#label}} must have at most {{#limit}} items",
1208
+ "array.length": "{{#label}} must have exactly {{#limit}} items",
1209
+ "array.unique": "{{#label}} must not contain duplicate items",
1210
+ "array.sparse": "{{#label}} must not be a sparse array",
1211
+ "array.includesRequired": "{{#label}} must include required items",
1212
+ // Date
1213
+ "date.base": "{{#label}} must be a valid date",
1214
+ "date.min": "{{#label}} must be no earlier than {{#limit}}",
1215
+ "date.max": "{{#label}} must be no later than {{#limit}}",
1216
+ "date.format": "{{#label}} date format is invalid",
1217
+ "date.greater": "{{#label}} must be after {{#limit}}",
1218
+ "date.less": "{{#label}} must be before {{#limit}}",
1219
+ // Any
1220
+ "any.required": "{{#label}} is required",
1221
+ "any.invalid": "{{#label}} contains an invalid value",
1222
+ "any.only": "{{#label}} must match {{#valids}}",
1223
+ "any.unknown": "Field {{#key}} is not allowed",
1224
+ // Patterns
1225
+ "pattern.phone": "Invalid phone number",
1226
+ "pattern.phone.international": "Invalid international phone number",
1227
+ "pattern.idCard": "Invalid ID card number",
1228
+ "pattern.creditCard": "Invalid credit card number",
1229
+ "pattern.creditCard.visa": "Invalid Visa card number",
1230
+ "pattern.creditCard.mastercard": "Invalid Mastercard number",
1231
+ "pattern.creditCard.amex": "Invalid American Express card number",
1232
+ "pattern.creditCard.discover": "Invalid Discover card number",
1233
+ "pattern.creditCard.jcb": "Invalid JCB card number",
1234
+ "pattern.creditCard.unionpay": "Invalid UnionPay card number",
1235
+ "pattern.licensePlate": "Invalid license plate number",
1236
+ "pattern.postalCode": "Invalid postal code",
1237
+ "pattern.passport": "Invalid passport number",
1238
+ "pattern.objectId": "Invalid ObjectId",
1239
+ "pattern.hexColor": "Invalid Hex Color",
1240
+ "pattern.macAddress": "Invalid MAC Address",
1241
+ "pattern.cron": "Invalid Cron Expression",
1242
+ "pattern.slug": "URL slug can only contain lowercase letters, numbers, and hyphens",
1243
+ "pattern.domain": "{{#label}} must be a valid domain name",
1244
+ "pattern.ip": "{{#label}} must be a valid IP address",
1245
+ "pattern.base64": "{{#label}} must be a valid Base64 string",
1246
+ "pattern.jwt": "{{#label}} must be a valid JWT token",
1247
+ "pattern.json": "{{#label}} must be a valid JSON string",
1248
+ "pattern.username": "Username must start with a letter and contain only letters, numbers, and underscores",
1249
+ "pattern.password.weak": "Password must be at least 6 characters",
1250
+ "pattern.password.medium": "Password must be at least 8 characters and contain letters and numbers",
1251
+ "pattern.password.strong": "Password must be at least 8 characters and contain uppercase, lowercase letters and numbers",
1252
+ "pattern.password.veryStrong": "Password must be at least 10 characters and contain uppercase, lowercase letters, numbers and special characters",
1253
+ "pattern.emailOrPhone": "Must be an email or phone number",
1254
+ "pattern.usernameOrEmail": "Must be a username or email",
1255
+ "pattern.httpOrHttps": "Must be a URL starting with http or https",
1256
+ // oneOf
1257
+ oneOf: "{{#label}} must match one of the following types",
1258
+ "oneOf.invalid": "{{#label}} value does not match any allowed type",
1259
+ // Error fallback
1260
+ UNKNOWN_ERROR: "Unknown validation error",
1261
+ CUSTOM_VALIDATION_FAILED: "Validation failed",
1262
+ ASYNC_VALIDATION_NOT_SUPPORTED: "Async validation not supported in synchronous validate()",
1263
+ VALIDATE_MUST_BE_FUNCTION: "validate must be a function"
1264
+ };
1265
+ en_US_default = enUS;
1266
+ }
1267
+ });
1268
+
1269
+ // src/locales/ja-JP.ts
1270
+ var jaJP, ja_JP_default;
1271
+ var init_ja_JP = __esm({
1272
+ "src/locales/ja-JP.ts"() {
1273
+ "use strict";
1274
+ jaJP = {
1275
+ // Generic
1276
+ required: "{{#label}}\u306F\u5FC5\u9808\u3067\u3059",
1277
+ type: "{{#label}}\u306F{{#expected}}\u578B\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u304C\u3001{{#actual}}\u304C\u6E21\u3055\u308C\u307E\u3057\u305F",
1278
+ min: "{{#label}}\u306E\u9577\u3055\u306F{{#limit}}\u4EE5\u4E0A\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1279
+ max: "{{#label}}\u306E\u9577\u3055\u306F{{#limit}}\u4EE5\u4E0B\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1280
+ length: "{{#label}}\u306E\u9577\u3055\u306F\u6B63\u78BA\u306B{{#expected}}\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1281
+ pattern: "{{#label}}\u306E\u5F62\u5F0F\u304C\u7121\u52B9\u3067\u3059",
1282
+ enum: "{{#label}}\u306F\u6B21\u306E\u3044\u305A\u308C\u304B\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059: {{#allowed}}",
1283
+ custom: "{{#label}}\u306E\u691C\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F: {{#message}}",
1284
+ circular: "{{#label}}\u3067\u5FAA\u74B0\u53C2\u7167\u304C\u691C\u51FA\u3055\u308C\u307E\u3057\u305F",
1285
+ "max-depth": "{{#label}}\u3067\u6700\u5927\u518D\u5E30\u6DF1\u5EA6 ({{#depth}}) \u3092\u8D85\u3048\u307E\u3057\u305F",
1286
+ exception: "{{#label}}\u306E\u691C\u8A3C\u4F8B\u5916: {{#message}}",
1287
+ // Conditional
1288
+ "conditional.underAge": "\u672A\u6210\u5E74\u8005\u306F\u767B\u9332\u3067\u304D\u307E\u305B\u3093",
1289
+ "conditional.blocked": "\u30A2\u30AB\u30A6\u30F3\u30C8\u304C\u30D6\u30ED\u30C3\u30AF\u3055\u308C\u3066\u3044\u307E\u3059",
1290
+ "conditional.notAllowed": "\u767B\u9332\u306F\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093",
1291
+ // I18nError — generic (v2 additions)
1292
+ "error.notFound": "{{#resource}}\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
1293
+ "error.forbidden": "{{#resource}}\u3078\u306E\u30A2\u30AF\u30BB\u30B9\u304C\u7981\u6B62\u3055\u308C\u3066\u3044\u307E\u3059",
1294
+ "error.unauthorized": "\u8A8D\u8A3C\u304C\u5FC5\u8981\u3067\u3059\u3002\u30ED\u30B0\u30A4\u30F3\u3057\u3066\u304F\u3060\u3055\u3044",
1295
+ "error.invalid": "{{#field}}\u304C\u7121\u52B9\u3067\u3059",
1296
+ "error.duplicate": "{{#resource}}\u306F\u3059\u3067\u306B\u5B58\u5728\u3057\u307E\u3059",
1297
+ "error.conflict": "\u64CD\u4F5C\u306E\u7AF6\u5408: {{#reason}}",
1298
+ // Account (v2 additions)
1299
+ "account.notFound": { code: "ACCOUNT_NOT_FOUND", message: "\u30A2\u30AB\u30A6\u30F3\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093" },
1300
+ "account.inactive": "\u30A2\u30AB\u30A6\u30F3\u30C8\u304C\u7121\u52B9\u5316\u3055\u308C\u3066\u3044\u307E\u3059",
1301
+ "account.banned": "\u30A2\u30AB\u30A6\u30F3\u30C8\u304C\u7981\u6B62\u3055\u308C\u3066\u3044\u307E\u3059",
1302
+ "account.insufficientBalance": {
1303
+ code: "INSUFFICIENT_BALANCE",
1304
+ message: "\u6B8B\u9AD8\u4E0D\u8DB3\u3002\u73FE\u5728: {{#balance}}\u3001\u5FC5\u8981: {{#required}}"
1305
+ },
1306
+ "account.insufficientCredits": "\u30AF\u30EC\u30B8\u30C3\u30C8\u4E0D\u8DB3\u3002\u73FE\u5728: {{#credits}}\u3001\u5FC5\u8981: {{#required}}",
1307
+ // User (v2 additions)
1308
+ "user.notFound": "\u30E6\u30FC\u30B6\u30FC\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
1309
+ "user.notVerified": "\u30E6\u30FC\u30B6\u30FC\u304C\u78BA\u8A8D\u3055\u308C\u3066\u3044\u307E\u305B\u3093",
1310
+ "user.noPermission": "\u7BA1\u7406\u8005\u6A29\u9650\u304C\u3042\u308A\u307E\u305B\u3093",
1311
+ // Order (v2 additions)
1312
+ "order.notPaid": { code: "ORDER_NOT_PAID", message: "\u6CE8\u6587\u304C\u652F\u6255\u308F\u308C\u3066\u3044\u307E\u305B\u3093" },
1313
+ "order.paymentMissing": "\u652F\u6255\u3044\u60C5\u5831\u304C\u3042\u308A\u307E\u305B\u3093",
1314
+ "order.addressMissing": "\u914D\u9001\u5148\u4F4F\u6240\u304C\u3042\u308A\u307E\u305B\u3093",
1315
+ // Format
1316
+ "format.email": "{{#label}}\u306F\u6709\u52B9\u306A\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1317
+ "format.url": "{{#label}}\u306F\u6709\u52B9\u306AURL\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1318
+ "format.uuid": "{{#label}}\u306F\u6709\u52B9\u306AUUID\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1319
+ "format.date": "{{#label}}\u306F\u6709\u52B9\u306A\u65E5\u4ED8 (YYYY-MM-DD) \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1320
+ "format.datetime": "{{#label}}\u306F\u6709\u52B9\u306A\u65E5\u6642 (ISO 8601) \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1321
+ "format.time": "{{#label}}\u306F\u6709\u52B9\u306A\u6642\u523B (HH:mm:ss) \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1322
+ "format.ipv4": "{{#label}}\u306F\u6709\u52B9\u306AIPv4\u30A2\u30C9\u30EC\u30B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1323
+ "format.ipv6": "{{#label}}\u306F\u6709\u52B9\u306AIPv6\u30A2\u30C9\u30EC\u30B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1324
+ "format.binary": "{{#label}}\u306F\u6709\u52B9\u306Abase64\u6587\u5B57\u5217\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1325
+ // String
1326
+ "string.hostname": "{{#label}}\u306F\u6709\u52B9\u306A\u30DB\u30B9\u30C8\u540D\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1327
+ "string.pattern": "{{#label}}\u306E\u5F62\u5F0F\u304C\u5FC5\u8981\u306A\u30D1\u30BF\u30FC\u30F3\u3068\u4E00\u81F4\u3057\u307E\u305B\u3093",
1328
+ "string.enum": "{{#label}}\u306F\u6B21\u306E\u3044\u305A\u308C\u304B\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059: {{#valids}}",
1329
+ "string.length": "{{#label}}\u306E\u9577\u3055\u306F\u6B63\u78BA\u306B{{#limit}}\u6587\u5B57\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1330
+ "string.alphanum": "{{#label}}\u306B\u306F\u82F1\u6570\u5B57\u306E\u307F\u3092\u542B\u3081\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059",
1331
+ "string.trim": "{{#label}}\u306E\u524D\u5F8C\u306B\u7A7A\u767D\u3092\u542B\u3081\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093",
1332
+ "string.lowercase": "{{#label}}\u306F\u5C0F\u6587\u5B57\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1333
+ "string.uppercase": "{{#label}}\u306F\u5927\u6587\u5B57\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1334
+ // Number
1335
+ "number.base": "{{#label}}\u306F\u6570\u5024\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1336
+ "number.min": "{{#label}}\u306F{{#limit}}\u4EE5\u4E0A\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1337
+ "number.max": "{{#label}}\u306F{{#limit}}\u4EE5\u4E0B\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1338
+ "number.integer": "{{#label}}\u306F\u6574\u6570\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1339
+ "number.positive": "{{#label}}\u306F\u6B63\u306E\u6570\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1340
+ "number.negative": "{{#label}}\u306F\u8CA0\u306E\u6570\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1341
+ "number.precision": "{{#label}}\u306E\u5C0F\u6570\u70B9\u4EE5\u4E0B\u306F{{#limit}}\u6841\u4EE5\u5185\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1342
+ "number.port": "{{#label}}\u306F\u6709\u52B9\u306A\u30DD\u30FC\u30C8\u756A\u53F7 (1-65535) \u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1343
+ // Boolean
1344
+ "boolean.base": "{{#label}}\u306F\u30D6\u30FC\u30EB\u5024\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1345
+ // Object
1346
+ "object.base": "{{#label}}\u306F\u30AA\u30D6\u30B8\u30A7\u30AF\u30C8\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1347
+ "object.min": "{{#label}}\u306F\u5C11\u306A\u304F\u3068\u3082{{#limit}}\u500B\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u6301\u3064\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1348
+ "object.max": "{{#label}}\u306F\u6700\u5927{{#limit}}\u500B\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u6301\u3064\u3053\u3068\u304C\u3067\u304D\u307E\u3059",
1349
+ "object.unknown": "{{#label}}\u306B\u672A\u77E5\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059: {{#key}}",
1350
+ "object.missing": "{{#label}}\u306B\u306F\u5FC5\u9808\u30D7\u30ED\u30D1\u30C6\u30A3\u304C\u3042\u308A\u307E\u305B\u3093",
1351
+ "object.schema": "{{#label}}\u306B\u8FFD\u52A0\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059",
1352
+ "additionalProperties": "{{#label}}\u306B\u8FFD\u52A0\u306E\u30D7\u30ED\u30D1\u30C6\u30A3\u3092\u542B\u3081\u3066\u306F\u3044\u3051\u307E\u305B\u3093: {{#key}}",
1353
+ // Array
1354
+ "array.base": "{{#label}}\u306F\u914D\u5217\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1355
+ "array.min": "{{#label}}\u306F\u5C11\u306A\u304F\u3068\u3082{{#limit}}\u500B\u306E\u8981\u7D20\u3092\u6301\u3064\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1356
+ "array.max": "{{#label}}\u306F\u6700\u5927{{#limit}}\u500B\u306E\u8981\u7D20\u3092\u6301\u3064\u3053\u3068\u304C\u3067\u304D\u307E\u3059",
1357
+ "array.length": "{{#label}}\u306F\u6B63\u78BA\u306B{{#limit}}\u500B\u306E\u8981\u7D20\u3092\u6301\u3064\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1358
+ "array.unique": "{{#label}}\u306B\u91CD\u8907\u3059\u308B\u8981\u7D20\u3092\u542B\u3081\u308B\u3053\u3068\u306F\u3067\u304D\u307E\u305B\u3093",
1359
+ "array.sparse": "{{#label}}\u306F\u30B9\u30D1\u30FC\u30B9\u914D\u5217\u3067\u3042\u3063\u3066\u306F\u306A\u308A\u307E\u305B\u3093",
1360
+ "array.includesRequired": "{{#label}}\u306B\u306F\u5FC5\u9808\u30A2\u30A4\u30C6\u30E0\u3092\u542B\u3081\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1361
+ // Date
1362
+ "date.base": "{{#label}}\u306F\u6709\u52B9\u306A\u65E5\u4ED8\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1363
+ "date.min": "{{#label}}\u306F{{#limit}}\u3088\u308A\u524D\u3067\u3042\u3063\u3066\u306F\u306A\u308A\u307E\u305B\u3093",
1364
+ "date.max": "{{#label}}\u306F{{#limit}}\u3088\u308A\u5F8C\u3067\u3042\u3063\u3066\u306F\u306A\u308A\u307E\u305B\u3093",
1365
+ "date.format": "{{#label}}\u306E\u65E5\u4ED8\u5F62\u5F0F\u304C\u7121\u52B9\u3067\u3059",
1366
+ "date.greater": "{{#label}}\u306F{{#limit}}\u3088\u308A\u5F8C\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1367
+ "date.less": "{{#label}}\u306F{{#limit}}\u3088\u308A\u524D\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1368
+ // Any
1369
+ "any.required": "{{#label}}\u306F\u5FC5\u9808\u3067\u3059",
1370
+ "any.invalid": "{{#label}}\u306B\u7121\u52B9\u306A\u5024\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059",
1371
+ "any.only": "{{#label}}\u306F{{#valids}}\u3068\u4E00\u81F4\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1372
+ "any.unknown": "\u30D5\u30A3\u30FC\u30EB\u30C9{{#key}}\u306F\u8A31\u53EF\u3055\u308C\u3066\u3044\u307E\u305B\u3093",
1373
+ // Patterns
1374
+ "pattern.phone": "\u7121\u52B9\u306A\u96FB\u8A71\u756A\u53F7",
1375
+ "pattern.phone.international": "\u7121\u52B9\u306A\u56FD\u969B\u96FB\u8A71\u756A\u53F7",
1376
+ "pattern.idCard": "\u7121\u52B9\u306AID\u30AB\u30FC\u30C9\u756A\u53F7",
1377
+ "pattern.creditCard": "\u7121\u52B9\u306A\u30AF\u30EC\u30B8\u30C3\u30C8\u30AB\u30FC\u30C9\u756A\u53F7",
1378
+ "pattern.creditCard.visa": "\u7121\u52B9\u306AVisa\u30AB\u30FC\u30C9\u756A\u53F7",
1379
+ "pattern.creditCard.mastercard": "\u7121\u52B9\u306AMastercard\u30AB\u30FC\u30C9\u756A\u53F7",
1380
+ "pattern.creditCard.amex": "\u7121\u52B9\u306AAmerican Express\u30AB\u30FC\u30C9\u756A\u53F7",
1381
+ "pattern.creditCard.discover": "\u7121\u52B9\u306ADiscover\u30AB\u30FC\u30C9\u756A\u53F7",
1382
+ "pattern.creditCard.jcb": "\u7121\u52B9\u306AJCB\u30AB\u30FC\u30C9\u756A\u53F7",
1383
+ "pattern.creditCard.unionpay": "\u7121\u52B9\u306AUnionPay\u30AB\u30FC\u30C9\u756A\u53F7",
1384
+ "pattern.licensePlate": "\u7121\u52B9\u306A\u30CA\u30F3\u30D0\u30FC\u30D7\u30EC\u30FC\u30C8",
1385
+ "pattern.postalCode": "\u7121\u52B9\u306A\u90F5\u4FBF\u756A\u53F7",
1386
+ "pattern.passport": "\u7121\u52B9\u306A\u30D1\u30B9\u30DD\u30FC\u30C8\u756A\u53F7",
1387
+ "pattern.objectId": "\u7121\u52B9\u306AObjectId",
1388
+ "pattern.hexColor": "\u7121\u52B9\u306A16\u9032\u30AB\u30E9\u30FC",
1389
+ "pattern.macAddress": "\u7121\u52B9\u306AMAC\u30A2\u30C9\u30EC\u30B9",
1390
+ "pattern.cron": "\u7121\u52B9\u306ACron\u5F0F",
1391
+ "pattern.slug": "URL\u30B9\u30E9\u30C3\u30B0\u306B\u306F\u5C0F\u6587\u5B57\u3001\u6570\u5B57\u3001\u30CF\u30A4\u30D5\u30F3\u306E\u307F\u3092\u542B\u3081\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059",
1392
+ "pattern.domain": "{{#label}}\u306F\u6709\u52B9\u306A\u30C9\u30E1\u30A4\u30F3\u540D\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1393
+ "pattern.ip": "{{#label}}\u306F\u6709\u52B9\u306AIP\u30A2\u30C9\u30EC\u30B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1394
+ "pattern.base64": "{{#label}}\u306F\u6709\u52B9\u306ABase64\u6587\u5B57\u5217\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1395
+ "pattern.jwt": "{{#label}}\u306F\u6709\u52B9\u306AJWT\u30C8\u30FC\u30AF\u30F3\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1396
+ "pattern.json": "{{#label}}\u306F\u6709\u52B9\u306AJSON\u6587\u5B57\u5217\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1397
+ "pattern.username": "\u30E6\u30FC\u30B6\u30FC\u540D\u306F\u6587\u5B57\u3067\u59CB\u307E\u308A\u3001\u6587\u5B57\u3001\u6570\u5B57\u3001\u30A2\u30F3\u30C0\u30FC\u30B9\u30B3\u30A2\u306E\u307F\u3092\u542B\u3080\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1398
+ "pattern.password.weak": "\u30D1\u30B9\u30EF\u30FC\u30C9\u306F\u5C11\u306A\u304F\u3068\u30826\u6587\u5B57\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1399
+ "pattern.password.medium": "\u30D1\u30B9\u30EF\u30FC\u30C9\u306F\u5C11\u306A\u304F\u3068\u30828\u6587\u5B57\u3067\u3001\u6587\u5B57\u3068\u6570\u5B57\u3092\u542B\u3080\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1400
+ "pattern.password.strong": "\u30D1\u30B9\u30EF\u30FC\u30C9\u306F\u5C11\u306A\u304F\u3068\u30828\u6587\u5B57\u3067\u3001\u5927\u6587\u5B57\u3001\u5C0F\u6587\u5B57\u3001\u6570\u5B57\u3092\u542B\u3080\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1401
+ "pattern.password.veryStrong": "\u30D1\u30B9\u30EF\u30FC\u30C9\u306F\u5C11\u306A\u304F\u3068\u308210\u6587\u5B57\u3067\u3001\u5927\u6587\u5B57\u3001\u5C0F\u6587\u5B57\u3001\u6570\u5B57\u3001\u7279\u6B8A\u6587\u5B57\u3092\u542B\u3080\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1402
+ "pattern.emailOrPhone": "\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u307E\u305F\u306F\u96FB\u8A71\u756A\u53F7\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1403
+ "pattern.usernameOrEmail": "\u30E6\u30FC\u30B6\u30FC\u540D\u307E\u305F\u306F\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1404
+ "pattern.httpOrHttps": "http \u307E\u305F\u306F https \u3067\u59CB\u307E\u308BURL\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1405
+ // oneOf
1406
+ oneOf: "{{#label}}\u306F\u6B21\u306E\u3044\u305A\u308C\u304B\u306E\u578B\u306B\u4E00\u81F4\u3059\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
1407
+ "oneOf.invalid": "{{#label}}\u306E\u5024\u306F\u8A31\u53EF\u3055\u308C\u305F\u578B\u306E\u3044\u305A\u308C\u3068\u3082\u4E00\u81F4\u3057\u307E\u305B\u3093",
1408
+ // Error fallback
1409
+ UNKNOWN_ERROR: "\u4E0D\u660E\u306A\u691C\u8A3C\u30A8\u30E9\u30FC",
1410
+ CUSTOM_VALIDATION_FAILED: "\u691C\u8A3C\u306B\u5931\u6557\u3057\u307E\u3057\u305F",
1411
+ ASYNC_VALIDATION_NOT_SUPPORTED: "\u540C\u671Fvalidate()\u3067\u306F\u975E\u540C\u671F\u691C\u8A3C\u306F\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u307E\u305B\u3093",
1412
+ VALIDATE_MUST_BE_FUNCTION: "validate\u306F\u95A2\u6570\u3067\u3042\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059"
1413
+ };
1414
+ ja_JP_default = jaJP;
1415
+ }
1416
+ });
1417
+
1418
+ // src/locales/es-ES.ts
1419
+ var esES, es_ES_default;
1420
+ var init_es_ES = __esm({
1421
+ "src/locales/es-ES.ts"() {
1422
+ "use strict";
1423
+ esES = {
1424
+ // Generic
1425
+ required: "{{#label}} es obligatorio",
1426
+ type: "{{#label}} debe ser de tipo {{#expected}}, pero se obtuvo {{#actual}}",
1427
+ min: "La longitud de {{#label}} debe ser al menos {{#limit}}",
1428
+ max: "La longitud de {{#label}} debe ser como m\xE1ximo {{#limit}}",
1429
+ length: "La longitud de {{#label}} debe ser exactamente {{#expected}}",
1430
+ pattern: "El formato de {{#label}} no es v\xE1lido",
1431
+ enum: "{{#label}} debe ser uno de: {{#allowed}}",
1432
+ custom: "Validaci\xF3n fallida para {{#label}}: {{#message}}",
1433
+ circular: "Referencia circular detectada en {{#label}}",
1434
+ "max-depth": "Profundidad m\xE1xima de recursi\xF3n ({{#depth}}) excedida en {{#label}}",
1435
+ exception: "Excepci\xF3n de validaci\xF3n en {{#label}}: {{#message}}",
1436
+ // Conditional (v2 additions)
1437
+ "conditional.underAge": "Los menores de edad no pueden registrarse",
1438
+ "conditional.blocked": "La cuenta ha sido bloqueada",
1439
+ "conditional.notAllowed": "El registro no est\xE1 permitido",
1440
+ // I18nError — generic (v2 additions)
1441
+ "error.notFound": "{{#resource}} no encontrado",
1442
+ "error.forbidden": "Acceso a {{#resource}} est\xE1 prohibido",
1443
+ "error.unauthorized": "No autorizado, por favor inicie sesi\xF3n",
1444
+ "error.invalid": "{{#field}} no es v\xE1lido",
1445
+ "error.duplicate": "{{#resource}} ya existe",
1446
+ "error.conflict": "Conflicto de operaci\xF3n: {{#reason}}",
1447
+ // Account (v2 additions)
1448
+ "account.notFound": { code: "ACCOUNT_NOT_FOUND", message: "Cuenta no encontrada" },
1449
+ "account.inactive": "La cuenta est\xE1 inactiva",
1450
+ "account.banned": "La cuenta ha sido suspendida",
1451
+ "account.insufficientBalance": {
1452
+ code: "INSUFFICIENT_BALANCE",
1453
+ message: "Saldo insuficiente, actual: {{#balance}}, requerido: {{#required}}"
1454
+ },
1455
+ "account.insufficientCredits": "Cr\xE9ditos insuficientes, actual: {{#credits}}, requerido: {{#required}}",
1456
+ // User (v2 additions)
1457
+ "user.notFound": "Usuario no encontrado",
1458
+ "user.notVerified": "El usuario no est\xE1 verificado",
1459
+ "user.noPermission": "Sin permisos de administrador",
1460
+ // Order (v2 additions)
1461
+ "order.notPaid": { code: "ORDER_NOT_PAID", message: "Pedido no pagado" },
1462
+ "order.paymentMissing": "Falta informaci\xF3n de pago",
1463
+ "order.addressMissing": "Falta la direcci\xF3n de env\xEDo",
1464
+ // Format
1465
+ "format.email": "{{#label}} debe ser una direcci\xF3n de correo electr\xF3nico v\xE1lida",
1466
+ "format.url": "{{#label}} debe ser una URL v\xE1lida",
1467
+ "format.uuid": "{{#label}} debe ser un UUID v\xE1lido",
1468
+ "format.date": "{{#label}} debe ser una fecha v\xE1lida (YYYY-MM-DD)",
1469
+ "format.datetime": "{{#label}} debe ser una fecha y hora v\xE1lida (ISO 8601)",
1470
+ "format.time": "{{#label}} debe ser una hora v\xE1lida (HH:mm:ss)",
1471
+ "format.ipv4": "{{#label}} debe ser una direcci\xF3n IPv4 v\xE1lida",
1472
+ "format.ipv6": "{{#label}} debe ser una direcci\xF3n IPv6 v\xE1lida",
1473
+ "format.binary": "{{#label}} debe ser una cadena base64 v\xE1lida",
1474
+ // String
1475
+ "string.hostname": "{{#label}} debe ser un nombre de host v\xE1lido",
1476
+ "string.pattern": "El formato de {{#label}} no coincide con el patr\xF3n requerido",
1477
+ "string.enum": "{{#label}} debe ser uno de: {{#valids}}",
1478
+ "string.length": "La longitud de {{#label}} debe ser exactamente {{#limit}} caracteres",
1479
+ "string.alphanum": "{{#label}} solo puede contener caracteres alfanum\xE9ricos",
1480
+ "string.trim": "{{#label}} no debe tener espacios al principio ni al final",
1481
+ "string.lowercase": "{{#label}} debe estar en min\xFAsculas",
1482
+ "string.uppercase": "{{#label}} debe estar en may\xFAsculas",
1483
+ // Number
1484
+ "number.base": "{{#label}} debe ser un n\xFAmero",
1485
+ "number.min": "{{#label}} debe ser mayor o igual a {{#limit}}",
1486
+ "number.max": "{{#label}} debe ser menor o igual a {{#limit}}",
1487
+ "number.integer": "{{#label}} debe ser un n\xFAmero entero",
1488
+ "number.positive": "{{#label}} debe ser un n\xFAmero positivo",
1489
+ "number.negative": "{{#label}} debe ser un n\xFAmero negativo",
1490
+ "number.precision": "{{#label}} debe tener como m\xE1ximo {{#limit}} decimales",
1491
+ "number.port": "{{#label}} debe ser un n\xFAmero de puerto v\xE1lido (1-65535)",
1492
+ // Boolean
1493
+ "boolean.base": "{{#label}} debe ser un booleano",
1494
+ // Object
1495
+ "object.base": "{{#label}} debe ser un objeto",
1496
+ "object.min": "{{#label}} debe tener al menos {{#limit}} propiedades",
1497
+ "object.max": "{{#label}} debe tener como m\xE1ximo {{#limit}} propiedades",
1498
+ "object.unknown": "{{#label}} contiene una propiedad desconocida: {{#key}}",
1499
+ "object.missing": "A {{#label}} le faltan propiedades requeridas",
1500
+ "object.schema": "{{#label}} contiene propiedades adicionales",
1501
+ "additionalProperties": "{{#label}} NO debe tener propiedades adicionales: {{#key}}",
1502
+ // Array
1503
+ "array.base": "{{#label}} debe ser un array",
1504
+ "array.min": "{{#label}} debe tener al menos {{#limit}} elementos",
1505
+ "array.max": "{{#label}} debe tener como m\xE1ximo {{#limit}} elementos",
1506
+ "array.length": "{{#label}} debe tener exactamente {{#limit}} elementos",
1507
+ "array.unique": "{{#label}} no debe contener elementos duplicados",
1508
+ "array.sparse": "{{#label}} no debe ser un array disperso",
1509
+ "array.includesRequired": "{{#label}} debe incluir los elementos requeridos",
1510
+ // Date
1511
+ "date.base": "{{#label}} debe ser una fecha v\xE1lida",
1512
+ "date.min": "{{#label}} no debe ser anterior a {{#limit}}",
1513
+ "date.max": "{{#label}} no debe ser posterior a {{#limit}}",
1514
+ "date.format": "El formato de fecha de {{#label}} no es v\xE1lido",
1515
+ "date.greater": "{{#label}} debe ser posterior a {{#limit}}",
1516
+ "date.less": "{{#label}} debe ser anterior a {{#limit}}",
1517
+ // Any
1518
+ "any.required": "{{#label}} es obligatorio",
1519
+ "any.invalid": "{{#label}} contiene un valor no v\xE1lido",
1520
+ "any.only": "{{#label}} debe coincidir con {{#valids}}",
1521
+ "any.unknown": "El campo {{#key}} no est\xE1 permitido",
1522
+ // Patterns
1523
+ "pattern.phone": "N\xFAmero de tel\xE9fono no v\xE1lido",
1524
+ "pattern.phone.international": "N\xFAmero de tel\xE9fono internacional no v\xE1lido",
1525
+ "pattern.idCard": "N\xFAmero de tarjeta de identificaci\xF3n no v\xE1lido",
1526
+ "pattern.creditCard": "N\xFAmero de tarjeta de cr\xE9dito no v\xE1lido",
1527
+ "pattern.creditCard.visa": "N\xFAmero de tarjeta Visa no v\xE1lido",
1528
+ "pattern.creditCard.mastercard": "N\xFAmero de Mastercard no v\xE1lido",
1529
+ "pattern.creditCard.amex": "N\xFAmero de tarjeta American Express no v\xE1lido",
1530
+ "pattern.creditCard.discover": "N\xFAmero de tarjeta Discover no v\xE1lido",
1531
+ "pattern.creditCard.jcb": "N\xFAmero de tarjeta JCB no v\xE1lido",
1532
+ "pattern.creditCard.unionpay": "N\xFAmero de tarjeta UnionPay no v\xE1lido",
1533
+ "pattern.licensePlate": "N\xFAmero de matr\xEDcula no v\xE1lido",
1534
+ "pattern.postalCode": "C\xF3digo postal no v\xE1lido",
1535
+ "pattern.passport": "N\xFAmero de pasaporte no v\xE1lido",
1536
+ "pattern.objectId": "ObjectId no v\xE1lido",
1537
+ "pattern.hexColor": "Color hexadecimal no v\xE1lido",
1538
+ "pattern.macAddress": "Direcci\xF3n MAC no v\xE1lida",
1539
+ "pattern.cron": "Expresi\xF3n Cron no v\xE1lida",
1540
+ "pattern.slug": "El slug de URL solo puede contener letras min\xFAsculas, n\xFAmeros y guiones",
1541
+ "pattern.domain": "{{#label}} debe ser un nombre de dominio v\xE1lido",
1542
+ "pattern.ip": "{{#label}} debe ser una direcci\xF3n IP v\xE1lida",
1543
+ "pattern.base64": "{{#label}} debe ser una cadena Base64 v\xE1lida",
1544
+ "pattern.jwt": "{{#label}} debe ser un token JWT v\xE1lido",
1545
+ "pattern.json": "{{#label}} debe ser una cadena JSON v\xE1lida",
1546
+ "pattern.username": "El nombre de usuario debe comenzar con una letra y contener solo letras, n\xFAmeros y guiones bajos",
1547
+ "pattern.password.weak": "La contrase\xF1a debe tener al menos 6 caracteres",
1548
+ "pattern.password.medium": "La contrase\xF1a debe tener al menos 8 caracteres y contener letras y n\xFAmeros",
1549
+ "pattern.password.strong": "La contrase\xF1a debe tener al menos 8 caracteres y contener letras may\xFAsculas, min\xFAsculas y n\xFAmeros",
1550
+ "pattern.password.veryStrong": "La contrase\xF1a debe tener al menos 10 caracteres y contener letras may\xFAsculas, min\xFAsculas, n\xFAmeros y caracteres especiales",
1551
+ "pattern.emailOrPhone": "Debe ser un correo electr\xF3nico o n\xFAmero de tel\xE9fono",
1552
+ "pattern.usernameOrEmail": "Debe ser un nombre de usuario o correo electr\xF3nico",
1553
+ "pattern.httpOrHttps": "Debe ser una URL que comience con http o https",
1554
+ // oneOf
1555
+ oneOf: "{{#label}} debe coincidir con uno de los siguientes tipos",
1556
+ "oneOf.invalid": "El valor de {{#label}} no coincide con ning\xFAn tipo permitido",
1557
+ // Error fallback
1558
+ UNKNOWN_ERROR: "Error de validaci\xF3n desconocido",
1559
+ CUSTOM_VALIDATION_FAILED: "Validaci\xF3n fallida",
1560
+ ASYNC_VALIDATION_NOT_SUPPORTED: "La validaci\xF3n as\xEDncrona no es compatible en validate() s\xEDncrono",
1561
+ VALIDATE_MUST_BE_FUNCTION: "validate debe ser una funci\xF3n"
1562
+ };
1563
+ es_ES_default = esES;
1564
+ }
1565
+ });
1566
+
1567
+ // src/locales/fr-FR.ts
1568
+ var frFR, fr_FR_default;
1569
+ var init_fr_FR = __esm({
1570
+ "src/locales/fr-FR.ts"() {
1571
+ "use strict";
1572
+ frFR = {
1573
+ // Generic
1574
+ required: "{{#label}} est requis",
1575
+ type: "{{#label}} doit \xEAtre de type {{#expected}}, mais {{#actual}} a \xE9t\xE9 re\xE7u",
1576
+ min: "La longueur de {{#label}} doit \xEAtre d'au moins {{#limit}}",
1577
+ max: "La longueur de {{#label}} doit \xEAtre d'au plus {{#limit}}",
1578
+ length: "La longueur de {{#label}} doit \xEAtre exactement {{#expected}}",
1579
+ pattern: "Le format de {{#label}} n'est pas valide",
1580
+ enum: "{{#label}} doit \xEAtre l'un de : {{#allowed}}",
1581
+ custom: "Validation \xE9chou\xE9e pour {{#label}} : {{#message}}",
1582
+ circular: "R\xE9f\xE9rence circulaire d\xE9tect\xE9e dans {{#label}}",
1583
+ "max-depth": "Profondeur maximale de r\xE9cursion ({{#depth}}) d\xE9pass\xE9e dans {{#label}}",
1584
+ exception: "Exception de validation dans {{#label}} : {{#message}}",
1585
+ // Conditional (v2 additions)
1586
+ "conditional.underAge": "Les mineurs ne peuvent pas s'inscrire",
1587
+ "conditional.blocked": "Le compte a \xE9t\xE9 bloqu\xE9",
1588
+ "conditional.notAllowed": "L'inscription n'est pas autoris\xE9e",
1589
+ // I18nError — generic (v2 additions)
1590
+ "error.notFound": "{{#resource}} introuvable",
1591
+ "error.forbidden": "Acc\xE8s \xE0 {{#resource}} interdit",
1592
+ "error.unauthorized": "Non autoris\xE9, veuillez vous connecter",
1593
+ "error.invalid": "{{#field}} n'est pas valide",
1594
+ "error.duplicate": "{{#resource}} existe d\xE9j\xE0",
1595
+ "error.conflict": "Conflit d'op\xE9ration : {{#reason}}",
1596
+ // Account (v2 additions)
1597
+ "account.notFound": { code: "ACCOUNT_NOT_FOUND", message: "Compte introuvable" },
1598
+ "account.inactive": "Le compte est inactif",
1599
+ "account.banned": "Le compte a \xE9t\xE9 banni",
1600
+ "account.insufficientBalance": {
1601
+ code: "INSUFFICIENT_BALANCE",
1602
+ message: "Solde insuffisant, actuel : {{#balance}}, requis : {{#required}}"
1603
+ },
1604
+ "account.insufficientCredits": "Cr\xE9dits insuffisants, actuels : {{#credits}}, requis : {{#required}}",
1605
+ // User (v2 additions)
1606
+ "user.notFound": "Utilisateur introuvable",
1607
+ "user.notVerified": "L'utilisateur n'est pas v\xE9rifi\xE9",
1608
+ "user.noPermission": "Pas de permission d'administrateur",
1609
+ // Order (v2 additions)
1610
+ "order.notPaid": { code: "ORDER_NOT_PAID", message: "Commande non pay\xE9e" },
1611
+ "order.paymentMissing": "Informations de paiement manquantes",
1612
+ "order.addressMissing": "Adresse de livraison manquante",
1613
+ // Format
1614
+ "format.email": "{{#label}} doit \xEAtre une adresse e-mail valide",
1615
+ "format.url": "{{#label}} doit \xEAtre une URL valide",
1616
+ "format.uuid": "{{#label}} doit \xEAtre un UUID valide",
1617
+ "format.date": "{{#label}} doit \xEAtre une date valide (YYYY-MM-DD)",
1618
+ "format.datetime": "{{#label}} doit \xEAtre une date et heure valide (ISO 8601)",
1619
+ "format.time": "{{#label}} doit \xEAtre une heure valide (HH:mm:ss)",
1620
+ "format.ipv4": "{{#label}} doit \xEAtre une adresse IPv4 valide",
1621
+ "format.ipv6": "{{#label}} doit \xEAtre une adresse IPv6 valide",
1622
+ "format.binary": "{{#label}} doit \xEAtre une cha\xEEne base64 valide",
1623
+ // String
1624
+ "string.hostname": "{{#label}} doit \xEAtre un nom d'h\xF4te valide",
1625
+ "string.pattern": "Le format de {{#label}} ne correspond pas au mod\xE8le requis",
1626
+ "string.enum": "{{#label}} doit \xEAtre l'un de : {{#valids}}",
1627
+ "string.length": "La longueur de {{#label}} doit \xEAtre exactement {{#limit}} caract\xE8res",
1628
+ "string.alphanum": "{{#label}} ne doit contenir que des caract\xE8res alphanum\xE9riques",
1629
+ "string.trim": "{{#label}} ne doit pas avoir d'espaces en d\xE9but ou en fin",
1630
+ "string.lowercase": "{{#label}} doit \xEAtre en minuscules",
1631
+ "string.uppercase": "{{#label}} doit \xEAtre en majuscules",
1632
+ // Number
1633
+ "number.base": "{{#label}} doit \xEAtre un nombre",
1634
+ "number.min": "{{#label}} doit \xEAtre sup\xE9rieur ou \xE9gal \xE0 {{#limit}}",
1635
+ "number.max": "{{#label}} doit \xEAtre inf\xE9rieur ou \xE9gal \xE0 {{#limit}}",
1636
+ "number.integer": "{{#label}} doit \xEAtre un nombre entier",
1637
+ "number.positive": "{{#label}} doit \xEAtre un nombre positif",
1638
+ "number.negative": "{{#label}} doit \xEAtre un nombre n\xE9gatif",
1639
+ "number.precision": "{{#label}} doit avoir au plus {{#limit}} d\xE9cimales",
1640
+ "number.port": "{{#label}} doit \xEAtre un num\xE9ro de port valide (1-65535)",
1641
+ // Boolean
1642
+ "boolean.base": "{{#label}} doit \xEAtre un bool\xE9en",
1643
+ // Object
1644
+ "object.base": "{{#label}} doit \xEAtre un objet",
1645
+ "object.min": "{{#label}} doit avoir au moins {{#limit}} propri\xE9t\xE9s",
1646
+ "object.max": "{{#label}} doit avoir au plus {{#limit}} propri\xE9t\xE9s",
1647
+ "object.unknown": "{{#label}} contient une propri\xE9t\xE9 inconnue : {{#key}}",
1648
+ "object.missing": "{{#label}} est manquant les propri\xE9t\xE9s requises",
1649
+ "object.schema": "{{#label}} contient des propri\xE9t\xE9s suppl\xE9mentaires",
1650
+ "additionalProperties": "{{#label}} NE doit PAS avoir de propri\xE9t\xE9s suppl\xE9mentaires : {{#key}}",
1651
+ // Array
1652
+ "array.base": "{{#label}} doit \xEAtre un tableau",
1653
+ "array.min": "{{#label}} doit avoir au moins {{#limit}} \xE9l\xE9ments",
1654
+ "array.max": "{{#label}} doit avoir au plus {{#limit}} \xE9l\xE9ments",
1655
+ "array.length": "{{#label}} doit avoir exactement {{#limit}} \xE9l\xE9ments",
1656
+ "array.unique": "{{#label}} ne doit pas contenir d'\xE9l\xE9ments en double",
1657
+ "array.sparse": "{{#label}} ne doit pas \xEAtre un tableau clairsem\xE9",
1658
+ "array.includesRequired": "{{#label}} doit inclure les \xE9l\xE9ments requis",
1659
+ // Date
1660
+ "date.base": "{{#label}} doit \xEAtre une date valide",
1661
+ "date.min": "{{#label}} ne doit pas \xEAtre ant\xE9rieur \xE0 {{#limit}}",
1662
+ "date.max": "{{#label}} ne doit pas \xEAtre post\xE9rieur \xE0 {{#limit}}",
1663
+ "date.format": "Le format de date de {{#label}} n'est pas valide",
1664
+ "date.greater": "{{#label}} doit \xEAtre apr\xE8s {{#limit}}",
1665
+ "date.less": "{{#label}} doit \xEAtre avant {{#limit}}",
1666
+ // Any
1667
+ "any.required": "{{#label}} est requis",
1668
+ "any.invalid": "{{#label}} contient une valeur non valide",
1669
+ "any.only": "{{#label}} doit correspondre \xE0 {{#valids}}",
1670
+ "any.unknown": "Le champ {{#key}} n'est pas autoris\xE9",
1671
+ // Patterns
1672
+ "pattern.phone": "Num\xE9ro de t\xE9l\xE9phone non valide",
1673
+ "pattern.phone.international": "Num\xE9ro de t\xE9l\xE9phone international non valide",
1674
+ "pattern.idCard": "Num\xE9ro de carte d'identit\xE9 non valide",
1675
+ "pattern.creditCard": "Num\xE9ro de carte de cr\xE9dit non valide",
1676
+ "pattern.creditCard.visa": "Num\xE9ro de carte Visa non valide",
1677
+ "pattern.creditCard.mastercard": "Num\xE9ro Mastercard non valide",
1678
+ "pattern.creditCard.amex": "Num\xE9ro de carte American Express non valide",
1679
+ "pattern.creditCard.discover": "Num\xE9ro de carte Discover non valide",
1680
+ "pattern.creditCard.jcb": "Num\xE9ro de carte JCB non valide",
1681
+ "pattern.creditCard.unionpay": "Num\xE9ro de carte UnionPay non valide",
1682
+ "pattern.licensePlate": "Num\xE9ro de plaque d'immatriculation non valide",
1683
+ "pattern.postalCode": "Code postal non valide",
1684
+ "pattern.passport": "Num\xE9ro de passeport non valide",
1685
+ "pattern.objectId": "ObjectId non valide",
1686
+ "pattern.hexColor": "Couleur hexad\xE9cimale non valide",
1687
+ "pattern.macAddress": "Adresse MAC non valide",
1688
+ "pattern.cron": "Expression Cron non valide",
1689
+ "pattern.slug": "Le slug d'URL ne peut contenir que des lettres minuscules, des chiffres et des tirets",
1690
+ "pattern.domain": "{{#label}} doit \xEAtre un nom de domaine valide",
1691
+ "pattern.ip": "{{#label}} doit \xEAtre une adresse IP valide",
1692
+ "pattern.base64": "{{#label}} doit \xEAtre une cha\xEEne Base64 valide",
1693
+ "pattern.jwt": "{{#label}} doit \xEAtre un token JWT valide",
1694
+ "pattern.json": "{{#label}} doit \xEAtre une cha\xEEne JSON valide",
1695
+ "pattern.username": "Le nom d'utilisateur doit commencer par une lettre et contenir uniquement des lettres, des chiffres et des tirets bas",
1696
+ "pattern.password.weak": "Le mot de passe doit contenir au moins 6 caract\xE8res",
1697
+ "pattern.password.medium": "Le mot de passe doit contenir au moins 8 caract\xE8res et inclure des lettres et des chiffres",
1698
+ "pattern.password.strong": "Le mot de passe doit contenir au moins 8 caract\xE8res et inclure des lettres majuscules, minuscules et des chiffres",
1699
+ "pattern.password.veryStrong": "Le mot de passe doit contenir au moins 10 caract\xE8res et inclure des lettres majuscules, minuscules, des chiffres et des caract\xE8res sp\xE9ciaux",
1700
+ "pattern.emailOrPhone": "Doit \xEAtre un e-mail ou un num\xE9ro de t\xE9l\xE9phone",
1701
+ "pattern.usernameOrEmail": "Doit \xEAtre un nom d'utilisateur ou un e-mail",
1702
+ "pattern.httpOrHttps": "Doit \xEAtre une URL commen\xE7ant par http ou https",
1703
+ // oneOf
1704
+ oneOf: "{{#label}} doit correspondre \xE0 l'un des types suivants",
1705
+ "oneOf.invalid": "{{#label}} ne correspond \xE0 aucun type autoris\xE9",
1706
+ // Error fallback
1707
+ UNKNOWN_ERROR: "Erreur de validation inconnue",
1708
+ CUSTOM_VALIDATION_FAILED: "Validation \xE9chou\xE9e",
1709
+ ASYNC_VALIDATION_NOT_SUPPORTED: "La validation asynchrone n'est pas prise en charge dans validate() synchrone",
1710
+ VALIDATE_MUST_BE_FUNCTION: "validate doit \xEAtre une fonction"
1711
+ };
1712
+ fr_FR_default = frFR;
1713
+ }
1714
+ });
1715
+
1716
+ // src/locales/index.ts
1717
+ function getMessage(key, locale = DEFAULT_LOCALE) {
1718
+ const messages = LOCALES[locale];
1719
+ if (messages && key in messages) {
1720
+ return messages[key];
1721
+ }
1722
+ if (locale !== DEFAULT_LOCALE) {
1723
+ const defaultMessages = LOCALES[DEFAULT_LOCALE];
1724
+ if (defaultMessages && key in defaultMessages) {
1725
+ return defaultMessages[key];
1726
+ }
1727
+ }
1728
+ const fallbackMessages = LOCALES[FALLBACK_LOCALE];
1729
+ if (fallbackMessages && key in fallbackMessages) {
1730
+ return fallbackMessages[key];
1731
+ }
1732
+ return key;
1733
+ }
1734
+ function getMessages(locale = DEFAULT_LOCALE) {
1735
+ return LOCALES[locale] ?? LOCALES[DEFAULT_LOCALE];
1736
+ }
1737
+ function isSupportedLocale(locale) {
1738
+ return locale in LOCALES;
1739
+ }
1740
+ function getSupportedLocales() {
1741
+ return Object.keys(LOCALES);
1742
+ }
1743
+ var LOCALES, DEFAULT_LOCALE, FALLBACK_LOCALE;
1744
+ var init_locales = __esm({
1745
+ "src/locales/index.ts"() {
1746
+ "use strict";
1747
+ init_zh_CN();
1748
+ init_en_US();
1749
+ init_ja_JP();
1750
+ init_es_ES();
1751
+ init_fr_FR();
1752
+ LOCALES = {
1753
+ "zh-CN": zh_CN_default,
1754
+ "en-US": en_US_default,
1755
+ "ja-JP": ja_JP_default,
1756
+ "es-ES": es_ES_default,
1757
+ "fr-FR": fr_FR_default
1758
+ };
1759
+ DEFAULT_LOCALE = "en-US";
1760
+ FALLBACK_LOCALE = "en-US";
1761
+ }
1762
+ });
1763
+
1764
+ // src/core/Locale.ts
1765
+ var DEFAULT_LOCALE2, Locale;
1766
+ var init_Locale = __esm({
1767
+ "src/core/Locale.ts"() {
1768
+ "use strict";
1769
+ init_locales();
1770
+ DEFAULT_LOCALE2 = "en-US";
1771
+ Locale = class {
1772
+ static _currentLocale = DEFAULT_LOCALE2;
1773
+ static _customMessages = {};
1774
+ /** v1 compat: expose custom messages */
1775
+ static get customMessages() {
1776
+ return this._customMessages;
1777
+ }
1778
+ /** v1 compat: expose all locales as { locale: messages } map */
1779
+ static get locales() {
1780
+ const result = {};
1781
+ for (const locale of getSupportedLocales()) {
1782
+ result[locale] = getMessages(locale);
1783
+ }
1784
+ for (const key of Object.keys(this._customMessages)) {
1785
+ if (key.includes(":")) {
1786
+ const colonIdx = key.indexOf(":");
1787
+ const locale = key.substring(0, colonIdx);
1788
+ const msgKey = key.substring(colonIdx + 1);
1789
+ if (!result[locale]) result[locale] = {};
1790
+ result[locale][msgKey] = this._customMessages[key];
1791
+ }
1792
+ }
1793
+ return result;
1794
+ }
1795
+ // ─── Locale Switching ─────────────────────────────────────────────────────
1796
+ static setLocale(locale) {
1797
+ this._currentLocale = locale;
1798
+ }
1799
+ static getLocale() {
1800
+ return this._currentLocale;
1801
+ }
1802
+ // ─── Custom Messages (global override) ───────────────────────────────────
1803
+ static setMessages(messages) {
1804
+ this._customMessages = { ...this._customMessages, ...messages };
1805
+ }
1806
+ static addLocale(locale, messages) {
1807
+ for (const [k, v] of Object.entries(messages)) {
1808
+ this._customMessages[`${locale}:${k}`] = v;
1809
+ }
1810
+ }
1811
+ static getAvailableLocales() {
1812
+ return getSupportedLocales();
1813
+ }
1814
+ static isSupportedLocale(locale) {
1815
+ return isSupportedLocale(locale);
1816
+ }
1817
+ // ─── Core Query Methods ───────────────────────────────────────────────────
1818
+ /**
1819
+ * Get a resolved message (v1 compat: returns { code, message } on hit).
1820
+ *
1821
+ * Priority: custom messages > locale pack > key itself.
1822
+ */
1823
+ static getMessage(type, customMessages = {}, locale = null) {
1824
+ const resolved = this._resolveMessage(type, customMessages, locale);
1825
+ if (!resolved) return type;
1826
+ return this._normalizeResolvedMessage(type, resolved);
1827
+ }
1828
+ /**
1829
+ * Get the final message text (used internally by v2 to avoid "[object Object]" in message field).
1830
+ */
1831
+ static getMessageText(type, customMessages = {}, locale = null) {
1832
+ const resolved = this.getMessage(type, customMessages, locale);
1833
+ return typeof resolved === "string" ? resolved : resolved.message;
1834
+ }
1835
+ /**
1836
+ * Get raw message config (used by I18nError; may include a numeric code).
1837
+ */
1838
+ static getMessageConfig(type, customMessages = {}, locale = null) {
1839
+ return this._resolveMessage(type, customMessages, locale) ?? { code: type, message: type };
1840
+ }
1841
+ /**
1842
+ * Get the full message table for the given locale (built-in + custom).
1843
+ */
1844
+ static getMessages(locale) {
1845
+ const targetLocale = locale ?? this._currentLocale;
1846
+ const builtinMessages = getMessages(targetLocale);
1847
+ const customForLocale = {};
1848
+ for (const [k, v] of Object.entries(this._customMessages)) {
1849
+ if (k.startsWith(`${targetLocale}:`)) {
1850
+ customForLocale[k.slice(targetLocale.length + 1)] = v;
1851
+ } else if (!k.includes(":")) {
1852
+ customForLocale[k] = v;
1853
+ }
1854
+ }
1855
+ return { ...builtinMessages, ...customForLocale };
1856
+ }
1857
+ /**
1858
+ * Reset to defaults (for testing).
1859
+ */
1860
+ static reset() {
1861
+ this._currentLocale = DEFAULT_LOCALE2;
1862
+ this._customMessages = {};
1863
+ }
1864
+ // ─── Private Helpers ──────────────────────────────────────────────────────
1865
+ static _normalizeResolvedMessage(type, msg) {
1866
+ if (typeof msg === "string") {
1867
+ return { code: type, message: msg };
1868
+ }
1869
+ return {
1870
+ code: msg.code ?? type,
1871
+ message: msg.message
1872
+ };
1873
+ }
1874
+ static _resolveMessage(type, customMessages, locale) {
1875
+ const targetLocale = locale ?? this._currentLocale;
1876
+ const callerMsg = customMessages[type];
1877
+ if (callerMsg !== void 0) return callerMsg;
1878
+ const globalMsg = this._customMessages[type];
1879
+ if (globalMsg !== void 0) return globalMsg;
1880
+ const globalLocaleMsg = this._customMessages[`${targetLocale}:${type}`];
1881
+ if (globalLocaleMsg !== void 0) return globalLocaleMsg;
1882
+ if (this._isLocaleKey(type)) {
1883
+ return getMessage(type, targetLocale);
1884
+ }
1885
+ return null;
1886
+ }
1887
+ static _isLocaleKey(key) {
1888
+ const msgs = getMessages();
1889
+ return key in msgs;
1890
+ }
1891
+ };
1892
+ }
1893
+ });
1894
+
1895
+ // src/core/ErrorFormatter.ts
1896
+ var ErrorFormatter;
1897
+ var init_ErrorFormatter = __esm({
1898
+ "src/core/ErrorFormatter.ts"() {
1899
+ "use strict";
1900
+ init_TemplateEngine();
1901
+ init_ErrorCodes();
1902
+ init_locales();
1903
+ init_Locale();
1904
+ ErrorFormatter = class {
1905
+ messages;
1906
+ _locale;
1907
+ _constructorCustomMessages;
1908
+ constructor(locale = DEFAULT_LOCALE2, messages = {}) {
1909
+ this._locale = locale;
1910
+ const rawLocaleMessages = getMessages(locale);
1911
+ const localeMessages = Object.fromEntries(
1912
+ Object.entries(rawLocaleMessages).map(([k, v]) => [
1913
+ k,
1914
+ typeof v === "string" ? v : v.message
1915
+ ])
1916
+ );
1917
+ const normMessages = Object.fromEntries(
1918
+ Object.entries(messages).map(([k, v]) => [
1919
+ k,
1920
+ v == null ? void 0 : typeof v === "string" ? v : v.message
1921
+ ])
1922
+ );
1923
+ this._constructorCustomMessages = normMessages;
1924
+ this.messages = { ...localeMessages, ...normMessages };
1925
+ }
1926
+ get locale() {
1927
+ return this._locale;
1928
+ }
1929
+ /**
1930
+ * Format a single error object → message string (v1 API).
1931
+ */
1932
+ format(error, locale) {
1933
+ let msgs = this.messages;
1934
+ if (locale && locale !== this._locale) {
1935
+ const rawLocaleMessages = getMessages(locale);
1936
+ const localeMessages = Object.fromEntries(
1937
+ Object.entries(rawLocaleMessages).map(([k, v]) => [
1938
+ k,
1939
+ typeof v === "string" ? v : v.message
1940
+ ])
1941
+ );
1942
+ msgs = { ...localeMessages, ...this._constructorCustomMessages };
1943
+ }
1944
+ const raw = error;
1945
+ const ajvError = {
1946
+ keyword: raw["keyword"] ?? raw["type"] ?? "validation",
1947
+ instancePath: raw["instancePath"] ?? "/" + (raw["path"] ?? ""),
1948
+ params: raw["params"] ?? {},
1949
+ parentSchema: raw["parentSchema"]
1950
+ };
1951
+ const item = this._formatOne(ajvError, msgs, locale);
1952
+ return item.message;
1953
+ }
1954
+ /**
1955
+ * Format an AJV raw error array → ValidationErrorItem[].
1956
+ *
1957
+ * @param alreadyMerged - when true, customMessages is already a fully merged locale+custom result;
1958
+ * skip `{ ...this.messages, ...customMessages }` spread (avoids 100+ key cold-spread overhead).
1959
+ */
1960
+ formatDetailed(errors, locale, customMessages, alreadyMerged = false) {
1961
+ const msgs = customMessages ? alreadyMerged ? customMessages : { ...this.messages, ...customMessages } : this.messages;
1962
+ const hasConcreteErrors = errors.some(
1963
+ (e) => e.keyword !== "if" && e.keyword !== "anyOf" && e.keyword !== "oneOf" && e.keyword !== "error"
1964
+ );
1965
+ const filtered = hasConcreteErrors ? errors.filter((e) => e.keyword !== "if" && e.keyword !== "anyOf" && e.keyword !== "oneOf") : errors;
1966
+ return filtered.map((err) => this._formatOne(err, msgs, locale));
1967
+ }
1968
+ /**
1969
+ * Format a single error entry into a ValidationErrorItem.
1970
+ */
1971
+ _formatOne(err, messages, _locale) {
1972
+ const keyword = err.keyword ?? "validation";
1973
+ const instancePath = err.instancePath ?? "";
1974
+ const params = err.params ?? {};
1975
+ let fieldName;
1976
+ if (keyword === "required" && params["missingProperty"]) {
1977
+ const parentPath = instancePath.replace(/^\//, "");
1978
+ const missing = String(params["missingProperty"]);
1979
+ fieldName = parentPath ? `${parentPath}/${missing}` : missing;
1980
+ } else {
1981
+ fieldName = instancePath.replace(/^\//, "") || "value";
1982
+ }
1983
+ const schema = err.parentSchema ?? {};
1984
+ let label;
1985
+ if (keyword === "required" && params["missingProperty"]) {
1986
+ const missingProp = String(params["missingProperty"]);
1987
+ const properties = schema["properties"];
1988
+ if (properties && properties[missingProp]) {
1989
+ label = properties[missingProp]["_label"];
1990
+ }
1991
+ }
1992
+ if (!label) {
1993
+ label = schema["_label"];
1994
+ }
1995
+ if (label) {
1996
+ label = (messages[label] != null ? String(messages[label]) : void 0) ?? label;
1997
+ }
1998
+ if (!label) {
1999
+ let labelKey;
2000
+ if (keyword === "required" && params["missingProperty"]) {
2001
+ labelKey = String(params["missingProperty"]);
2002
+ } else {
2003
+ const parts = fieldName.split("/");
2004
+ labelKey = parts[parts.length - 1] ?? fieldName;
2005
+ }
2006
+ const autoKey = `label.${labelKey.replace(/\//g, ".")}`;
2007
+ label = messages[autoKey] ?? labelKey;
2008
+ }
2009
+ let schemaCustomMessages = schema["_customMessages"] ?? {};
2010
+ if (keyword === "required" && params["missingProperty"]) {
2011
+ const missingProp = String(params["missingProperty"]);
2012
+ const properties = schema["properties"];
2013
+ if (properties && properties[missingProp] && properties[missingProp]["_customMessages"]) {
2014
+ schemaCustomMessages = { ...schemaCustomMessages, ...properties[missingProp]["_customMessages"] };
2015
+ }
2016
+ }
2017
+ const hasCustomMessages = Object.keys(schemaCustomMessages).length > 0;
2018
+ const mergedMessages = hasCustomMessages ? { ...messages, ...schemaCustomMessages } : messages;
2019
+ const mappedKeyword = KEYWORD_MAP[keyword] ?? keyword;
2020
+ const schemaType = typeof schema["type"] === "string" ? schema["type"] : "string";
2021
+ let message = hasCustomMessages ? schemaCustomMessages[keyword] ?? schemaCustomMessages[mappedKeyword] : void 0;
2022
+ if (message) {
2023
+ message = mergedMessages[message] ?? message;
2024
+ } else {
2025
+ if (mappedKeyword === "format" && params["format"]) {
2026
+ let fmt = String(params["format"]);
2027
+ if (fmt === "uri") fmt = "url";
2028
+ message = mergedMessages[`format.${fmt}`];
2029
+ }
2030
+ message ??= mergedMessages[`${schemaType}.${keyword}`] ?? mergedMessages[`${schemaType}.${mappedKeyword}`] ?? mergedMessages[mappedKeyword] ?? mergedMessages[keyword] ?? mergedMessages["default"] ?? err.message ?? "Validation error";
2031
+ }
2032
+ const limit = params["limit"] ?? params["limitLength"] ?? params["comparison"] ?? "";
2033
+ const allowedVals = Array.isArray(params["allowedValues"]) ? params["allowedValues"].join(", ") : void 0;
2034
+ const interpolateData = {
2035
+ ...params,
2036
+ path: label,
2037
+ label,
2038
+ value: err.data !== void 0 ? err.data : "",
2039
+ limit,
2040
+ min: limit,
2041
+ max: limit,
2042
+ expected: params["type"],
2043
+ actual: err.data === null ? "null" : err.data === void 0 ? "undefined" : Array.isArray(err.data) ? "array" : typeof err.data,
2044
+ valids: allowedVals,
2045
+ allowed: allowedVals,
2046
+ key: params["additionalProperty"]
2047
+ };
2048
+ const rendered = renderTemplate(message, interpolateData);
2049
+ return {
2050
+ path: fieldName,
2051
+ message: rendered,
2052
+ keyword,
2053
+ params,
2054
+ field: fieldName,
2055
+ type: keyword,
2056
+ expected: params["type"] !== void 0 ? String(params["type"]) : void 0
2057
+ };
2058
+ }
2059
+ setLocale(locale) {
2060
+ this._locale = locale;
2061
+ const rawLocaleMessages = getMessages(locale);
2062
+ const localeMessages = Object.fromEntries(
2063
+ Object.entries(rawLocaleMessages).map(([k, v]) => [
2064
+ k,
2065
+ typeof v === "string" ? v : v.message
2066
+ ])
2067
+ );
2068
+ this.messages = { ...localeMessages, ...this._constructorCustomMessages };
2069
+ }
2070
+ addMessage(type, template) {
2071
+ this.messages[type] = template;
2072
+ }
2073
+ addMessages(messages) {
2074
+ Object.assign(this.messages, messages);
2075
+ }
2076
+ };
2077
+ }
2078
+ });
2079
+
2080
+ // src/validators/CustomKeywords.ts
2081
+ import safeRegex from "safe-regex";
2082
+ var CustomKeywords;
2083
+ var init_CustomKeywords = __esm({
2084
+ "src/validators/CustomKeywords.ts"() {
2085
+ "use strict";
2086
+ init_Locale();
2087
+ CustomKeywords = class _CustomKeywords {
2088
+ /**
2089
+ * Register all custom keywords on an AJV instance
2090
+ */
2091
+ static registerAll(ajv) {
2092
+ _CustomKeywords.registerRegexKeyword(ajv);
2093
+ _CustomKeywords.registerFunctionKeyword(ajv);
2094
+ _CustomKeywords.registerCustomValidatorsKeyword(ajv);
2095
+ _CustomKeywords.registerMetadataKeywords(ajv);
2096
+ _CustomKeywords.registerStringValidators(ajv);
2097
+ _CustomKeywords.registerNumberValidators(ajv);
2098
+ _CustomKeywords.registerObjectValidators(ajv);
2099
+ _CustomKeywords.registerArrayValidators(ajv);
2100
+ _CustomKeywords.registerDateValidators(ajv);
2101
+ }
2102
+ // ─── Metadata keywords ──────────────────────────────────────────────────
2103
+ static registerMetadataKeywords(ajv) {
2104
+ ajv.addKeyword({ keyword: "_label", metaSchema: { type: "string" } });
2105
+ ajv.addKeyword({ keyword: "_customMessages", metaSchema: { type: "object" } });
2106
+ ajv.addKeyword({ keyword: "_description", metaSchema: { type: "string" } });
2107
+ ajv.addKeyword({ keyword: "_whenConditions", metaSchema: { type: "array" } });
2108
+ ajv.addKeyword({ keyword: "_required", metaSchema: { type: "boolean" } });
2109
+ ajv.addKeyword({ keyword: "_isConditional", metaSchema: { type: "boolean" } });
2110
+ ajv.addKeyword({ keyword: "_runtimeOnlyConditional", metaSchema: { type: "boolean" } });
2111
+ ajv.addKeyword({ keyword: "conditions" });
2112
+ ajv.addKeyword({ keyword: "_evaluateCondition" });
2113
+ }
2114
+ // ─── _customValidators ──────────────────────────────────────────────────
2115
+ static registerCustomValidatorsKeyword(ajv) {
2116
+ const validate = (validators, data) => {
2117
+ if (!Array.isArray(validators)) return true;
2118
+ for (const validator of validators) {
2119
+ if (typeof validator !== "function") continue;
2120
+ try {
2121
+ const result = validator(data);
2122
+ if (result instanceof Promise) {
2123
+ validate.errors = [{
2124
+ keyword: "_customValidators",
2125
+ message: "Async validation not supported in sync validate(). Use validateAsync() instead.",
2126
+ params: {}
2127
+ }];
2128
+ return false;
2129
+ }
2130
+ if (result === false) {
2131
+ const msg = Locale.getMessageText("CUSTOM_VALIDATION_FAILED");
2132
+ validate.errors = [{ keyword: "_customValidators", message: msg, params: {} }];
2133
+ return false;
2134
+ }
2135
+ if (typeof result === "string") {
2136
+ validate.errors = [{ keyword: "_customValidators", message: result, params: {} }];
2137
+ return false;
2138
+ }
2139
+ if (result !== null && typeof result === "object" && result["error"]) {
2140
+ const msg = String(result["message"] ?? Locale.getMessageText("CUSTOM_VALIDATION_FAILED"));
2141
+ validate.errors = [{ keyword: "_customValidators", message: msg, params: {} }];
2142
+ return false;
2143
+ }
2144
+ } catch (error) {
2145
+ const msg = error instanceof Error ? error.message : String(error);
2146
+ validate.errors = [{ keyword: "_customValidators", message: msg, params: {} }];
2147
+ return false;
2148
+ }
2149
+ }
2150
+ return true;
2151
+ };
2152
+ ajv.addKeyword({ keyword: "_customValidators", validate, errors: true });
2153
+ }
2154
+ // ─── regex ──────────────────────────────────────────────────────────────
2155
+ // Detect potentially catastrophic patterns via a dedicated regex safety analyzer
2156
+ static _isUnsafePattern(pattern) {
2157
+ return !safeRegex(pattern);
2158
+ }
2159
+ static registerRegexKeyword(ajv) {
2160
+ const validate = (schema, data) => {
2161
+ const patternStr = String(schema);
2162
+ try {
2163
+ const regex = new RegExp(patternStr);
2164
+ if (_CustomKeywords._isUnsafePattern(regex)) {
2165
+ validate.errors = [{
2166
+ keyword: "regex",
2167
+ message: Locale.getMessageText("string.pattern"),
2168
+ params: { pattern: patternStr, reason: "unsafe regex pattern" }
2169
+ }];
2170
+ return false;
2171
+ }
2172
+ if (regex.test(String(data))) return true;
2173
+ validate.errors = [{
2174
+ keyword: "regex",
2175
+ message: Locale.getMessageText("string.pattern"),
2176
+ params: { pattern: schema }
2177
+ }];
2178
+ return false;
2179
+ } catch (error) {
2180
+ validate.errors = [{
2181
+ keyword: "regex",
2182
+ message: Locale.getMessageText("string.pattern"),
2183
+ params: { error: error instanceof Error ? error.message : String(error) }
2184
+ }];
2185
+ return false;
2186
+ }
2187
+ };
2188
+ ajv.addKeyword({ keyword: "regex", type: "string", schemaType: "string", validate, errors: true });
2189
+ }
2190
+ // ─── validate (function validator) ──────────────────────────────────────
2191
+ static registerFunctionKeyword(ajv) {
2192
+ const validate = (schema, data) => {
2193
+ if (typeof schema !== "function") {
2194
+ validate.errors = [{
2195
+ keyword: "validate",
2196
+ message: Locale.getMessageText("VALIDATE_MUST_BE_FUNCTION"),
2197
+ params: {}
2198
+ }];
2199
+ return false;
2200
+ }
2201
+ try {
2202
+ const result = schema(data);
2203
+ if (typeof result === "boolean") return result;
2204
+ if (result !== null && typeof result === "object") {
2205
+ const res = result;
2206
+ if (typeof res["valid"] === "boolean") {
2207
+ if (!res["valid"] && res["message"]) {
2208
+ validate.errors = [{
2209
+ keyword: "validate",
2210
+ message: String(res["message"]),
2211
+ params: {}
2212
+ }];
2213
+ }
2214
+ return res["valid"];
2215
+ }
2216
+ }
2217
+ return true;
2218
+ } catch (error) {
2219
+ validate.errors = [{
2220
+ keyword: "validate",
2221
+ message: error instanceof Error ? error.message : String(error),
2222
+ params: {}
2223
+ }];
2224
+ return false;
2225
+ }
2226
+ };
2227
+ ajv.addKeyword({ keyword: "validate", validate, errors: true });
2228
+ }
2229
+ // ─── String validators ───────────────────────────────────────────────────
2230
+ static registerStringValidators(ajv) {
2231
+ const exactLength = (schema, data) => {
2232
+ const codePointLength = [...String(data)].length;
2233
+ if (codePointLength !== Number(schema)) {
2234
+ exactLength.errors = [{
2235
+ keyword: "exactLength",
2236
+ message: Locale.getMessageText("string.length"),
2237
+ params: { limit: schema }
2238
+ }];
2239
+ return false;
2240
+ }
2241
+ return true;
2242
+ };
2243
+ ajv.addKeyword({ keyword: "exactLength", type: "string", schemaType: "number", validate: exactLength, errors: true });
2244
+ const alphanum = (schema, data) => {
2245
+ if (schema && !/^[a-zA-Z0-9]*$/.test(String(data))) {
2246
+ alphanum.errors = [{ keyword: "alphanum", message: Locale.getMessageText("string.alphanum"), params: {} }];
2247
+ return false;
2248
+ }
2249
+ return true;
2250
+ };
2251
+ ajv.addKeyword({ keyword: "alphanum", type: "string", schemaType: "boolean", validate: alphanum, errors: true });
2252
+ const trim = (schema, data) => {
2253
+ const str = String(data);
2254
+ if (schema && str !== str.trim()) {
2255
+ trim.errors = [{ keyword: "trim", message: Locale.getMessageText("string.trim"), params: {} }];
2256
+ return false;
2257
+ }
2258
+ return true;
2259
+ };
2260
+ ajv.addKeyword({ keyword: "trim", type: "string", schemaType: "boolean", validate: trim, errors: true });
2261
+ const lowercase = (schema, data) => {
2262
+ const str = String(data);
2263
+ if (schema && str !== str.toLowerCase()) {
2264
+ lowercase.errors = [{ keyword: "lowercase", message: Locale.getMessageText("string.lowercase"), params: {} }];
2265
+ return false;
2266
+ }
2267
+ return true;
2268
+ };
2269
+ ajv.addKeyword({ keyword: "lowercase", type: "string", schemaType: "boolean", validate: lowercase, errors: true });
2270
+ const uppercase = (schema, data) => {
2271
+ const str = String(data);
2272
+ if (schema && str !== str.toUpperCase()) {
2273
+ uppercase.errors = [{ keyword: "uppercase", message: Locale.getMessageText("string.uppercase"), params: {} }];
2274
+ return false;
2275
+ }
2276
+ return true;
2277
+ };
2278
+ ajv.addKeyword({ keyword: "uppercase", type: "string", schemaType: "boolean", validate: uppercase, errors: true });
2279
+ const jsonString = (schema, data) => {
2280
+ if (schema) {
2281
+ try {
2282
+ JSON.parse(String(data));
2283
+ } catch {
2284
+ jsonString.errors = [{ keyword: "jsonString", message: Locale.getMessageText("pattern.json"), params: {} }];
2285
+ return false;
2286
+ }
2287
+ }
2288
+ return true;
2289
+ };
2290
+ ajv.addKeyword({ keyword: "jsonString", type: "string", schemaType: "boolean", validate: jsonString, errors: true });
2291
+ }
2292
+ // ─── Number validators ───────────────────────────────────────────────────
2293
+ static registerNumberValidators(ajv) {
2294
+ const precision = (schema, data) => {
2295
+ const n = data;
2296
+ const limit = Number(schema);
2297
+ const factor = Math.pow(10, limit);
2298
+ const shifted = n * factor;
2299
+ if (Math.abs(shifted - Math.round(shifted)) > 1e-10) {
2300
+ precision.errors = [{ keyword: "precision", message: Locale.getMessageText("number.precision"), params: { limit: schema } }];
2301
+ return false;
2302
+ }
2303
+ return true;
2304
+ };
2305
+ ajv.addKeyword({ keyword: "precision", type: "number", schemaType: "number", validate: precision, errors: true });
2306
+ const port = (schema, data) => {
2307
+ const num = data;
2308
+ if (schema && (!Number.isInteger(num) || num < 1 || num > 65535)) {
2309
+ port.errors = [{ keyword: "port", message: Locale.getMessageText("number.port"), params: {} }];
2310
+ return false;
2311
+ }
2312
+ return true;
2313
+ };
2314
+ ajv.addKeyword({ keyword: "port", type: ["integer", "number"], schemaType: "boolean", validate: port, errors: true });
2315
+ }
2316
+ // ─── Object validators ──────────────────────────────────────────────────
2317
+ static registerObjectValidators(ajv) {
2318
+ const requiredAll = (schema, data, parentSchema) => {
2319
+ if (!schema) return true;
2320
+ const props = parentSchema?.["properties"] ?? {};
2321
+ const missingKeys = Object.keys(props).filter((k) => !(k in data));
2322
+ if (missingKeys.length > 0) {
2323
+ requiredAll.errors = [{
2324
+ keyword: "requiredAll",
2325
+ message: Locale.getMessageText("object.missing"),
2326
+ params: { missing: missingKeys }
2327
+ }];
2328
+ return false;
2329
+ }
2330
+ return true;
2331
+ };
2332
+ ajv.addKeyword({ keyword: "requiredAll", type: "object", schemaType: "boolean", validate: requiredAll, errors: true });
2333
+ const strictSchema = (schema, data, parentSchema) => {
2334
+ if (!schema) return true;
2335
+ const props = parentSchema?.["properties"] ?? {};
2336
+ const allowedKeys = Object.keys(props);
2337
+ const extraKeys = Object.keys(data).filter((k) => !allowedKeys.includes(k));
2338
+ if (extraKeys.length > 0) {
2339
+ strictSchema.errors = [{
2340
+ keyword: "strictSchema",
2341
+ message: Locale.getMessageText("object.schema"),
2342
+ params: { extra: extraKeys }
2343
+ }];
2344
+ return false;
2345
+ }
2346
+ return true;
2347
+ };
2348
+ ajv.addKeyword({ keyword: "strictSchema", type: "object", schemaType: "boolean", validate: strictSchema, errors: true });
2349
+ }
2350
+ // ─── Array validators ───────────────────────────────────────────────────
2351
+ static _deepEqual(a, b) {
2352
+ if (a === b) return true;
2353
+ if (a === null || b === null || typeof a !== typeof b) return false;
2354
+ if (typeof a !== "object") return false;
2355
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
2356
+ if (Array.isArray(a)) {
2357
+ if (a.length !== b.length) return false;
2358
+ return a.every((item, i) => _CustomKeywords._deepEqual(item, b[i]));
2359
+ }
2360
+ const aKeys = Object.keys(a).sort();
2361
+ const bKeys = Object.keys(b).sort();
2362
+ if (aKeys.length !== bKeys.length) return false;
2363
+ return aKeys.every(
2364
+ (k) => _CustomKeywords._deepEqual(a[k], b[k])
2365
+ );
2366
+ }
2367
+ static registerArrayValidators(ajv) {
2368
+ const noSparse = (schema, data) => {
2369
+ const arr = data;
2370
+ if (schema) {
2371
+ for (let i = 0; i < arr.length; i++) {
2372
+ if (!(i in arr)) {
2373
+ noSparse.errors = [{
2374
+ keyword: "noSparse",
2375
+ message: Locale.getMessageText("array.sparse"),
2376
+ params: { index: i }
2377
+ }];
2378
+ return false;
2379
+ }
2380
+ }
2381
+ }
2382
+ return true;
2383
+ };
2384
+ ajv.addKeyword({ keyword: "noSparse", type: "array", schemaType: "boolean", validate: noSparse, errors: true });
2385
+ const includesRequired = (schema, data) => {
2386
+ if (!Array.isArray(schema) || schema.length === 0) return true;
2387
+ const arr = data;
2388
+ const missing = schema.filter((required) => {
2389
+ return !arr.some((item) => {
2390
+ if (typeof required === "object" && required !== null) {
2391
+ return _CustomKeywords._deepEqual(item, required);
2392
+ }
2393
+ return item === required;
2394
+ });
2395
+ });
2396
+ if (missing.length > 0) {
2397
+ includesRequired.errors = [{
2398
+ keyword: "includesRequired",
2399
+ message: Locale.getMessageText("array.includesRequired"),
2400
+ params: { missing }
2401
+ }];
2402
+ return false;
2403
+ }
2404
+ return true;
2405
+ };
2406
+ ajv.addKeyword({ keyword: "includesRequired", type: "array", schemaType: "array", validate: includesRequired, errors: true });
2407
+ }
2408
+ // ─── Date validators ────────────────────────────────────────────────────
2409
+ static registerDateValidators(ajv) {
2410
+ const DATE_FORMATS = {
2411
+ "YYYY-MM-DD": /^\d{4}-\d{2}-\d{2}$/,
2412
+ "YYYY/MM/DD": /^\d{4}\/\d{2}\/\d{2}$/,
2413
+ "DD-MM-YYYY": /^\d{2}-\d{2}-\d{4}$/,
2414
+ "DD/MM/YYYY": /^\d{2}\/\d{2}\/\d{4}$/,
2415
+ "ISO8601": /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$/
2416
+ };
2417
+ const dateFormat = (schema, data) => {
2418
+ const fmt = String(schema);
2419
+ const pattern = DATE_FORMATS[fmt];
2420
+ const str = String(data);
2421
+ if (!pattern || !pattern.test(str)) {
2422
+ dateFormat.errors = [{
2423
+ keyword: "dateFormat",
2424
+ message: Locale.getMessageText("date.format"),
2425
+ params: { format: schema }
2426
+ }];
2427
+ return false;
2428
+ }
2429
+ const sep = /[-/]/.exec(str)?.[0] ?? "-";
2430
+ const parts = str.split(sep);
2431
+ let y, m, dd;
2432
+ if (fmt === "DD-MM-YYYY" || fmt === "DD/MM/YYYY") {
2433
+ [dd, m, y] = [parseInt(parts[0], 10), parseInt(parts[1], 10), parseInt(parts[2], 10)];
2434
+ } else if (fmt === "ISO8601") {
2435
+ const d2 = new Date(str);
2436
+ if (isNaN(d2.getTime())) {
2437
+ dateFormat.errors = [{ keyword: "dateFormat", message: Locale.getMessageText("date.format"), params: { format: schema } }];
2438
+ return false;
2439
+ }
2440
+ return true;
2441
+ } else {
2442
+ [y, m, dd] = [parseInt(parts[0], 10), parseInt(parts[1], 10), parseInt(parts[2], 10)];
2443
+ }
2444
+ const probe = new Date(y, m - 1, dd);
2445
+ if (probe.getFullYear() !== y || probe.getMonth() !== m - 1 || probe.getDate() !== dd) {
2446
+ dateFormat.errors = [{ keyword: "dateFormat", message: Locale.getMessageText("date.format"), params: { format: schema } }];
2447
+ return false;
2448
+ }
2449
+ return true;
2450
+ };
2451
+ ajv.addKeyword({ keyword: "dateFormat", type: "string", schemaType: "string", validate: dateFormat, errors: true });
2452
+ const dateGreater = (schema, data) => {
2453
+ const dataDate = new Date(String(data));
2454
+ const compareDate = new Date(String(schema));
2455
+ if (isNaN(dataDate.getTime()) || isNaN(compareDate.getTime()) || dataDate <= compareDate) {
2456
+ dateGreater.errors = [{
2457
+ keyword: "dateGreater",
2458
+ message: Locale.getMessageText("date.greater"),
2459
+ params: { limit: schema }
2460
+ }];
2461
+ return false;
2462
+ }
2463
+ return true;
2464
+ };
2465
+ ajv.addKeyword({ keyword: "dateGreater", type: "string", schemaType: "string", validate: dateGreater, errors: true });
2466
+ const dateLess = (schema, data) => {
2467
+ const dataDate = new Date(String(data));
2468
+ const compareDate = new Date(String(schema));
2469
+ if (isNaN(dataDate.getTime()) || isNaN(compareDate.getTime()) || dataDate >= compareDate) {
2470
+ dateLess.errors = [{
2471
+ keyword: "dateLess",
2472
+ message: Locale.getMessageText("date.less"),
2473
+ params: { limit: schema }
2474
+ }];
2475
+ return false;
2476
+ }
2477
+ return true;
2478
+ };
2479
+ ajv.addKeyword({ keyword: "dateLess", type: "string", schemaType: "string", validate: dateLess, errors: true });
2480
+ }
2481
+ };
2482
+ }
2483
+ });
2484
+
2485
+ // src/core/ConditionalRuntime.ts
2486
+ var CONDITIONAL_RUNTIME_STATE;
2487
+ var init_ConditionalRuntime = __esm({
2488
+ "src/core/ConditionalRuntime.ts"() {
2489
+ "use strict";
2490
+ CONDITIONAL_RUNTIME_STATE = /* @__PURE__ */ Symbol("schema-dsl.conditionalRuntimeState");
2491
+ }
2492
+ });
2493
+
2494
+ // src/core/ConditionalValidator.ts
2495
+ var EMPTY_ERRORS, ConditionalValidator;
2496
+ var init_ConditionalValidator = __esm({
2497
+ "src/core/ConditionalValidator.ts"() {
2498
+ "use strict";
2499
+ init_DslParser();
2500
+ init_Locale();
2501
+ init_ConditionalRuntime();
2502
+ EMPTY_ERRORS = [];
2503
+ ConditionalValidator = class {
2504
+ constructor(hooks) {
2505
+ this.hooks = hooks;
2506
+ }
2507
+ hooks;
2508
+ hasAnyConditional(schema) {
2509
+ if (!schema.properties) return false;
2510
+ return Object.values(schema.properties).some((fieldSchema) => {
2511
+ const fs = fieldSchema;
2512
+ if (fs._isConditional) return true;
2513
+ if (fs.properties) return this.hasAnyConditional(fs);
2514
+ return false;
2515
+ });
2516
+ }
2517
+ validateWithConditionals(schema, data, options, rootData) {
2518
+ const errors = [];
2519
+ const effectiveRoot = rootData ?? data;
2520
+ const cleanSchema = JSON.parse(JSON.stringify(schema));
2521
+ const conditionalFields = {};
2522
+ const nestedObjectFields = {};
2523
+ for (const [fieldName, fieldSchema] of Object.entries(schema.properties ?? {})) {
2524
+ const fs = fieldSchema;
2525
+ if (fs._isConditional) {
2526
+ conditionalFields[fieldName] = fs;
2527
+ delete cleanSchema.properties?.[fieldName];
2528
+ if (cleanSchema.required) {
2529
+ cleanSchema.required = cleanSchema.required.filter((r) => r !== fieldName);
2530
+ }
2531
+ } else if (fs.properties && this.hasAnyConditional(fs)) {
2532
+ nestedObjectFields[fieldName] = fs;
2533
+ delete cleanSchema.properties?.[fieldName];
2534
+ }
2535
+ }
2536
+ const baseResult = this.hooks.validateSchema(cleanSchema, data, options);
2537
+ if (!baseResult.valid) {
2538
+ errors.push(...baseResult.errors ?? []);
2539
+ }
2540
+ for (const [fieldName, conditionalSchema] of Object.entries(conditionalFields)) {
2541
+ const dataRecord = data;
2542
+ const fieldResult = this.validateConditional(conditionalSchema, effectiveRoot, fieldName, dataRecord[fieldName], options);
2543
+ if (!fieldResult.valid) {
2544
+ for (const err of fieldResult.errors ?? []) {
2545
+ const errPath = !err.path || err.path === "value" ? fieldName : err.path;
2546
+ errors.push({ ...err, path: errPath, field: errPath });
2547
+ }
2548
+ }
2549
+ }
2550
+ for (const [fieldName, nestedSchema] of Object.entries(nestedObjectFields)) {
2551
+ const dataRecord = data;
2552
+ const nestedData = dataRecord[fieldName];
2553
+ if (nestedData === void 0 || nestedData === null) {
2554
+ const partialSchema = JSON.parse(JSON.stringify(schema));
2555
+ partialSchema.properties = { [fieldName]: nestedSchema };
2556
+ partialSchema.required = (schema.required ?? []).filter((r) => r === fieldName);
2557
+ const partialResult = this.hooks.validateSchema(partialSchema, data, options);
2558
+ if (!partialResult.valid) {
2559
+ errors.push(...partialResult.errors ?? []);
2560
+ }
2561
+ continue;
2562
+ }
2563
+ const nestedResult = this.validateWithConditionals(nestedSchema, nestedData, options, effectiveRoot);
2564
+ if (!nestedResult.valid) {
2565
+ for (const err of nestedResult.errors ?? []) {
2566
+ const errPath = err.path ? `${fieldName}/${err.path}` : fieldName;
2567
+ errors.push({ ...err, path: errPath, field: errPath });
2568
+ }
2569
+ }
2570
+ }
2571
+ if (errors.length === 0) return { valid: true, data, errors: EMPTY_ERRORS };
2572
+ return { valid: false, data, errors, errorMessage: errors[0]?.message };
2573
+ }
2574
+ validateConditional(conditionalSchema, data, fieldName, fieldValue, options) {
2575
+ const locale = options.locale ?? Locale.getLocale();
2576
+ const runtimeState = conditionalSchema[CONDITIONAL_RUNTIME_STATE];
2577
+ const conditions = runtimeState?.conditions ?? conditionalSchema.conditions ?? [];
2578
+ if (conditions.length === 0 && conditionalSchema._runtimeOnlyConditional) {
2579
+ return {
2580
+ valid: false,
2581
+ data: fieldValue,
2582
+ errors: [{
2583
+ message: "[schema-dsl] Function-based conditional schemas are runtime-only and cannot be restored from JSON serialization.",
2584
+ path: "",
2585
+ keyword: "conditional",
2586
+ params: {}
2587
+ }],
2588
+ errorMessage: "[schema-dsl] Function-based conditional schemas are runtime-only and cannot be restored from JSON serialization."
2589
+ };
2590
+ }
2591
+ try {
2592
+ for (const cond of conditions) {
2593
+ const evaluation = runtimeState?.evaluateCondition(cond, data) ?? conditionalSchema._evaluateCondition?.(cond, data) ?? { result: false };
2594
+ const matched = evaluation.result;
2595
+ if (cond.action === "throw") {
2596
+ if (matched) {
2597
+ const errorMsg = evaluation.failedMessage ?? cond.message ?? "Conditional validation failed";
2598
+ const message = Locale.getMessageText(errorMsg, options.messages ?? {}, locale);
2599
+ return {
2600
+ valid: false,
2601
+ data: fieldValue,
2602
+ errors: [{ message, path: "", keyword: "conditional", params: { condition: cond["type"] } }],
2603
+ errorMessage: message
2604
+ };
2605
+ }
2606
+ continue;
2607
+ }
2608
+ if (matched) {
2609
+ const thenSchema = cond["then"];
2610
+ if (thenSchema !== void 0 && thenSchema !== null) {
2611
+ return this.executeThenBranch(thenSchema, data, fieldValue, fieldName, options);
2612
+ }
2613
+ return { valid: true, data: fieldValue, errors: EMPTY_ERRORS };
2614
+ }
2615
+ if (evaluation.requirementFailed) {
2616
+ const errorMsg = cond.message ?? "Condition not met";
2617
+ const message = Locale.getMessageText(errorMsg, options.messages ?? {}, locale);
2618
+ return {
2619
+ valid: false,
2620
+ data: fieldValue,
2621
+ errors: [{ message, path: "", keyword: "conditional", params: {} }],
2622
+ errorMessage: message
2623
+ };
2624
+ }
2625
+ }
2626
+ const elseSchema = runtimeState ? runtimeState.elseSchema : conditionalSchema.else;
2627
+ if (elseSchema !== void 0) {
2628
+ if (elseSchema === null) return { valid: true, data: fieldValue, errors: EMPTY_ERRORS };
2629
+ return this.executeThenBranch(elseSchema, data, fieldValue, fieldName, options);
2630
+ }
2631
+ return { valid: true, data: fieldValue, errors: EMPTY_ERRORS };
2632
+ } catch (error) {
2633
+ return this.hooks.internalError(error, fieldValue);
2634
+ }
2635
+ }
2636
+ executeThenBranch(thenSchema, data, fieldValue, fieldName, options) {
2637
+ let resolved = thenSchema;
2638
+ if (typeof resolved === "string") {
2639
+ resolved = DslParser.parseString(resolved);
2640
+ }
2641
+ if (resolved !== null && typeof resolved === "object") {
2642
+ const obj = resolved;
2643
+ if (typeof obj["toSchema"] === "function") {
2644
+ resolved = obj["toSchema"]();
2645
+ }
2646
+ }
2647
+ const resolvedSchema = resolved;
2648
+ if (resolvedSchema?._isConditional) {
2649
+ return this.validateConditional(resolvedSchema, data, fieldName, fieldValue, options);
2650
+ }
2651
+ if (resolved !== null && typeof resolved === "object" && !Array.isArray(resolved)) {
2652
+ const obj = resolved;
2653
+ if (obj["type"] === void 0 && obj["oneOf"] === void 0 && obj["anyOf"] === void 0 && obj["allOf"] === void 0) {
2654
+ resolved = DslParser.parseObject(resolved);
2655
+ }
2656
+ }
2657
+ return this.validateFieldValue(resolved, fieldValue, options);
2658
+ }
2659
+ validateFieldValue(schema, fieldValue, options) {
2660
+ const internalSchema = schema;
2661
+ const isRequired = internalSchema._required === true;
2662
+ if (!isRequired && (fieldValue === void 0 || fieldValue === "")) {
2663
+ return { valid: true, data: fieldValue, errors: EMPTY_ERRORS };
2664
+ }
2665
+ if (isRequired && fieldValue === void 0) {
2666
+ const locale = options.locale ?? Locale.getLocale();
2667
+ const label = internalSchema._label ?? "";
2668
+ const customMsgs = internalSchema._customMessages ?? {};
2669
+ const allMsgs = { ...options.messages ?? {}, ...customMsgs };
2670
+ let message;
2671
+ if (allMsgs["required"]) {
2672
+ message = Locale.getMessageText(allMsgs["required"], allMsgs, locale);
2673
+ } else {
2674
+ message = Locale.getMessageText("required", allMsgs, locale);
2675
+ if (label) message = `${label} ${message}`;
2676
+ }
2677
+ return {
2678
+ valid: false,
2679
+ data: fieldValue,
2680
+ errors: [{ message, path: "", keyword: "required", params: {} }],
2681
+ errorMessage: message
2682
+ };
2683
+ }
2684
+ return this.hooks.validateSchema(schema, fieldValue, options);
2685
+ }
2686
+ };
2687
+ }
2688
+ });
2689
+
2690
+ // src/errors/ValidationError.ts
2691
+ var ValidationError_exports = {};
2692
+ __export(ValidationError_exports, {
2693
+ ValidationError: () => ValidationError
2694
+ });
2695
+ var ErrorCtor, ValidationError;
2696
+ var init_ValidationError = __esm({
2697
+ "src/errors/ValidationError.ts"() {
2698
+ "use strict";
2699
+ ErrorCtor = Error;
2700
+ ValidationError = class _ValidationError extends Error {
2701
+ name = "ValidationError";
2702
+ errors;
2703
+ data;
2704
+ statusCode;
2705
+ constructor(errors, data, statusCode = 400) {
2706
+ const messages = errors.length === 0 ? "Validation failed" : errors.map((e) => {
2707
+ if (e.path) {
2708
+ const field = e.path.replace(/^\//, "");
2709
+ return field ? `${field}: ${e.message}` : e.message;
2710
+ }
2711
+ return e.message;
2712
+ }).join("; ");
2713
+ const hasNoPath = errors.every((e) => e.path === void 0 || e.path === null || e.path === "");
2714
+ const isSingleConditional = errors.length === 1 && errors[0].keyword === "conditional" && hasNoPath;
2715
+ if (isSingleConditional) {
2716
+ super(messages);
2717
+ } else {
2718
+ super(hasNoPath ? `Validation failed - ${messages}` : `Validation failed: ${messages}`);
2719
+ }
2720
+ this.errors = errors;
2721
+ this.data = data;
2722
+ this.statusCode = statusCode;
2723
+ if (ErrorCtor.captureStackTrace) {
2724
+ ErrorCtor.captureStackTrace(this, _ValidationError);
2725
+ }
2726
+ }
2727
+ toJSON() {
2728
+ return {
2729
+ error: this.name,
2730
+ message: this.message,
2731
+ statusCode: this.statusCode,
2732
+ details: this.errors.map((e) => ({
2733
+ field: e.path ? e.path.replace(/^\//, "") : null,
2734
+ message: e.message,
2735
+ keyword: e.keyword,
2736
+ ...e.params !== void 0 ? { params: e.params } : {}
2737
+ }))
2738
+ };
2739
+ }
2740
+ getFieldError(field) {
2741
+ const normalized = field.replace(/^\//, "");
2742
+ return this.errors.find((e) => {
2743
+ if (!e.path) return false;
2744
+ return e.path.replace(/^\//, "") === normalized;
2745
+ }) ?? null;
2746
+ }
2747
+ getFieldErrors() {
2748
+ const result = {};
2749
+ for (const e of this.errors) {
2750
+ if (e.path) {
2751
+ const field = e.path.replace(/^\//, "");
2752
+ if (field) result[field] = e.message;
2753
+ }
2754
+ }
2755
+ return result;
2756
+ }
2757
+ hasFieldError(field) {
2758
+ return this.getFieldError(field) !== null;
2759
+ }
2760
+ getErrorCount() {
2761
+ return this.errors.length;
2762
+ }
2763
+ };
2764
+ }
2765
+ });
2766
+
2767
+ // src/core/Validator.ts
2768
+ var Validator_exports = {};
2769
+ __export(Validator_exports, {
2770
+ Validator: () => Validator
2771
+ });
2772
+ import { Ajv } from "ajv";
2773
+ import addFormats from "ajv-formats";
2774
+ var NON_AJV_KEYS, EMPTY_ERRORS2, Validator;
2775
+ var init_Validator = __esm({
2776
+ "src/core/Validator.ts"() {
2777
+ "use strict";
2778
+ init_CacheManager();
2779
+ init_ErrorFormatter();
2780
+ init_CustomKeywords();
2781
+ init_Locale();
2782
+ init_ConditionalValidator();
2783
+ NON_AJV_KEYS = /* @__PURE__ */ new Set([
2784
+ "cache",
2785
+ "smartCoerce",
2786
+ "locale",
2787
+ "messages",
2788
+ "format",
2789
+ "strict"
2790
+ // v2 redefines this as strictSchema; do not forward to AJV
2791
+ ]);
2792
+ EMPTY_ERRORS2 = [];
2793
+ Validator = class _Validator {
2794
+ _ajvOptions;
2795
+ _ajv;
2796
+ _cache;
2797
+ _errorFormatter;
2798
+ // WeakMap: schema object → unique cacheKey (avoids JSON.stringify)
2799
+ _schemaMap = /* @__PURE__ */ new WeakMap();
2800
+ _schemaKeyCounter = 0;
2801
+ // Performance: cache whether a schema has any conditional fields (avoids traversing properties on every validation)
2802
+ _conditionalFlagCache = /* @__PURE__ */ new WeakMap();
2803
+ _conditionalValidator = new ConditionalValidator({
2804
+ validateSchema: (schema, data, options) => this._validateInternal(schema, data, options),
2805
+ internalError: (error, data) => this._internalError(error, data)
2806
+ });
2807
+ // V-Y03 fix: cached removeAdditional Ajv instance (no longer new Validator each time)
2808
+ _removeAdditionalAjv = null;
2809
+ // V-Y07 fix: static singleton Ajv
2810
+ static _quickValidateAjv = null;
2811
+ constructor(options = {}) {
2812
+ const ajvOptions = {
2813
+ allErrors: options.allErrors !== false,
2814
+ useDefaults: options.useDefaults !== false,
2815
+ coerceTypes: options.coerceTypes ?? false,
2816
+ removeAdditional: options.removeAdditional ?? false,
2817
+ verbose: true
2818
+ // verbose mode: enables parentSchema access on error objects
2819
+ };
2820
+ for (const [k, v] of Object.entries(options)) {
2821
+ if (!NON_AJV_KEYS.has(k) && !(k in ajvOptions)) {
2822
+ ajvOptions[k] = v;
2823
+ }
2824
+ }
2825
+ this._ajvOptions = ajvOptions;
2826
+ this._ajv = new Ajv(ajvOptions);
2827
+ addFormats(this._ajv);
2828
+ CustomKeywords.registerAll(this._ajv);
2829
+ const cacheOpts = options.cache === false ? { enabled: false } : options.cache === true || options.cache == null ? {} : options.cache;
2830
+ this._cache = new CacheManager({
2831
+ ...cacheOpts.maxSize !== void 0 ? { maxSize: cacheOpts.maxSize } : {},
2832
+ ...cacheOpts.ttl !== void 0 ? { ttl: cacheOpts.ttl } : {},
2833
+ ...cacheOpts.enabled !== void 0 ? { enabled: cacheOpts.enabled } : {},
2834
+ ...cacheOpts.statsEnabled !== void 0 ? { statsEnabled: cacheOpts.statsEnabled } : {}
2835
+ });
2836
+ this._errorFormatter = new ErrorFormatter();
2837
+ }
2838
+ get ajvOptions() {
2839
+ return this._ajvOptions;
2840
+ }
2841
+ // ─── Public API ────────────────────────────────────────────────────────
2842
+ /**
2843
+ * Compile a schema → AJV validate function (with cache).
2844
+ */
2845
+ compile(schema, cacheKey) {
2846
+ const key = cacheKey ?? null;
2847
+ if (key) {
2848
+ const cached = this._cache.get(key);
2849
+ if (cached !== null) return cached;
2850
+ }
2851
+ try {
2852
+ const validate = this._ajv.compile(schema);
2853
+ if (key) this._cache.set(key, validate);
2854
+ return validate;
2855
+ } catch (error) {
2856
+ throw new Error(`Schema compilation failed: ${error instanceof Error ? error.message : String(error)}`);
2857
+ }
2858
+ }
2859
+ /**
2860
+ * Synchronous validation.
2861
+ */
2862
+ validate(schema, data, options = {}) {
2863
+ return this._validateInternal(schema, data, options);
2864
+ }
2865
+ /**
2866
+ * Async validation (throws ValidationError on failure).
2867
+ * V-Y02 fix: v1 validateAsync lacked smartCoerceTypes; v2 routes through _validateInternal uniformly.
2868
+ * BC-6 fix: validateAsync runs async custom validators (sync AJV pass skips async fn; this method runs the full set).
2869
+ */
2870
+ async validateAsync(schema, data, options = {}) {
2871
+ let resolvedSchema = schema;
2872
+ if (typeof schema["toSchema"] === "function") {
2873
+ const obj = schema;
2874
+ resolvedSchema = obj["toSchema"]();
2875
+ }
2876
+ const result = this._validateInternal(schema, data, options);
2877
+ if (!result.valid) {
2878
+ const { ValidationError: ValidationError2 } = await Promise.resolve().then(() => (init_ValidationError(), ValidationError_exports));
2879
+ throw new ValidationError2(result.errors ?? [], data);
2880
+ }
2881
+ const customErr = await this._runCustomValidators(resolvedSchema, data);
2882
+ if (customErr) {
2883
+ const { ValidationError: ValidationError2 } = await Promise.resolve().then(() => (init_ValidationError(), ValidationError_exports));
2884
+ throw new ValidationError2([customErr], data);
2885
+ }
2886
+ return result.data;
2887
+ }
2888
+ /**
2889
+ * BC-6: run all validators in schema._customValidators (including async).
2890
+ * AJV's sync keyword skips Promise-returning validators; this method runs the complete set in validateAsync.
2891
+ * Returns the first failing ValidationErrorItem, or null if all pass.
2892
+ */
2893
+ async _runCustomValidators(schema, data) {
2894
+ const validators = schema["_customValidators"];
2895
+ if (!validators?.length) return null;
2896
+ for (const fn of validators) {
2897
+ try {
2898
+ const result = await Promise.resolve(fn(data));
2899
+ if (result === false) {
2900
+ return { message: Locale.getMessageText("CUSTOM_VALIDATION_FAILED"), path: "", keyword: "_customValidators", params: {} };
2901
+ }
2902
+ if (typeof result === "string") {
2903
+ return { message: result, path: "", keyword: "_customValidators", params: {} };
2904
+ }
2905
+ if (result !== null && typeof result === "object" && result["error"]) {
2906
+ const r = result;
2907
+ return {
2908
+ message: r.message ?? Locale.getMessageText("CUSTOM_VALIDATION_FAILED"),
2909
+ path: "",
2910
+ keyword: "_customValidators",
2911
+ params: {}
2912
+ };
2913
+ }
2914
+ } catch (err) {
2915
+ return {
2916
+ message: err instanceof Error ? err.message : String(err),
2917
+ path: "",
2918
+ keyword: "_customValidators",
2919
+ params: {}
2920
+ };
2921
+ }
2922
+ }
2923
+ return null;
2924
+ }
2925
+ /**
2926
+ * Batch validation (compile once, reuse for each item).
2927
+ */
2928
+ validateBatch(schema, dataArray) {
2929
+ if (!Array.isArray(dataArray)) throw new Error("Data must be an array");
2930
+ const cacheKey = this._generateCacheKey(schema);
2931
+ const validate = this.compile(schema, cacheKey);
2932
+ return dataArray.map((data) => this.validate(validate, data));
2933
+ }
2934
+ /**
2935
+ * Add a custom keyword.
2936
+ */
2937
+ addKeyword(keyword, definition) {
2938
+ try {
2939
+ this._ajv.addKeyword({
2940
+ ...definition,
2941
+ keyword
2942
+ });
2943
+ return this;
2944
+ } catch (error) {
2945
+ throw new Error(`Failed to add keyword '${keyword}': ${error instanceof Error ? error.message : String(error)}`);
2946
+ }
2947
+ }
2948
+ /**
2949
+ * Add a custom format.
2950
+ */
2951
+ addFormat(name, validator) {
2952
+ this._ajv.addFormat(name, validator);
2953
+ return this;
2954
+ }
2955
+ /**
2956
+ * Add a schema reference.
2957
+ */
2958
+ addSchema(uri, schema) {
2959
+ this._ajv.addSchema(schema, uri);
2960
+ return this;
2961
+ }
2962
+ /**
2963
+ * Remove a schema reference.
2964
+ */
2965
+ removeSchema(uri) {
2966
+ this._ajv.removeSchema(uri);
2967
+ return this;
2968
+ }
2969
+ getAjv() {
2970
+ return this._ajv;
2971
+ }
2972
+ get cache() {
2973
+ return this._cache;
2974
+ }
2975
+ clearCache() {
2976
+ this._cache.clear();
2977
+ }
2978
+ getCacheStats() {
2979
+ return this._cache.getStats();
2980
+ }
2981
+ // ─── Static Factory ────────────────────────────────────────────────────
2982
+ static create(options) {
2983
+ return new _Validator(options);
2984
+ }
2985
+ /**
2986
+ * Quick validate (V-Y07 fix: reuses singleton Ajv instead of creating new Ajv each time).
2987
+ */
2988
+ static quickValidate(schema, data) {
2989
+ if (!_Validator._quickValidateAjv) {
2990
+ _Validator._quickValidateAjv = new Ajv();
2991
+ addFormats(_Validator._quickValidateAjv);
2992
+ CustomKeywords.registerAll(_Validator._quickValidateAjv);
2993
+ }
2994
+ try {
2995
+ return _Validator._quickValidateAjv.validate(schema, data);
2996
+ } catch {
2997
+ return false;
2998
+ }
2999
+ }
3000
+ // ─── Internal Implementation ───────────────────────────────────────────
3001
+ _validateInternal(schema, data, options = {}) {
3002
+ const shouldFormat = options.format !== false;
3003
+ const locale = options.locale ?? Locale.getLocale();
3004
+ const messages = options.messages ?? {};
3005
+ if (typeof schema["toSchema"] === "function") {
3006
+ const obj = schema;
3007
+ schema = obj["toSchema"]();
3008
+ }
3009
+ const internalSchema = schema;
3010
+ if (internalSchema._isConditional) {
3011
+ return this._conditionalValidator.validateConditional(internalSchema, data, null, data, options);
3012
+ }
3013
+ if (internalSchema.properties) {
3014
+ let hasConditionals = this._conditionalFlagCache.get(internalSchema);
3015
+ if (hasConditionals === void 0) {
3016
+ hasConditionals = this._conditionalValidator.hasAnyConditional(internalSchema);
3017
+ this._conditionalFlagCache.set(internalSchema, hasConditionals);
3018
+ }
3019
+ if (hasConditionals) {
3020
+ return this._conditionalValidator.validateWithConditionals(internalSchema, data, options);
3021
+ }
3022
+ }
3023
+ if (internalSchema._removeAdditional) {
3024
+ if (!this._removeAdditionalAjv) {
3025
+ this._removeAdditionalAjv = new Ajv({ ...this._ajvOptions, removeAdditional: true });
3026
+ addFormats(this._removeAdditionalAjv);
3027
+ CustomKeywords.registerAll(this._removeAdditionalAjv);
3028
+ }
3029
+ const cleanSchema = JSON.parse(JSON.stringify(schema));
3030
+ delete cleanSchema._removeAdditional;
3031
+ try {
3032
+ const validate = this._removeAdditionalAjv.compile(cleanSchema);
3033
+ const valid = validate(data);
3034
+ if (valid) return { valid: true, data, errors: EMPTY_ERRORS2 };
3035
+ const fmtErrors = this._formatErrors(validate.errors ?? [], messages, locale, shouldFormat);
3036
+ return { valid: false, data, errors: fmtErrors, errorMessage: fmtErrors[0]?.message };
3037
+ } catch (error) {
3038
+ return this._internalError(error, data);
3039
+ }
3040
+ }
3041
+ try {
3042
+ let validate;
3043
+ if (typeof schema === "function") {
3044
+ validate = schema;
3045
+ } else {
3046
+ const schemaObj = schema;
3047
+ let cacheKey = this._schemaMap.get(schemaObj);
3048
+ if (!cacheKey) {
3049
+ cacheKey = `s${++this._schemaKeyCounter}`;
3050
+ this._schemaMap.set(schemaObj, cacheKey);
3051
+ }
3052
+ const cached = this._cache.get(cacheKey);
3053
+ if (cached !== null) {
3054
+ validate = cached;
3055
+ } else {
3056
+ try {
3057
+ validate = this._ajv.compile(schema);
3058
+ this._cache.set(cacheKey, validate);
3059
+ } catch (error) {
3060
+ throw new Error(`Schema compilation failed: ${error instanceof Error ? error.message : String(error)}`);
3061
+ }
3062
+ }
3063
+ }
3064
+ const valid = validate(data);
3065
+ if (valid) return { valid: true, data, errors: EMPTY_ERRORS2 };
3066
+ const fmtErrors2 = this._formatErrors(validate.errors ?? [], messages, locale, shouldFormat);
3067
+ return { valid: false, data, errors: fmtErrors2, errorMessage: fmtErrors2[0]?.message };
3068
+ } catch (error) {
3069
+ return this._internalError(error, data);
3070
+ }
3071
+ }
3072
+ // ─── Helper methods ─────────────────────────────────────────────────────
3073
+ _generateCacheKey(schema) {
3074
+ if (!this._schemaMap.has(schema)) {
3075
+ this._schemaMap.set(schema, `schema_${++this._schemaKeyCounter}`);
3076
+ }
3077
+ return this._schemaMap.get(schema);
3078
+ }
3079
+ // Performance: cache flattened locale messages (key = locale, value = flat ErrorMessages)
3080
+ // to avoid re-running Locale.getMessages + Object.entries.map on every validation failure
3081
+ _flatLocaleCache = /* @__PURE__ */ new Map();
3082
+ _getFlatLocaleMessages(locale) {
3083
+ let flat = this._flatLocaleCache.get(locale);
3084
+ if (!flat) {
3085
+ const raw = Locale.getMessages(locale);
3086
+ flat = Object.fromEntries(
3087
+ Object.entries(raw).map(([k, v]) => [
3088
+ k,
3089
+ typeof v === "string" ? v : v.message
3090
+ ])
3091
+ );
3092
+ this._flatLocaleCache.set(locale, flat);
3093
+ }
3094
+ return flat;
3095
+ }
3096
+ _formatErrors(rawErrors, messages, locale, shouldFormat) {
3097
+ if (!shouldFormat) return rawErrors;
3098
+ const localeMessages = this._getFlatLocaleMessages(locale);
3099
+ const mergedMessages = Object.keys(messages).length === 0 ? localeMessages : { ...localeMessages, ...messages };
3100
+ return this._errorFormatter.formatDetailed(rawErrors, locale, mergedMessages, true);
3101
+ }
3102
+ _internalError(error, data) {
3103
+ const message = `Validation error: ${error instanceof Error ? error.message : String(error)}`;
3104
+ return {
3105
+ valid: false,
3106
+ data,
3107
+ errors: [{ message, path: "", keyword: "error", params: {} }],
3108
+ errorMessage: message
3109
+ };
3110
+ }
3111
+ };
3112
+ }
3113
+ });
3114
+
3115
+ // src/core/DslBuilder.ts
3116
+ init_DslParser();
3117
+ init_TypeRegistry();
3118
+ init_patterns();
3119
+ var PASSWORD_PATTERNS = {
3120
+ weak: /.{6,}/,
3121
+ medium: /^(?=.*[a-zA-Z])(?=.*\d).{8,}$/,
3122
+ strong: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/,
3123
+ veryStrong: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&]).{10,}$/
3124
+ };
3125
+ var PASSWORD_MIN_LENGTHS = {
3126
+ weak: 6,
3127
+ medium: 8,
3128
+ strong: 8,
3129
+ veryStrong: 10
3130
+ };
3131
+ var DslBuilder = class _DslBuilder {
3132
+ // Required IDslBuilder field
3133
+ _isDslBuilder = true;
3134
+ /** schema-dsl custom validation keyword set (stripped during toJsonSchema). */
3135
+ static _internalKeys = TypeRegistry.getInternalKeys();
3136
+ /** Custom type cache (BC with v1 DslBuilder._customTypes). */
3137
+ static _customTypes = /* @__PURE__ */ new Map();
3138
+ _baseSchema;
3139
+ _required;
3140
+ _optional;
3141
+ _customMessages;
3142
+ _label;
3143
+ _description;
3144
+ _customValidators;
3145
+ _whenConditions;
3146
+ // ==================== Constructor ====================
3147
+ constructor(dslString) {
3148
+ if (!dslString || typeof dslString !== "string") {
3149
+ throw new Error("[schema-dsl] DSL string is required");
3150
+ }
3151
+ let s = dslString.trim();
3152
+ const arrayBangMatch = /^array!([\d-]+)$/.exec(s);
3153
+ if (arrayBangMatch) {
3154
+ s = `array:${arrayBangMatch[1]}`;
3155
+ this._required = true;
3156
+ this._optional = false;
3157
+ } else {
3158
+ this._required = s.endsWith("!");
3159
+ this._optional = s.endsWith("?") && !this._required;
3160
+ if (this._required || this._optional) s = s.slice(0, -1);
3161
+ }
3162
+ this._customMessages = {};
3163
+ this._label = null;
3164
+ this._description = null;
3165
+ this._customValidators = [];
3166
+ this._whenConditions = [];
3167
+ this._baseSchema = _DslBuilder._parseBody(s);
3168
+ }
3169
+ // ==================== Internal Parsing ====================
3170
+ /**
3171
+ * Parse DSL body (without ! or ?).
3172
+ * Delegates to the unified parser so string and builder DSL parsing stay in lockstep.
3173
+ */
3174
+ static _parseBody(dsl) {
3175
+ return DslParser.parseString(dsl);
3176
+ }
3177
+ // ==================== Static Methods (BC with v1) ====================
3178
+ /**
3179
+ * Register a custom type (delegates to TypeRegistry).
3180
+ */
3181
+ static registerType(name, schema) {
3182
+ if (!name || typeof name !== "string") {
3183
+ throw new Error("[schema-dsl] Type name must be a non-empty string");
3184
+ }
3185
+ if (!schema || typeof schema !== "object" && typeof schema !== "function") {
3186
+ throw new Error("[schema-dsl] Schema must be an object or function");
3187
+ }
3188
+ _DslBuilder._customTypes.set(name, schema);
3189
+ if (typeof schema === "function") {
3190
+ TypeRegistry.registerDynamic(name, schema);
3191
+ } else {
3192
+ TypeRegistry.register(name, schema);
3193
+ }
3194
+ }
3195
+ /** Check whether a type is registered (built-in or custom). */
3196
+ static hasType(type) {
3197
+ return TypeRegistry.has(type);
3198
+ }
3199
+ /** Get all registered custom type names. */
3200
+ static getCustomTypes() {
3201
+ return Array.from(_DslBuilder._customTypes.keys());
3202
+ }
3203
+ /** Clear all custom types (primarily for testing). */
3204
+ static clearCustomTypes() {
3205
+ TypeRegistry.clearCustomTypes();
3206
+ _DslBuilder._customTypes.clear();
3207
+ }
3208
+ /**
3209
+ * Validate schema nesting depth.
3210
+ * @param schema - JSON Schema to validate
3211
+ * @param maxDepth - maximum allowed depth (default 3)
3212
+ */
3213
+ static validateNestingDepth(schema, maxDepth = 3) {
3214
+ let maxFound = 0;
3215
+ let deepestPath = "";
3216
+ function traverse(obj, depth, path, isRoot) {
3217
+ if (!isRoot && (obj.properties || obj.items)) {
3218
+ if (depth > maxFound) {
3219
+ maxFound = depth;
3220
+ deepestPath = path;
3221
+ }
3222
+ }
3223
+ if (obj.properties) {
3224
+ const nextDepth = depth + 1;
3225
+ for (const key of Object.keys(obj.properties)) {
3226
+ traverse(
3227
+ obj.properties[key],
3228
+ nextDepth,
3229
+ `${path}.${key}`.replace(/^\./, ""),
3230
+ false
3231
+ );
3232
+ }
3233
+ }
3234
+ if (obj.items && !Array.isArray(obj.items)) {
3235
+ traverse(obj.items, depth, `${path}[]`, false);
3236
+ }
3237
+ }
3238
+ traverse(schema, 0, "", true);
3239
+ return {
3240
+ valid: maxFound <= maxDepth,
3241
+ depth: maxFound,
3242
+ path: deepestPath,
3243
+ message: maxFound > maxDepth ? `Nesting depth ${maxFound} exceeds limit ${maxDepth}, path: ${deepestPath}` : `Nesting depth ${maxFound} is within the limit`
3244
+ };
3245
+ }
3246
+ // ==================== Private Utilities ====================
3247
+ _assertType(method, ...types) {
3248
+ const t = this._baseSchema.type;
3249
+ if (!types.includes(t)) {
3250
+ throw new Error(`[schema-dsl] ${method}() only applies to ${types.join("/")} type`);
3251
+ }
3252
+ }
3253
+ _assertStringType(method) {
3254
+ this._assertType(method, "string");
3255
+ }
3256
+ _assertNumberType(method) {
3257
+ this._assertType(method, "number", "integer");
3258
+ }
3259
+ _assertObjectType(method) {
3260
+ this._assertType(method, "object");
3261
+ }
3262
+ _assertArrayType(method) {
3263
+ this._assertType(method, "array");
3264
+ }
3265
+ // ==================== Common Chain Methods ====================
3266
+ /**
3267
+ * Set format.
3268
+ */
3269
+ format(fmt) {
3270
+ this._baseSchema.format = fmt;
3271
+ return this;
3272
+ }
3273
+ /**
3274
+ * Add regex validation.
3275
+ */
3276
+ pattern(regex, message) {
3277
+ this._baseSchema.pattern = regex instanceof RegExp ? regex.source : regex;
3278
+ if (message) {
3279
+ this._customMessages["string.pattern"] = message;
3280
+ }
3281
+ return this;
3282
+ }
3283
+ /**
3284
+ * Custom error messages (IDslBuilder: error; BC alias: messages).
3285
+ */
3286
+ messages(msgs) {
3287
+ Object.assign(this._customMessages, msgs);
3288
+ return this;
3289
+ }
3290
+ /** IDslBuilder.error — alias for messages() */
3291
+ error(msgs) {
3292
+ return this.messages(msgs);
3293
+ }
3294
+ /**
3295
+ * Set field label (used in error messages).
3296
+ */
3297
+ label(text) {
3298
+ this._label = text;
3299
+ return this;
3300
+ }
3301
+ /**
3302
+ * Set description.
3303
+ */
3304
+ description(text) {
3305
+ this._description = text;
3306
+ return this;
3307
+ }
3308
+ /**
3309
+ * Set default value.
3310
+ */
3311
+ default(value) {
3312
+ this._baseSchema.default = value;
3313
+ return this;
3314
+ }
3315
+ /**
3316
+ * Set allowed enum values (IDslBuilder).
3317
+ */
3318
+ enum(...values) {
3319
+ this._baseSchema.enum = values;
3320
+ return this;
3321
+ }
3322
+ /**
3323
+ * Mark field as optional.
3324
+ */
3325
+ optional() {
3326
+ this._required = false;
3327
+ this._optional = true;
3328
+ return this;
3329
+ }
3330
+ /**
3331
+ * Mark field as required.
3332
+ */
3333
+ required() {
3334
+ this._required = true;
3335
+ this._optional = false;
3336
+ return this;
3337
+ }
3338
+ /**
3339
+ * Add a custom validator function.
3340
+ */
3341
+ custom(validatorFn) {
3342
+ if (typeof validatorFn !== "function") {
3343
+ throw new Error("[schema-dsl] Custom validator must be a function");
3344
+ }
3345
+ this._customValidators.push(validatorFn);
3346
+ return this;
3347
+ }
3348
+ // ==================== String Chain Methods ====================
3349
+ /** String minimum length. */
3350
+ min(n) {
3351
+ this._assertStringType("min");
3352
+ this._baseSchema.minLength = n;
3353
+ return this;
3354
+ }
3355
+ /** String maximum length. */
3356
+ max(n) {
3357
+ this._assertStringType("max");
3358
+ this._baseSchema.maxLength = n;
3359
+ return this;
3360
+ }
3361
+ /** String exact length (→ exactLength custom keyword). */
3362
+ length(n) {
3363
+ this._assertStringType("length");
3364
+ this._baseSchema.exactLength = n;
3365
+ return this;
3366
+ }
3367
+ /** String: only alphanumeric characters allowed. */
3368
+ alphanum() {
3369
+ this._assertStringType("alphanum");
3370
+ this._baseSchema.alphanum = true;
3371
+ return this;
3372
+ }
3373
+ /** String: no leading/trailing whitespace. */
3374
+ trim() {
3375
+ this._assertStringType("trim");
3376
+ this._baseSchema.trim = true;
3377
+ return this;
3378
+ }
3379
+ /** String: must be lowercase. */
3380
+ lowercase() {
3381
+ this._assertStringType("lowercase");
3382
+ this._baseSchema.lowercase = true;
3383
+ return this;
3384
+ }
3385
+ /** String: must be uppercase. */
3386
+ uppercase() {
3387
+ this._assertStringType("uppercase");
3388
+ this._baseSchema.uppercase = true;
3389
+ return this;
3390
+ }
3391
+ /** String: must be a valid JSON string. */
3392
+ json() {
3393
+ this._assertStringType("json");
3394
+ this._baseSchema.jsonString = true;
3395
+ return this;
3396
+ }
3397
+ /** String date format validation. */
3398
+ dateFormat(fmt) {
3399
+ this._assertStringType("dateFormat");
3400
+ this._baseSchema.dateFormat = fmt;
3401
+ return this;
3402
+ }
3403
+ /** String: must be after the given date. */
3404
+ after(date) {
3405
+ this._assertStringType("after");
3406
+ this._baseSchema.dateGreater = date;
3407
+ return this;
3408
+ }
3409
+ /** String: must be before the given date. */
3410
+ before(date) {
3411
+ this._assertStringType("before");
3412
+ this._baseSchema.dateLess = date;
3413
+ return this;
3414
+ }
3415
+ /** v1.0.2 alias: dateGreater. */
3416
+ dateGreater(date) {
3417
+ this._assertStringType("dateGreater");
3418
+ this._baseSchema.dateGreater = date;
3419
+ return this;
3420
+ }
3421
+ /** v1.0.2 alias: dateLess. */
3422
+ dateLess(date) {
3423
+ this._assertStringType("dateLess");
3424
+ this._baseSchema.dateLess = date;
3425
+ return this;
3426
+ }
3427
+ /** String slug format validation. */
3428
+ slug() {
3429
+ this._assertStringType("slug");
3430
+ this._baseSchema.pattern = "^[a-z0-9]+(?:-[a-z0-9]+)*$";
3431
+ const existing = this._baseSchema._customMessages || {};
3432
+ this._baseSchema._customMessages = { ...existing, pattern: "pattern.slug" };
3433
+ return this;
3434
+ }
3435
+ /** String domain validation. */
3436
+ domain() {
3437
+ this._assertStringType("domain");
3438
+ const cfg = PATTERNS.common.domain;
3439
+ return this.pattern(cfg.pattern).messages({ pattern: cfg.key });
3440
+ }
3441
+ /** String IP address validation (IPv4 or IPv6). */
3442
+ ip() {
3443
+ this._assertStringType("ip");
3444
+ const cfg = PATTERNS.common.ip;
3445
+ return this.pattern(cfg.pattern).messages({ pattern: cfg.key });
3446
+ }
3447
+ /** String Base64 encoding validation. */
3448
+ base64() {
3449
+ this._assertStringType("base64");
3450
+ const cfg = PATTERNS.common.base64;
3451
+ return this.pattern(cfg.pattern).messages({ pattern: cfg.key });
3452
+ }
3453
+ /** String JWT token validation. */
3454
+ jwt() {
3455
+ this._assertStringType("jwt");
3456
+ const cfg = PATTERNS.common.jwt;
3457
+ return this.pattern(cfg.pattern).messages({ pattern: cfg.key });
3458
+ }
3459
+ // ==================== Identity / Pattern Chain Methods ====================
3460
+ /** Phone number validation (auto-corrects number → string). */
3461
+ phone(country = "cn") {
3462
+ if (this._baseSchema.type === "number" || this._baseSchema.type === "integer") {
3463
+ this._baseSchema.type = "string";
3464
+ delete this._baseSchema["minimum"];
3465
+ delete this._baseSchema["maximum"];
3466
+ }
3467
+ const cfg = PATTERNS.phone[country];
3468
+ if (!cfg) throw new Error(`[schema-dsl] Unsupported country: ${country}`);
3469
+ if (cfg.min !== void 0 && !this._baseSchema.minLength) this._baseSchema.minLength = cfg.min;
3470
+ if (cfg.max !== void 0 && !this._baseSchema.maxLength) this._baseSchema.maxLength = cfg.max;
3471
+ return this.pattern(cfg.pattern).messages({ pattern: cfg.key });
3472
+ }
3473
+ /** phone() alias (BC). */
3474
+ phoneNumber(country = "cn") {
3475
+ return this.phone(country);
3476
+ }
3477
+ /** National ID (idCard) validation. */
3478
+ idCard(country = "cn") {
3479
+ const lower = country.toLowerCase();
3480
+ const cfg = PATTERNS.idCard[lower];
3481
+ if (!cfg) throw new Error(`[schema-dsl] Unsupported country for idCard: ${country}`);
3482
+ if (cfg.min !== void 0 && !this._baseSchema.minLength) this._baseSchema.minLength = cfg.min;
3483
+ if (cfg.max !== void 0 && !this._baseSchema.maxLength) this._baseSchema.maxLength = cfg.max;
3484
+ return this.pattern(cfg.pattern).messages({ pattern: cfg.key });
3485
+ }
3486
+ /** URL slug validation. */
3487
+ slugChain() {
3488
+ return this.pattern(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).messages({ pattern: "pattern.slug" });
3489
+ }
3490
+ /** Credit card number validation. */
3491
+ creditCard(type = "visa") {
3492
+ const cfg = PATTERNS.creditCard[type.toLowerCase()];
3493
+ if (!cfg) throw new Error(`[schema-dsl] Unsupported credit card type: ${type}`);
3494
+ return this.pattern(cfg.pattern).messages({ pattern: cfg.key });
3495
+ }
3496
+ /** Vehicle license plate validation. */
3497
+ licensePlate(country = "cn") {
3498
+ const cfg = PATTERNS.licensePlate[country.toLowerCase()];
3499
+ if (!cfg) throw new Error(`[schema-dsl] Unsupported country for licensePlate: ${country}`);
3500
+ return this.pattern(cfg.pattern).messages({ pattern: cfg.key });
3501
+ }
3502
+ /** Postal code validation. */
3503
+ postalCode(country = "cn") {
3504
+ const cfg = PATTERNS.postalCode[country.toLowerCase()];
3505
+ if (!cfg) throw new Error(`[schema-dsl] Unsupported country for postalCode: ${country}`);
3506
+ return this.pattern(cfg.pattern).messages({ pattern: cfg.key });
3507
+ }
3508
+ /** Passport number validation. */
3509
+ passport(country = "cn") {
3510
+ const cfg = PATTERNS.passport[country.toLowerCase()];
3511
+ if (!cfg) throw new Error(`[schema-dsl] Unsupported country for passport: ${country}`);
3512
+ return this.pattern(cfg.pattern).messages({ pattern: cfg.key });
3513
+ }
3514
+ /**
3515
+ * Username validation.
3516
+ * @param preset - 'short'(3-16) | 'medium'(3-32) | 'long'(3-64) | 'N-M' | object
3517
+ */
3518
+ username(preset = "medium") {
3519
+ let minLength;
3520
+ let maxLength;
3521
+ let allowUnderscore = true;
3522
+ let allowNumber = true;
3523
+ if (typeof preset === "string") {
3524
+ const rangeMatch = /^(\d+)-(\d+)$/.exec(preset);
3525
+ if (rangeMatch) {
3526
+ minLength = parseInt(rangeMatch[1], 10);
3527
+ maxLength = parseInt(rangeMatch[2], 10);
3528
+ } else {
3529
+ const presets = {
3530
+ short: { min: 3, max: 16 },
3531
+ medium: { min: 3, max: 32 },
3532
+ long: { min: 3, max: 64 }
3533
+ };
3534
+ const p = presets[preset] ?? presets["medium"];
3535
+ minLength = p.min;
3536
+ maxLength = p.max;
3537
+ }
3538
+ } else {
3539
+ minLength = preset.minLength ?? 3;
3540
+ maxLength = preset.maxLength ?? 32;
3541
+ allowUnderscore = preset.allowUnderscore !== false;
3542
+ allowNumber = preset.allowNumber !== false;
3543
+ }
3544
+ if (!this._baseSchema.minLength) this._baseSchema.minLength = minLength;
3545
+ if (!this._baseSchema.maxLength) this._baseSchema.maxLength = maxLength;
3546
+ let pat = "^[a-zA-Z]";
3547
+ if (allowUnderscore && allowNumber) {
3548
+ pat += "[a-zA-Z0-9_]*$";
3549
+ } else if (allowNumber) {
3550
+ pat += "[a-zA-Z0-9]*$";
3551
+ } else {
3552
+ pat += "[a-zA-Z]*$";
3553
+ }
3554
+ return this.pattern(new RegExp(pat)).messages({ pattern: "pattern.username" });
3555
+ }
3556
+ /**
3557
+ * Password strength validation.
3558
+ * @param strength - 'weak' | 'medium' | 'strong' | 'veryStrong'
3559
+ */
3560
+ password(strength = "medium") {
3561
+ const pat = PASSWORD_PATTERNS[strength];
3562
+ if (!pat) throw new Error(`[schema-dsl] Invalid password strength: ${strength}`);
3563
+ if (!this._baseSchema.minLength) this._baseSchema.minLength = PASSWORD_MIN_LENGTHS[strength];
3564
+ if (!this._baseSchema.maxLength) this._baseSchema.maxLength = 64;
3565
+ return this.pattern(pat).messages({ pattern: `pattern.password.${strength}` });
3566
+ }
3567
+ // ==================== Number Chain Methods ====================
3568
+ /** Number decimal places limit. */
3569
+ precision(n) {
3570
+ this._assertNumberType("precision");
3571
+ this._baseSchema.precision = n;
3572
+ return this;
3573
+ }
3574
+ /** Number multiple-of validation (standard JSON Schema multipleOf). */
3575
+ multiple(n) {
3576
+ this._assertNumberType("multiple");
3577
+ this._baseSchema.multipleOf = n;
3578
+ return this;
3579
+ }
3580
+ /** Number port validation (1–65535). */
3581
+ port() {
3582
+ this._assertNumberType("port");
3583
+ this._baseSchema.port = true;
3584
+ return this;
3585
+ }
3586
+ // ==================== Object Chain Methods ====================
3587
+ /** Object: all defined properties are required. */
3588
+ requireAll() {
3589
+ this._assertObjectType("requireAll");
3590
+ this._baseSchema.requiredAll = true;
3591
+ return this;
3592
+ }
3593
+ /** Object strict mode: no additional properties allowed. */
3594
+ strict() {
3595
+ this._assertObjectType("strict");
3596
+ this._baseSchema.strictSchema = true;
3597
+ return this;
3598
+ }
3599
+ // ==================== Array Chain Methods ====================
3600
+ /** Array: sparse arrays are not allowed. */
3601
+ noSparse() {
3602
+ this._assertArrayType("noSparse");
3603
+ this._baseSchema.noSparse = true;
3604
+ return this;
3605
+ }
3606
+ /** Array: must contain the specified element. */
3607
+ includesRequired(items) {
3608
+ this._assertArrayType("includesRequired");
3609
+ if (!Array.isArray(items)) {
3610
+ throw new Error("[schema-dsl] includesRequired() requires an array parameter");
3611
+ }
3612
+ this._baseSchema.includesRequired = items;
3613
+ return this;
3614
+ }
3615
+ // ==================== Output Methods ====================
3616
+ /**
3617
+ * Convert to a schema with schema-dsl internal fields (for use by Validator).
3618
+ */
3619
+ toSchema() {
3620
+ const schema = { ...this._baseSchema };
3621
+ if (this._description) {
3622
+ schema.description = this._description;
3623
+ }
3624
+ const baseCustomMsgs = schema._customMessages || {};
3625
+ const mergedMsgs = { ...baseCustomMsgs, ...this._customMessages };
3626
+ if (Object.keys(mergedMsgs).length > 0) {
3627
+ schema._customMessages = mergedMsgs;
3628
+ } else {
3629
+ delete schema["_customMessages"];
3630
+ }
3631
+ if (this._label) {
3632
+ schema._label = this._label;
3633
+ }
3634
+ if (this._customValidators.length > 0) {
3635
+ schema._customValidators = this._customValidators;
3636
+ }
3637
+ if (this._whenConditions.length > 0) {
3638
+ schema._whenConditions = this._whenConditions;
3639
+ }
3640
+ schema._required = this._required;
3641
+ return schema;
3642
+ }
3643
+ /**
3644
+ * Output a clean JSON Schema (strips all schema-dsl internal fields and custom keywords).
3645
+ * Can be embedded directly in OpenAPI / standard JSON Schema documents.
3646
+ */
3647
+ toJsonSchema() {
3648
+ return TypeRegistry.toJsonSchema(this.toSchema());
3649
+ }
3650
+ toString() {
3651
+ return JSON.stringify(this.toJsonSchema());
3652
+ }
3653
+ /**
3654
+ * Validate data (BC with v1).
3655
+ * @param data - data to validate
3656
+ */
3657
+ _validator = null;
3658
+ async validate(data) {
3659
+ if (!this._validator) {
3660
+ const { Validator: Validator2 } = await Promise.resolve().then(() => (init_Validator(), Validator_exports));
3661
+ this._validator = new Validator2();
3662
+ }
3663
+ const schema = this.toSchema();
3664
+ return this._validator.validate(schema, data);
3665
+ }
3666
+ };
3667
+
3668
+ // src/plugins/custom-format.ts
3669
+ var FORMATS = {
3670
+ "phone-cn": {
3671
+ pattern: /^1[3-9]\d{9}$/,
3672
+ schema: { type: "string", pattern: /^1[3-9]\d{9}$/.source, minLength: 11, maxLength: 11 }
3673
+ },
3674
+ "postal-code-cn": {
3675
+ pattern: /^\d{6}$/,
3676
+ schema: { type: "string", pattern: /^\d{6}$/.source, minLength: 6, maxLength: 6 }
3677
+ },
3678
+ "ipv4-custom": {
3679
+ pattern: /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
3680
+ schema: { type: "string", format: "ipv4" }
3681
+ },
3682
+ "wechat": {
3683
+ pattern: /^[a-zA-Z][-_a-zA-Z0-9]{5,19}$/,
3684
+ schema: { type: "string", pattern: /^[a-zA-Z][-_a-zA-Z0-9]{5,19}$/.source, minLength: 6, maxLength: 20 }
3685
+ },
3686
+ "qq": {
3687
+ pattern: /^[1-9][0-9]{4,10}$/,
3688
+ schema: { type: "string", pattern: /^[1-9][0-9]{4,10}$/.source, minLength: 5, maxLength: 11 }
3689
+ },
3690
+ "bank-card": {
3691
+ validate: (value) => {
3692
+ if (!/^\d{16,19}$/.test(value)) return false;
3693
+ let sum = 0;
3694
+ let shouldDouble = false;
3695
+ for (let i = value.length - 1; i >= 0; i -= 1) {
3696
+ let digit = Number.parseInt(value[i], 10);
3697
+ if (shouldDouble) {
3698
+ digit *= 2;
3699
+ if (digit > 9) digit -= 9;
3700
+ }
3701
+ sum += digit;
3702
+ shouldDouble = !shouldDouble;
3703
+ }
3704
+ return sum % 10 === 0;
3705
+ },
3706
+ schema: { type: "string", minLength: 16, maxLength: 19, pattern: /^\d{16,19}$/.source }
3707
+ },
3708
+ "license-plate": {
3709
+ pattern: /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳]$/,
3710
+ schema: {
3711
+ type: "string",
3712
+ pattern: /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4,5}[A-HJ-NP-Z0-9挂学警港澳]$/.source
3713
+ }
3714
+ },
3715
+ "credit-code": {
3716
+ pattern: /^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/,
3717
+ schema: {
3718
+ type: "string",
3719
+ pattern: /^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$/.source,
3720
+ minLength: 18,
3721
+ maxLength: 18
3722
+ }
3723
+ },
3724
+ "passport-cn": {
3725
+ pattern: /^[EG]\d{8}$/,
3726
+ schema: { type: "string", pattern: /^[EG]\d{8}$/.source, minLength: 9, maxLength: 9 }
3727
+ },
3728
+ "hk-macao-pass": {
3729
+ pattern: /^[HM]\d{8,10}$/,
3730
+ schema: { type: "string", pattern: /^[HM]\d{8,10}$/.source, minLength: 9, maxLength: 11 }
3731
+ }
3732
+ };
3733
+ function getAjvLike(core) {
3734
+ const coreRecord = core;
3735
+ const validator = coreRecord.getDefaultValidator?.();
3736
+ if (!validator) {
3737
+ throw new Error("getDefaultValidator() is not available. Please provide schema-dsl core object.");
3738
+ }
3739
+ return validator.getAjv();
3740
+ }
3741
+ function getDslBuilderLike(core) {
3742
+ const coreRecord = core;
3743
+ return coreRecord.DslBuilder ?? DslBuilder;
3744
+ }
3745
+ var customFormatPlugin = {
3746
+ name: "custom-format",
3747
+ version: "2.0.0",
3748
+ description: "Custom format validation plugin (with DSL type registration)",
3749
+ install(core, _options = {}, _context) {
3750
+ const ajv = getAjvLike(core);
3751
+ const dslBuilder = getDslBuilderLike(core);
3752
+ this.addCustomFormats(ajv, dslBuilder);
3753
+ console.log("[Plugin] custom-format v2.0.0 installed (with DSL type registration)");
3754
+ },
3755
+ uninstall() {
3756
+ console.log("[Plugin] custom-format uninstalled");
3757
+ },
3758
+ addCustomFormats(ajv, dslBuilder) {
3759
+ for (const [name, config] of Object.entries(FORMATS)) {
3760
+ ajv.addFormat(name, {
3761
+ validate: config.validate ?? config.pattern
3762
+ });
3763
+ dslBuilder.registerType(name, config.schema);
3764
+ }
3765
+ }
3766
+ };
3767
+ var custom_format_default = customFormatPlugin;
3768
+ export {
3769
+ customFormatPlugin,
3770
+ custom_format_default as default
3771
+ };
3772
+ //# sourceMappingURL=custom-format.js.map