schema-dsl 1.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.
- package/.eslintignore +10 -0
- package/.eslintrc.json +27 -0
- package/.github/CODE_OF_CONDUCT.md +45 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +57 -0
- package/.github/ISSUE_TEMPLATE/config.yml +11 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +45 -0
- package/.github/ISSUE_TEMPLATE/question.md +31 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +70 -0
- package/.github/SECURITY.md +184 -0
- package/.github/workflows/ci.yml +33 -0
- package/CHANGELOG.md +633 -0
- package/CONTRIBUTING.md +368 -0
- package/LICENSE +21 -0
- package/README.md +1184 -0
- package/STATUS.md +101 -0
- package/docs/FEATURE-INDEX.md +519 -0
- package/docs/INDEX.md +253 -0
- package/docs/api-reference.md +1096 -0
- package/docs/best-practices.md +672 -0
- package/docs/cache-manager.md +336 -0
- package/docs/design-philosophy.md +601 -0
- package/docs/dsl-syntax.md +653 -0
- package/docs/dynamic-locale.md +552 -0
- package/docs/error-handling.md +703 -0
- package/docs/export-guide.md +462 -0
- package/docs/export-limitations.md +551 -0
- package/docs/faq.md +577 -0
- package/docs/frontend-i18n-guide.md +290 -0
- package/docs/i18n-user-guide.md +476 -0
- package/docs/label-vs-description.md +262 -0
- package/docs/markdown-exporter.md +397 -0
- package/docs/mongodb-exporter.md +295 -0
- package/docs/multi-type-support.md +319 -0
- package/docs/mysql-exporter.md +273 -0
- package/docs/plugin-system.md +542 -0
- package/docs/postgresql-exporter.md +304 -0
- package/docs/quick-start.md +761 -0
- package/docs/schema-helper.md +340 -0
- package/docs/schema-utils-chaining.md +143 -0
- package/docs/schema-utils.md +490 -0
- package/docs/string-extensions.md +480 -0
- package/docs/troubleshooting.md +471 -0
- package/docs/type-converter.md +319 -0
- package/docs/type-reference.md +219 -0
- package/docs/validate-async.md +480 -0
- package/docs/validate.md +486 -0
- package/docs/validation-guide.md +484 -0
- package/examples/array-dsl-example.js +227 -0
- package/examples/custom-extension.js +85 -0
- package/examples/dsl-match-example.js +74 -0
- package/examples/dsl-style.js +118 -0
- package/examples/dynamic-locale-configuration.js +348 -0
- package/examples/dynamic-locale-example.js +287 -0
- package/examples/export-demo.js +130 -0
- package/examples/express-integration.js +376 -0
- package/examples/i18n-full-demo.js +310 -0
- package/examples/i18n-memory-safety.examples.js +268 -0
- package/examples/markdown-export.js +71 -0
- package/examples/middleware-usage.js +93 -0
- package/examples/new-features-comparison.js +315 -0
- package/examples/password-reset/README.md +153 -0
- package/examples/password-reset/schema.js +26 -0
- package/examples/password-reset/test.js +101 -0
- package/examples/plugin-system.examples.js +205 -0
- package/examples/schema-utils-chaining.examples.js +250 -0
- package/examples/simple-example.js +122 -0
- package/examples/string-extensions.js +297 -0
- package/examples/user-registration/README.md +156 -0
- package/examples/user-registration/routes.js +92 -0
- package/examples/user-registration/schema.js +150 -0
- package/examples/user-registration/server.js +74 -0
- package/index.d.ts +1999 -0
- package/index.js +282 -0
- package/index.mjs +30 -0
- package/lib/adapters/DslAdapter.js +699 -0
- package/lib/adapters/index.js +20 -0
- package/lib/config/constants.js +286 -0
- package/lib/config/patterns/creditCard.js +9 -0
- package/lib/config/patterns/idCard.js +9 -0
- package/lib/config/patterns/index.js +8 -0
- package/lib/config/patterns/licensePlate.js +4 -0
- package/lib/config/patterns/passport.js +4 -0
- package/lib/config/patterns/phone.js +9 -0
- package/lib/config/patterns/postalCode.js +5 -0
- package/lib/core/CacheManager.js +376 -0
- package/lib/core/DslBuilder.js +740 -0
- package/lib/core/ErrorCodes.js +233 -0
- package/lib/core/ErrorFormatter.js +342 -0
- package/lib/core/JSONSchemaCore.js +347 -0
- package/lib/core/Locale.js +119 -0
- package/lib/core/MessageTemplate.js +89 -0
- package/lib/core/PluginManager.js +448 -0
- package/lib/core/StringExtensions.js +209 -0
- package/lib/core/Validator.js +376 -0
- package/lib/errors/ValidationError.js +191 -0
- package/lib/exporters/MarkdownExporter.js +420 -0
- package/lib/exporters/MongoDBExporter.js +162 -0
- package/lib/exporters/MySQLExporter.js +212 -0
- package/lib/exporters/PostgreSQLExporter.js +289 -0
- package/lib/exporters/index.js +24 -0
- package/lib/locales/en-US.js +65 -0
- package/lib/locales/es-ES.js +66 -0
- package/lib/locales/fr-FR.js +66 -0
- package/lib/locales/index.js +8 -0
- package/lib/locales/ja-JP.js +66 -0
- package/lib/locales/zh-CN.js +93 -0
- package/lib/utils/LRUCache.js +174 -0
- package/lib/utils/SchemaHelper.js +240 -0
- package/lib/utils/SchemaUtils.js +445 -0
- package/lib/utils/TypeConverter.js +245 -0
- package/lib/utils/index.js +13 -0
- package/lib/validators/CustomKeywords.js +203 -0
- package/lib/validators/index.js +11 -0
- package/package.json +70 -0
- package/plugins/custom-format.js +101 -0
- package/plugins/custom-validator.js +200 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON Schema核心类
|
|
3
|
+
*
|
|
4
|
+
* 负责管理JSON Schema对象,提供统一的Schema表示
|
|
5
|
+
* 所有适配器转换后的Schema都使用此类表示
|
|
6
|
+
*
|
|
7
|
+
* @module lib/core/JSONSchemaCore
|
|
8
|
+
* @version 1.0.0
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const CONSTANTS = require('../config/constants');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* JSON Schema核心类
|
|
15
|
+
*
|
|
16
|
+
* @class JSONSchemaCore
|
|
17
|
+
* @description 基于JSON Schema Draft 7标准
|
|
18
|
+
*/
|
|
19
|
+
class JSONSchemaCore {
|
|
20
|
+
/**
|
|
21
|
+
* 构造函数
|
|
22
|
+
* @param {Object} schema - JSON Schema对象
|
|
23
|
+
* @param {Object} options - 配置选项
|
|
24
|
+
* @param {boolean} options.strict - 是否启用严格模式(默认false)
|
|
25
|
+
* @param {string} options.draft - JSON Schema草案版本(默认'draft-07')
|
|
26
|
+
*/
|
|
27
|
+
constructor(schema = {}, options = {}) {
|
|
28
|
+
this.schema = this._normalizeSchema(schema);
|
|
29
|
+
this.options = {
|
|
30
|
+
strict: options.strict || false,
|
|
31
|
+
draft: options.draft || 'draft-07',
|
|
32
|
+
...options
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// 确保$schema字段
|
|
36
|
+
if (!this.schema.$schema) {
|
|
37
|
+
this.schema.$schema = 'http://json-schema.org/draft-07/schema#';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 规范化Schema对象
|
|
43
|
+
* @private
|
|
44
|
+
* @param {Object} schema - 原始Schema
|
|
45
|
+
* @returns {Object} 规范化后的Schema
|
|
46
|
+
*/
|
|
47
|
+
_normalizeSchema(schema) {
|
|
48
|
+
if (!schema || typeof schema !== 'object') {
|
|
49
|
+
return { type: 'object' };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 深拷贝避免修改原对象
|
|
53
|
+
return JSON.parse(JSON.stringify(schema));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 获取Schema对象
|
|
58
|
+
* @returns {Object} JSON Schema对象
|
|
59
|
+
*/
|
|
60
|
+
getSchema() {
|
|
61
|
+
return this.schema;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 设置Schema类型
|
|
66
|
+
* @param {string} type - 类型名称(string/number/boolean/object/array/null)
|
|
67
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
68
|
+
*/
|
|
69
|
+
setType(type) {
|
|
70
|
+
const validTypes = ['string', 'number', 'integer', 'boolean', 'object', 'array', 'null'];
|
|
71
|
+
if (!validTypes.includes(type)) {
|
|
72
|
+
throw new Error(`Invalid type: ${type}. Valid types: ${validTypes.join(', ')}`);
|
|
73
|
+
}
|
|
74
|
+
this.schema.type = type;
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* 设置必填字段
|
|
80
|
+
* @param {string[]} required - 必填字段数组
|
|
81
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
82
|
+
*/
|
|
83
|
+
setRequired(required) {
|
|
84
|
+
if (!Array.isArray(required)) {
|
|
85
|
+
throw new Error('Required must be an array');
|
|
86
|
+
}
|
|
87
|
+
this.schema.required = required;
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 设置属性定义
|
|
93
|
+
* @param {string} name - 属性名
|
|
94
|
+
* @param {Object} propertySchema - 属性Schema
|
|
95
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
96
|
+
*/
|
|
97
|
+
setProperty(name, propertySchema) {
|
|
98
|
+
if (!this.schema.properties) {
|
|
99
|
+
this.schema.properties = {};
|
|
100
|
+
}
|
|
101
|
+
this.schema.properties[name] = propertySchema;
|
|
102
|
+
return this;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 设置多个属性
|
|
107
|
+
* @param {Object} properties - 属性对象
|
|
108
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
109
|
+
*/
|
|
110
|
+
setProperties(properties) {
|
|
111
|
+
if (typeof properties !== 'object' || properties === null) {
|
|
112
|
+
throw new Error('Properties must be an object');
|
|
113
|
+
}
|
|
114
|
+
this.schema.properties = { ...this.schema.properties, ...properties };
|
|
115
|
+
return this;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 设置数组items
|
|
120
|
+
* @param {Object} itemsSchema - items的Schema
|
|
121
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
122
|
+
*/
|
|
123
|
+
setItems(itemsSchema) {
|
|
124
|
+
this.schema.items = itemsSchema;
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* 设置字符串格式
|
|
130
|
+
* @param {string} format - 格式(email/uri/date-time等)
|
|
131
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
132
|
+
*/
|
|
133
|
+
setFormat(format) {
|
|
134
|
+
this.schema.format = format;
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* 设置字符串正则模式
|
|
140
|
+
* @param {string} pattern - 正则表达式字符串
|
|
141
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
142
|
+
*/
|
|
143
|
+
setPattern(pattern) {
|
|
144
|
+
this.schema.pattern = pattern;
|
|
145
|
+
return this;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 设置数值范围(最小值)
|
|
150
|
+
* @param {number} min - 最小值
|
|
151
|
+
* @param {boolean} exclusive - 是否不包含边界(默认false)
|
|
152
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
153
|
+
*/
|
|
154
|
+
setMinimum(min, exclusive = false) {
|
|
155
|
+
if (exclusive) {
|
|
156
|
+
this.schema.exclusiveMinimum = min;
|
|
157
|
+
} else {
|
|
158
|
+
this.schema.minimum = min;
|
|
159
|
+
}
|
|
160
|
+
return this;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* 设置数值范围(最大值)
|
|
165
|
+
* @param {number} max - 最大值
|
|
166
|
+
* @param {boolean} exclusive - 是否不包含边界(默认false)
|
|
167
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
168
|
+
*/
|
|
169
|
+
setMaximum(max, exclusive = false) {
|
|
170
|
+
if (exclusive) {
|
|
171
|
+
this.schema.exclusiveMaximum = max;
|
|
172
|
+
} else {
|
|
173
|
+
this.schema.maximum = max;
|
|
174
|
+
}
|
|
175
|
+
return this;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* 设置字符串长度范围
|
|
180
|
+
* @param {number} min - 最小长度
|
|
181
|
+
* @param {number} max - 最大长度
|
|
182
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
183
|
+
*/
|
|
184
|
+
setLength(min, max) {
|
|
185
|
+
if (min !== undefined) {
|
|
186
|
+
this.schema.minLength = min;
|
|
187
|
+
}
|
|
188
|
+
if (max !== undefined) {
|
|
189
|
+
this.schema.maxLength = max;
|
|
190
|
+
}
|
|
191
|
+
return this;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 设置数组长度范围
|
|
196
|
+
* @param {number} min - 最小长度
|
|
197
|
+
* @param {number} max - 最大长度
|
|
198
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
199
|
+
*/
|
|
200
|
+
setArrayLength(min, max) {
|
|
201
|
+
if (min !== undefined) {
|
|
202
|
+
this.schema.minItems = min;
|
|
203
|
+
}
|
|
204
|
+
if (max !== undefined) {
|
|
205
|
+
this.schema.maxItems = max;
|
|
206
|
+
}
|
|
207
|
+
return this;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* 设置枚举值
|
|
212
|
+
* @param {Array} values - 枚举值数组
|
|
213
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
214
|
+
*/
|
|
215
|
+
setEnum(values) {
|
|
216
|
+
if (!Array.isArray(values)) {
|
|
217
|
+
throw new Error('Enum values must be an array');
|
|
218
|
+
}
|
|
219
|
+
this.schema.enum = values;
|
|
220
|
+
return this;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* 设置默认值
|
|
225
|
+
* @param {*} value - 默认值
|
|
226
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
227
|
+
*/
|
|
228
|
+
setDefault(value) {
|
|
229
|
+
this.schema.default = value;
|
|
230
|
+
return this;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* 设置描述
|
|
235
|
+
* @param {string} description - 描述文本
|
|
236
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
237
|
+
*/
|
|
238
|
+
setDescription(description) {
|
|
239
|
+
this.schema.description = description;
|
|
240
|
+
return this;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* 设置标题
|
|
245
|
+
* @param {string} title - 标题文本
|
|
246
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
247
|
+
*/
|
|
248
|
+
setTitle(title) {
|
|
249
|
+
this.schema.title = title;
|
|
250
|
+
return this;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* 添加自定义关键字
|
|
255
|
+
* @param {string} keyword - 关键字名称
|
|
256
|
+
* @param {*} value - 关键字值
|
|
257
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
258
|
+
*/
|
|
259
|
+
addCustomKeyword(keyword, value) {
|
|
260
|
+
this.schema[keyword] = value;
|
|
261
|
+
return this;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* 合并另一个Schema
|
|
266
|
+
* @param {Object} otherSchema - 要合并的Schema对象
|
|
267
|
+
* @returns {JSONSchemaCore} 返回this支持链式调用
|
|
268
|
+
*/
|
|
269
|
+
merge(otherSchema) {
|
|
270
|
+
this.schema = {
|
|
271
|
+
...this.schema,
|
|
272
|
+
...otherSchema
|
|
273
|
+
};
|
|
274
|
+
return this;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* 转换为JSON字符串
|
|
279
|
+
* @param {number} space - 缩进空格数(默认2)
|
|
280
|
+
* @returns {string} JSON字符串
|
|
281
|
+
*/
|
|
282
|
+
toJSON(space = 2) {
|
|
283
|
+
return JSON.stringify(this.schema, null, space);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* 克隆当前Schema
|
|
288
|
+
* @returns {JSONSchemaCore} 新的JSONSchemaCore实例
|
|
289
|
+
*/
|
|
290
|
+
clone() {
|
|
291
|
+
return new JSONSchemaCore(this.schema, this.options);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* 验证Schema是否有效
|
|
296
|
+
* @returns {Object} 验证结果 { valid: boolean, errors: Array }
|
|
297
|
+
*/
|
|
298
|
+
validateSchema() {
|
|
299
|
+
const errors = [];
|
|
300
|
+
|
|
301
|
+
// 基本验证
|
|
302
|
+
if (!this.schema.type && !this.schema.properties && !this.schema.items) {
|
|
303
|
+
errors.push('Schema must have type, properties, or items');
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// 类型验证
|
|
307
|
+
if (this.schema.type) {
|
|
308
|
+
const validTypes = ['string', 'number', 'integer', 'boolean', 'object', 'array', 'null'];
|
|
309
|
+
if (!validTypes.includes(this.schema.type)) {
|
|
310
|
+
errors.push(`Invalid type: ${this.schema.type}`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return {
|
|
315
|
+
valid: errors.length === 0,
|
|
316
|
+
errors
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* 静态方法:从JSON字符串创建
|
|
322
|
+
* @static
|
|
323
|
+
* @param {string} jsonString - JSON字符串
|
|
324
|
+
* @returns {JSONSchemaCore} JSONSchemaCore实例
|
|
325
|
+
*/
|
|
326
|
+
static fromJSON(jsonString) {
|
|
327
|
+
try {
|
|
328
|
+
const schema = JSON.parse(jsonString);
|
|
329
|
+
return new JSONSchemaCore(schema);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
throw new Error(`Invalid JSON: ${error.message}`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* 静态方法:创建简单类型Schema
|
|
337
|
+
* @static
|
|
338
|
+
* @param {string} type - 类型名称
|
|
339
|
+
* @returns {JSONSchemaCore} JSONSchemaCore实例
|
|
340
|
+
*/
|
|
341
|
+
static createSimpleType(type) {
|
|
342
|
+
return new JSONSchemaCore({ type });
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
module.exports = JSONSchemaCore;
|
|
347
|
+
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 语言管理器
|
|
3
|
+
*
|
|
4
|
+
* 管理多语言支持,提供语言切换功能
|
|
5
|
+
*
|
|
6
|
+
* @module lib/core/Locale
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { getErrorInfo } = require('./ErrorCodes');
|
|
10
|
+
const defaultLocales = require('../locales');
|
|
11
|
+
|
|
12
|
+
class Locale {
|
|
13
|
+
/**
|
|
14
|
+
* 当前语言
|
|
15
|
+
* @private
|
|
16
|
+
*/
|
|
17
|
+
static currentLocale = 'en-US';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 语言包存储
|
|
21
|
+
* @private
|
|
22
|
+
*/
|
|
23
|
+
static locales = { ...defaultLocales };
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 自定义消息(全局)
|
|
27
|
+
* @private
|
|
28
|
+
*/
|
|
29
|
+
static customMessages = {};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 设置当前语言
|
|
33
|
+
* @param {string} locale - 语言代码 (zh-CN, en-US等)
|
|
34
|
+
*/
|
|
35
|
+
static setLocale(locale) {
|
|
36
|
+
this.currentLocale = locale;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 获取当前语言
|
|
41
|
+
* @returns {string} 当前语言代码
|
|
42
|
+
*/
|
|
43
|
+
static getLocale() {
|
|
44
|
+
return this.currentLocale;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 添加语言包
|
|
49
|
+
* @param {string} locale - 语言代码
|
|
50
|
+
* @param {Object} messages - 消息对象
|
|
51
|
+
*/
|
|
52
|
+
static addLocale(locale, messages) {
|
|
53
|
+
this.locales[locale] = { ...(this.locales[locale] || {}), ...messages };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* 设置全局自定义消息
|
|
58
|
+
* @param {Object} messages - 消息对象
|
|
59
|
+
*/
|
|
60
|
+
static setMessages(messages) {
|
|
61
|
+
this.customMessages = { ...this.customMessages, ...messages };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 获取错误消息模板
|
|
66
|
+
* @param {string} type - 错误类型
|
|
67
|
+
* @param {Object} [customMessages] - 自定义消息
|
|
68
|
+
* @returns {string} 消息模板
|
|
69
|
+
*/
|
|
70
|
+
static getMessage(type, customMessages = {}) {
|
|
71
|
+
// 优先级: 自定义消息 > 全局自定义消息 > 语言包 > 默认消息
|
|
72
|
+
|
|
73
|
+
// 1. 自定义消息
|
|
74
|
+
if (customMessages[type]) {
|
|
75
|
+
return customMessages[type];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 2. 全局自定义消息
|
|
79
|
+
if (this.customMessages[type]) {
|
|
80
|
+
return this.customMessages[type];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 3. 语言包
|
|
84
|
+
const localeMessages = this.locales[this.currentLocale];
|
|
85
|
+
if (localeMessages && localeMessages[type]) {
|
|
86
|
+
return localeMessages[type];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 4. 默认消息(从ErrorCodes获取)
|
|
90
|
+
const errorInfo = getErrorInfo(type);
|
|
91
|
+
|
|
92
|
+
// 5. 如果是未知错误,尝试从语言包获取本地化的UNKNOWN_ERROR消息
|
|
93
|
+
if (errorInfo.code === 'UNKNOWN_ERROR' && localeMessages && localeMessages['UNKNOWN_ERROR']) {
|
|
94
|
+
return localeMessages['UNKNOWN_ERROR'];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return errorInfo.message;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 获取所有可用语言
|
|
102
|
+
* @returns {Array<string>} 语言代码数组
|
|
103
|
+
*/
|
|
104
|
+
static getAvailableLocales() {
|
|
105
|
+
return ['en-US', 'zh-CN', ...Object.keys(this.locales)];
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* 重置语言管理器
|
|
110
|
+
* 用于测试
|
|
111
|
+
*/
|
|
112
|
+
static reset() {
|
|
113
|
+
this.currentLocale = 'en-US';
|
|
114
|
+
this.locales = { ...defaultLocales };
|
|
115
|
+
this.customMessages = {};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = Locale;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 消息模板引擎
|
|
3
|
+
*
|
|
4
|
+
* 支持模板变量替换,如 {{#label}}, {{#limit}} 等
|
|
5
|
+
*
|
|
6
|
+
* @module lib/core/MessageTemplate
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
class MessageTemplate {
|
|
10
|
+
/**
|
|
11
|
+
* 创建消息模板实例
|
|
12
|
+
* @param {string} template - 模板字符串
|
|
13
|
+
*/
|
|
14
|
+
constructor(template) {
|
|
15
|
+
this.template = template || '';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 渲染模板
|
|
20
|
+
* @param {Object} context - 上下文对象
|
|
21
|
+
* @param {string} [context.label] - 字段标签
|
|
22
|
+
* @param {string} [context.key] - 字段名
|
|
23
|
+
* @param {*} [context.value] - 当前值
|
|
24
|
+
* @param {*} [context.limit] - 限制值
|
|
25
|
+
* @param {Array|string} [context.valids] - 有效值列表
|
|
26
|
+
* @param {RegExp} [context.pattern] - 正则表达式
|
|
27
|
+
* @returns {string} 渲染后的消息
|
|
28
|
+
*/
|
|
29
|
+
render(context = {}) {
|
|
30
|
+
let message = this.template;
|
|
31
|
+
|
|
32
|
+
// 替换所有模板变量
|
|
33
|
+
message = message.replace(/\{\{#(\w+)\}\}/g, (match, key) => {
|
|
34
|
+
const value = context[key];
|
|
35
|
+
|
|
36
|
+
// 特殊处理
|
|
37
|
+
if (value === undefined || value === null) {
|
|
38
|
+
return match; // 保留原样
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 数组转字符串
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
return value.join(', ');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// RegExp转字符串
|
|
47
|
+
if (value instanceof RegExp) {
|
|
48
|
+
return value.toString();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Date转字符串
|
|
52
|
+
if (value instanceof Date) {
|
|
53
|
+
return value.toISOString();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return String(value);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return message;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 静态方法:快速渲染
|
|
64
|
+
* @param {string} template - 模板字符串
|
|
65
|
+
* @param {Object} context - 上下文对象
|
|
66
|
+
* @returns {string} 渲染后的消息
|
|
67
|
+
*/
|
|
68
|
+
static render(template, context) {
|
|
69
|
+
const instance = new MessageTemplate(template);
|
|
70
|
+
return instance.render(context);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 批量渲染
|
|
75
|
+
* @param {Object} templates - 模板对象 { type: template }
|
|
76
|
+
* @param {Object} context - 上下文对象
|
|
77
|
+
* @returns {Object} 渲染后的消息对象
|
|
78
|
+
*/
|
|
79
|
+
static renderBatch(templates, context) {
|
|
80
|
+
const result = {};
|
|
81
|
+
for (const [type, template] of Object.entries(templates)) {
|
|
82
|
+
result[type] = MessageTemplate.render(template, context);
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = MessageTemplate;
|
|
89
|
+
|