schema-dsl 1.2.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/CHANGELOG.md +87 -210
  2. package/README.md +391 -2249
  3. package/dist/DslBuilder-DQDN0ZxZ.d.cts +341 -0
  4. package/dist/DslBuilder-DkLaOo9Q.d.ts +341 -0
  5. package/dist/Validator-C7GsVQOH.d.cts +192 -0
  6. package/dist/Validator-hFWKGxir.d.ts +192 -0
  7. package/dist/index.cjs +6594 -0
  8. package/dist/index.d.cts +1145 -0
  9. package/dist/index.d.ts +1145 -0
  10. package/dist/index.js +6528 -0
  11. package/dist/plugin-CIKtTMtS.d.cts +246 -0
  12. package/dist/plugin-CIKtTMtS.d.ts +246 -0
  13. package/dist/plugins/custom-format.cjs +3802 -0
  14. package/dist/plugins/custom-format.d.cts +12 -0
  15. package/dist/plugins/custom-format.d.ts +12 -0
  16. package/dist/plugins/custom-format.js +3772 -0
  17. package/dist/plugins/custom-type-example.cjs +3795 -0
  18. package/dist/plugins/custom-type-example.d.cts +8 -0
  19. package/dist/plugins/custom-type-example.d.ts +8 -0
  20. package/dist/plugins/custom-type-example.js +3765 -0
  21. package/dist/plugins/custom-validator.cjs +146 -0
  22. package/dist/plugins/custom-validator.d.cts +10 -0
  23. package/dist/plugins/custom-validator.d.ts +10 -0
  24. package/dist/plugins/custom-validator.js +121 -0
  25. package/docs/FEATURE-INDEX.md +102 -68
  26. package/docs/add-custom-locale.md +48 -35
  27. package/docs/add-keyword.md +24 -0
  28. package/docs/api-reference.md +396 -154
  29. package/docs/api.md +13 -0
  30. package/docs/best-practices-project-structure.md +19 -10
  31. package/docs/best-practices.md +93 -53
  32. package/docs/cache-manager.md +23 -15
  33. package/docs/compile.md +45 -0
  34. package/docs/conditional-api.md +40 -11
  35. package/docs/custom-extensions-guide.md +80 -152
  36. package/docs/design-philosophy.md +76 -71
  37. package/docs/doc-index.md +324 -0
  38. package/docs/dsl-syntax.md +69 -19
  39. package/docs/dynamic-locale.md +24 -14
  40. package/docs/enum.md +12 -5
  41. package/docs/error-handling.md +53 -44
  42. package/docs/export-guide.md +47 -8
  43. package/docs/export-limitations.md +27 -11
  44. package/docs/faq.md +86 -67
  45. package/docs/frontend-i18n-guide.md +26 -12
  46. package/docs/i18n-user-guide.md +60 -47
  47. package/docs/i18n.md +51 -32
  48. package/docs/index.md +48 -0
  49. package/docs/json-schema-basics.md +40 -0
  50. package/docs/label-vs-description.md +12 -3
  51. package/docs/markdown-exporter.md +15 -6
  52. package/docs/mongodb-exporter.md +11 -4
  53. package/docs/multi-language.md +26 -0
  54. package/docs/multi-type-support.md +26 -33
  55. package/docs/mysql-exporter.md +9 -2
  56. package/docs/number-operators.md +12 -5
  57. package/docs/optional-marker-guide.md +28 -23
  58. package/docs/performance-guide.md +49 -0
  59. package/docs/plugin-system.md +205 -366
  60. package/docs/plugin-type-registration.md +34 -0
  61. package/docs/postgresql-exporter.md +9 -2
  62. package/docs/public/favicon.svg +5 -0
  63. package/docs/quick-start.md +37 -363
  64. package/docs/runtime-locale-support.md +20 -9
  65. package/docs/schema-helper.md +10 -5
  66. package/docs/schema-utils-advanced-issues.md +23 -0
  67. package/docs/schema-utils-best-practices.md +20 -0
  68. package/docs/schema-utils-chaining.md +7 -0
  69. package/docs/schema-utils.md +76 -42
  70. package/docs/security-checklist.md +20 -0
  71. package/docs/string-extensions.md +17 -9
  72. package/docs/troubleshooting.md +36 -21
  73. package/docs/type-converter.md +41 -50
  74. package/docs/type-reference.md +38 -15
  75. package/docs/typescript-guide.md +53 -42
  76. package/docs/union-type-guide.md +11 -1
  77. package/docs/union-types.md +10 -3
  78. package/docs/validate-async.md +36 -25
  79. package/docs/validate-batch.md +49 -0
  80. package/docs/validate-dsl-object-support.md +33 -28
  81. package/docs/validate.md +36 -16
  82. package/docs/validation-guide.md +25 -7
  83. package/docs/validator.md +39 -0
  84. package/package.json +85 -27
  85. package/plugins/custom-format.cjs +8 -0
  86. package/plugins/custom-type-example.cjs +8 -0
  87. package/plugins/custom-validator.cjs +8 -0
  88. package/src/adapters/DslAdapter.ts +111 -0
  89. package/src/adapters/index.ts +1 -0
  90. package/src/config/constants.ts +83 -0
  91. package/src/config/index.ts +2 -0
  92. package/src/config/patterns.ts +77 -0
  93. package/src/core/CacheManager.ts +159 -0
  94. package/src/core/ConditionalBuilder.ts +382 -0
  95. package/src/core/ConditionalRuntime.ts +28 -0
  96. package/src/core/ConditionalValidator.ts +255 -0
  97. package/src/core/DslBuilder.ts +677 -0
  98. package/src/core/ErrorCodes.ts +38 -0
  99. package/src/core/ErrorFormatter.ts +271 -0
  100. package/src/core/JSONSchemaCore.ts +65 -0
  101. package/src/core/Locale.ts +187 -0
  102. package/src/core/MessageTemplate.ts +42 -0
  103. package/src/core/ObjectDslBuilder.ts +64 -0
  104. package/src/core/PluginManager.ts +326 -0
  105. package/src/core/StringExtensions.ts +140 -0
  106. package/src/core/TemplateEngine.ts +44 -0
  107. package/src/core/Validator.ts +448 -0
  108. package/src/errors/I18nError.ts +159 -0
  109. package/src/errors/ValidationError.ts +105 -0
  110. package/src/exporters/BaseExporter.ts +60 -0
  111. package/src/exporters/MarkdownExporter.ts +305 -0
  112. package/src/exporters/MongoDBExporter.ts +126 -0
  113. package/src/exporters/MySQLExporter.ts +155 -0
  114. package/src/exporters/PostgreSQLExporter.ts +222 -0
  115. package/src/exporters/index.ts +18 -0
  116. package/src/index.ts +633 -0
  117. package/{lib/locales/en-US.js → src/locales/en-US.ts} +21 -37
  118. package/{lib/locales/es-ES.js → src/locales/es-ES.ts} +63 -16
  119. package/{lib/locales/fr-FR.js → src/locales/fr-FR.ts} +74 -27
  120. package/src/locales/index.ts +103 -0
  121. package/{lib/locales/ja-JP.js → src/locales/ja-JP.ts} +59 -17
  122. package/src/locales/types.ts +156 -0
  123. package/{lib/locales/zh-CN.js → src/locales/zh-CN.ts} +21 -38
  124. package/src/parser/ConstraintParser.ts +101 -0
  125. package/src/parser/DslParser.ts +470 -0
  126. package/src/parser/SchemaCompiler.ts +66 -0
  127. package/src/parser/TypeRegistry.ts +250 -0
  128. package/src/parser/index.ts +6 -0
  129. package/src/plugins/custom-format.ts +126 -0
  130. package/src/plugins/custom-type-example.ts +108 -0
  131. package/src/plugins/custom-validator.ts +140 -0
  132. package/src/types/conditional.ts +28 -0
  133. package/src/types/config.ts +59 -0
  134. package/src/types/dsl.ts +131 -0
  135. package/src/types/error.ts +60 -0
  136. package/src/types/index.ts +17 -0
  137. package/src/types/infer.ts +128 -0
  138. package/src/types/plugin.ts +58 -0
  139. package/src/types/safe-regex.d.ts +9 -0
  140. package/src/types/schema.ts +66 -0
  141. package/src/types/validate.ts +71 -0
  142. package/src/utils/SchemaHelper.ts +196 -0
  143. package/src/utils/SchemaUtils.ts +346 -0
  144. package/src/utils/TypeConverter.ts +215 -0
  145. package/src/utils/index.ts +10 -0
  146. package/src/validators/CustomKeywords.ts +477 -0
  147. package/.eslintignore +0 -11
  148. package/.eslintrc.json +0 -27
  149. package/CONTRIBUTING.md +0 -368
  150. package/STATUS.md +0 -491
  151. package/changelogs/v1.0.0.md +0 -328
  152. package/changelogs/v1.0.9.md +0 -367
  153. package/changelogs/v1.1.0.md +0 -389
  154. package/changelogs/v1.1.1.md +0 -308
  155. package/changelogs/v1.1.2.md +0 -183
  156. package/changelogs/v1.1.3.md +0 -161
  157. package/changelogs/v1.1.4.md +0 -432
  158. package/changelogs/v1.1.5.md +0 -493
  159. package/changelogs/v1.1.6.md +0 -211
  160. package/changelogs/v1.1.8.md +0 -376
  161. package/changelogs/v1.2.3.md +0 -124
  162. package/docs/INDEX.md +0 -252
  163. package/docs/issues-resolved-summary.md +0 -196
  164. package/docs/performance-benchmark-report.md +0 -179
  165. package/docs/performance-quick-reference.md +0 -123
  166. package/docs/user-questions-answered.md +0 -353
  167. package/docs/validation-rules-v1.0.2.md +0 -1608
  168. package/examples/README.md +0 -81
  169. package/examples/array-dsl-example.js +0 -227
  170. package/examples/conditional-example.js +0 -288
  171. package/examples/conditional-non-object.js +0 -129
  172. package/examples/conditional-validate-example.js +0 -321
  173. package/examples/custom-extension.js +0 -85
  174. package/examples/dsl-match-example.js +0 -74
  175. package/examples/dsl-style.js +0 -118
  176. package/examples/dynamic-locale-configuration.js +0 -348
  177. package/examples/dynamic-locale-example.js +0 -287
  178. package/examples/enum.examples.js +0 -324
  179. package/examples/export-demo.js +0 -130
  180. package/examples/express-integration.js +0 -376
  181. package/examples/i18n-error-handling-complete.js +0 -381
  182. package/examples/i18n-error-handling-quickstart.md +0 -0
  183. package/examples/i18n-error.examples.js +0 -181
  184. package/examples/i18n-full-demo.js +0 -301
  185. package/examples/i18n-memory-safety.examples.js +0 -268
  186. package/examples/markdown-export.js +0 -71
  187. package/examples/middleware-usage.js +0 -93
  188. package/examples/new-features-comparison.js +0 -315
  189. package/examples/password-reset/README.md +0 -153
  190. package/examples/password-reset/schema.js +0 -26
  191. package/examples/password-reset/test.js +0 -101
  192. package/examples/plugin-system.examples.js +0 -205
  193. package/examples/schema-utils-chaining.examples.js +0 -250
  194. package/examples/simple-example.js +0 -122
  195. package/examples/slug.examples.js +0 -179
  196. package/examples/string-extensions.js +0 -297
  197. package/examples/union-type-example.js +0 -127
  198. package/examples/union-types-example.js +0 -77
  199. package/examples/user-registration/README.md +0 -156
  200. package/examples/user-registration/routes.js +0 -92
  201. package/examples/user-registration/schema.js +0 -150
  202. package/examples/user-registration/server.js +0 -74
  203. package/index.d.ts +0 -3540
  204. package/index.js +0 -457
  205. package/index.mjs +0 -60
  206. package/lib/adapters/DslAdapter.js +0 -871
  207. package/lib/adapters/index.js +0 -20
  208. package/lib/config/constants.js +0 -286
  209. package/lib/config/patterns/common.js +0 -47
  210. package/lib/config/patterns/creditCard.js +0 -9
  211. package/lib/config/patterns/idCard.js +0 -9
  212. package/lib/config/patterns/index.js +0 -9
  213. package/lib/config/patterns/licensePlate.js +0 -4
  214. package/lib/config/patterns/passport.js +0 -4
  215. package/lib/config/patterns/phone.js +0 -9
  216. package/lib/config/patterns/postalCode.js +0 -5
  217. package/lib/core/CacheManager.js +0 -376
  218. package/lib/core/ConditionalBuilder.js +0 -503
  219. package/lib/core/DslBuilder.js +0 -1400
  220. package/lib/core/ErrorCodes.js +0 -233
  221. package/lib/core/ErrorFormatter.js +0 -445
  222. package/lib/core/JSONSchemaCore.js +0 -347
  223. package/lib/core/Locale.js +0 -130
  224. package/lib/core/MessageTemplate.js +0 -98
  225. package/lib/core/PluginManager.js +0 -448
  226. package/lib/core/StringExtensions.js +0 -240
  227. package/lib/core/Validator.js +0 -654
  228. package/lib/errors/I18nError.js +0 -328
  229. package/lib/errors/ValidationError.js +0 -191
  230. package/lib/exporters/MarkdownExporter.js +0 -420
  231. package/lib/exporters/MongoDBExporter.js +0 -162
  232. package/lib/exporters/MySQLExporter.js +0 -212
  233. package/lib/exporters/PostgreSQLExporter.js +0 -289
  234. package/lib/exporters/index.js +0 -24
  235. package/lib/locales/index.js +0 -8
  236. package/lib/utils/LRUCache.js +0 -174
  237. package/lib/utils/SchemaHelper.js +0 -240
  238. package/lib/utils/SchemaUtils.js +0 -445
  239. package/lib/utils/TypeConverter.js +0 -245
  240. package/lib/utils/index.js +0 -13
  241. package/lib/validators/CustomKeywords.js +0 -616
  242. package/lib/validators/index.js +0 -11
@@ -1,328 +0,0 @@
1
- /**
2
- * I18nError - 多语言错误工具类
3
- *
4
- * 提供统一的多语言错误抛出机制,支持:
5
- * - 多语言 key 自动翻译
6
- * - 参数插值(如 {{field}}, {{limit}})
7
- * - 自定义错误代码
8
- * - Express/Koa 集成
9
- *
10
- * @module lib/errors/I18nError
11
- * @version 1.1.1
12
- *
13
- * @example 基础用法
14
- * const { I18nError } = require('schema-dsl');
15
- *
16
- * // 抛出多语言错误
17
- * throw I18nError.create('error.notFound', { resource: '账户' });
18
- * // 中文: "找不到账户"
19
- * // 英文: "Account not found"
20
- *
21
- * @example 业务代码中使用
22
- * function getAccount(id) {
23
- * const account = db.findAccount(id);
24
- * if (!account) {
25
- * throw I18nError.create('account.notFound', { accountId: id });
26
- * }
27
- * if (account.balance < 100) {
28
- * throw I18nError.create('account.insufficientBalance', {
29
- * balance: account.balance,
30
- * required: 100
31
- * });
32
- * }
33
- * return account;
34
- * }
35
- *
36
- * @example Express 中间件
37
- * app.use((error, req, res, next) => {
38
- * if (error instanceof I18nError) {
39
- * return res.status(error.statusCode).json(error.toJSON());
40
- * }
41
- * next(error);
42
- * });
43
- */
44
-
45
- const Locale = require('../core/Locale');
46
- const MessageTemplate = require('../core/MessageTemplate');
47
-
48
- /**
49
- * 智能参数识别工具函数
50
- * @private
51
- * @param {Object|string} paramsOrLocale - 参数对象 或 语言代码
52
- * @param {number} statusCode - HTTP 状态码
53
- * @param {string} locale - 语言环境
54
- * @returns {Object} 规范化后的参数 { params, statusCode, locale }
55
- */
56
- function normalizeParams(paramsOrLocale, statusCode, locale) {
57
- let params = {};
58
- let actualStatusCode = 400;
59
- let actualLocale = null;
60
-
61
- if (typeof paramsOrLocale === 'string') {
62
- // 情况1:第2个参数是字符串 → 视为语言
63
- actualLocale = paramsOrLocale;
64
- actualStatusCode = typeof statusCode === 'number' ? statusCode : 400;
65
- } else if (paramsOrLocale && typeof paramsOrLocale === 'object' && !Array.isArray(paramsOrLocale)) {
66
- // 情况2:第2个参数是对象(非数组)→ 视为参数对象
67
- params = paramsOrLocale;
68
- actualStatusCode = typeof statusCode === 'number' ? statusCode : 400;
69
- actualLocale = locale;
70
- } else {
71
- // 情况3:第2个参数是 null/undefined/数组 → 使用默认值和后续参数
72
- actualStatusCode = typeof statusCode === 'number' ? statusCode : 400;
73
- actualLocale = locale;
74
- }
75
-
76
- return { params, statusCode: actualStatusCode, locale: actualLocale };
77
- }
78
-
79
- /**
80
- * 多语言错误类
81
- *
82
- * @class I18nError
83
- * @extends Error
84
- *
85
- * @property {string} name - 错误名称(固定为 'I18nError')
86
- * @property {string} message - 错误消息(已翻译)
87
- * @property {string} code - 错误代码(多语言 key)
88
- * @property {Object} params - 错误参数(用于插值)
89
- * @property {number} statusCode - HTTP 状态码(默认 400)
90
- * @property {string} locale - 使用的语言环境
91
- */
92
- class I18nError extends Error {
93
- /**
94
- * 构造函数
95
- * @param {string} key - 错误代码(多语言 key)
96
- * @param {Object} params - 错误参数(用于插值)
97
- * @param {number} statusCode - HTTP 状态码(默认 400)
98
- * @param {string} locale - 语言环境(默认使用当前语言)
99
- * @version 1.1.5 - 支持对象格式配置
100
- */
101
- constructor(key, params = {}, statusCode = 400, locale = null) {
102
- // 获取语言环境
103
- const actualLocale = locale || Locale.getLocale();
104
-
105
- // 获取消息配置(v1.1.5: 返回对象 { code, message })
106
- const messageConfig = Locale.getMessage(key, {}, actualLocale);
107
-
108
- // 判断返回类型(向后兼容)
109
- let errorCode, template;
110
- if (typeof messageConfig === 'object' && messageConfig.code && messageConfig.message) {
111
- // 对象格式:提取 code 和 message
112
- errorCode = messageConfig.code;
113
- template = messageConfig.message;
114
- } else if (typeof messageConfig === 'string') {
115
- // 字符串格式(向后兼容)
116
- errorCode = key;
117
- template = messageConfig;
118
- } else {
119
- // 降级处理
120
- errorCode = key;
121
- template = key;
122
- }
123
-
124
- // 使用 MessageTemplate 进行参数插值
125
- const messageTemplate = new MessageTemplate(template);
126
- const message = messageTemplate.render(params || {});
127
-
128
- super(message);
129
-
130
- this.name = 'I18nError';
131
- this.originalKey = key; // v1.1.5 新增:保留原始 key
132
- this.code = errorCode; // v1.1.5 修改:从对象提取或使用 key
133
- this.params = params || {};
134
- this.statusCode = statusCode;
135
- this.locale = actualLocale;
136
-
137
- // 保持堆栈跟踪
138
- if (Error.captureStackTrace) {
139
- Error.captureStackTrace(this, I18nError);
140
- }
141
- }
142
-
143
- /**
144
- * 静态工厂方法 - 创建并抛出错误
145
- *
146
- * @param {string} code - 错误代码(多语言 key)
147
- * @param {Object|string} paramsOrLocale - 错误参数对象 或 语言代码(智能识别)
148
- * @param {number} statusCode - HTTP 状态码
149
- * @param {string} locale - 语言环境(仅当第2个参数是对象时有效)
150
- * @returns {I18nError} 错误实例
151
- *
152
- * @example
153
- * // 方式1:简化语法(直接传语言)
154
- * const error = I18nError.create('account.notFound', 'zh-CN');
155
- * const error = I18nError.create('account.notFound', 'en-US', 404);
156
- *
157
- * @example
158
- * // 方式2:标准语法(带参数对象)
159
- * const error = I18nError.create('account.notFound', { userId: '123' }, 404, 'zh-CN');
160
- *
161
- * @example
162
- * // 方式3:省略参数(使用全局语言)
163
- * const error = I18nError.create('account.notFound');
164
- *
165
- * @example
166
- * // 直接抛出
167
- * throw I18nError.create('error.notFound', { resource: '用户' });
168
- *
169
- * @example
170
- * // 运行时指定语言
171
- * const error = I18nError.create('error.notFound', {}, 404, 'en-US');
172
- */
173
- static create(code, paramsOrLocale, statusCode, locale) {
174
- const { params, statusCode: actualStatusCode, locale: actualLocale } = normalizeParams(paramsOrLocale, statusCode, locale);
175
- return new I18nError(code, params, actualStatusCode, actualLocale);
176
- }
177
-
178
- /**
179
- * 静态工厂方法 - 快速抛出错误
180
- *
181
- * @param {string} code - 错误代码(多语言 key)
182
- * @param {Object|string} paramsOrLocale - 错误参数对象 或 语言代码(智能识别)
183
- * @param {number} statusCode - HTTP 状态码
184
- * @param {string} locale - 语言环境(仅当第2个参数是对象时有效)
185
- * @throws {I18nError} 直接抛出错误
186
- *
187
- * @example
188
- * // 方式1:简化语法(直接传语言)
189
- * I18nError.throw('account.notFound', 'zh-CN');
190
- * I18nError.throw('account.notFound', 'en-US', 404);
191
- *
192
- * @example
193
- * // 方式2:标准语法(带参数对象)
194
- * I18nError.throw('account.notFound', { userId: '123' }, 404, 'zh-CN');
195
- *
196
- * @example
197
- * // 方式3:省略参数(使用全局语言)
198
- * I18nError.throw('account.notFound');
199
- *
200
- * @example
201
- * I18nError.throw('error.notFound', { resource: '用户' });
202
- * // 等同于:throw I18nError.create('error.notFound', { resource: '用户' });
203
- *
204
- * @example
205
- * // 运行时指定语言
206
- * I18nError.throw('error.notFound', {}, 404, 'en-US');
207
- */
208
- static throw(code, paramsOrLocale, statusCode, locale) {
209
- const { params, statusCode: actualStatusCode, locale: actualLocale } = normalizeParams(paramsOrLocale, statusCode, locale);
210
- throw new I18nError(code, params, actualStatusCode, actualLocale);
211
- }
212
-
213
- /**
214
- * 断言方法 - 条件不满足时抛错
215
- *
216
- * @param {boolean} condition - 条件表达式
217
- * @param {string} code - 错误代码(多语言 key)
218
- * @param {Object|string} paramsOrLocale - 错误参数对象 或 语言代码(智能识别)
219
- * @param {number} statusCode - HTTP 状态码
220
- * @param {string} locale - 语言环境(仅当第3个参数是对象时有效)
221
- * @throws {I18nError} 条件为 false 时抛出错误
222
- *
223
- * @example
224
- * // 方式1:简化语法(直接传语言)
225
- * I18nError.assert(account, 'account.notFound', 'zh-CN');
226
- * I18nError.assert(account, 'account.notFound', 'en-US', 404);
227
- *
228
- * @example
229
- * // 方式2:标准语法(带参数对象)
230
- * I18nError.assert(account, 'account.notFound', { accountId: id }, 404, 'zh-CN');
231
- * // 等同于:if (!account) throw I18nError.create('account.notFound', { accountId: id });
232
- *
233
- * @example
234
- * I18nError.assert(
235
- * account.balance >= 100,
236
- * 'account.insufficientBalance',
237
- * { balance: account.balance, required: 100 }
238
- * );
239
- *
240
- * @example
241
- * // 运行时指定语言
242
- * I18nError.assert(account, 'account.notFound', {}, 404, 'en-US');
243
- */
244
- static assert(condition, code, paramsOrLocale, statusCode, locale) {
245
- if (!condition) {
246
- const { params, statusCode: actualStatusCode, locale: actualLocale } = normalizeParams(paramsOrLocale, statusCode, locale);
247
- throw new I18nError(code, params, actualStatusCode, actualLocale);
248
- }
249
- }
250
-
251
- /**
252
- * 检查错误是否为指定代码
253
- *
254
- * @param {string} codeOrKey - 错误代码或原始 key
255
- * @returns {boolean} 是否匹配
256
- *
257
- * @example
258
- * try {
259
- * // ...
260
- * } catch (error) {
261
- * if (error instanceof I18nError && error.is('account.notFound')) {
262
- * // 处理账户不存在的情况
263
- * }
264
- *
265
- * // v1.1.5: 也可以用 code 判断
266
- * if (error instanceof I18nError && error.is('ACCOUNT_NOT_FOUND')) {
267
- * // 也能匹配
268
- * }
269
- * }
270
- */
271
- is(codeOrKey) {
272
- // v1.1.5: 同时比较 code 和 originalKey(向后兼容)
273
- return this.code === codeOrKey || this.originalKey === codeOrKey;
274
- }
275
-
276
- /**
277
- * 转换为 JSON 格式(用于 API 响应)
278
- *
279
- * @returns {Object} JSON 对象
280
- * @returns {string} return.error - 错误名称
281
- * @returns {string} return.originalKey - 原始 key(v1.1.5 新增)
282
- * @returns {string} return.code - 错误代码
283
- * @returns {string} return.message - 错误消息(已翻译)
284
- * @returns {Object} return.params - 错误参数
285
- * @returns {number} return.statusCode - 状态码
286
- * @returns {string} return.locale - 语言环境
287
- *
288
- * @example
289
- * const json = error.toJSON();
290
- * res.status(error.statusCode).json(json);
291
- * // {
292
- * // error: 'I18nError',
293
- * // originalKey: 'account.notFound', // v1.1.5 新增
294
- * // code: 'ACCOUNT_NOT_FOUND',
295
- * // message: '找不到账户',
296
- * // params: { accountId: '123' },
297
- * // statusCode: 404,
298
- * // locale: 'zh-CN'
299
- * // }
300
- */
301
- toJSON() {
302
- return {
303
- error: this.name,
304
- originalKey: this.originalKey, // v1.1.5 新增
305
- code: this.code,
306
- message: this.message,
307
- params: this.params,
308
- statusCode: this.statusCode,
309
- locale: this.locale
310
- };
311
- }
312
-
313
- /**
314
- * 转换为字符串
315
- *
316
- * @returns {string} 格式化的错误信息
317
- *
318
- * @example
319
- * console.log(error.toString());
320
- * // "I18nError [account.notFound]: 找不到账户"
321
- */
322
- toString() {
323
- return `${this.name} [${this.code}]: ${this.message}`;
324
- }
325
- }
326
-
327
- module.exports = I18nError;
328
-
@@ -1,191 +0,0 @@
1
- /**
2
- * ValidationError - 验证错误类
3
- *
4
- * 用于 validateAsync() 方法,验证失败时自动抛出
5
- *
6
- * @module lib/errors/ValidationError
7
- * @version 1.0.3
8
- */
9
-
10
- /**
11
- * 验证错误类
12
- *
13
- * @class ValidationError
14
- * @extends Error
15
- *
16
- * @property {string} name - 错误名称(固定为 'ValidationError')
17
- * @property {string} message - 错误消息(所有错误的汇总)
18
- * @property {Array<Object>} errors - 详细错误列表
19
- * @property {*} data - 原始验证数据
20
- * @property {number} statusCode - HTTP 状态码(默认 400)
21
- *
22
- * @example
23
- * // 创建错误
24
- * const errors = [
25
- * { path: '/name', message: '字段必填', keyword: 'required' }
26
- * ];
27
- * const error = new ValidationError(errors, inputData);
28
- *
29
- * @example
30
- * // 在 Express 中使用
31
- * app.use((error, req, res, next) => {
32
- * if (error instanceof ValidationError) {
33
- * return res.status(error.statusCode).json(error.toJSON());
34
- * }
35
- * next(error);
36
- * });
37
- */
38
- class ValidationError extends Error {
39
- /**
40
- * 构造函数
41
- * @param {Array<Object>} errors - 错误列表
42
- * @param {string} errors[].path - 字段路径(如 '/name')
43
- * @param {string} errors[].message - 错误消息
44
- * @param {string} errors[].keyword - 验证关键字(如 'required', 'format')
45
- * @param {Object} errors[].params - 错误参数
46
- * @param {*} data - 原始数据
47
- */
48
- constructor(errors, data) {
49
- // 生成友好的错误消息
50
- const messages = errors.map(e => {
51
- if (e.path) {
52
- const field = e.path.replace(/^\//, '');
53
- // 只有字段名非空时才添加前缀
54
- return field ? `${field}: ${e.message}` : e.message;
55
- }
56
- return e.message;
57
- }).join('; ');
58
-
59
- // 检查是否所有错误都完全没有 path 属性(而不是空路径)
60
- const hasNoPath = errors.every(e => e.path === undefined || e.path === null);
61
-
62
- // 如果都是无 path 属性的错误,使用简单格式;否则使用标准格式
63
- super(hasNoPath ? `Validation failed - ${messages}` : `Validation failed: ${messages}`);
64
-
65
- this.name = 'ValidationError';
66
- this.errors = errors;
67
- this.data = data;
68
- this.statusCode = 400;
69
-
70
- // 保持堆栈跟踪
71
- if (Error.captureStackTrace) {
72
- Error.captureStackTrace(this, ValidationError);
73
- }
74
- }
75
-
76
- /**
77
- * 转换为 JSON 格式(用于 API 响应)
78
- *
79
- * @returns {Object} JSON 对象
80
- * @returns {string} return.error - 错误名称
81
- * @returns {string} return.message - 错误消息
82
- * @returns {number} return.statusCode - 状态码
83
- * @returns {Array<Object>} return.details - 详细错误列表
84
- *
85
- * @example
86
- * const json = error.toJSON();
87
- * res.status(400).json(json);
88
- * // {
89
- * // error: 'ValidationError',
90
- * // message: 'Validation failed: name: 字段必填',
91
- * // statusCode: 400,
92
- * // details: [...]
93
- * // }
94
- */
95
- toJSON() {
96
- return {
97
- error: this.name,
98
- message: this.message,
99
- statusCode: this.statusCode,
100
- details: this.errors.map(e => ({
101
- field: e.path ? e.path.replace(/^\//, '') : null,
102
- message: e.message,
103
- keyword: e.keyword,
104
- params: e.params
105
- }))
106
- };
107
- }
108
-
109
- /**
110
- * 获取指定字段的错误
111
- *
112
- * @param {string} field - 字段名称(如 'name' 或 '/name')
113
- * @returns {Object|null} 错误对象或 null
114
- *
115
- * @example
116
- * const nameError = error.getFieldError('name');
117
- * if (nameError) {
118
- * console.log('姓名错误:', nameError.message);
119
- * }
120
- */
121
- getFieldError(field) {
122
- // 规范化字段名(移除前导斜杠)
123
- const normalizedField = field.replace(/^\//, '');
124
-
125
- // 查找匹配的错误(支持多种路径格式)
126
- return this.errors.find(e => {
127
- if (!e.path) return false;
128
- const errorField = e.path.replace(/^\//, '');
129
- return errorField === normalizedField;
130
- }) || null;
131
- }
132
-
133
- /**
134
- * 获取所有字段的错误映射
135
- *
136
- * @returns {Object} 字段错误映射 { fieldName: errorMessage }
137
- *
138
- * @example
139
- * const fieldErrors = error.getFieldErrors();
140
- * // { name: '字段必填', email: '邮箱格式错误' }
141
- */
142
- getFieldErrors() {
143
- const result = {};
144
- this.errors.forEach(e => {
145
- if (e.path) {
146
- const field = e.path.replace(/^\//, '');
147
- if (field) {
148
- result[field] = e.message;
149
- }
150
- }
151
- });
152
- return result;
153
- }
154
-
155
- /**
156
- * 检查是否包含指定字段的错误
157
- *
158
- * @param {string} field - 字段名称
159
- * @returns {boolean} 是否包含错误
160
- *
161
- * @example
162
- * if (error.hasFieldError('name')) {
163
- * console.log('姓名字段有错误');
164
- * }
165
- */
166
- hasFieldError(field) {
167
- return this.getFieldError(field) !== null;
168
- }
169
-
170
- /**
171
- * 获取错误数量
172
- *
173
- * @returns {number} 错误数量
174
- *
175
- * @example
176
- * console.log(`共 ${error.getErrorCount()} 个错误`);
177
- */
178
- getErrorCount() {
179
- return this.errors.length;
180
- }
181
- }
182
-
183
- // Support calling without new
184
- const ValidationErrorProxy = new Proxy(ValidationError, {
185
- apply: function (target, thisArg, argumentsList) {
186
- return new target(...argumentsList);
187
- }
188
- });
189
-
190
- module.exports = ValidationErrorProxy;
191
-