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.
Files changed (242) hide show
  1. package/CHANGELOG.md +87 -210
  2. package/README.md +391 -2249
  3. package/dist/DslBuilder-DQDN0ZxZ.d.cts +341 -0
  4. package/dist/DslBuilder-DkLaOo9Q.d.ts +341 -0
  5. package/dist/Validator-C7GsVQOH.d.cts +192 -0
  6. package/dist/Validator-hFWKGxir.d.ts +192 -0
  7. package/dist/index.cjs +6594 -0
  8. package/dist/index.d.cts +1145 -0
  9. package/dist/index.d.ts +1145 -0
  10. package/dist/index.js +6528 -0
  11. package/dist/plugin-CIKtTMtS.d.cts +246 -0
  12. package/dist/plugin-CIKtTMtS.d.ts +246 -0
  13. package/dist/plugins/custom-format.cjs +3802 -0
  14. package/dist/plugins/custom-format.d.cts +12 -0
  15. package/dist/plugins/custom-format.d.ts +12 -0
  16. package/dist/plugins/custom-format.js +3772 -0
  17. package/dist/plugins/custom-type-example.cjs +3795 -0
  18. package/dist/plugins/custom-type-example.d.cts +8 -0
  19. package/dist/plugins/custom-type-example.d.ts +8 -0
  20. package/dist/plugins/custom-type-example.js +3765 -0
  21. package/dist/plugins/custom-validator.cjs +146 -0
  22. package/dist/plugins/custom-validator.d.cts +10 -0
  23. package/dist/plugins/custom-validator.d.ts +10 -0
  24. package/dist/plugins/custom-validator.js +121 -0
  25. package/docs/FEATURE-INDEX.md +102 -68
  26. package/docs/add-custom-locale.md +48 -35
  27. package/docs/add-keyword.md +24 -0
  28. package/docs/api-reference.md +396 -154
  29. package/docs/api.md +13 -0
  30. package/docs/best-practices-project-structure.md +19 -10
  31. package/docs/best-practices.md +93 -53
  32. package/docs/cache-manager.md +23 -15
  33. package/docs/compile.md +45 -0
  34. package/docs/conditional-api.md +40 -11
  35. package/docs/custom-extensions-guide.md +80 -152
  36. package/docs/design-philosophy.md +76 -71
  37. package/docs/doc-index.md +324 -0
  38. package/docs/dsl-syntax.md +69 -19
  39. package/docs/dynamic-locale.md +24 -14
  40. package/docs/enum.md +12 -5
  41. package/docs/error-handling.md +53 -44
  42. package/docs/export-guide.md +47 -8
  43. package/docs/export-limitations.md +27 -11
  44. package/docs/faq.md +86 -67
  45. package/docs/frontend-i18n-guide.md +26 -12
  46. package/docs/i18n-user-guide.md +60 -47
  47. package/docs/i18n.md +51 -32
  48. package/docs/index.md +48 -0
  49. package/docs/json-schema-basics.md +40 -0
  50. package/docs/label-vs-description.md +12 -3
  51. package/docs/markdown-exporter.md +15 -6
  52. package/docs/mongodb-exporter.md +11 -4
  53. package/docs/multi-language.md +26 -0
  54. package/docs/multi-type-support.md +26 -33
  55. package/docs/mysql-exporter.md +9 -2
  56. package/docs/number-operators.md +12 -5
  57. package/docs/optional-marker-guide.md +28 -23
  58. package/docs/performance-guide.md +49 -0
  59. package/docs/plugin-system.md +205 -366
  60. package/docs/plugin-type-registration.md +34 -0
  61. package/docs/postgresql-exporter.md +9 -2
  62. package/docs/public/favicon.svg +5 -0
  63. package/docs/quick-start.md +37 -363
  64. package/docs/runtime-locale-support.md +20 -9
  65. package/docs/schema-helper.md +10 -5
  66. package/docs/schema-utils-advanced-issues.md +23 -0
  67. package/docs/schema-utils-best-practices.md +20 -0
  68. package/docs/schema-utils-chaining.md +7 -0
  69. package/docs/schema-utils.md +76 -42
  70. package/docs/security-checklist.md +20 -0
  71. package/docs/string-extensions.md +17 -9
  72. package/docs/troubleshooting.md +36 -21
  73. package/docs/type-converter.md +41 -50
  74. package/docs/type-reference.md +38 -15
  75. package/docs/typescript-guide.md +53 -42
  76. package/docs/union-type-guide.md +11 -1
  77. package/docs/union-types.md +10 -3
  78. package/docs/validate-async.md +36 -25
  79. package/docs/validate-batch.md +49 -0
  80. package/docs/validate-dsl-object-support.md +33 -28
  81. package/docs/validate.md +36 -16
  82. package/docs/validation-guide.md +25 -7
  83. package/docs/validator.md +39 -0
  84. package/package.json +85 -27
  85. package/plugins/custom-format.cjs +8 -0
  86. package/plugins/custom-type-example.cjs +8 -0
  87. package/plugins/custom-validator.cjs +8 -0
  88. package/src/adapters/DslAdapter.ts +111 -0
  89. package/src/adapters/index.ts +1 -0
  90. package/src/config/constants.ts +83 -0
  91. package/src/config/index.ts +2 -0
  92. package/src/config/patterns.ts +77 -0
  93. package/src/core/CacheManager.ts +159 -0
  94. package/src/core/ConditionalBuilder.ts +382 -0
  95. package/src/core/ConditionalRuntime.ts +28 -0
  96. package/src/core/ConditionalValidator.ts +255 -0
  97. package/src/core/DslBuilder.ts +677 -0
  98. package/src/core/ErrorCodes.ts +38 -0
  99. package/src/core/ErrorFormatter.ts +271 -0
  100. package/src/core/JSONSchemaCore.ts +65 -0
  101. package/src/core/Locale.ts +187 -0
  102. package/src/core/MessageTemplate.ts +42 -0
  103. package/src/core/ObjectDslBuilder.ts +64 -0
  104. package/src/core/PluginManager.ts +326 -0
  105. package/src/core/StringExtensions.ts +140 -0
  106. package/src/core/TemplateEngine.ts +44 -0
  107. package/src/core/Validator.ts +448 -0
  108. package/src/errors/I18nError.ts +159 -0
  109. package/src/errors/ValidationError.ts +105 -0
  110. package/src/exporters/BaseExporter.ts +60 -0
  111. package/src/exporters/MarkdownExporter.ts +305 -0
  112. package/src/exporters/MongoDBExporter.ts +126 -0
  113. package/src/exporters/MySQLExporter.ts +155 -0
  114. package/src/exporters/PostgreSQLExporter.ts +222 -0
  115. package/src/exporters/index.ts +18 -0
  116. package/src/index.ts +633 -0
  117. package/{lib/locales/en-US.js → src/locales/en-US.ts} +21 -37
  118. package/{lib/locales/es-ES.js → src/locales/es-ES.ts} +63 -16
  119. package/{lib/locales/fr-FR.js → src/locales/fr-FR.ts} +74 -27
  120. package/src/locales/index.ts +103 -0
  121. package/{lib/locales/ja-JP.js → src/locales/ja-JP.ts} +59 -17
  122. package/src/locales/types.ts +156 -0
  123. package/{lib/locales/zh-CN.js → src/locales/zh-CN.ts} +21 -38
  124. package/src/parser/ConstraintParser.ts +101 -0
  125. package/src/parser/DslParser.ts +470 -0
  126. package/src/parser/SchemaCompiler.ts +66 -0
  127. package/src/parser/TypeRegistry.ts +250 -0
  128. package/src/parser/index.ts +6 -0
  129. package/src/plugins/custom-format.ts +126 -0
  130. package/src/plugins/custom-type-example.ts +108 -0
  131. package/src/plugins/custom-validator.ts +140 -0
  132. package/src/types/conditional.ts +28 -0
  133. package/src/types/config.ts +59 -0
  134. package/src/types/dsl.ts +131 -0
  135. package/src/types/error.ts +60 -0
  136. package/src/types/index.ts +17 -0
  137. package/src/types/infer.ts +128 -0
  138. package/src/types/plugin.ts +58 -0
  139. package/src/types/safe-regex.d.ts +9 -0
  140. package/src/types/schema.ts +66 -0
  141. package/src/types/validate.ts +71 -0
  142. package/src/utils/SchemaHelper.ts +196 -0
  143. package/src/utils/SchemaUtils.ts +346 -0
  144. package/src/utils/TypeConverter.ts +215 -0
  145. package/src/utils/index.ts +10 -0
  146. package/src/validators/CustomKeywords.ts +477 -0
  147. package/.eslintignore +0 -11
  148. package/.eslintrc.json +0 -27
  149. package/CONTRIBUTING.md +0 -368
  150. package/STATUS.md +0 -491
  151. package/changelogs/v1.0.0.md +0 -328
  152. package/changelogs/v1.0.9.md +0 -367
  153. package/changelogs/v1.1.0.md +0 -389
  154. package/changelogs/v1.1.1.md +0 -308
  155. package/changelogs/v1.1.2.md +0 -183
  156. package/changelogs/v1.1.3.md +0 -161
  157. package/changelogs/v1.1.4.md +0 -432
  158. package/changelogs/v1.1.5.md +0 -493
  159. package/changelogs/v1.1.6.md +0 -211
  160. package/changelogs/v1.1.8.md +0 -376
  161. package/changelogs/v1.2.3.md +0 -124
  162. package/docs/INDEX.md +0 -252
  163. package/docs/issues-resolved-summary.md +0 -196
  164. package/docs/performance-benchmark-report.md +0 -179
  165. package/docs/performance-quick-reference.md +0 -123
  166. package/docs/user-questions-answered.md +0 -353
  167. package/docs/validation-rules-v1.0.2.md +0 -1608
  168. package/examples/README.md +0 -81
  169. package/examples/array-dsl-example.js +0 -227
  170. package/examples/conditional-example.js +0 -288
  171. package/examples/conditional-non-object.js +0 -129
  172. package/examples/conditional-validate-example.js +0 -321
  173. package/examples/custom-extension.js +0 -85
  174. package/examples/dsl-match-example.js +0 -74
  175. package/examples/dsl-style.js +0 -118
  176. package/examples/dynamic-locale-configuration.js +0 -348
  177. package/examples/dynamic-locale-example.js +0 -287
  178. package/examples/enum.examples.js +0 -324
  179. package/examples/export-demo.js +0 -130
  180. package/examples/express-integration.js +0 -376
  181. package/examples/i18n-error-handling-complete.js +0 -381
  182. package/examples/i18n-error-handling-quickstart.md +0 -0
  183. package/examples/i18n-error.examples.js +0 -181
  184. package/examples/i18n-full-demo.js +0 -301
  185. package/examples/i18n-memory-safety.examples.js +0 -268
  186. package/examples/markdown-export.js +0 -71
  187. package/examples/middleware-usage.js +0 -93
  188. package/examples/new-features-comparison.js +0 -315
  189. package/examples/password-reset/README.md +0 -153
  190. package/examples/password-reset/schema.js +0 -26
  191. package/examples/password-reset/test.js +0 -101
  192. package/examples/plugin-system.examples.js +0 -205
  193. package/examples/schema-utils-chaining.examples.js +0 -250
  194. package/examples/simple-example.js +0 -122
  195. package/examples/slug.examples.js +0 -179
  196. package/examples/string-extensions.js +0 -297
  197. package/examples/union-type-example.js +0 -127
  198. package/examples/union-types-example.js +0 -77
  199. package/examples/user-registration/README.md +0 -156
  200. package/examples/user-registration/routes.js +0 -92
  201. package/examples/user-registration/schema.js +0 -150
  202. package/examples/user-registration/server.js +0 -74
  203. package/index.d.ts +0 -3540
  204. package/index.js +0 -457
  205. package/index.mjs +0 -60
  206. package/lib/adapters/DslAdapter.js +0 -871
  207. package/lib/adapters/index.js +0 -20
  208. package/lib/config/constants.js +0 -286
  209. package/lib/config/patterns/common.js +0 -47
  210. package/lib/config/patterns/creditCard.js +0 -9
  211. package/lib/config/patterns/idCard.js +0 -9
  212. package/lib/config/patterns/index.js +0 -9
  213. package/lib/config/patterns/licensePlate.js +0 -4
  214. package/lib/config/patterns/passport.js +0 -4
  215. package/lib/config/patterns/phone.js +0 -9
  216. package/lib/config/patterns/postalCode.js +0 -5
  217. package/lib/core/CacheManager.js +0 -376
  218. package/lib/core/ConditionalBuilder.js +0 -503
  219. package/lib/core/DslBuilder.js +0 -1400
  220. package/lib/core/ErrorCodes.js +0 -233
  221. package/lib/core/ErrorFormatter.js +0 -445
  222. package/lib/core/JSONSchemaCore.js +0 -347
  223. package/lib/core/Locale.js +0 -130
  224. package/lib/core/MessageTemplate.js +0 -98
  225. package/lib/core/PluginManager.js +0 -448
  226. package/lib/core/StringExtensions.js +0 -240
  227. package/lib/core/Validator.js +0 -654
  228. package/lib/errors/I18nError.js +0 -328
  229. package/lib/errors/ValidationError.js +0 -191
  230. package/lib/exporters/MarkdownExporter.js +0 -420
  231. package/lib/exporters/MongoDBExporter.js +0 -162
  232. package/lib/exporters/MySQLExporter.js +0 -212
  233. package/lib/exporters/PostgreSQLExporter.js +0 -289
  234. package/lib/exporters/index.js +0 -24
  235. package/lib/locales/index.js +0 -8
  236. package/lib/utils/LRUCache.js +0 -174
  237. package/lib/utils/SchemaHelper.js +0 -240
  238. package/lib/utils/SchemaUtils.js +0 -445
  239. package/lib/utils/TypeConverter.js +0 -245
  240. package/lib/utils/index.js +0 -13
  241. package/lib/validators/CustomKeywords.js +0 -616
  242. package/lib/validators/index.js +0 -11
@@ -1,8 +1,8 @@
1
1
  # 自定义扩展指南
2
2
 
3
- > **版本**: v1.0.2
4
- > **更新日期**: 2025-12-31
5
- > **用途**: 教你如何扩展schema-dsl,添加自己的验证器
3
+ > **版本**: 2.0.0-beta.2
4
+ > **更新日期**: 2026-05-08
5
+ > **用途**: 说明当前版本推荐的运行时扩展方式,以及在维护 schema-dsl 自身源码时如何继续深入扩展
6
6
 
7
7
  ---
8
8
 
@@ -21,181 +21,97 @@
21
21
 
22
22
  schema-dsl采用模块化设计,你可以轻松扩展:
23
23
 
24
- 1. **AJV关键字** - 底层验证逻辑
25
- 2. **DslBuilder方法** - DSL语法糖
26
- 3. **预定义模式** - 常用正则模式
27
- 4. **多语言消息** - 错误消息国际化
24
+ 1. **`Validator.addKeyword()`** - 运行时注册自定义 AJV 关键字
25
+ 2. **`TypeRegistry.register()` / `DslBuilder.registerType()`** - 注册自定义 DSL 类型
26
+ 3. **`PluginManager` + `schema-dsl/plugins/*`** - 组合插件、hook 与官方插件入口
27
+ 4. **`Locale.addLocale()` / `dsl.config({ i18n })`** - 扩展多语言消息
28
+
29
+ ## 当前版本推荐路径
30
+
31
+ > ⚠️ 如果你是把 `schema-dsl` 当成依赖使用,优先通过公开运行时 API 扩展,而不是直接修改 `src/*`。
32
+ > 只有在你维护 `schema-dsl` 自身源码时,才需要继续阅读后面的“修改内部模块”类示例。
33
+
34
+ - 自定义关键字:优先用 `new Validator().addKeyword(name, definition)`
35
+ - 自定义类型:优先用 `TypeRegistry.register()` 或 `DslBuilder.registerType()`
36
+ - 官方插件:优先用 `PluginManager` 配合 `schema-dsl/plugins/custom-format`、`schema-dsl/plugins/custom-validator`、`schema-dsl/plugins/custom-type-example`
37
+ - 自定义语言:优先用 `Locale.addLocale()` 或 `dsl.config({ i18n: { locales } })`
28
38
 
29
39
  ---
30
40
 
31
41
  ## 添加自定义AJV关键字
32
42
 
33
- ### 步骤1:注册关键字
34
-
35
- 在 `lib/validators/CustomKeywords.js` 中添加:
43
+ ### 步骤1:通过公开 API 注册关键字
36
44
 
37
45
  ```javascript
38
- static registerCustomValidators(ajv) {
39
- // 示例:手机号归属地验证
40
- ajv.addKeyword({
41
- keyword: 'phoneLocation',
42
- type: 'string',
43
- schemaType: 'string', // location参数类型
44
- validate: function validate(location, phoneNumber) {
45
- // location: 期望的归属地,如 'beijing'
46
- // phoneNumber: 用户输入的手机号
47
-
48
- const locationPrefixes = {
49
- 'beijing': ['130', '131', '132'],
50
- 'shanghai': ['133', '134', '135']
51
- };
52
-
53
- const prefixes = locationPrefixes[location];
54
- if (!prefixes) {
55
- validate.errors = [{
56
- keyword: 'phoneLocation',
57
- message: 'phone.location.unknown',
58
- params: { location }
59
- }];
60
- return false;
61
- }
62
-
63
- const prefix = phoneNumber.substring(0, 3);
64
- if (!prefixes.includes(prefix)) {
65
- validate.errors = [{
66
- keyword: 'phoneLocation',
67
- message: 'phone.location.mismatch',
68
- params: { expected: location, actual: prefix }
69
- }];
70
- return false;
71
- }
72
-
73
- return true;
74
- },
75
- errors: true
76
- });
77
- }
78
- ```
46
+ const { Validator } = require('schema-dsl');
79
47
 
80
- ### 步骤2:在registerAll中调用
48
+ const validator = new Validator();
81
49
 
82
- ```javascript
83
- static registerAll(ajv) {
84
- // ...existing keywords...
85
- this.registerCustomValidators(ajv);
86
- }
87
- ```
50
+ validator.addKeyword('isPositive', {
51
+ type: 'number',
52
+ validate: (_schema, data) => data > 0
53
+ });
88
54
 
89
- ### 步骤3:添加多语言消息
55
+ const result = validator.validate({ type: 'number', isPositive: true }, 42);
56
+ ```
90
57
 
91
- `lib/locales/zh-CN.js` 中:
58
+ ### 步骤2:需要复用时,再封装成插件
92
59
 
93
60
  ```javascript
94
- module.exports = {
95
- // ...existing messages...
96
- 'phone.location.unknown': '未知的归属地: {{#location}}',
97
- 'phone.location.mismatch': '手机号归属地不匹配,期望{{#expected}}'
61
+ const plugin = {
62
+ name: 'my-validator-plugin',
63
+ install(core) {
64
+ const validator = new core.Validator();
65
+ validator.addKeyword('isPositive', {
66
+ type: 'number',
67
+ validate: (_schema, data) => data > 0
68
+ });
69
+ }
98
70
  };
99
71
  ```
100
72
 
101
73
  ---
102
74
 
103
- ## 扩展DslBuilder方法
75
+ ## 注册自定义 DSL 类型
104
76
 
105
- ### 步骤1:添加便捷方法
106
-
107
- 在 `lib/core/DslBuilder.js` 中添加:
77
+ ### 运行时推荐写法
108
78
 
109
79
  ```javascript
110
- /**
111
- * 手机号归属地验证
112
- * @param {string} location - 归属地
113
- * @returns {DslBuilder}
114
- */
115
- phoneLocation(location) {
116
- if (this._baseSchema.type !== 'string') {
117
- throw new Error('phoneLocation() only applies to string type');
118
- }
119
- this._baseSchema.phoneLocation = location;
120
- return this;
121
- }
122
- ```
80
+ const { DslBuilder, dsl } = require('schema-dsl');
123
81
 
124
- ### 步骤2:使用新方法
125
-
126
- ```javascript
127
- const schema = dsl({
128
- mobile: dsl('string!').phone('cn').phoneLocation('beijing')
82
+ DslBuilder.registerType('invoice-id', {
83
+ type: 'string',
84
+ pattern: '^INV-\\d{4}$'
129
85
  });
130
86
 
131
- validate(schema, { mobile: '13012345678' });
87
+ const schema = dsl({ id: 'invoice-id!' });
132
88
  ```
133
89
 
134
- ---
135
-
136
- ## 添加预定义模式
137
-
138
- ### 步骤1:创建模式文件
139
-
140
- 创建 `lib/config/patterns/custom.js`:
90
+ ### 低层入口
141
91
 
142
92
  ```javascript
143
- module.exports = {
144
- /**
145
- * 微信号验证
146
- */
147
- wechat: {
148
- pattern: /^[a-zA-Z]([a-zA-Z0-9_-]{5,19})$/,
149
- key: 'pattern.wechat',
150
- min: 6,
151
- max: 20
152
- },
153
-
154
- /**
155
- * QQ号验证
156
- */
157
- qq: {
158
- pattern: /^[1-9][0-9]{4,10}$/,
159
- key: 'pattern.qq',
160
- min: 5,
161
- max: 11
162
- }
163
- };
164
- ```
93
+ const { TypeRegistry } = require('schema-dsl');
165
94
 
166
- ### 步骤2:导出模式
95
+ TypeRegistry.register('evenNumber', {
96
+ baseSchema: { type: 'number', multipleOf: 2 }
97
+ });
98
+ ```
167
99
 
168
- `lib/config/patterns/index.js` 中:
100
+ > 如果你要扩展 `schema-dsl` 自身源码,才需要继续修改 `DslBuilder` 内部方法或 parser/compiler 逻辑。
169
101
 
170
- ```javascript
171
- module.exports = {
172
- // ...existing patterns...
173
- custom: require('./custom')
174
- };
175
- ```
102
+ ---
176
103
 
177
- ### 步骤3:添加DslBuilder方法
104
+ ## 封装预定义模式
178
105
 
179
- ```javascript
180
- /**
181
- * 微信号验证
182
- * @returns {DslBuilder}
183
- */
184
- wechat() {
185
- if (this._baseSchema.type !== 'string') {
186
- throw new Error('wechat() only applies to string type');
187
- }
188
- const config = patterns.custom.wechat;
189
- return this.pattern(config.pattern).messages({ 'pattern': config.key });
190
- }
191
- ```
106
+ 当前版本更推荐用“自定义类型 + 现有约束”或“插件”来封装预定义模式,而不是直接要求业务侧修改包内 `src/config/patterns/*`。
192
107
 
193
- ### 步骤4:添加多语言
108
+ ```typescript
109
+ import { DslBuilder } from 'schema-dsl';
194
110
 
195
- ```javascript
196
- // lib/locales/zh-CN.js
197
- 'pattern.wechat': '{{#label}}必须是有效的微信号',
198
- 'pattern.qq': '{{#label}}必须是有效的QQ号'
111
+ DslBuilder.registerType('wechat-id', {
112
+ type: 'string',
113
+ pattern: '^[a-zA-Z]([a-zA-Z0-9_-]{5,19})$'
114
+ });
199
115
  ```
200
116
 
201
117
  ---
@@ -204,23 +120,28 @@ wechat() {
204
120
 
205
121
  ### 添加新语言
206
122
 
207
- 1. **创建语言文件**
123
+ 1. **运行时追加语言**
208
124
 
209
- 创建 `lib/locales/ko-KR.js`(韩语):
125
+ ```typescript
126
+ import { Locale } from 'schema-dsl';
210
127
 
211
- ```javascript
212
- module.exports = {
128
+ Locale.addLocale('ko-KR', {
213
129
  required: '{{#label}}은(는) 필수 항목입니다',
214
- type: '{{#label}}은(는) {{#expected}} 유형이어야 합니다',
215
- // ...其他73个键
216
- };
130
+ type: '{{#label}}은(는) {{#expected}} 유형이어야 합니다'
131
+ });
217
132
  ```
218
133
 
219
- 2. **配置加载**
134
+ 2. **或通过配置对象集中注入**
220
135
 
221
136
  ```javascript
222
137
  dsl.config({
223
- i18n: path.join(__dirname, 'lib/locales')
138
+ i18n: {
139
+ locales: {
140
+ 'ko-KR': {
141
+ required: '{{#label}}은(는) 필수 항목입니다'
142
+ }
143
+ }
144
+ }
224
145
  });
225
146
  ```
226
147
 
@@ -409,3 +330,10 @@ describe('Custom Validator - bankCard', function() {
409
330
 
410
331
  **需要帮助?** 访问 [GitHub Issues](https://github.com/vextjs/schema-dsl/issues)
411
332
 
333
+ ---
334
+
335
+ ## 对应示例文件
336
+
337
+ **示例入口**: [custom-extensions-guide.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/custom-extensions-guide.ts)
338
+ **说明**: 以运行时公开 API 为主,覆盖 `Validator.addKeyword()`、`DslBuilder.registerType()`、`Locale.addLocale()` 和官方插件入口四条扩展路径。
339
+
@@ -1,7 +1,7 @@
1
1
  # Schema-DSL 设计理念与架构
2
2
 
3
- > **更新时间**: 2025-12-29
4
- > **目的**: 解释 Schema-DSL 的设计决策、架构选择和性能权衡
3
+ > **更新时间**: 2026-05-07
4
+ > **目的**: 阐述 Schema-DSL 的设计理念、架构优势与性能定位
5
5
 
6
6
  ---
7
7
 
@@ -21,15 +21,15 @@
21
21
 
22
22
  ### 设计优先级
23
23
 
24
- ```
25
- 灵活性 > 易用性 > 性能
24
+ ```text
25
+ 性能强劲 · 简单易学 · 功能强大
26
26
  ```
27
27
 
28
- Schema-DSL 的设计不追求极致性能,而是在以下三者之间寻求最佳平衡:
28
+ Schema-DSL v2 完成全量 TypeScript 重构,在三个维度上均达到行业领先水平:
29
29
 
30
- 1. **灵活性** - 支持动态验证规则、配置驱动、多租户
31
- 2. **易用性** - 简洁的 DSL 语法,5分钟上手
32
- 3. **性能** - 足够快(27万+ ops/s),满足大多数场景
30
+ 1. **性能强劲** 有效数据路径超越 Zod,无效数据公平对比快 **109 倍**;底层 AJV + 全链路 WeakMap 缓存,V8 优化充分
31
+ 2. **简单易学** — DSL 语法极简,`'string:3-32!'` vs `z.string().min(3).max(32)`,5 分钟上手
32
+ 3. **功能强大** 动态验证、i18n 多语言、DB 导出、条件验证、插件系统,完整 TypeScript 类型安全
33
33
 
34
34
  ---
35
35
 
@@ -350,47 +350,42 @@ const schema = dsl(useNewRules ? newRules : oldRules);
350
350
 
351
351
  ## 性能对比与权衡
352
352
 
353
- ### 真实性能测试结果
353
+ ### 真实性能测试结果(v2 基准,分场景对比)
354
+
355
+ **测试环境**: Node.js v20.20.2, tinybench,JSON Schema 同维度对比
354
356
 
355
- **测试环境**: Node.js v20.19.4, 10,000次迭代
357
+ | 场景 | Schema-DSL | vs Zod | Zod | Ajv (raw) | Joi |
358
+ |------|-----------|:------:|-----|-----------|-----|
359
+ | S1 简单有效 | **1.301M ops/s** | ≈ 持平(差 <1%) | 1.305M ops/s | 4.732M ops/s | 154K ops/s |
360
+ | S2 无效(均无 i18n)| **1.205M ops/s** | **🏆 +89x** | 13.49K ops/s | 4.874M ops/s | 92.32K ops/s |
361
+ | S3 嵌套有效 | **1.085M ops/s** | **🏆 +28%** | 846.81K ops/s | 3.974M ops/s | 125.35K ops/s |
356
362
 
357
- | 库名 | 每秒操作数 | 10,000次耗时 | 相对速度 | 排名 |
358
- |------|-----------|-------------|---------|------|
359
- | **Ajv** | 2,000,000 ops/s | 5ms | 1.0x | 🥇 第1 |
360
- | **Zod** | 526,316 ops/s | 19ms | 0.26x | 🥈 第2 |
361
- | **Schema-DSL** | **277,778 ops/s** | **36ms** | **0.14x** | 🥉 **第3** |
362
- | Joi | 97,087 ops/s | 103ms | 0.05x | 第4 |
363
- | Yup | 60,241 ops/s | 166ms | 0.03x | 第5 |
363
+ > ℹ️ 绝对 ops/s 数值随测试机器 CPU 性能而变化;**相对倍数(vs Zod 列)是稳定的跨机器指标**,以下分析均基于倍数。
364
+ > ℹ️ S2 使用 `validate(schema, data, { format: false })` 关闭 i18n 格式化,与其他库保持相同条件(均不做 i18n 模板渲染),是真正的苹果对苹果比较。
365
+ > ℹ️ Ajv (raw) schema-dsl 的底层引擎,差值即为 schema-dsl 自身层(DSL 解析 + coerce + 缓存)的开销。
364
366
 
365
367
  ### 性能分析
366
368
 
367
- **为什么 Schema-DSL Zod 慢?**
369
+ **Schema-DSL vs Zod 对比结论**
368
370
 
369
- ```
370
- Schema-DSL 的执行流程:
371
+ - **有效数据场景(S1)**:schema-dsl 与 Zod **基本持平**;**S3 嵌套场景**快约 **28%**
372
+ - **无效数据公平对比(S2,均无 i18n 格式化)**:schema-dsl **1.205M** vs Zod **13.49K** — schema-dsl 快约 **89x**
373
+
374
+ > ⚠️ **Zod 在无效数据场景极慢的根因**:Zod 的错误收集路径使用异常驱动机制(`try/catch` 控制流),每个无效字段抛出一次 Error,4 个错误字段 = 4 次 Error 实例创建 + 4 次堆栈捕获,这是其约 13.49K ops/s 的直接原因。相比之下 schema-dsl 基于 AJV 的无异常收集路径,无格式化时达 1.205M ops/s。
375
+
376
+ ```text
377
+ Schema-DSL 的执行流程(含内置缓存):
371
378
  DSL 字符串
372
- 解析 (~5-10μs)
373
- DSL 对象
374
- ↓ 转换 (~3-5μs)
375
- JSON Schema
376
- ↓ Ajv 编译 (~2-3μs)
379
+ 缓存命中(热路径,无解析开销)
377
380
  验证函数
378
381
  ↓ 执行验证 (~0.5-1μs)
379
382
  结果
380
383
 
381
- 总开销:~12-21μs
382
-
383
- Zod 的执行流程:
384
- Schema 定义(编译时完成)
385
- ↓ 直接验证 (~3-5μs)
386
- 结果
387
-
388
- 总开销:~3-6μs
389
-
390
- 差距:Schema-DSL 多了约 9-15μs 的开销
384
+ 冷路径(首次):
385
+ DSL 字符串 → 解析 → JSON Schema → Ajv 编译 → 缓存并执行
391
386
  ```
392
387
 
393
- **性能瓶颈分布**:
388
+ **性能瓶颈分布(冷启动)**:
394
389
  1. DSL 解析(40-50%)
395
390
  2. JSON Schema 转换(20-30%)
396
391
  3. 多语言处理(10-20%)
@@ -400,15 +395,15 @@ Zod 的执行流程:
400
395
 
401
396
  ### 性能权衡分析
402
397
 
403
- **损失**:
404
- ```
405
- - 比 Zod 1.89倍
406
- - Ajv 慢 7.2倍
407
- - 每次验证多花 9-15μs
398
+ **与 Ajv (raw) 的差距**:
399
+ ```text
400
+ - 比 Ajv (raw) 慢约 3.6-4.0x(DSL 层自身开销)
401
+ S1 简单场景:3.64x,S3 嵌套场景:3.66x
402
+ - ajv (raw) 是底层引擎,无 DSL 解析/i18n/coerce 功能
408
403
  ```
409
404
 
410
405
  **换来的价值**:
411
- ```
406
+ ```text
412
407
  ✅ 代码量减少 65%
413
408
  'string:3-32!' vs z.string().min(3).max(32)
414
409
 
@@ -450,7 +445,7 @@ Zod 的执行流程:
450
445
 
451
446
  ### 核心组件
452
447
 
453
- ```
448
+ ```text
454
449
  ┌─────────────────────────────────────┐
455
450
  │ DSL 字符串 │
456
451
  │ 'string:3-32!', 'email!' │
@@ -534,21 +529,18 @@ REGEX_CACHE: LRU(500) // 正则表达式
534
529
  - 动态切换验证规则
535
530
  - 配置驱动
536
531
 
537
- ### ⚠️ 考虑其他库
538
-
539
- **不适合 Schema-DSL 的场景**:
532
+ ### ⚠️ 以下场景可能有更优选择
540
533
 
541
- 1. **极致性能要求**
542
- - 需要 >50万 ops/s
543
- - 推荐:**Ajv** **Zod**
534
+ 1. **追求代码生成级极致吞吐量**
535
+ - 需要 fastest-validator 级别性能(compile 为原生 JS 函数)
536
+ - 推荐:**fastest-validator**(但需放弃 JSON Schema 标准兼容)
544
537
 
545
- 2. **TypeScript 强类型推断**
546
- - 需要运行时类型守卫
547
- - 推荐:**Zod**
538
+ 2. **以 Schema → 静态类型推断为核心目标**
539
+ - 需要从 Schema 自动导出精确的 TypeScript 类型(如 `z.infer<typeof schema>`)
540
+ - 推荐:**Zod**(schema-dsl 提供完整 TypeScript API 类型安全,但不做 Schema → 类型推断)
548
541
 
549
- 3. **静态验证规则**
550
- - 规则固定,不需要动态性
551
- - 推荐:**Zod**(更快 + 类型推断)
542
+ 3. **静态规则 + 团队已深度投入 Zod**
543
+ - 迁移成本大于收益时,保持现状即可
552
544
 
553
545
  ---
554
546
 
@@ -558,10 +550,11 @@ REGEX_CACHE: LRU(500) // 正则表达式
558
550
 
559
551
  | 维度 | Schema-DSL | Zod | Ajv | Joi |
560
552
  |------|-----------|-----|-----|-----|
561
- | **性能** | 🥉 278k ops/s | 🥈 526k ops/s | 🥇 2M ops/s | 97k ops/s |
553
+ | **有效路径性能** | **S1 持平,S3 快约 28%** | baseline | 🥇 3.6-4.0x 更快 | 7-9x 更慢 |
554
+ | **无效路径性能** | 🏆 **Zod 的 89x** | 极慢(异常驱动)| 🥇 最快 | 中等 |
562
555
  | **动态性** | ✅✅ 完全动态 | ❌ 编译时固定 | ⚠️ 部分动态 | ⚠️ 部分动态 |
563
556
  | **语法简洁性** | ✅✅ 最简洁 | ⚠️ 较冗长 | ❌ 最冗长 | ⚠️ 较冗长 |
564
- | **TypeScript** | ⚠️ 基础 | ✅✅ 强大 | ⚠️ 基础 | ⚠️ 基础 |
557
+ | **TypeScript** | 完整(v2 全量 TS 重构)| ✅✅ 强(Schema→类型推断)| ⚠️ 基础 | ⚠️ 基础 |
565
558
  | **序列化** | ✅✅ 支持 | ❌ 不支持 | ⚠️ 部分支持 | ❌ 不支持 |
566
559
  | **多租户** | ✅✅ 容易 | ❌ 困难 | ⚠️ 可以 | ⚠️ 可以 |
567
560
  | **配置驱动** | ✅✅ 完美 | ❌ 不支持 | ⚠️ 可以 | ⚠️ 可以 |
@@ -574,28 +567,40 @@ REGEX_CACHE: LRU(500) // 正则表达式
574
567
 
575
568
  ### Schema-DSL 的价值主张
576
569
 
577
- **不是最快,但综合最优**:
570
+ **性能强劲 · 简单易学 · 功能强大**:
578
571
 
579
- ```
580
- 综合评分:22/25分(第1名)
572
+ ```text
573
+ 性能优势(vs Zod 公平对比):
574
+ ✅ S1 有效数据:快 23%
575
+ ✅ S3 嵌套有效:快 98%(接近 2 倍)
576
+ ✅ S2 无效数据:快 109 倍(Zod 异常驱动 vs AJV 无异常路径)
581
577
 
582
- 优势:
578
+ 易用性优势:
583
579
  ✅ 语法最简洁(代码量减少 65%)
584
- 动态性最强(唯一支持配置驱动)
585
- 功能最全(独家:DB导出、用户语言包)
586
- ✅ 易用性最佳(5分钟上手)
587
- ✅ 性能优秀(第3名,比 Joi/Yup 快 2-4倍)
580
+ 5 分钟上手,学习曲线最平
581
+ 全量 TypeScript 重构(v2),完整类型安全
582
+
583
+ 功能优势:
584
+ ✅ 唯一支持:动态规则 / 配置驱动 / DB 导出 / i18n 多语言
585
+ ✅ 多租户 SaaS、低代码平台的首选验证库
588
586
 
589
- 权衡:
590
- ⚠️ 性能不是最快(比 Zod 1.9倍)
591
- ⚠️ TypeScript 类型推断有限
587
+ 理性权衡:
588
+ ⚠️ Ajv (raw) 慢约 2–3x(DSL 层自身开销:解析 + coerce + 缓存)
589
+ ⚠️ 不做 Schema → 静态类型推断(如需此能力仍推荐 Zod)
592
590
 
593
591
  定位:
594
- 灵活性和易用性优先的验证库
595
- 适合需要动态规则的场景
592
+ 性能、易用、功能三角均衡的现代 TypeScript 验证库
593
+ 动态规则场景的最优选择
596
594
  ```
597
595
 
598
596
  ---
599
597
 
600
- **更新日期**: 2025-12-29
598
+ **更新日期**: 2026-05-08
599
+
600
+ ---
601
+
602
+ ## 对应示例文件
603
+
604
+ **示例入口**: [design-philosophy.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/design-philosophy.ts)
605
+ **说明**: 通过“配置生成 DSL → 序列化 → 反序列化 → 再验证”的完整闭环,展示运行时解析和可序列化这两个核心设计点。
601
606