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.
- package/CHANGELOG.md +87 -210
- package/README.md +391 -2249
- package/dist/DslBuilder-DQDN0ZxZ.d.cts +341 -0
- package/dist/DslBuilder-DkLaOo9Q.d.ts +341 -0
- package/dist/Validator-C7GsVQOH.d.cts +192 -0
- package/dist/Validator-hFWKGxir.d.ts +192 -0
- package/dist/index.cjs +6594 -0
- package/dist/index.d.cts +1145 -0
- package/dist/index.d.ts +1145 -0
- package/dist/index.js +6528 -0
- package/dist/plugin-CIKtTMtS.d.cts +246 -0
- package/dist/plugin-CIKtTMtS.d.ts +246 -0
- package/dist/plugins/custom-format.cjs +3802 -0
- package/dist/plugins/custom-format.d.cts +12 -0
- package/dist/plugins/custom-format.d.ts +12 -0
- package/dist/plugins/custom-format.js +3772 -0
- package/dist/plugins/custom-type-example.cjs +3795 -0
- package/dist/plugins/custom-type-example.d.cts +8 -0
- package/dist/plugins/custom-type-example.d.ts +8 -0
- package/dist/plugins/custom-type-example.js +3765 -0
- package/dist/plugins/custom-validator.cjs +146 -0
- package/dist/plugins/custom-validator.d.cts +10 -0
- package/dist/plugins/custom-validator.d.ts +10 -0
- package/dist/plugins/custom-validator.js +121 -0
- package/docs/FEATURE-INDEX.md +102 -68
- package/docs/add-custom-locale.md +48 -35
- package/docs/add-keyword.md +24 -0
- package/docs/api-reference.md +396 -154
- package/docs/api.md +13 -0
- package/docs/best-practices-project-structure.md +19 -10
- package/docs/best-practices.md +93 -53
- package/docs/cache-manager.md +23 -15
- package/docs/compile.md +45 -0
- package/docs/conditional-api.md +40 -11
- package/docs/custom-extensions-guide.md +80 -152
- package/docs/design-philosophy.md +76 -71
- package/docs/doc-index.md +324 -0
- package/docs/dsl-syntax.md +69 -19
- package/docs/dynamic-locale.md +24 -14
- package/docs/enum.md +12 -5
- package/docs/error-handling.md +53 -44
- package/docs/export-guide.md +47 -8
- package/docs/export-limitations.md +27 -11
- package/docs/faq.md +86 -67
- package/docs/frontend-i18n-guide.md +26 -12
- package/docs/i18n-user-guide.md +60 -47
- package/docs/i18n.md +51 -32
- package/docs/index.md +48 -0
- package/docs/json-schema-basics.md +40 -0
- package/docs/label-vs-description.md +12 -3
- package/docs/markdown-exporter.md +15 -6
- package/docs/mongodb-exporter.md +11 -4
- package/docs/multi-language.md +26 -0
- package/docs/multi-type-support.md +26 -33
- package/docs/mysql-exporter.md +9 -2
- package/docs/number-operators.md +12 -5
- package/docs/optional-marker-guide.md +28 -23
- package/docs/performance-guide.md +49 -0
- package/docs/plugin-system.md +205 -366
- package/docs/plugin-type-registration.md +34 -0
- package/docs/postgresql-exporter.md +9 -2
- package/docs/public/favicon.svg +5 -0
- package/docs/quick-start.md +37 -363
- package/docs/runtime-locale-support.md +20 -9
- package/docs/schema-helper.md +10 -5
- package/docs/schema-utils-advanced-issues.md +23 -0
- package/docs/schema-utils-best-practices.md +20 -0
- package/docs/schema-utils-chaining.md +7 -0
- package/docs/schema-utils.md +76 -42
- package/docs/security-checklist.md +20 -0
- package/docs/string-extensions.md +17 -9
- package/docs/troubleshooting.md +36 -21
- package/docs/type-converter.md +41 -50
- package/docs/type-reference.md +38 -15
- package/docs/typescript-guide.md +53 -42
- package/docs/union-type-guide.md +11 -1
- package/docs/union-types.md +10 -3
- package/docs/validate-async.md +36 -25
- package/docs/validate-batch.md +49 -0
- package/docs/validate-dsl-object-support.md +33 -28
- package/docs/validate.md +36 -16
- package/docs/validation-guide.md +25 -7
- package/docs/validator.md +39 -0
- package/package.json +85 -27
- package/plugins/custom-format.cjs +8 -0
- package/plugins/custom-type-example.cjs +8 -0
- package/plugins/custom-validator.cjs +8 -0
- package/src/adapters/DslAdapter.ts +111 -0
- package/src/adapters/index.ts +1 -0
- package/src/config/constants.ts +83 -0
- package/src/config/index.ts +2 -0
- package/src/config/patterns.ts +77 -0
- package/src/core/CacheManager.ts +159 -0
- package/src/core/ConditionalBuilder.ts +382 -0
- package/src/core/ConditionalRuntime.ts +28 -0
- package/src/core/ConditionalValidator.ts +255 -0
- package/src/core/DslBuilder.ts +677 -0
- package/src/core/ErrorCodes.ts +38 -0
- package/src/core/ErrorFormatter.ts +271 -0
- package/src/core/JSONSchemaCore.ts +65 -0
- package/src/core/Locale.ts +187 -0
- package/src/core/MessageTemplate.ts +42 -0
- package/src/core/ObjectDslBuilder.ts +64 -0
- package/src/core/PluginManager.ts +326 -0
- package/src/core/StringExtensions.ts +140 -0
- package/src/core/TemplateEngine.ts +44 -0
- package/src/core/Validator.ts +448 -0
- package/src/errors/I18nError.ts +159 -0
- package/src/errors/ValidationError.ts +105 -0
- package/src/exporters/BaseExporter.ts +60 -0
- package/src/exporters/MarkdownExporter.ts +305 -0
- package/src/exporters/MongoDBExporter.ts +126 -0
- package/src/exporters/MySQLExporter.ts +155 -0
- package/src/exporters/PostgreSQLExporter.ts +222 -0
- package/src/exporters/index.ts +18 -0
- package/src/index.ts +633 -0
- package/{lib/locales/en-US.js → src/locales/en-US.ts} +21 -37
- package/{lib/locales/es-ES.js → src/locales/es-ES.ts} +63 -16
- package/{lib/locales/fr-FR.js → src/locales/fr-FR.ts} +74 -27
- package/src/locales/index.ts +103 -0
- package/{lib/locales/ja-JP.js → src/locales/ja-JP.ts} +59 -17
- package/src/locales/types.ts +156 -0
- package/{lib/locales/zh-CN.js → src/locales/zh-CN.ts} +21 -38
- package/src/parser/ConstraintParser.ts +101 -0
- package/src/parser/DslParser.ts +470 -0
- package/src/parser/SchemaCompiler.ts +66 -0
- package/src/parser/TypeRegistry.ts +250 -0
- package/src/parser/index.ts +6 -0
- package/src/plugins/custom-format.ts +126 -0
- package/src/plugins/custom-type-example.ts +108 -0
- package/src/plugins/custom-validator.ts +140 -0
- package/src/types/conditional.ts +28 -0
- package/src/types/config.ts +59 -0
- package/src/types/dsl.ts +131 -0
- package/src/types/error.ts +60 -0
- package/src/types/index.ts +17 -0
- package/src/types/infer.ts +128 -0
- package/src/types/plugin.ts +58 -0
- package/src/types/safe-regex.d.ts +9 -0
- package/src/types/schema.ts +66 -0
- package/src/types/validate.ts +71 -0
- package/src/utils/SchemaHelper.ts +196 -0
- package/src/utils/SchemaUtils.ts +346 -0
- package/src/utils/TypeConverter.ts +215 -0
- package/src/utils/index.ts +10 -0
- package/src/validators/CustomKeywords.ts +477 -0
- package/.eslintignore +0 -11
- package/.eslintrc.json +0 -27
- package/CONTRIBUTING.md +0 -368
- package/STATUS.md +0 -491
- package/changelogs/v1.0.0.md +0 -328
- package/changelogs/v1.0.9.md +0 -367
- package/changelogs/v1.1.0.md +0 -389
- package/changelogs/v1.1.1.md +0 -308
- package/changelogs/v1.1.2.md +0 -183
- package/changelogs/v1.1.3.md +0 -161
- package/changelogs/v1.1.4.md +0 -432
- package/changelogs/v1.1.5.md +0 -493
- package/changelogs/v1.1.6.md +0 -211
- package/changelogs/v1.1.8.md +0 -376
- package/changelogs/v1.2.3.md +0 -124
- package/docs/INDEX.md +0 -252
- package/docs/issues-resolved-summary.md +0 -196
- package/docs/performance-benchmark-report.md +0 -179
- package/docs/performance-quick-reference.md +0 -123
- package/docs/user-questions-answered.md +0 -353
- package/docs/validation-rules-v1.0.2.md +0 -1608
- package/examples/README.md +0 -81
- package/examples/array-dsl-example.js +0 -227
- package/examples/conditional-example.js +0 -288
- package/examples/conditional-non-object.js +0 -129
- package/examples/conditional-validate-example.js +0 -321
- package/examples/custom-extension.js +0 -85
- package/examples/dsl-match-example.js +0 -74
- package/examples/dsl-style.js +0 -118
- package/examples/dynamic-locale-configuration.js +0 -348
- package/examples/dynamic-locale-example.js +0 -287
- package/examples/enum.examples.js +0 -324
- package/examples/export-demo.js +0 -130
- package/examples/express-integration.js +0 -376
- package/examples/i18n-error-handling-complete.js +0 -381
- package/examples/i18n-error-handling-quickstart.md +0 -0
- package/examples/i18n-error.examples.js +0 -181
- package/examples/i18n-full-demo.js +0 -301
- package/examples/i18n-memory-safety.examples.js +0 -268
- package/examples/markdown-export.js +0 -71
- package/examples/middleware-usage.js +0 -93
- package/examples/new-features-comparison.js +0 -315
- package/examples/password-reset/README.md +0 -153
- package/examples/password-reset/schema.js +0 -26
- package/examples/password-reset/test.js +0 -101
- package/examples/plugin-system.examples.js +0 -205
- package/examples/schema-utils-chaining.examples.js +0 -250
- package/examples/simple-example.js +0 -122
- package/examples/slug.examples.js +0 -179
- package/examples/string-extensions.js +0 -297
- package/examples/union-type-example.js +0 -127
- package/examples/union-types-example.js +0 -77
- package/examples/user-registration/README.md +0 -156
- package/examples/user-registration/routes.js +0 -92
- package/examples/user-registration/schema.js +0 -150
- package/examples/user-registration/server.js +0 -74
- package/index.d.ts +0 -3540
- package/index.js +0 -457
- package/index.mjs +0 -60
- package/lib/adapters/DslAdapter.js +0 -871
- package/lib/adapters/index.js +0 -20
- package/lib/config/constants.js +0 -286
- package/lib/config/patterns/common.js +0 -47
- package/lib/config/patterns/creditCard.js +0 -9
- package/lib/config/patterns/idCard.js +0 -9
- package/lib/config/patterns/index.js +0 -9
- package/lib/config/patterns/licensePlate.js +0 -4
- package/lib/config/patterns/passport.js +0 -4
- package/lib/config/patterns/phone.js +0 -9
- package/lib/config/patterns/postalCode.js +0 -5
- package/lib/core/CacheManager.js +0 -376
- package/lib/core/ConditionalBuilder.js +0 -503
- package/lib/core/DslBuilder.js +0 -1400
- package/lib/core/ErrorCodes.js +0 -233
- package/lib/core/ErrorFormatter.js +0 -445
- package/lib/core/JSONSchemaCore.js +0 -347
- package/lib/core/Locale.js +0 -130
- package/lib/core/MessageTemplate.js +0 -98
- package/lib/core/PluginManager.js +0 -448
- package/lib/core/StringExtensions.js +0 -240
- package/lib/core/Validator.js +0 -654
- package/lib/errors/I18nError.js +0 -328
- package/lib/errors/ValidationError.js +0 -191
- package/lib/exporters/MarkdownExporter.js +0 -420
- package/lib/exporters/MongoDBExporter.js +0 -162
- package/lib/exporters/MySQLExporter.js +0 -212
- package/lib/exporters/PostgreSQLExporter.js +0 -289
- package/lib/exporters/index.js +0 -24
- package/lib/locales/index.js +0 -8
- package/lib/utils/LRUCache.js +0 -174
- package/lib/utils/SchemaHelper.js +0 -240
- package/lib/utils/SchemaUtils.js +0 -445
- package/lib/utils/TypeConverter.js +0 -245
- package/lib/utils/index.js +0 -13
- package/lib/validators/CustomKeywords.js +0 -616
- package/lib/validators/index.js +0 -11
package/docs/plugin-system.md
CHANGED
|
@@ -1,494 +1,316 @@
|
|
|
1
1
|
# 插件系统
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
> **更新**: 2025-12-26
|
|
3
|
+
> **更新**: 2026-05-01
|
|
5
4
|
> **状态**: ✅ 稳定
|
|
6
5
|
|
|
7
6
|
---
|
|
8
7
|
|
|
9
|
-
## 📑 目录
|
|
10
|
-
|
|
11
|
-
- [概述](#概述)
|
|
12
|
-
- [快速开始](#快速开始)
|
|
13
|
-
- [插件开发](#插件开发)
|
|
14
|
-
- [钩子系统](#钩子系统)
|
|
15
|
-
- [官方插件](#官方插件)
|
|
16
|
-
- [最佳实践](#最佳实践)
|
|
17
|
-
- [API 参考](#api-参考)
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
8
|
## 概述
|
|
22
9
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
### 特性
|
|
10
|
+
`PluginManager` 是一个独立的插件管理器,负责:
|
|
26
11
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
✅ **TypeScript 支持** - 完整的类型定义
|
|
12
|
+
- 注册 / 安装 / 卸载插件
|
|
13
|
+
- 管理插件钩子
|
|
14
|
+
- 提供 `EventEmitter` 兼容事件系统
|
|
15
|
+
- 通过 `context` 暴露插件注册表和钩子表
|
|
32
16
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
PluginManager
|
|
37
|
-
├── 插件注册表 (Map)
|
|
38
|
-
├── 钩子系统 (Hooks)
|
|
39
|
-
├── 事件系统 (EventEmitter)
|
|
40
|
-
└── 上下文 (Context)
|
|
41
|
-
```
|
|
17
|
+
> **重要说明**
|
|
18
|
+
> `PluginManager` 本身不会自动接入 `dsl()`、`Validator`、各类 Exporter 的执行流程。
|
|
19
|
+
> 如果你希望在验证、编译或导出阶段运行某些 hook,需要由你的集成代码显式调用 `pluginManager.runHook(...)`。
|
|
42
20
|
|
|
43
21
|
---
|
|
44
22
|
|
|
45
23
|
## 快速开始
|
|
46
24
|
|
|
47
|
-
### 1. 创建插件管理器
|
|
48
|
-
|
|
49
25
|
```javascript
|
|
50
26
|
const { PluginManager } = require('schema-dsl');
|
|
27
|
+
const schemaDsl = require('schema-dsl');
|
|
51
28
|
|
|
52
29
|
const pluginManager = new PluginManager();
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### 2. 注册插件
|
|
56
30
|
|
|
57
|
-
```javascript
|
|
58
31
|
const myPlugin = {
|
|
59
32
|
name: 'my-plugin',
|
|
60
33
|
version: '1.0.0',
|
|
61
34
|
description: '我的自定义插件',
|
|
62
35
|
|
|
63
|
-
install(
|
|
64
|
-
console.log('
|
|
36
|
+
install(core, options, context) {
|
|
37
|
+
console.log('installed:', !!core, options);
|
|
38
|
+
console.log('registered plugins:', context.plugins.size);
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
uninstall(core, context) {
|
|
42
|
+
console.log('cleanup:', !!core, context.hooks.size);
|
|
65
43
|
}
|
|
66
44
|
};
|
|
67
45
|
|
|
68
46
|
pluginManager.register(myPlugin);
|
|
47
|
+
pluginManager.install(schemaDsl, 'my-plugin', { enabled: true });
|
|
48
|
+
pluginManager.uninstall('my-plugin', schemaDsl);
|
|
69
49
|
```
|
|
70
50
|
|
|
71
|
-
### 3. 安装插件
|
|
72
|
-
|
|
73
|
-
```javascript
|
|
74
|
-
const schemaDsl = require('schema-dsl');
|
|
75
|
-
|
|
76
|
-
pluginManager.install(schemaDsl, 'my-plugin');
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### 4. 使用插件
|
|
80
|
-
|
|
81
|
-
插件安装后,自动生效,无需额外配置。
|
|
82
|
-
|
|
83
51
|
---
|
|
84
52
|
|
|
85
|
-
##
|
|
86
|
-
|
|
87
|
-
### 插件结构
|
|
88
|
-
|
|
89
|
-
一个标准的插件对象包含以下字段:
|
|
53
|
+
## 插件对象结构
|
|
90
54
|
|
|
91
55
|
```javascript
|
|
92
56
|
module.exports = {
|
|
93
|
-
//
|
|
94
|
-
name: 'plugin-name',
|
|
95
|
-
install
|
|
57
|
+
// 必填
|
|
58
|
+
name: 'plugin-name',
|
|
59
|
+
install(core, options, context) {
|
|
96
60
|
// 安装逻辑
|
|
97
61
|
},
|
|
98
62
|
|
|
99
|
-
//
|
|
100
|
-
version: '1.0.0',
|
|
101
|
-
description: '插件描述',
|
|
102
|
-
uninstall
|
|
63
|
+
// 可选
|
|
64
|
+
version: '1.0.0',
|
|
65
|
+
description: '插件描述',
|
|
66
|
+
uninstall(core, context) {
|
|
103
67
|
// 卸载逻辑
|
|
104
68
|
},
|
|
105
|
-
hooks: {
|
|
106
|
-
onBeforeValidate
|
|
107
|
-
onAfterValidate
|
|
69
|
+
hooks: {
|
|
70
|
+
onBeforeValidate(schema, data) {},
|
|
71
|
+
onAfterValidate(result) {}
|
|
108
72
|
},
|
|
109
|
-
options: {
|
|
73
|
+
options: {
|
|
110
74
|
enabled: true
|
|
111
75
|
}
|
|
112
76
|
};
|
|
113
77
|
```
|
|
114
78
|
|
|
115
|
-
###
|
|
79
|
+
### 参数说明
|
|
116
80
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
81
|
+
| 参数 | 说明 |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `core` | 传给 `install()` / `uninstall()` 的核心对象,通常是 `require('schema-dsl')` 的结果或你自己的集成对象 |
|
|
84
|
+
| `options` | 安装时的合并配置:`{ ...plugin.options, ...installOptions }` |
|
|
85
|
+
| `context.plugins` | 当前已注册插件的 `Map<string, Plugin>` |
|
|
86
|
+
| `context.hooks` | 当前 hook 注册表的 `Map<string, Function[]>` |
|
|
121
87
|
|
|
122
|
-
|
|
123
|
-
const { Validator } = schemaDsl;
|
|
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
|
-
```
|
|
88
|
+
---
|
|
137
89
|
|
|
138
|
-
|
|
90
|
+
## 钩子系统
|
|
139
91
|
|
|
140
|
-
|
|
141
|
-
module.exports = {
|
|
142
|
-
name: 'custom-format',
|
|
143
|
-
version: '1.0.0',
|
|
92
|
+
### 1. 自动触发的内置生命周期
|
|
144
93
|
|
|
145
|
-
|
|
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
|
-
```
|
|
94
|
+
这些 hook 由 `PluginManager` 自动触发:
|
|
156
95
|
|
|
157
|
-
|
|
96
|
+
| 名称 | 触发时机 | 参数 |
|
|
97
|
+
|---|---|---|
|
|
98
|
+
| `onBeforeRegister` | `register(plugin)` 写入注册表前 | `(plugin)` |
|
|
99
|
+
| `onAfterRegister` | `register(plugin)` 完成后 | `(plugin)` |
|
|
100
|
+
| `onError` | 某个 hook 执行抛错后 | `(error, meta)` |
|
|
158
101
|
|
|
159
|
-
|
|
102
|
+
### 2. 约定式 hook 名称
|
|
103
|
+
|
|
104
|
+
以下名称是常用约定,`PluginManager` 支持注册它们,但**是否执行取决于你的代码是否调用 `runHook()`**:
|
|
160
105
|
|
|
161
|
-
|
|
106
|
+
| 名称 | 常见用途 |
|
|
107
|
+
|---|---|
|
|
108
|
+
| `onBeforeValidate` / `onAfterValidate` | 验证前后 |
|
|
109
|
+
| `onBeforeCompile` / `onAfterCompile` | 编译前后 |
|
|
110
|
+
| `onBeforeExport` / `onAfterExport` | 导出前后 |
|
|
111
|
+
| `beforeParse` / `afterParse` | 解析阶段 |
|
|
112
|
+
| `beforeValidate` / `afterValidate` | v2 风格命名 |
|
|
113
|
+
| `beforeCompile` / `afterCompile` | v2 风格命名 |
|
|
162
114
|
|
|
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)` |
|
|
115
|
+
> `hook()` / `runHook()` 支持任意字符串名称,不限于上表。
|
|
172
116
|
|
|
173
|
-
###
|
|
117
|
+
### 3. 注册与运行 hook
|
|
174
118
|
|
|
175
119
|
```javascript
|
|
176
120
|
pluginManager.hook('onBeforeValidate', (schema, data) => {
|
|
177
121
|
console.log('验证前:', schema, data);
|
|
178
122
|
});
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
### 运行钩子
|
|
182
123
|
|
|
183
|
-
```javascript
|
|
184
124
|
const results = await pluginManager.runHook('onBeforeValidate', schema, data);
|
|
185
125
|
```
|
|
186
126
|
|
|
187
|
-
###
|
|
127
|
+
### 4. 在插件中声明 hook
|
|
188
128
|
|
|
189
129
|
```javascript
|
|
190
|
-
|
|
191
|
-
name: '
|
|
192
|
-
|
|
130
|
+
const loggingPlugin = {
|
|
131
|
+
name: 'logging',
|
|
132
|
+
install() {},
|
|
193
133
|
hooks: {
|
|
194
134
|
onBeforeValidate(schema, data) {
|
|
195
|
-
|
|
135
|
+
console.log('before validate', schema, data);
|
|
196
136
|
},
|
|
197
|
-
|
|
198
137
|
onAfterValidate(result) {
|
|
199
|
-
|
|
138
|
+
console.log('after validate', result);
|
|
200
139
|
}
|
|
201
140
|
}
|
|
202
141
|
};
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
---
|
|
206
142
|
|
|
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);
|
|
143
|
+
pluginManager.register(loggingPlugin);
|
|
144
|
+
await pluginManager.runHook('onBeforeValidate', schema, data);
|
|
218
145
|
```
|
|
219
146
|
|
|
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
147
|
---
|
|
245
148
|
|
|
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
|
-
```
|
|
149
|
+
## 事件系统
|
|
269
150
|
|
|
270
|
-
|
|
151
|
+
`PluginManager` 继承自 `EventEmitter`,因此可以使用:
|
|
271
152
|
|
|
272
|
-
|
|
153
|
+
- `on()`
|
|
154
|
+
- `once()`
|
|
155
|
+
- `off()`
|
|
156
|
+
- `emit()`
|
|
157
|
+
- `removeListener()`
|
|
158
|
+
- `removeAllListeners()`
|
|
273
159
|
|
|
274
|
-
|
|
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
|
-
```
|
|
160
|
+
### 可用事件
|
|
284
161
|
|
|
285
|
-
|
|
162
|
+
| 事件名 | 触发时机 | 参数 |
|
|
163
|
+
|---|---|---|
|
|
164
|
+
| `plugin:registered` | 插件注册成功 | `(plugin)` |
|
|
165
|
+
| `plugin:installed` | 插件安装成功 | `(plugin)` |
|
|
166
|
+
| `plugin:uninstalled` | 插件卸载成功 | `(plugin)` |
|
|
167
|
+
| `plugin:error` | 插件安装 / 卸载失败 | `({ plugin, error })` |
|
|
168
|
+
| `hook:error` | hook 执行失败 | `({ hookName, handler, error })` |
|
|
169
|
+
| `plugins:cleared` | `clear()` 完成后 | `()` |
|
|
286
170
|
|
|
287
|
-
|
|
171
|
+
### 示例
|
|
288
172
|
|
|
289
173
|
```javascript
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
}
|
|
294
|
-
```
|
|
174
|
+
pluginManager.on('plugin:registered', (plugin) => {
|
|
175
|
+
console.log('插件已注册:', plugin.name);
|
|
176
|
+
});
|
|
295
177
|
|
|
296
|
-
|
|
178
|
+
pluginManager.on('plugin:installed', (plugin) => {
|
|
179
|
+
console.log('插件已安装:', plugin.name);
|
|
180
|
+
});
|
|
297
181
|
|
|
298
|
-
|
|
182
|
+
pluginManager.on('plugin:error', ({ plugin, error }) => {
|
|
183
|
+
console.error('插件错误:', plugin.name, error.message);
|
|
184
|
+
});
|
|
299
185
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
*
|
|
304
|
-
* @description 添加业务特定的验证规则
|
|
305
|
-
*
|
|
306
|
-
* @example
|
|
307
|
-
* ```javascript
|
|
308
|
-
* pluginManager.register(myPlugin);
|
|
309
|
-
* pluginManager.install(schema-dsl);
|
|
310
|
-
* ```
|
|
311
|
-
*/
|
|
312
|
-
module.exports = { /* ... */ };
|
|
186
|
+
pluginManager.on('hook:error', ({ hookName, error }) => {
|
|
187
|
+
console.error('Hook 错误:', hookName, error.message);
|
|
188
|
+
});
|
|
313
189
|
```
|
|
314
190
|
|
|
315
191
|
---
|
|
316
192
|
|
|
317
193
|
## API 参考
|
|
318
194
|
|
|
319
|
-
###
|
|
320
|
-
|
|
321
|
-
#### `register(plugin)`
|
|
195
|
+
### `register(plugin)`
|
|
322
196
|
|
|
323
|
-
|
|
197
|
+
注册插件,并自动触发:
|
|
324
198
|
|
|
325
|
-
|
|
326
|
-
|
|
199
|
+
1. `onBeforeRegister`
|
|
200
|
+
2. 写入注册表 / 注册插件自带 hooks
|
|
201
|
+
3. `onAfterRegister`
|
|
202
|
+
4. `plugin:registered`
|
|
327
203
|
|
|
328
|
-
|
|
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])`
|
|
204
|
+
### `install(core, [pluginName], [options])`
|
|
341
205
|
|
|
342
206
|
安装插件。
|
|
343
207
|
|
|
344
|
-
|
|
345
|
-
- `
|
|
346
|
-
- `
|
|
347
|
-
- `
|
|
348
|
-
|
|
349
|
-
**返回**: `this`
|
|
208
|
+
- `install(core)`:安装所有已注册插件
|
|
209
|
+
- `install(core, 'name', options)`:安装指定插件
|
|
210
|
+
- `install()` 时会把第三个参数 `context` 传给插件
|
|
211
|
+
- 安装成功后触发 `plugin:installed`
|
|
212
|
+
- 安装失败时触发 `plugin:error`,然后抛错
|
|
350
213
|
|
|
351
|
-
|
|
214
|
+
### `unregister(name, [core])`
|
|
352
215
|
|
|
353
|
-
|
|
216
|
+
卸载插件并移除该插件注册的 hooks。
|
|
354
217
|
|
|
355
|
-
|
|
356
|
-
- `
|
|
357
|
-
- `
|
|
218
|
+
- `plugin.uninstall(core, context)` 成功后才会真正移除插件
|
|
219
|
+
- 卸载成功后触发 `plugin:uninstalled`
|
|
220
|
+
- 卸载失败时触发 `plugin:error`,然后抛错
|
|
358
221
|
|
|
359
|
-
|
|
222
|
+
### `uninstall(name, [core])`
|
|
360
223
|
|
|
361
|
-
|
|
224
|
+
`unregister()` 的别名,兼容 v1。
|
|
362
225
|
|
|
363
|
-
|
|
226
|
+
### `hook(name, handler)`
|
|
364
227
|
|
|
365
|
-
|
|
366
|
-
- `hookName` (String) - 钩子名称
|
|
367
|
-
- `handler` (Function) - 钩子处理函数
|
|
228
|
+
注册一个 hook 处理器。
|
|
368
229
|
|
|
369
|
-
|
|
230
|
+
### `unhook(name, handler)`
|
|
370
231
|
|
|
371
|
-
|
|
232
|
+
移除指定 hook 处理器。
|
|
372
233
|
|
|
373
|
-
|
|
234
|
+
### `runHook(name, ...args)`
|
|
374
235
|
|
|
375
|
-
|
|
376
|
-
- `hookName` (String) - 钩子名称
|
|
377
|
-
- `...args` (any) - 钩子参数
|
|
236
|
+
异步运行某个 hook 下的全部处理器,返回结果数组。
|
|
378
237
|
|
|
379
|
-
|
|
238
|
+
- 单个 handler 抛错不会中断后续 handler
|
|
239
|
+
- 抛错时会触发 `hook:error`
|
|
240
|
+
- 同时会执行 `onError`
|
|
380
241
|
|
|
381
|
-
|
|
242
|
+
### `has(name)`
|
|
382
243
|
|
|
383
|
-
|
|
244
|
+
检查插件是否已注册。
|
|
384
245
|
|
|
385
|
-
|
|
246
|
+
### `get([name])`
|
|
386
247
|
|
|
387
|
-
|
|
248
|
+
- `get(name)`:获取单个插件
|
|
249
|
+
- `get()`:获取全部插件 `Map`
|
|
388
250
|
|
|
389
|
-
|
|
251
|
+
### `list()`
|
|
390
252
|
|
|
391
|
-
|
|
392
|
-
- `pluginName` (String) - 插件名称
|
|
253
|
+
返回插件元数据数组:
|
|
393
254
|
|
|
394
|
-
|
|
255
|
+
```javascript
|
|
256
|
+
[{ name, version, description }]
|
|
257
|
+
```
|
|
395
258
|
|
|
396
|
-
|
|
259
|
+
### `clear([core])`
|
|
397
260
|
|
|
398
|
-
|
|
261
|
+
逐个卸载所有插件,清空注册表和 hooks,最后触发 `plugins:cleared`。
|
|
399
262
|
|
|
400
|
-
|
|
401
|
-
- `schema-dsl` (Object) - SchemaI-DSL 实例
|
|
263
|
+
### 属性
|
|
402
264
|
|
|
403
|
-
|
|
265
|
+
| 属性 | 说明 |
|
|
266
|
+
|---|---|
|
|
267
|
+
| `pluginManager.plugins` | 插件注册表 `Map<string, Plugin>` |
|
|
268
|
+
| `pluginManager.hooks` | hook 注册表 `Map<string, Function[]>` |
|
|
269
|
+
| `pluginManager.context` | `{ plugins, hooks }` |
|
|
270
|
+
| `pluginManager.size` | 已注册插件数量 |
|
|
271
|
+
| `pluginManager.pluginCount` | 已注册插件数量(别名) |
|
|
404
272
|
|
|
405
273
|
---
|
|
406
274
|
|
|
407
|
-
##
|
|
275
|
+
## 最佳实践
|
|
408
276
|
|
|
409
|
-
|
|
277
|
+
### 1. 命名
|
|
410
278
|
|
|
411
|
-
|
|
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
|
-
});
|
|
279
|
+
使用 `kebab-case`:
|
|
419
280
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
281
|
+
```javascript
|
|
282
|
+
name: 'custom-validator'
|
|
283
|
+
name: 'mongodb-plugin'
|
|
423
284
|
```
|
|
424
285
|
|
|
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` 参数访问其他插件:
|
|
286
|
+
### 2. 错误处理
|
|
440
287
|
|
|
441
288
|
```javascript
|
|
442
|
-
install(
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
289
|
+
install(core, options, context) {
|
|
290
|
+
try {
|
|
291
|
+
// 安装逻辑
|
|
292
|
+
} catch (error) {
|
|
293
|
+
throw error;
|
|
446
294
|
}
|
|
447
|
-
|
|
448
|
-
// 获取其他插件实例
|
|
449
|
-
const depPlugin = context.plugins.get('dependency-plugin');
|
|
450
295
|
}
|
|
451
296
|
```
|
|
452
297
|
|
|
453
|
-
###
|
|
454
|
-
|
|
455
|
-
通过 `options` 参数传递配置:
|
|
298
|
+
### 3. 资源清理
|
|
456
299
|
|
|
457
300
|
```javascript
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
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
|
-
});
|
|
301
|
+
uninstall(core, context) {
|
|
302
|
+
// 清理注册的资源
|
|
303
|
+
}
|
|
476
304
|
```
|
|
477
305
|
|
|
478
|
-
###
|
|
479
|
-
|
|
480
|
-
插件安装函数可以是异步的:
|
|
306
|
+
### 4. 插件间通信
|
|
481
307
|
|
|
482
308
|
```javascript
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
async install(schema-dsl, options) {
|
|
487
|
-
// 异步初始化
|
|
488
|
-
await this.loadConfig();
|
|
489
|
-
await this.connectDatabase();
|
|
309
|
+
install(core, options, context) {
|
|
310
|
+
if (!context.plugins.has('dependency-plugin')) {
|
|
311
|
+
throw new Error('需要先安装 dependency-plugin');
|
|
490
312
|
}
|
|
491
|
-
}
|
|
313
|
+
}
|
|
492
314
|
```
|
|
493
315
|
|
|
494
316
|
---
|
|
@@ -497,46 +319,63 @@ module.exports = {
|
|
|
497
319
|
|
|
498
320
|
### 插件未生效
|
|
499
321
|
|
|
500
|
-
1. 检查插件是否已注册:
|
|
501
322
|
```javascript
|
|
502
|
-
|
|
323
|
+
pluginManager.has('my-plugin');
|
|
324
|
+
pluginManager.list();
|
|
503
325
|
```
|
|
504
326
|
|
|
505
|
-
|
|
506
|
-
```javascript
|
|
507
|
-
pluginManager.list(); // 是否在列表中?
|
|
508
|
-
```
|
|
327
|
+
确认插件已注册、已安装,并且 `install()` 确实执行到了你的逻辑。
|
|
509
328
|
|
|
510
|
-
|
|
329
|
+
### hook 未触发
|
|
511
330
|
|
|
512
|
-
|
|
331
|
+
检查两件事:
|
|
513
332
|
|
|
514
|
-
1.
|
|
515
|
-
2.
|
|
333
|
+
1. hook 名称是否一致
|
|
334
|
+
2. 你的代码是否真的调用了 `pluginManager.runHook('hookName', ...)`
|
|
516
335
|
|
|
517
|
-
###
|
|
336
|
+
### 当前仓库的发布方式
|
|
518
337
|
|
|
519
|
-
|
|
520
|
-
- 使用不同的方法名
|
|
521
|
-
- 在插件中保存原始方法的引用
|
|
338
|
+
当前仓库已恢复 v1 风格的官方插件子路径入口,可直接使用:
|
|
522
339
|
|
|
523
|
-
|
|
340
|
+
- `schema-dsl/plugins/custom-format`
|
|
341
|
+
- `schema-dsl/plugins/custom-validator`
|
|
342
|
+
- `schema-dsl/plugins/custom-type-example`
|
|
524
343
|
|
|
525
|
-
|
|
344
|
+
```javascript
|
|
345
|
+
const { PluginManager } = require('schema-dsl');
|
|
346
|
+
const schemaDsl = require('schema-dsl');
|
|
347
|
+
const customFormat = require('schema-dsl/plugins/custom-format');
|
|
348
|
+
|
|
349
|
+
const pluginManager = new PluginManager();
|
|
350
|
+
pluginManager.register(customFormat);
|
|
351
|
+
pluginManager.install(schemaDsl, 'custom-format');
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
import { PluginManager } from 'schema-dsl';
|
|
356
|
+
import * as schemaDsl from 'schema-dsl';
|
|
357
|
+
import customTypeExample from 'schema-dsl/plugins/custom-type-example';
|
|
358
|
+
|
|
359
|
+
const pluginManager = new PluginManager();
|
|
360
|
+
pluginManager.register(customTypeExample);
|
|
361
|
+
pluginManager.install(schemaDsl, 'custom-type-example');
|
|
362
|
+
```
|
|
526
363
|
|
|
527
|
-
|
|
364
|
+
> ⚠️ 注意:官方插件子路径只补齐了 v1 已存在的三个示例插件入口;
|
|
365
|
+
> `PluginManager` 仍然不会自动接入 `validate()` / `compile()` / exporter 流程,hook 是否执行仍取决于你的集成代码是否显式调用 `runHook()`。
|
|
528
366
|
|
|
529
367
|
---
|
|
530
368
|
|
|
531
369
|
## 相关文档
|
|
532
370
|
|
|
533
371
|
- [API 参考](api-reference.md)
|
|
534
|
-
- [
|
|
535
|
-
- [
|
|
372
|
+
- [验证指南](validate.md)
|
|
373
|
+
- [DSL 语法](dsl-syntax.md)
|
|
536
374
|
|
|
537
375
|
---
|
|
538
376
|
|
|
539
|
-
|
|
377
|
+
## 对应示例文件
|
|
540
378
|
|
|
541
|
-
|
|
379
|
+
**示例入口**: [plugin-system.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/plugin-system.ts)
|
|
380
|
+
**说明**: 覆盖自定义插件的注册 / 安装 / 卸载、`runHook()` 执行结果,以及官方 `custom-format` 子路径插件的安装效果。
|
|
542
381
|
|