schema-dsl 1.2.5 → 2.0.1

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