schema-dsl 2.3.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 +35 -0
- package/CHANGELOG.md +633 -0
- package/CONTRIBUTING.md +368 -0
- package/LICENSE +21 -0
- package/README.md +1122 -0
- package/STATUS.md +273 -0
- package/docs/FEATURE-INDEX.md +521 -0
- package/docs/INDEX.md +224 -0
- package/docs/api-reference.md +1098 -0
- package/docs/best-practices.md +672 -0
- package/docs/cache-manager.md +336 -0
- package/docs/design-philosophy.md +602 -0
- package/docs/dsl-syntax.md +654 -0
- package/docs/dynamic-locale.md +552 -0
- package/docs/error-handling.md +703 -0
- package/docs/export-guide.md +459 -0
- package/docs/faq.md +576 -0
- package/docs/frontend-i18n-guide.md +290 -0
- package/docs/i18n-user-guide.md +488 -0
- package/docs/label-vs-description.md +262 -0
- package/docs/markdown-exporter.md +398 -0
- package/docs/mongodb-exporter.md +279 -0
- package/docs/multi-type-support.md +319 -0
- package/docs/mysql-exporter.md +257 -0
- package/docs/plugin-system.md +542 -0
- package/docs/postgresql-exporter.md +290 -0
- package/docs/quick-start.md +761 -0
- package/docs/schema-helper.md +340 -0
- package/docs/schema-utils.md +492 -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.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/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/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/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 +270 -0
- package/index.mjs +30 -0
- package/lib/adapters/DslAdapter.js +653 -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 +316 -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 +313 -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,448 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 插件管理器
|
|
3
|
+
*
|
|
4
|
+
* @description SchemaIO 插件系统的核心类,负责插件的注册、加载和生命周期管理
|
|
5
|
+
* @module lib/core/PluginManager
|
|
6
|
+
* @version 2.2.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const EventEmitter = require('events');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 插件生命周期钩子
|
|
13
|
+
* @typedef {Object} PluginHooks
|
|
14
|
+
* @property {Function} onBeforeRegister - 注册前钩子
|
|
15
|
+
* @property {Function} onAfterRegister - 注册后钩子
|
|
16
|
+
* @property {Function} onBeforeValidate - 验证前钩子
|
|
17
|
+
* @property {Function} onAfterValidate - 验证后钩子
|
|
18
|
+
* @property {Function} onError - 错误处理钩子
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 插件配置
|
|
23
|
+
* @typedef {Object} PluginConfig
|
|
24
|
+
* @property {string} name - 插件名称(必填)
|
|
25
|
+
* @property {string} version - 插件版本
|
|
26
|
+
* @property {string} description - 插件描述
|
|
27
|
+
* @property {Function} install - 插件安装函数(必填)
|
|
28
|
+
* @property {Function} [uninstall] - 插件卸载函数
|
|
29
|
+
* @property {PluginHooks} [hooks] - 生命周期钩子
|
|
30
|
+
* @property {Object} [options] - 插件选项
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
class PluginManager extends EventEmitter {
|
|
34
|
+
constructor() {
|
|
35
|
+
super();
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 已注册的插件
|
|
39
|
+
* @type {Map<string, PluginConfig>}
|
|
40
|
+
*/
|
|
41
|
+
this.plugins = new Map();
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 钩子函数集合
|
|
45
|
+
* @type {Map<string, Array<Function>>}
|
|
46
|
+
*/
|
|
47
|
+
this.hooks = new Map();
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 插件上下文
|
|
51
|
+
* @type {Object}
|
|
52
|
+
*/
|
|
53
|
+
this.context = {
|
|
54
|
+
plugins: this.plugins,
|
|
55
|
+
hooks: this.hooks
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// 初始化钩子
|
|
59
|
+
this._initializeHooks();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 初始化默认钩子
|
|
64
|
+
* @private
|
|
65
|
+
*/
|
|
66
|
+
_initializeHooks() {
|
|
67
|
+
const defaultHooks = [
|
|
68
|
+
'onBeforeRegister',
|
|
69
|
+
'onAfterRegister',
|
|
70
|
+
'onBeforeValidate',
|
|
71
|
+
'onAfterValidate',
|
|
72
|
+
'onError',
|
|
73
|
+
'onBeforeExport',
|
|
74
|
+
'onAfterExport',
|
|
75
|
+
'onBeforeCompile',
|
|
76
|
+
'onAfterCompile'
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
defaultHooks.forEach(hookName => {
|
|
80
|
+
this.hooks.set(hookName, []);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 注册插件
|
|
86
|
+
*
|
|
87
|
+
* @param {PluginConfig} plugin - 插件配置
|
|
88
|
+
* @throws {Error} 插件配置无效时抛出错误
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```javascript
|
|
92
|
+
* const pluginManager = new PluginManager();
|
|
93
|
+
*
|
|
94
|
+
* pluginManager.register({
|
|
95
|
+
* name: 'custom-validator',
|
|
96
|
+
* version: '1.0.0',
|
|
97
|
+
* install(coreInstance, options) {
|
|
98
|
+
* // 安装逻辑
|
|
99
|
+
* }
|
|
100
|
+
* });
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
register(plugin) {
|
|
104
|
+
// 验证插件配置
|
|
105
|
+
this._validatePlugin(plugin);
|
|
106
|
+
|
|
107
|
+
const { name } = plugin;
|
|
108
|
+
|
|
109
|
+
// 检查插件是否已注册
|
|
110
|
+
if (this.plugins.has(name)) {
|
|
111
|
+
throw new Error(`Plugin "${name}" is already registered`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 触发注册前钩子
|
|
115
|
+
this._runHook('onBeforeRegister', plugin);
|
|
116
|
+
|
|
117
|
+
// 注册插件
|
|
118
|
+
this.plugins.set(name, plugin);
|
|
119
|
+
|
|
120
|
+
// 注册插件的钩子
|
|
121
|
+
if (plugin.hooks) {
|
|
122
|
+
Object.keys(plugin.hooks).forEach(hookName => {
|
|
123
|
+
this.hook(hookName, plugin.hooks[hookName]);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 触发注册后钩子
|
|
128
|
+
this._runHook('onAfterRegister', plugin);
|
|
129
|
+
|
|
130
|
+
// 触发事件
|
|
131
|
+
this.emit('plugin:registered', plugin);
|
|
132
|
+
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* 验证插件配置
|
|
138
|
+
* @private
|
|
139
|
+
* @param {PluginConfig} plugin - 插件配置
|
|
140
|
+
* @throws {Error} 配置无效时抛出错误
|
|
141
|
+
*/
|
|
142
|
+
_validatePlugin(plugin) {
|
|
143
|
+
if (!plugin || typeof plugin !== 'object') {
|
|
144
|
+
throw new Error('Plugin must be an object');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (!plugin.name || typeof plugin.name !== 'string') {
|
|
148
|
+
throw new Error('Plugin must have a valid name');
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!plugin.install || typeof plugin.install !== 'function') {
|
|
152
|
+
throw new Error('Plugin must have an install function');
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* 安装插件
|
|
158
|
+
*
|
|
159
|
+
* @param {Object} coreInstance - SchemaIO 实例
|
|
160
|
+
* @param {string} [pluginName] - 插件名称(可选,如果不指定则安装所有插件)
|
|
161
|
+
* @param {Object} [options] - 安装选项
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```javascript
|
|
165
|
+
* // 安装单个插件
|
|
166
|
+
* pluginManager.install(coreInstance, 'custom-validator', { strict: true });
|
|
167
|
+
*
|
|
168
|
+
* // 安装所有插件
|
|
169
|
+
* pluginManager.install(schema-dsl);
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
install(coreInstance, pluginName, options = {}) {
|
|
173
|
+
if (!pluginName) {
|
|
174
|
+
// 安装所有插件
|
|
175
|
+
this.plugins.forEach((plugin, name) => {
|
|
176
|
+
this._installPlugin(coreInstance, plugin, options);
|
|
177
|
+
});
|
|
178
|
+
return this;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const plugin = this.plugins.get(pluginName);
|
|
182
|
+
if (!plugin) {
|
|
183
|
+
throw new Error(`Plugin "${pluginName}" not found`);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
this._installPlugin(coreInstance, plugin, options);
|
|
187
|
+
return this;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* 安装单个插件
|
|
192
|
+
* @private
|
|
193
|
+
* @param {Object} coreInstance - SchemaIO 实例
|
|
194
|
+
* @param {PluginConfig} plugin - 插件配置
|
|
195
|
+
* @param {Object} options - 安装选项
|
|
196
|
+
*/
|
|
197
|
+
_installPlugin(coreInstance, plugin, options = {}) {
|
|
198
|
+
try {
|
|
199
|
+
// 合并选项
|
|
200
|
+
const pluginOptions = { ...plugin.options, ...options };
|
|
201
|
+
|
|
202
|
+
// 执行安装函数
|
|
203
|
+
plugin.install(coreInstance, pluginOptions, this.context);
|
|
204
|
+
|
|
205
|
+
// 触发事件
|
|
206
|
+
this.emit('plugin:installed', plugin);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
this.emit('plugin:error', { plugin, error });
|
|
209
|
+
throw new Error(`Failed to install plugin "${plugin.name}": ${error.message}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* 卸载插件
|
|
215
|
+
*
|
|
216
|
+
* @param {string} pluginName - 插件名称
|
|
217
|
+
* @param {Object} coreInstance - SchemaIO 实例
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```javascript
|
|
221
|
+
* pluginManager.uninstall('custom-validator', coreInstance);
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
uninstall(pluginName, coreInstance) {
|
|
225
|
+
const plugin = this.plugins.get(pluginName);
|
|
226
|
+
if (!plugin) {
|
|
227
|
+
throw new Error(`Plugin "${pluginName}" not found`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// 执行卸载函数(如果有)
|
|
231
|
+
if (plugin.uninstall && typeof plugin.uninstall === 'function') {
|
|
232
|
+
try {
|
|
233
|
+
plugin.uninstall(coreInstance, this.context);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
this.emit('plugin:error', { plugin, error });
|
|
236
|
+
throw new Error(`Failed to uninstall plugin "${pluginName}": ${error.message}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// 移除插件的钩子
|
|
241
|
+
if (plugin.hooks) {
|
|
242
|
+
Object.keys(plugin.hooks).forEach(hookName => {
|
|
243
|
+
this.unhook(hookName, plugin.hooks[hookName]);
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// 从注册表中移除
|
|
248
|
+
this.plugins.delete(pluginName);
|
|
249
|
+
|
|
250
|
+
// 触发事件
|
|
251
|
+
this.emit('plugin:uninstalled', plugin);
|
|
252
|
+
|
|
253
|
+
return this;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* 注册钩子函数
|
|
258
|
+
*
|
|
259
|
+
* @param {string} hookName - 钩子名称
|
|
260
|
+
* @param {Function} handler - 钩子处理函数
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```javascript
|
|
264
|
+
* pluginManager.hook('onBeforeValidate', (schema, data) => {
|
|
265
|
+
* console.log('Before validation:', schema, data);
|
|
266
|
+
* });
|
|
267
|
+
* ```
|
|
268
|
+
*/
|
|
269
|
+
hook(hookName, handler) {
|
|
270
|
+
if (typeof handler !== 'function') {
|
|
271
|
+
throw new Error('Hook handler must be a function');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (!this.hooks.has(hookName)) {
|
|
275
|
+
this.hooks.set(hookName, []);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
this.hooks.get(hookName).push(handler);
|
|
279
|
+
return this;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* 移除钩子函数
|
|
284
|
+
*
|
|
285
|
+
* @param {string} hookName - 钩子名称
|
|
286
|
+
* @param {Function} handler - 钩子处理函数
|
|
287
|
+
*/
|
|
288
|
+
unhook(hookName, handler) {
|
|
289
|
+
if (!this.hooks.has(hookName)) {
|
|
290
|
+
return this;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const handlers = this.hooks.get(hookName);
|
|
294
|
+
const index = handlers.indexOf(handler);
|
|
295
|
+
if (index !== -1) {
|
|
296
|
+
handlers.splice(index, 1);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return this;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* 运行钩子
|
|
304
|
+
*
|
|
305
|
+
* @param {string} hookName - 钩子名称
|
|
306
|
+
* @param {...any} args - 钩子参数
|
|
307
|
+
* @returns {Promise<any[]>} 钩子返回值数组
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* ```javascript
|
|
311
|
+
* const results = await pluginManager.runHook('onBeforeValidate', schema, data);
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
async runHook(hookName, ...args) {
|
|
315
|
+
if (!this.hooks.has(hookName)) {
|
|
316
|
+
return [];
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const handlers = this.hooks.get(hookName);
|
|
320
|
+
const results = [];
|
|
321
|
+
|
|
322
|
+
for (const handler of handlers) {
|
|
323
|
+
try {
|
|
324
|
+
const result = await handler(...args);
|
|
325
|
+
results.push(result);
|
|
326
|
+
} catch (error) {
|
|
327
|
+
this.emit('hook:error', { hookName, handler, error });
|
|
328
|
+
// 运行错误钩子
|
|
329
|
+
this._runHook('onError', error, { hookName, handler });
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
return results;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* 同步运行钩子(不等待异步)
|
|
338
|
+
* @private
|
|
339
|
+
* @param {string} hookName - 钩子名称
|
|
340
|
+
* @param {...any} args - 钩子参数
|
|
341
|
+
*/
|
|
342
|
+
_runHook(hookName, ...args) {
|
|
343
|
+
if (!this.hooks.has(hookName)) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const handlers = this.hooks.get(hookName);
|
|
348
|
+
handlers.forEach(handler => {
|
|
349
|
+
try {
|
|
350
|
+
handler(...args);
|
|
351
|
+
} catch (error) {
|
|
352
|
+
this.emit('hook:error', { hookName, handler, error });
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* 获取已注册的插件
|
|
359
|
+
*
|
|
360
|
+
* @param {string} [pluginName] - 插件名称(可选)
|
|
361
|
+
* @returns {PluginConfig|Map<string, PluginConfig>} 插件配置或插件集合
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
364
|
+
* ```javascript
|
|
365
|
+
* // 获取单个插件
|
|
366
|
+
* const plugin = pluginManager.get('custom-validator');
|
|
367
|
+
*
|
|
368
|
+
* // 获取所有插件
|
|
369
|
+
* const allPlugins = pluginManager.get();
|
|
370
|
+
* ```
|
|
371
|
+
*/
|
|
372
|
+
get(pluginName) {
|
|
373
|
+
if (pluginName) {
|
|
374
|
+
return this.plugins.get(pluginName);
|
|
375
|
+
}
|
|
376
|
+
return this.plugins;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* 检查插件是否已注册
|
|
381
|
+
*
|
|
382
|
+
* @param {string} pluginName - 插件名称
|
|
383
|
+
* @returns {boolean} 是否已注册
|
|
384
|
+
*/
|
|
385
|
+
has(pluginName) {
|
|
386
|
+
return this.plugins.has(pluginName);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* 获取插件列表
|
|
391
|
+
*
|
|
392
|
+
* @returns {Array<{name: string, version: string, description: string}>} 插件列表
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
* ```javascript
|
|
396
|
+
* const pluginList = pluginManager.list();
|
|
397
|
+
* console.log(pluginList);
|
|
398
|
+
* // [
|
|
399
|
+
* // { name: 'custom-validator', version: '1.0.0', description: '...' },
|
|
400
|
+
* // { name: 'custom-format', version: '1.0.0', description: '...' }
|
|
401
|
+
* // ]
|
|
402
|
+
* ```
|
|
403
|
+
*/
|
|
404
|
+
list() {
|
|
405
|
+
return Array.from(this.plugins.values()).map(plugin => ({
|
|
406
|
+
name: plugin.name,
|
|
407
|
+
version: plugin.version || 'unknown',
|
|
408
|
+
description: plugin.description || ''
|
|
409
|
+
}));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* 清空所有插件
|
|
414
|
+
*
|
|
415
|
+
* @param {Object} coreInstance - SchemaIO 实例
|
|
416
|
+
*/
|
|
417
|
+
clear(coreInstance) {
|
|
418
|
+
// 卸载所有插件
|
|
419
|
+
Array.from(this.plugins.keys()).forEach(name => {
|
|
420
|
+
try {
|
|
421
|
+
this.uninstall(name, coreInstance);
|
|
422
|
+
} catch (error) {
|
|
423
|
+
// 忽略卸载错误
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// 清空注册表
|
|
428
|
+
this.plugins.clear();
|
|
429
|
+
|
|
430
|
+
// 清空钩子
|
|
431
|
+
this.hooks.forEach(handlers => handlers.length = 0);
|
|
432
|
+
|
|
433
|
+
this.emit('plugins:cleared');
|
|
434
|
+
return this;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* 获取插件数量
|
|
439
|
+
*
|
|
440
|
+
* @returns {number} 插件数量
|
|
441
|
+
*/
|
|
442
|
+
get size() {
|
|
443
|
+
return this.plugins.size;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
module.exports = PluginManager;
|
|
448
|
+
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* String.prototype 扩展
|
|
3
|
+
*
|
|
4
|
+
* 让字符串可以直接链式调用 DSL 方法
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* 'email!'.pattern(/custom/).label('邮箱')
|
|
8
|
+
* 'string:3-32!'.messages({ ... }).label('用户名')
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 安装 String 扩展
|
|
13
|
+
* @param {Function} dslFunction - dsl() 函数
|
|
14
|
+
*/
|
|
15
|
+
function installStringExtensions(dslFunction) {
|
|
16
|
+
// 检查是否已安装
|
|
17
|
+
if (String.prototype._dslExtensionsInstalled) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 添加正则验证
|
|
23
|
+
* @param {RegExp} regex - 正则表达式
|
|
24
|
+
* @param {string} [message] - 错误消息
|
|
25
|
+
* @returns {DslBuilder}
|
|
26
|
+
*/
|
|
27
|
+
String.prototype.pattern = function(regex, message) {
|
|
28
|
+
return dslFunction(String(this)).pattern(regex, message);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 设置字段标签
|
|
33
|
+
* @param {string} label - 标签文本
|
|
34
|
+
* @returns {DslBuilder}
|
|
35
|
+
*/
|
|
36
|
+
String.prototype.label = function(label) {
|
|
37
|
+
return dslFunction(String(this)).label(label);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 自定义错误消息
|
|
42
|
+
* @param {Object} messages - 消息对象
|
|
43
|
+
* @returns {DslBuilder}
|
|
44
|
+
*/
|
|
45
|
+
String.prototype.messages = function(messages) {
|
|
46
|
+
return dslFunction(String(this)).messages(messages);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 设置描述
|
|
51
|
+
* @param {string} text - 描述文本
|
|
52
|
+
* @returns {DslBuilder}
|
|
53
|
+
*/
|
|
54
|
+
String.prototype.description = function(text) {
|
|
55
|
+
return dslFunction(String(this)).description(text);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 设置格式
|
|
60
|
+
* @param {string} format - 格式名称
|
|
61
|
+
* @returns {DslBuilder}
|
|
62
|
+
*/
|
|
63
|
+
String.prototype.format = function(format) {
|
|
64
|
+
return dslFunction(String(this)).format(format);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 添加自定义验证器
|
|
69
|
+
* @param {Function} validator - 验证函数
|
|
70
|
+
* @returns {DslBuilder}
|
|
71
|
+
*/
|
|
72
|
+
String.prototype.custom = function(validator) {
|
|
73
|
+
return dslFunction(String(this)).custom(validator);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 设置默认值
|
|
79
|
+
* @param {*} value - 默认值
|
|
80
|
+
* @returns {DslBuilder}
|
|
81
|
+
*/
|
|
82
|
+
String.prototype.default = function(value) {
|
|
83
|
+
return dslFunction(String(this)).default(value);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 转为 Schema
|
|
88
|
+
* @returns {Object}
|
|
89
|
+
*/
|
|
90
|
+
String.prototype.toSchema = function() {
|
|
91
|
+
return dslFunction(String(this)).toSchema();
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 用户名验证
|
|
96
|
+
* @param {Object} options - 选项
|
|
97
|
+
* @returns {DslBuilder}
|
|
98
|
+
*/
|
|
99
|
+
String.prototype.username = function(options) {
|
|
100
|
+
return dslFunction(String(this)).username(options);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 密码强度验证
|
|
105
|
+
* @param {string} strength - 强度级别
|
|
106
|
+
* @returns {DslBuilder}
|
|
107
|
+
*/
|
|
108
|
+
String.prototype.password = function(strength) {
|
|
109
|
+
return dslFunction(String(this)).password(strength);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 手机号验证
|
|
114
|
+
* @param {string} country - 国家代码
|
|
115
|
+
* @returns {DslBuilder}
|
|
116
|
+
*/
|
|
117
|
+
String.prototype.phone = function(country) {
|
|
118
|
+
return dslFunction(String(this)).phone(country);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* 手机号验证(别名)
|
|
123
|
+
* @param {string} country - 国家代码
|
|
124
|
+
* @returns {DslBuilder}
|
|
125
|
+
*/
|
|
126
|
+
String.prototype.phoneNumber = function(country) {
|
|
127
|
+
return dslFunction(String(this)).phone(country);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 身份证验证
|
|
132
|
+
* @param {string} country - 国家代码
|
|
133
|
+
* @returns {DslBuilder}
|
|
134
|
+
*/
|
|
135
|
+
String.prototype.idCard = function(country) {
|
|
136
|
+
return dslFunction(String(this)).idCard(country);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* 信用卡验证
|
|
141
|
+
* @param {string} type - 卡类型
|
|
142
|
+
* @returns {DslBuilder}
|
|
143
|
+
*/
|
|
144
|
+
String.prototype.creditCard = function(type) {
|
|
145
|
+
return dslFunction(String(this)).creditCard(type);
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 车牌号验证
|
|
150
|
+
* @param {string} country - 国家代码
|
|
151
|
+
* @returns {DslBuilder}
|
|
152
|
+
*/
|
|
153
|
+
String.prototype.licensePlate = function(country) {
|
|
154
|
+
return dslFunction(String(this)).licensePlate(country);
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* 邮政编码验证
|
|
159
|
+
* @param {string} country - 国家代码
|
|
160
|
+
* @returns {DslBuilder}
|
|
161
|
+
*/
|
|
162
|
+
String.prototype.postalCode = function(country) {
|
|
163
|
+
return dslFunction(String(this)).postalCode(country);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* 护照号码验证
|
|
168
|
+
* @param {string} country - 国家代码
|
|
169
|
+
* @returns {DslBuilder}
|
|
170
|
+
*/
|
|
171
|
+
String.prototype.passport = function(country) {
|
|
172
|
+
return dslFunction(String(this)).passport(country);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
// 标记已安装
|
|
176
|
+
String.prototype._dslExtensionsInstalled = true;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* 卸载 String 扩展(测试或清理用)
|
|
181
|
+
*/
|
|
182
|
+
function uninstallStringExtensions() {
|
|
183
|
+
if (!String.prototype._dslExtensionsInstalled) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
delete String.prototype.pattern;
|
|
188
|
+
delete String.prototype.label;
|
|
189
|
+
delete String.prototype.messages;
|
|
190
|
+
delete String.prototype.description;
|
|
191
|
+
delete String.prototype.custom;
|
|
192
|
+
delete String.prototype.when;
|
|
193
|
+
delete String.prototype.default;
|
|
194
|
+
delete String.prototype.toSchema;
|
|
195
|
+
delete String.prototype.username;
|
|
196
|
+
delete String.prototype.password;
|
|
197
|
+
delete String.prototype.phone;
|
|
198
|
+
delete String.prototype.idCard;
|
|
199
|
+
delete String.prototype.creditCard;
|
|
200
|
+
delete String.prototype.licensePlate;
|
|
201
|
+
delete String.prototype.postalCode;
|
|
202
|
+
delete String.prototype.passport;
|
|
203
|
+
delete String.prototype._dslExtensionsInstalled;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
module.exports = {
|
|
207
|
+
installStringExtensions,
|
|
208
|
+
uninstallStringExtensions
|
|
209
|
+
};
|