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.
Files changed (116) hide show
  1. package/.eslintignore +10 -0
  2. package/.eslintrc.json +27 -0
  3. package/.github/CODE_OF_CONDUCT.md +45 -0
  4. package/.github/ISSUE_TEMPLATE/bug_report.md +57 -0
  5. package/.github/ISSUE_TEMPLATE/config.yml +11 -0
  6. package/.github/ISSUE_TEMPLATE/feature_request.md +45 -0
  7. package/.github/ISSUE_TEMPLATE/question.md +31 -0
  8. package/.github/PULL_REQUEST_TEMPLATE.md +70 -0
  9. package/.github/SECURITY.md +184 -0
  10. package/.github/workflows/ci.yml +33 -0
  11. package/CHANGELOG.md +633 -0
  12. package/CONTRIBUTING.md +368 -0
  13. package/LICENSE +21 -0
  14. package/README.md +1184 -0
  15. package/STATUS.md +101 -0
  16. package/docs/FEATURE-INDEX.md +519 -0
  17. package/docs/INDEX.md +253 -0
  18. package/docs/api-reference.md +1096 -0
  19. package/docs/best-practices.md +672 -0
  20. package/docs/cache-manager.md +336 -0
  21. package/docs/design-philosophy.md +601 -0
  22. package/docs/dsl-syntax.md +653 -0
  23. package/docs/dynamic-locale.md +552 -0
  24. package/docs/error-handling.md +703 -0
  25. package/docs/export-guide.md +462 -0
  26. package/docs/export-limitations.md +551 -0
  27. package/docs/faq.md +577 -0
  28. package/docs/frontend-i18n-guide.md +290 -0
  29. package/docs/i18n-user-guide.md +476 -0
  30. package/docs/label-vs-description.md +262 -0
  31. package/docs/markdown-exporter.md +397 -0
  32. package/docs/mongodb-exporter.md +295 -0
  33. package/docs/multi-type-support.md +319 -0
  34. package/docs/mysql-exporter.md +273 -0
  35. package/docs/plugin-system.md +542 -0
  36. package/docs/postgresql-exporter.md +304 -0
  37. package/docs/quick-start.md +761 -0
  38. package/docs/schema-helper.md +340 -0
  39. package/docs/schema-utils-chaining.md +143 -0
  40. package/docs/schema-utils.md +490 -0
  41. package/docs/string-extensions.md +480 -0
  42. package/docs/troubleshooting.md +471 -0
  43. package/docs/type-converter.md +319 -0
  44. package/docs/type-reference.md +219 -0
  45. package/docs/validate-async.md +480 -0
  46. package/docs/validate.md +486 -0
  47. package/docs/validation-guide.md +484 -0
  48. package/examples/array-dsl-example.js +227 -0
  49. package/examples/custom-extension.js +85 -0
  50. package/examples/dsl-match-example.js +74 -0
  51. package/examples/dsl-style.js +118 -0
  52. package/examples/dynamic-locale-configuration.js +348 -0
  53. package/examples/dynamic-locale-example.js +287 -0
  54. package/examples/export-demo.js +130 -0
  55. package/examples/express-integration.js +376 -0
  56. package/examples/i18n-full-demo.js +310 -0
  57. package/examples/i18n-memory-safety.examples.js +268 -0
  58. package/examples/markdown-export.js +71 -0
  59. package/examples/middleware-usage.js +93 -0
  60. package/examples/new-features-comparison.js +315 -0
  61. package/examples/password-reset/README.md +153 -0
  62. package/examples/password-reset/schema.js +26 -0
  63. package/examples/password-reset/test.js +101 -0
  64. package/examples/plugin-system.examples.js +205 -0
  65. package/examples/schema-utils-chaining.examples.js +250 -0
  66. package/examples/simple-example.js +122 -0
  67. package/examples/string-extensions.js +297 -0
  68. package/examples/user-registration/README.md +156 -0
  69. package/examples/user-registration/routes.js +92 -0
  70. package/examples/user-registration/schema.js +150 -0
  71. package/examples/user-registration/server.js +74 -0
  72. package/index.d.ts +1999 -0
  73. package/index.js +282 -0
  74. package/index.mjs +30 -0
  75. package/lib/adapters/DslAdapter.js +699 -0
  76. package/lib/adapters/index.js +20 -0
  77. package/lib/config/constants.js +286 -0
  78. package/lib/config/patterns/creditCard.js +9 -0
  79. package/lib/config/patterns/idCard.js +9 -0
  80. package/lib/config/patterns/index.js +8 -0
  81. package/lib/config/patterns/licensePlate.js +4 -0
  82. package/lib/config/patterns/passport.js +4 -0
  83. package/lib/config/patterns/phone.js +9 -0
  84. package/lib/config/patterns/postalCode.js +5 -0
  85. package/lib/core/CacheManager.js +376 -0
  86. package/lib/core/DslBuilder.js +740 -0
  87. package/lib/core/ErrorCodes.js +233 -0
  88. package/lib/core/ErrorFormatter.js +342 -0
  89. package/lib/core/JSONSchemaCore.js +347 -0
  90. package/lib/core/Locale.js +119 -0
  91. package/lib/core/MessageTemplate.js +89 -0
  92. package/lib/core/PluginManager.js +448 -0
  93. package/lib/core/StringExtensions.js +209 -0
  94. package/lib/core/Validator.js +376 -0
  95. package/lib/errors/ValidationError.js +191 -0
  96. package/lib/exporters/MarkdownExporter.js +420 -0
  97. package/lib/exporters/MongoDBExporter.js +162 -0
  98. package/lib/exporters/MySQLExporter.js +212 -0
  99. package/lib/exporters/PostgreSQLExporter.js +289 -0
  100. package/lib/exporters/index.js +24 -0
  101. package/lib/locales/en-US.js +65 -0
  102. package/lib/locales/es-ES.js +66 -0
  103. package/lib/locales/fr-FR.js +66 -0
  104. package/lib/locales/index.js +8 -0
  105. package/lib/locales/ja-JP.js +66 -0
  106. package/lib/locales/zh-CN.js +93 -0
  107. package/lib/utils/LRUCache.js +174 -0
  108. package/lib/utils/SchemaHelper.js +240 -0
  109. package/lib/utils/SchemaUtils.js +445 -0
  110. package/lib/utils/TypeConverter.js +245 -0
  111. package/lib/utils/index.js +13 -0
  112. package/lib/validators/CustomKeywords.js +203 -0
  113. package/lib/validators/index.js +11 -0
  114. package/package.json +70 -0
  115. package/plugins/custom-format.js +101 -0
  116. package/plugins/custom-validator.js +200 -0
@@ -0,0 +1,542 @@
1
+ # 插件系统
2
+
3
+
4
+ > **更新**: 2025-12-26
5
+ > **状态**: ✅ 稳定
6
+
7
+ ---
8
+
9
+ ## 📑 目录
10
+
11
+ - [概述](#概述)
12
+ - [快速开始](#快速开始)
13
+ - [插件开发](#插件开发)
14
+ - [钩子系统](#钩子系统)
15
+ - [官方插件](#官方插件)
16
+ - [最佳实践](#最佳实践)
17
+ - [API 参考](#api-参考)
18
+
19
+ ---
20
+
21
+ ## 概述
22
+
23
+ SchemaIO 插件系统允许你扩展核心功能,添加自定义验证器、格式化器、导出器等。
24
+
25
+ ### 特性
26
+
27
+ ✅ **动态加载** - 运行时注册/卸载插件
28
+ ✅ **生命周期钩子** - 在关键时刻执行自定义逻辑
29
+ ✅ **事件驱动** - 基于 EventEmitter 的事件系统
30
+ ✅ **依赖管理** - 插件间通信和依赖注入
31
+ ✅ **TypeScript 支持** - 完整的类型定义
32
+
33
+ ### 架构
34
+
35
+ ```
36
+ PluginManager
37
+ ├── 插件注册表 (Map)
38
+ ├── 钩子系统 (Hooks)
39
+ ├── 事件系统 (EventEmitter)
40
+ └── 上下文 (Context)
41
+ ```
42
+
43
+ ---
44
+
45
+ ## 快速开始
46
+
47
+ ### 1. 创建插件管理器
48
+
49
+ ```javascript
50
+ const { PluginManager } = require('schema-dsl');
51
+
52
+ const pluginManager = new PluginManager();
53
+ ```
54
+
55
+ ### 2. 注册插件
56
+
57
+ ```javascript
58
+ const myPlugin = {
59
+ name: 'my-plugin',
60
+ version: '1.0.0',
61
+ description: '我的自定义插件',
62
+
63
+ install(schema-dsl, options, context) {
64
+ console.log('插件安装成功!');
65
+ }
66
+ };
67
+
68
+ pluginManager.register(myPlugin);
69
+ ```
70
+
71
+ ### 3. 安装插件
72
+
73
+ ```javascript
74
+ const schema-dsl = require('schema-dsl');
75
+
76
+ pluginManager.install(schema-dsl, 'my-plugin');
77
+ ```
78
+
79
+ ### 4. 使用插件
80
+
81
+ 插件安装后,自动生效,无需额外配置。
82
+
83
+ ---
84
+
85
+ ## 插件开发
86
+
87
+ ### 插件结构
88
+
89
+ 一个标准的插件对象包含以下字段:
90
+
91
+ ```javascript
92
+ module.exports = {
93
+ // ========== 必填 ==========
94
+ name: 'plugin-name', // 插件名称(唯一)
95
+ install: function(schema-dsl, options, context) {
96
+ // 安装逻辑
97
+ },
98
+
99
+ // ========== 可选 ==========
100
+ version: '1.0.0', // 插件版本
101
+ description: '插件描述', // 插件描述
102
+ uninstall: function(schema-dsl, context) {
103
+ // 卸载逻辑
104
+ },
105
+ hooks: { // 生命周期钩子
106
+ onBeforeValidate: function() {},
107
+ onAfterValidate: function() {}
108
+ },
109
+ options: { // 默认选项
110
+ enabled: true
111
+ }
112
+ };
113
+ ```
114
+
115
+ ### 示例:自定义验证器插件
116
+
117
+ ```javascript
118
+ module.exports = {
119
+ name: 'custom-validator',
120
+ version: '1.0.0',
121
+
122
+ install(schema-dsl, options, context) {
123
+ const { Validator } = schema-dsl;
124
+
125
+ // 添加自定义关键字
126
+ Validator.prototype.addKeyword('unique', {
127
+ async: true,
128
+ validate: async function(schema, data) {
129
+ // 验证逻辑
130
+ const exists = await checkDatabase(data);
131
+ return !exists;
132
+ }
133
+ });
134
+ }
135
+ };
136
+ ```
137
+
138
+ ### 示例:自定义格式插件
139
+
140
+ ```javascript
141
+ module.exports = {
142
+ name: 'custom-format',
143
+ version: '1.0.0',
144
+
145
+ install(schema-dsl, options, context) {
146
+ const validator = schemaDsl.getDefaultValidator();
147
+ const ajv = validator.getAjv();
148
+
149
+ // 添加自定义格式
150
+ ajv.addFormat('phone-cn', {
151
+ validate: /^1[3-9]\d{9}$/
152
+ });
153
+ }
154
+ };
155
+ ```
156
+
157
+ ---
158
+
159
+ ## 钩子系统
160
+
161
+ ### 可用钩子
162
+
163
+ | 钩子名称 | 触发时机 | 参数 |
164
+ |---------|---------|------|
165
+ | `onBeforeRegister` | 插件注册前 | `(plugin)` |
166
+ | `onAfterRegister` | 插件注册后 | `(plugin)` |
167
+ | `onBeforeValidate` | 验证前 | `(schema, data)` |
168
+ | `onAfterValidate` | 验证后 | `(result)` |
169
+ | `onBeforeExport` | 导出前 | `(schema, options)` |
170
+ | `onAfterExport` | 导出后 | `(result)` |
171
+ | `onError` | 错误发生时 | `(error, context)` |
172
+
173
+ ### 注册钩子
174
+
175
+ ```javascript
176
+ pluginManager.hook('onBeforeValidate', (schema, data) => {
177
+ console.log('验证前:', schema, data);
178
+ });
179
+ ```
180
+
181
+ ### 运行钩子
182
+
183
+ ```javascript
184
+ const results = await pluginManager.runHook('onBeforeValidate', schema, data);
185
+ ```
186
+
187
+ ### 插件中定义钩子
188
+
189
+ ```javascript
190
+ module.exports = {
191
+ name: 'my-plugin',
192
+
193
+ hooks: {
194
+ onBeforeValidate(schema, data) {
195
+ // 在这里修改 schema 或 data
196
+ },
197
+
198
+ onAfterValidate(result) {
199
+ // 在这里修改验证结果
200
+ }
201
+ }
202
+ };
203
+ ```
204
+
205
+ ---
206
+
207
+ ## 官方插件
208
+
209
+ ### 1. custom-validator
210
+
211
+ 添加业务特定的验证规则。
212
+
213
+ ```javascript
214
+ const customValidator = require('schema-dsl/plugins/custom-validator');
215
+
216
+ pluginManager.register(customValidator);
217
+ pluginManager.install(schema-dsl);
218
+ ```
219
+
220
+ **功能**:
221
+ - `unique` - 唯一性验证(异步)
222
+ - `passwordStrength` - 密码强度验证
223
+ - `idCard` - 身份证号验证
224
+
225
+ ### 2. custom-format
226
+
227
+ 添加常用的格式验证。
228
+
229
+ ```javascript
230
+ const customFormat = require('schema-dsl/plugins/custom-format');
231
+
232
+ pluginManager.register(customFormat);
233
+ pluginManager.install(schema-dsl);
234
+ ```
235
+
236
+ **格式**:
237
+ - `phone-cn` - 中国手机号
238
+ - `postal-code-cn` - 邮政编码
239
+ - `wechat` - 微信号
240
+ - `qq` - QQ号
241
+ - `bank-card` - 银行卡号
242
+ - `license-plate` - 车牌号
243
+
244
+ ---
245
+
246
+ ## 最佳实践
247
+
248
+ ### 1. 插件命名
249
+
250
+ 使用 `kebab-case` 命名:
251
+
252
+ ```javascript
253
+ // ✅ 推荐
254
+ name: 'custom-validator'
255
+ name: 'mongodb-plugin'
256
+
257
+ // ❌ 不推荐
258
+ name: 'CustomValidator'
259
+ name: 'mongodb_plugin'
260
+ ```
261
+
262
+ ### 2. 版本管理
263
+
264
+ 使用语义化版本:
265
+
266
+ ```javascript
267
+ version: '1.0.0' // 主版本.次版本.修订版本
268
+ ```
269
+
270
+ ### 3. 错误处理
271
+
272
+ 插件应该优雅地处理错误:
273
+
274
+ ```javascript
275
+ install(schema-dsl, options, context) {
276
+ try {
277
+ // 安装逻辑
278
+ } catch (error) {
279
+ console.error(`[${this.name}] 安装失败:`, error.message);
280
+ throw error; // 重新抛出,让调用者知道
281
+ }
282
+ }
283
+ ```
284
+
285
+ ### 4. 清理资源
286
+
287
+ 提供 `uninstall` 方法:
288
+
289
+ ```javascript
290
+ uninstall(schema-dsl, context) {
291
+ // 清理注册的验证器、格式、钩子等
292
+ delete schemaDsl.myCustomMethod;
293
+ }
294
+ ```
295
+
296
+ ### 5. 文档
297
+
298
+ 为你的插件编写清晰的文档:
299
+
300
+ ```javascript
301
+ /**
302
+ * 我的自定义插件
303
+ *
304
+ * @description 添加业务特定的验证规则
305
+ *
306
+ * @example
307
+ * ```javascript
308
+ * pluginManager.register(myPlugin);
309
+ * pluginManager.install(schema-dsl);
310
+ * ```
311
+ */
312
+ module.exports = { /* ... */ };
313
+ ```
314
+
315
+ ---
316
+
317
+ ## API 参考
318
+
319
+ ### PluginManager
320
+
321
+ #### `register(plugin)`
322
+
323
+ 注册插件。
324
+
325
+ **参数**:
326
+ - `plugin` (Object) - 插件配置
327
+
328
+ **返回**: `this`
329
+
330
+ **示例**:
331
+ ```javascript
332
+ pluginManager.register({
333
+ name: 'my-plugin',
334
+ install(schema-dsl) {
335
+ // ...
336
+ }
337
+ });
338
+ ```
339
+
340
+ #### `install(schema-dsl, [pluginName], [options])`
341
+
342
+ 安装插件。
343
+
344
+ **参数**:
345
+ - `schema-dsl` (Object) - SchemaIO 实例
346
+ - `pluginName` (String, optional) - 插件名称
347
+ - `options` (Object, optional) - 安装选项
348
+
349
+ **返回**: `this`
350
+
351
+ #### `uninstall(pluginName, schema-dsl)`
352
+
353
+ 卸载插件。
354
+
355
+ **参数**:
356
+ - `pluginName` (String) - 插件名称
357
+ - `schema-dsl` (Object) - SchemaIO 实例
358
+
359
+ **返回**: `this`
360
+
361
+ #### `hook(hookName, handler)`
362
+
363
+ 注册钩子。
364
+
365
+ **参数**:
366
+ - `hookName` (String) - 钩子名称
367
+ - `handler` (Function) - 钩子处理函数
368
+
369
+ **返回**: `this`
370
+
371
+ #### `runHook(hookName, ...args)`
372
+
373
+ 运行钩子。
374
+
375
+ **参数**:
376
+ - `hookName` (String) - 钩子名称
377
+ - `...args` (any) - 钩子参数
378
+
379
+ **返回**: `Promise<any[]>`
380
+
381
+ #### `list()`
382
+
383
+ 获取插件列表。
384
+
385
+ **返回**: `Array<{name, version, description}>`
386
+
387
+ #### `has(pluginName)`
388
+
389
+ 检查插件是否存在。
390
+
391
+ **参数**:
392
+ - `pluginName` (String) - 插件名称
393
+
394
+ **返回**: `Boolean`
395
+
396
+ #### `clear(schema-dsl)`
397
+
398
+ 清空所有插件。
399
+
400
+ **参数**:
401
+ - `schema-dsl` (Object) - SchemaIO 实例
402
+
403
+ **返回**: `this`
404
+
405
+ ---
406
+
407
+ ## 事件系统
408
+
409
+ PluginManager 继承自 EventEmitter,支持事件监听:
410
+
411
+ ```javascript
412
+ pluginManager.on('plugin:registered', (plugin) => {
413
+ console.log('插件已注册:', plugin.name);
414
+ });
415
+
416
+ pluginManager.on('plugin:installed', (plugin) => {
417
+ console.log('插件已安装:', plugin.name);
418
+ });
419
+
420
+ pluginManager.on('plugin:error', ({ plugin, error }) => {
421
+ console.error('插件错误:', plugin.name, error.message);
422
+ });
423
+ ```
424
+
425
+ **可用事件**:
426
+ - `plugin:registered` - 插件注册成功
427
+ - `plugin:installed` - 插件安装成功
428
+ - `plugin:uninstalled` - 插件卸载成功
429
+ - `plugin:error` - 插件错误
430
+ - `hook:error` - 钩子执行错误
431
+ - `plugins:cleared` - 所有插件已清空
432
+
433
+ ---
434
+
435
+ ## 进阶话题
436
+
437
+ ### 1. 插件间通信
438
+
439
+ 通过 `context` 参数访问其他插件:
440
+
441
+ ```javascript
442
+ install(schema-dsl, options, context) {
443
+ // 检查依赖插件
444
+ if (!context.plugins.has('dependency-plugin')) {
445
+ throw new Error('需要先安装 dependency-plugin');
446
+ }
447
+
448
+ // 获取其他插件实例
449
+ const depPlugin = context.plugins.get('dependency-plugin');
450
+ }
451
+ ```
452
+
453
+ ### 2. 插件配置
454
+
455
+ 通过 `options` 参数传递配置:
456
+
457
+ ```javascript
458
+ // 注册时设置默认配置
459
+ module.exports = {
460
+ name: 'my-plugin',
461
+ options: {
462
+ strict: false,
463
+ maxRetries: 3
464
+ },
465
+
466
+ install(schema-dsl, options) {
467
+ const config = { ...this.options, ...options };
468
+ console.log('配置:', config);
469
+ }
470
+ };
471
+
472
+ // 安装时覆盖配置
473
+ pluginManager.install(schema-dsl, 'my-plugin', {
474
+ strict: true
475
+ });
476
+ ```
477
+
478
+ ### 3. 异步安装
479
+
480
+ 插件安装函数可以是异步的:
481
+
482
+ ```javascript
483
+ module.exports = {
484
+ name: 'async-plugin',
485
+
486
+ async install(schema-dsl, options) {
487
+ // 异步初始化
488
+ await this.loadConfig();
489
+ await this.connectDatabase();
490
+ }
491
+ };
492
+ ```
493
+
494
+ ---
495
+
496
+ ## 故障排查
497
+
498
+ ### 插件未生效
499
+
500
+ 1. 检查插件是否已注册:
501
+ ```javascript
502
+ console.log(pluginManager.has('my-plugin')); // true?
503
+ ```
504
+
505
+ 2. 检查插件是否已安装:
506
+ ```javascript
507
+ pluginManager.list(); // 是否在列表中?
508
+ ```
509
+
510
+ 3. 检查 `install` 函数是否正确执行。
511
+
512
+ ### 钩子未触发
513
+
514
+ 1. 确认钩子名称拼写正确。
515
+ 2. 使用 `pluginManager.hooks.get('hookName')` 查看已注册的钩子。
516
+
517
+ ### 插件冲突
518
+
519
+ 如果两个插件修改同一个方法,后安装的会覆盖前一个。解决方案:
520
+ - 使用不同的方法名
521
+ - 在插件中保存原始方法的引用
522
+
523
+ ---
524
+
525
+ ## 完整示例
526
+
527
+ 见 [examples/plugin-system.examples.js](../examples/plugin-system.examples.js)
528
+
529
+ ---
530
+
531
+ ## 相关文档
532
+
533
+ - [API 参考](api-reference.md)
534
+ - [最佳实践](best-practices.md)
535
+ - [故障排查](troubleshooting.md)
536
+
537
+ ---
538
+
539
+ **贡献**
540
+
541
+ 欢迎提交你的插件到官方插件库!请提交 PR 到 `plugins/` 目录。
542
+