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
@@ -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
-