schema-dsl 2.0.0 → 2.0.1

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 (145) hide show
  1. package/CHANGELOG.md +130 -113
  2. package/LICENSE +21 -21
  3. package/README.md +628 -628
  4. package/dist/{DslBuilder-DkLaOo9Q.d.ts → DslBuilder-BIgQOAXp.d.ts} +2 -0
  5. package/dist/{DslBuilder-DQDN0ZxZ.d.cts → DslBuilder-CjHTucNQ.d.cts} +2 -0
  6. package/dist/{Validator-hFWKGxir.d.ts → Validator-CllRdrY0.d.ts} +1 -1
  7. package/dist/{Validator-C7GsVQOH.d.cts → Validator-D6okG9tr.d.cts} +1 -1
  8. package/dist/index.cjs +75 -29
  9. package/dist/index.d.cts +10 -4
  10. package/dist/index.d.ts +10 -4
  11. package/dist/index.js +75 -29
  12. package/dist/plugins/custom-format.cjs +33 -17
  13. package/dist/plugins/custom-format.d.cts +1 -1
  14. package/dist/plugins/custom-format.d.ts +1 -1
  15. package/dist/plugins/custom-format.js +33 -17
  16. package/dist/plugins/custom-type-example.cjs +33 -17
  17. package/dist/plugins/custom-type-example.d.cts +1 -1
  18. package/dist/plugins/custom-type-example.d.ts +1 -1
  19. package/dist/plugins/custom-type-example.js +33 -17
  20. package/dist/plugins/custom-validator.cjs +0 -2
  21. package/dist/plugins/custom-validator.d.cts +1 -1
  22. package/dist/plugins/custom-validator.d.ts +1 -1
  23. package/dist/plugins/custom-validator.js +0 -2
  24. package/docs/FEATURE-INDEX.md +553 -553
  25. package/docs/add-custom-locale.md +496 -496
  26. package/docs/add-keyword.md +24 -24
  27. package/docs/api-reference.md +1047 -1047
  28. package/docs/api.md +13 -13
  29. package/docs/best-practices-project-structure.md +417 -417
  30. package/docs/best-practices.md +712 -712
  31. package/docs/cache-manager.md +344 -344
  32. package/docs/compile.md +45 -45
  33. package/docs/conditional-api.md +1307 -1307
  34. package/docs/custom-extensions-guide.md +339 -339
  35. package/docs/design-philosophy.md +606 -606
  36. package/docs/doc-index.md +324 -324
  37. package/docs/dsl-syntax.md +714 -714
  38. package/docs/dynamic-locale.md +608 -608
  39. package/docs/enum.md +482 -482
  40. package/docs/error-handling.md +1975 -1975
  41. package/docs/export-guide.md +501 -501
  42. package/docs/export-limitations.md +567 -567
  43. package/docs/faq.md +596 -596
  44. package/docs/frontend-i18n-guide.md +307 -307
  45. package/docs/i18n-user-guide.md +487 -487
  46. package/docs/i18n.md +476 -476
  47. package/docs/index.md +48 -48
  48. package/docs/json-schema-basics.md +40 -40
  49. package/docs/label-vs-description.md +271 -271
  50. package/docs/markdown-exporter.md +406 -406
  51. package/docs/mongodb-exporter.md +302 -302
  52. package/docs/multi-language.md +26 -26
  53. package/docs/multi-type-support.md +322 -322
  54. package/docs/mysql-exporter.md +280 -280
  55. package/docs/number-operators.md +449 -449
  56. package/docs/optional-marker-guide.md +326 -326
  57. package/docs/performance-guide.md +49 -49
  58. package/docs/plugin-system.md +381 -381
  59. package/docs/plugin-type-registration.md +34 -34
  60. package/docs/postgresql-exporter.md +311 -311
  61. package/docs/public/favicon.svg +4 -4
  62. package/docs/quick-start.md +435 -435
  63. package/docs/runtime-locale-support.md +532 -532
  64. package/docs/schema-helper.md +345 -345
  65. package/docs/schema-utils-advanced-issues.md +23 -23
  66. package/docs/schema-utils-best-practices.md +20 -20
  67. package/docs/schema-utils-chaining.md +150 -150
  68. package/docs/schema-utils.md +524 -524
  69. package/docs/security-checklist.md +20 -20
  70. package/docs/string-extensions.md +488 -488
  71. package/docs/troubleshooting.md +486 -486
  72. package/docs/type-converter.md +310 -310
  73. package/docs/type-reference.md +242 -242
  74. package/docs/typescript-guide.md +584 -584
  75. package/docs/union-type-guide.md +157 -157
  76. package/docs/union-types.md +284 -284
  77. package/docs/validate-async.md +491 -491
  78. package/docs/validate-batch.md +49 -49
  79. package/docs/validate-dsl-object-support.md +578 -578
  80. package/docs/validate.md +506 -506
  81. package/docs/validation-guide.md +502 -502
  82. package/docs/validator.md +39 -39
  83. package/package.json +131 -131
  84. package/plugins/custom-format.cjs +8 -8
  85. package/plugins/custom-type-example.cjs +8 -8
  86. package/plugins/custom-validator.cjs +8 -8
  87. package/src/adapters/DslAdapter.ts +111 -111
  88. package/src/adapters/index.ts +1 -1
  89. package/src/config/constants.ts +83 -83
  90. package/src/config/index.ts +2 -2
  91. package/src/config/patterns.ts +77 -77
  92. package/src/core/CacheManager.ts +169 -159
  93. package/src/core/ConditionalBuilder.ts +382 -382
  94. package/src/core/ConditionalRuntime.ts +27 -27
  95. package/src/core/ConditionalValidator.ts +254 -254
  96. package/src/core/DslBuilder.ts +687 -677
  97. package/src/core/ErrorCodes.ts +38 -38
  98. package/src/core/ErrorFormatter.ts +271 -271
  99. package/src/core/JSONSchemaCore.ts +65 -65
  100. package/src/core/Locale.ts +187 -187
  101. package/src/core/MessageTemplate.ts +42 -42
  102. package/src/core/ObjectDslBuilder.ts +64 -64
  103. package/src/core/PluginManager.ts +326 -326
  104. package/src/core/StringExtensions.ts +140 -140
  105. package/src/core/TemplateEngine.ts +44 -44
  106. package/src/core/Validator.ts +448 -448
  107. package/src/errors/I18nError.ts +159 -159
  108. package/src/errors/ValidationError.ts +105 -105
  109. package/src/exporters/BaseExporter.ts +60 -60
  110. package/src/exporters/MarkdownExporter.ts +305 -305
  111. package/src/exporters/MongoDBExporter.ts +126 -126
  112. package/src/exporters/MySQLExporter.ts +156 -155
  113. package/src/exporters/PostgreSQLExporter.ts +222 -222
  114. package/src/exporters/index.ts +18 -18
  115. package/src/index.ts +651 -633
  116. package/src/locales/en-US.ts +160 -160
  117. package/src/locales/es-ES.ts +160 -160
  118. package/src/locales/fr-FR.ts +160 -160
  119. package/src/locales/index.ts +103 -103
  120. package/src/locales/ja-JP.ts +160 -160
  121. package/src/locales/types.ts +156 -156
  122. package/src/locales/zh-CN.ts +160 -160
  123. package/src/parser/ConstraintParser.ts +101 -101
  124. package/src/parser/DslParser.ts +470 -470
  125. package/src/parser/SchemaCompiler.ts +66 -66
  126. package/src/parser/TypeRegistry.ts +250 -250
  127. package/src/parser/index.ts +6 -6
  128. package/src/plugins/custom-format.ts +124 -126
  129. package/src/plugins/custom-type-example.ts +106 -108
  130. package/src/plugins/custom-validator.ts +138 -140
  131. package/src/types/conditional.ts +28 -28
  132. package/src/types/config.ts +59 -59
  133. package/src/types/dsl.ts +131 -131
  134. package/src/types/error.ts +60 -60
  135. package/src/types/index.ts +17 -17
  136. package/src/types/infer.ts +127 -127
  137. package/src/types/plugin.ts +58 -58
  138. package/src/types/safe-regex.d.ts +9 -9
  139. package/src/types/schema.ts +66 -66
  140. package/src/types/validate.ts +71 -71
  141. package/src/utils/SchemaHelper.ts +196 -196
  142. package/src/utils/SchemaUtils.ts +365 -346
  143. package/src/utils/TypeConverter.ts +215 -215
  144. package/src/utils/index.ts +10 -10
  145. package/src/validators/CustomKeywords.ts +477 -477
@@ -1,606 +1,606 @@
1
- # Schema-DSL 设计理念与架构
2
-
3
- > **更新时间**: 2026-05-07
4
- > **目的**: 阐述 Schema-DSL 的设计理念、架构优势与性能定位
5
-
6
- ---
7
-
8
- ## 📑 目录
9
-
10
- - [核心设计理念](#核心设计理念)
11
- - [为什么选择运行时解析](#为什么选择运行时解析)
12
- - [编译时构建的局限性](#编译时构建的局限性)
13
- - [性能对比与权衡](#性能对比与权衡)
14
- - [架构设计](#架构设计)
15
- - [适用场景](#适用场景)
16
- - [与其他库对比](#与其他库对比)
17
-
18
- ---
19
-
20
- ## 核心设计理念
21
-
22
- ### 设计优先级
23
-
24
- ```text
25
- 性能强劲 · 简单易学 · 功能强大
26
- ```
27
-
28
- Schema-DSL v2 完成全量 TypeScript 重构,在三个维度上均达到行业领先水平:
29
-
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
-
34
- ---
35
-
36
- ## 为什么选择运行时解析?
37
-
38
- ### 关键决策:运行时 vs 编译时
39
-
40
- Schema-DSL 选择**运行时解析 DSL**,而非**编译时构建**(如 Zod),这是有意为之的设计选择。
41
-
42
- ### ✅ 运行时解析的 5 大优势
43
-
44
- #### 1. 完全动态性
45
-
46
- **问题**: 编译时构建的 Schema 在运行时无法修改
47
-
48
- **Schema-DSL 的解决方案**:
49
- ```javascript
50
- // ✅ 从配置文件读取验证规则
51
- const config = require('./validation-config.json');
52
- const schema = dsl({
53
- username: `string:${config.username.min}-${config.username.max}!`
54
- });
55
-
56
- // ✅ 从数据库读取验证规则
57
- const rules = await db.collection('validation_rules').findOne({
58
- entity: 'user'
59
- });
60
- const schema = dsl({
61
- username: `string:${rules.username.min}-${rules.username.max}!`,
62
- email: 'email!',
63
- age: `number:${rules.age.min}-${rules.age.max}`
64
- });
65
-
66
- // ✅ 根据环境动态调整
67
- const maxLength = process.env.NODE_ENV === 'development' ? 100 : 32;
68
- const schema = dsl({
69
- username: `string:3-${maxLength}!`
70
- });
71
-
72
- // ✅ 根据用户角色动态调整
73
- function getUserSchema(userRole) {
74
- const maxLength = userRole === 'admin' ? 100 : 32;
75
- return dsl({
76
- username: `string:3-${maxLength}!`
77
- });
78
- }
79
- ```
80
-
81
- **Zod 的限制**:
82
- ```typescript
83
- // ❌ Schema 必须在编译时确定
84
- const schema = z.object({
85
- username: z.string().min(3).max(32) // 固定值
86
- });
87
-
88
- // ❌ 无法运行时动态调整
89
- ```
90
-
91
- ---
92
-
93
- #### 2. 多租户 SaaS 系统支持
94
-
95
- **真实场景**: 每个租户有不同的验证规则
96
-
97
- **Schema-DSL 的解决方案**:
98
- ```javascript
99
- // ✅ 租户配置存储在数据库
100
- const tenantRules = {
101
- 'tenant-a': { username: { min: 3, max: 32 } },
102
- 'tenant-b': { username: { min: 5, max: 50 } },
103
- 'tenant-c': { username: { min: 2, max: 20 } }
104
- };
105
-
106
- // ✅ 动态生成 Schema
107
- function getTenantSchema(tenantId) {
108
- const rules = tenantRules[tenantId];
109
- return dsl({
110
- username: `string:${rules.username.min}-${rules.username.max}!`,
111
- email: 'email!'
112
- });
113
- }
114
-
115
- // ✅ 新增租户 = 插入数据库记录,零代码修改
116
- ```
117
-
118
- **Zod 的限制**:
119
- ```typescript
120
- // ❌ 必须为每个租户硬编码 Schema
121
- const tenantASchema = z.object({ username: z.string().min(3).max(32) });
122
- const tenantBSchema = z.object({ username: z.string().min(5).max(50) });
123
- // ... 新增租户 = 修改代码 = 重新部署
124
- ```
125
-
126
- ---
127
-
128
- #### 3. 可序列化(存储、传输、共享)
129
-
130
- **问题**: 编译时构建的 Schema 是 JavaScript 对象,无法序列化
131
-
132
- **Schema-DSL 的解决方案**:
133
- ```javascript
134
- // ✅ DSL 是字符串,可以序列化
135
- const schemaConfig = {
136
- username: 'string:3-32!',
137
- email: 'email!',
138
- age: 'number:18-120'
139
- };
140
-
141
- // ✅ 可以存储到:
142
- // - JSON 文件
143
- fs.writeFileSync('schema.json', JSON.stringify(schemaConfig));
144
-
145
- // - 数据库
146
- await db.collection('schemas').insert({
147
- entity: 'user',
148
- rules: schemaConfig
149
- });
150
-
151
- // - Redis
152
- redis.set('user:schema', JSON.stringify(schemaConfig));
153
-
154
- // - 配置中心(Nacos/Apollo)
155
- await nacos.publishConfig({
156
- dataId: 'user-validation',
157
- group: 'DEFAULT_GROUP',
158
- content: JSON.stringify(schemaConfig)
159
- });
160
-
161
- // ✅ 可以通过 HTTP API 传输
162
- app.get('/api/validation-rules/:entity', async (req, res) => {
163
- const rules = await db.findOne({ entity: req.params.entity });
164
- res.json(rules); // 直接返回 DSL
165
- });
166
-
167
- // ✅ 前后端共享规则
168
- // 后端定义规则 → API 传输 → 前端使用相同的 DSL
169
- fetch('/api/validation-rules/user')
170
- .then(res => res.json())
171
- .then(rules => {
172
- const schema = dsl(rules); // 前后端验证规则完全一致
173
- });
174
- ```
175
-
176
- **Zod 的限制**:
177
- ```typescript
178
- // ❌ Schema 是对象,无法序列化
179
- const schema = z.object({
180
- username: z.string().min(3).max(32)
181
- });
182
-
183
- // ❌ JSON.stringify(schema) → 无法正确序列化
184
- // ❌ 无法存储到数据库
185
- // ❌ 无法通过 API 传输
186
- ```
187
-
188
- ---
189
-
190
- #### 4. 数据库驱动的验证规则
191
-
192
- **真实场景**: 后台管理系统,管理员可配置表单验证规则
193
-
194
- **Schema-DSL 的解决方案**:
195
- ```javascript
196
- // ✅ 管理员在后台界面配置验证规则
197
- // 后台界面:
198
- // - 字段名:username
199
- // - 类型:string
200
- // - 最小长度:3
201
- // - 最大长度:32
202
- // - 必填:是
203
-
204
- // ✅ 规则存储到数据库
205
- await db.collection('form_rules').insert({
206
- formId: 'user_registration',
207
- fields: {
208
- username: 'string:3-32!',
209
- email: 'email!',
210
- age: 'number:18-120'
211
- }
212
- });
213
-
214
- // ✅ 应用使用最新规则(无需重启)
215
- app.post('/api/users', async (req, res) => {
216
- // 从数据库读取最新规则
217
- const formRules = await db.collection('form_rules').findOne({
218
- formId: 'user_registration'
219
- });
220
-
221
- // 动态生成 Schema
222
- const schema = dsl(formRules.fields);
223
-
224
- // 验证
225
- const result = validate(schema, req.body);
226
- if (!result.valid) {
227
- return res.status(400).json({ errors: result.errors });
228
- }
229
-
230
- // ... 业务逻辑
231
- });
232
-
233
- // ✅ 管理员修改规则后,立即生效,无需重启服务
234
- ```
235
-
236
- **Zod 的限制**:
237
- ```typescript
238
- // ❌ 无法从数据库动态加载规则
239
- // ❌ 验证规则必须硬编码在代码中
240
- // ❌ 修改规则 = 修改代码 = 重新部署
241
- ```
242
-
243
- ---
244
-
245
- #### 5. 低代码/无代码平台基础
246
-
247
- **真实场景**: 可视化表单构建器
248
-
249
- **Schema-DSL 的解决方案**:
250
- ```javascript
251
- // ✅ 可视化表单构建器配置
252
- const formBuilder = {
253
- formId: 'contact',
254
- title: '联系我们',
255
- fields: [
256
- {
257
- name: 'name',
258
- label: '姓名',
259
- type: 'text',
260
- validation: 'string:2-50!', // ← 在 UI 中配置
261
- placeholder: '请输入您的姓名'
262
- },
263
- {
264
- name: 'email',
265
- label: '邮箱',
266
- type: 'email',
267
- validation: 'email!',
268
- placeholder: '请输入您的邮箱'
269
- },
270
- {
271
- name: 'message',
272
- label: '留言',
273
- type: 'textarea',
274
- validation: 'string:10-500!',
275
- placeholder: '请输入您的留言'
276
- }
277
- ]
278
- };
279
-
280
- // ✅ 自动生成验证 Schema
281
- const schema = dsl(
282
- formBuilder.fields.reduce((acc, field) => {
283
- acc[field.name] = field.validation;
284
- return acc;
285
- }, {})
286
- );
287
-
288
- // ✅ 自动生成前端表单
289
- function renderForm(formBuilder) {
290
- return formBuilder.fields.map(field => (
291
- `<div>
292
- <label>${field.label}</label>
293
- <input name="${field.name}" placeholder="${field.placeholder}" />
294
- </div>`
295
- ));
296
- }
297
-
298
- // ✅ 这是低代码平台的基础能力
299
- // - 用户在界面拖拽表单
300
- // - 配置验证规则(无需写代码)
301
- // - 自动生成前后端代码
302
- ```
303
-
304
- ---
305
-
306
- ### ⚠️ 其他场景
307
-
308
- #### A/B 测试验证规则
309
-
310
- ```javascript
311
- // ✅ 从配置中心读取 A/B 测试配置
312
- const abTestConfig = await configCenter.get('user_validation_ab_test');
313
-
314
- const schema = dsl({
315
- username: abTestConfig.userInGroupA
316
- ? 'string:2-50!' // A 组:宽松规则
317
- : 'string:5-20!' // B 组:严格规则
318
- });
319
-
320
- // 修改配置中心的值,立即生效,无需重新部署
321
- ```
322
-
323
- #### 灰度发布
324
-
325
- ```javascript
326
- // ✅ 根据灰度比例动态选择规则
327
- const grayConfig = await configCenter.get('validation_gray_config');
328
- const useNewRules = Math.random() < grayConfig.grayRatio;
329
-
330
- const schema = dsl(useNewRules ? newRules : oldRules);
331
- ```
332
-
333
- ---
334
-
335
- ## 编译时构建的局限性
336
-
337
- ### Zod 等编译时库的限制
338
-
339
- | 限制 | 说明 | 影响 |
340
- |------|------|------|
341
- | **无法动态调整** | Schema 在编译时固定 | 无法根据配置/环境/用户动态生成 |
342
- | **无法序列化** | Schema 是 JavaScript 对象 | 无法存储、传输、共享 |
343
- | **多租户困难** | 必须为每个租户写代码 | 新增租户 = 修改代码 = 重新部署 |
344
- | **数据库驱动困难** | 无法从数据库读取规则 | 后台配置表单验证无法实现 |
345
- | **配置驱动困难** | 必须硬编码 Schema | 无法从配置文件/API 动态生成 |
346
- | **前后端共享困难** | 无法通过 API 传输 | 前后端验证规则容易不一致 |
347
- | **低代码平台不适合** | 无法可视化配置 | 不适合低代码/无代码场景 |
348
-
349
- ---
350
-
351
- ## 性能对比与权衡
352
-
353
- ### 真实性能测试结果(v2 基准,分场景对比)
354
-
355
- **测试环境**: Node.js v20.20.2, tinybench,JSON Schema 同维度对比
356
-
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 |
362
-
363
- > ℹ️ 绝对 ops/s 数值随测试机器 CPU 性能而变化;**相对倍数(vs Zod 列)是稳定的跨机器指标**,以下分析均基于倍数。
364
- > ℹ️ S2 使用 `validate(schema, data, { format: false })` 关闭 i18n 格式化,与其他库保持相同条件(均不做 i18n 模板渲染),是真正的苹果对苹果比较。
365
- > ℹ️ Ajv (raw) 是 schema-dsl 的底层引擎,差值即为 schema-dsl 自身层(DSL 解析 + coerce + 缓存)的开销。
366
-
367
- ### 性能分析
368
-
369
- **Schema-DSL vs Zod 对比结论**
370
-
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 的执行流程(含内置缓存):
378
- DSL 字符串
379
- ↓ 缓存命中(热路径,无解析开销)
380
- 验证函数
381
- ↓ 执行验证 (~0.5-1μs)
382
- 结果
383
-
384
- 冷路径(首次):
385
- DSL 字符串 → 解析 → JSON Schema → Ajv 编译 → 缓存并执行
386
- ```
387
-
388
- **性能瓶颈分布(冷启动)**:
389
- 1. DSL 解析(40-50%)
390
- 2. JSON Schema 转换(20-30%)
391
- 3. 多语言处理(10-20%)
392
- 4. Ajv 编译(10-15%)
393
-
394
- ---
395
-
396
- ### 性能权衡分析
397
-
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 功能
403
- ```
404
-
405
- **换来的价值**:
406
- ```text
407
- ✅ 代码量减少 65%
408
- 'string:3-32!' vs z.string().min(3).max(32)
409
-
410
- ✅ 完全动态的验证规则
411
- 可从配置/数据库/API 动态生成
412
-
413
- ✅ 多租户支持
414
- 每个租户不同规则,零代码修改
415
-
416
- ✅ 可序列化
417
- 可存储、传输、共享
418
-
419
- ✅ 前后端共享规则
420
- 一套规则,两端使用
421
-
422
- ✅ 低代码平台基础
423
- 可视化配置表单验证
424
-
425
- ✅ 数据库驱动
426
- 管理员后台配置,立即生效
427
- ```
428
-
429
- ### 性能优化措施
430
-
431
- ### 缓存优化
432
- ```javascript
433
- // Schema 缓存:5000条(提升 5倍)
434
- // 正则缓存:500条(提升 2.5倍)
435
- // LRU 驱逐机制
436
-
437
- // 效果:
438
- // - 大型项目(3000 Schema):3倍提升
439
- // - 超大型项目(10000 Schema):5-10倍提升
440
- ```
441
-
442
- ---
443
-
444
- ## 架构设计
445
-
446
- ### 核心组件
447
-
448
- ```text
449
- ┌─────────────────────────────────────┐
450
- │ DSL 字符串 │
451
- │ 'string:3-32!', 'email!' │
452
- └──────────────┬──────────────────────┘
453
-
454
-
455
- ┌─────────────────────────────────────┐
456
- │ DslAdapter (解析器) │
457
- │ 正则解析 → DSL 对象 │
458
- └──────────────┬──────────────────────┘
459
-
460
-
461
- ┌─────────────────────────────────────┐
462
- │ JSONSchemaCore (转换器) │
463
- │ DSL 对象 → JSON Schema │
464
- └──────────────┬──────────────────────┘
465
-
466
-
467
- ┌─────────────────────────────────────┐
468
- │ Ajv (验证引擎) │
469
- │ JSON Schema → 验证函数 │
470
- └──────────────┬──────────────────────┘
471
-
472
-
473
- ┌─────────────────────────────────────┐
474
- │ ErrorFormatter (错误格式化) │
475
- │ Ajv 错误 → 友好消息 → 多语言 │
476
- └──────────────┬──────────────────────┘
477
-
478
-
479
- ┌─────────────────────────────────────┐
480
- │ ValidationResult │
481
- │ { valid, errors, data } │
482
- └─────────────────────────────────────┘
483
- ```
484
-
485
- ### 缓存机制
486
-
487
- ```javascript
488
- // Schema 缓存
489
- SCHEMA_CACHE: LRU(5000) // DSL → JSONSchema
490
- REGEX_CACHE: LRU(500) // 正则表达式
491
-
492
- // 缓存命中:0μs 开销
493
- // 缓存未命中:12-21μs 开销
494
- ```
495
-
496
- ---
497
-
498
- ## 适用场景
499
-
500
- ### ✅ 选择 Schema-DSL
501
-
502
- **最适合的场景**:
503
-
504
- 1. **多租户 SaaS 系统**
505
- - 每个租户不同验证规则
506
- - 新增租户零代码修改
507
-
508
- 2. **后台管理系统**
509
- - 管理员配置表单验证
510
- - 规则立即生效,无需重启
511
-
512
- 3. **配置驱动开发**
513
- - 验证规则存储在配置文件/数据库
514
- - 可通过 API 动态获取
515
-
516
- 4. **低代码/无代码平台**
517
- - 可视化表单构建器
518
- - 拖拽配置验证规则
519
-
520
- 5. **快速原型开发**
521
- - 5分钟上手
522
- - 代码量最少
523
-
524
- 6. **前后端共享验证**
525
- - 一套规则,两端使用
526
- - 通过 API 传输
527
-
528
- 7. **A/B 测试/灰度发布**
529
- - 动态切换验证规则
530
- - 配置驱动
531
-
532
- ### ⚠️ 以下场景可能有更优选择
533
-
534
- 1. **追求代码生成级极致吞吐量**
535
- - 需要 fastest-validator 级别性能(compile 为原生 JS 函数)
536
- - 推荐:**fastest-validator**(但需放弃 JSON Schema 标准兼容)
537
-
538
- 2. **以 Schema → 静态类型推断为核心目标**
539
- - 需要从 Schema 自动导出精确的 TypeScript 类型(如 `z.infer<typeof schema>`)
540
- - 推荐:**Zod**(schema-dsl 提供完整 TypeScript API 类型安全,但不做 Schema → 类型推断)
541
-
542
- 3. **静态规则 + 团队已深度投入 Zod**
543
- - 迁移成本大于收益时,保持现状即可
544
-
545
- ---
546
-
547
- ## 与其他库对比
548
-
549
- ### 综合对比
550
-
551
- | 维度 | Schema-DSL | Zod | Ajv | Joi |
552
- |------|-----------|-----|-----|-----|
553
- | **有效路径性能** | ✅ **S1 持平,S3 快约 28%** | baseline | 🥇 3.6-4.0x 更快 | 7-9x 更慢 |
554
- | **无效路径性能** | 🏆 **Zod 的 89x** | 极慢(异常驱动)| 🥇 最快 | 中等 |
555
- | **动态性** | ✅✅ 完全动态 | ❌ 编译时固定 | ⚠️ 部分动态 | ⚠️ 部分动态 |
556
- | **语法简洁性** | ✅✅ 最简洁 | ⚠️ 较冗长 | ❌ 最冗长 | ⚠️ 较冗长 |
557
- | **TypeScript** | ✅ 完整(v2 全量 TS 重构)| ✅✅ 强(Schema→类型推断)| ⚠️ 基础 | ⚠️ 基础 |
558
- | **序列化** | ✅✅ 支持 | ❌ 不支持 | ⚠️ 部分支持 | ❌ 不支持 |
559
- | **多租户** | ✅✅ 容易 | ❌ 困难 | ⚠️ 可以 | ⚠️ 可以 |
560
- | **配置驱动** | ✅✅ 完美 | ❌ 不支持 | ⚠️ 可以 | ⚠️ 可以 |
561
- | **数据库导出** | ✅✅ 唯一 | ❌ | ❌ | ❌ |
562
- | **学习曲线** | ✅✅ 5分钟 | ⚠️ 30分钟 | ❌ 1小时 | ⚠️ 30分钟 |
563
-
564
- ---
565
-
566
- ## 结论
567
-
568
- ### Schema-DSL 的价值主张
569
-
570
- **性能强劲 · 简单易学 · 功能强大**:
571
-
572
- ```text
573
- 性能优势(vs Zod 公平对比):
574
- ✅ S1 有效数据:快 23%
575
- ✅ S3 嵌套有效:快 98%(接近 2 倍)
576
- ✅ S2 无效数据:快 109 倍(Zod 异常驱动 vs AJV 无异常路径)
577
-
578
- 易用性优势:
579
- ✅ 语法最简洁(代码量减少 65%)
580
- ✅ 5 分钟上手,学习曲线最平
581
- ✅ 全量 TypeScript 重构(v2),完整类型安全
582
-
583
- 功能优势:
584
- ✅ 唯一支持:动态规则 / 配置驱动 / DB 导出 / i18n 多语言
585
- ✅ 多租户 SaaS、低代码平台的首选验证库
586
-
587
- 理性权衡:
588
- ⚠️ 比 Ajv (raw) 慢约 2–3x(DSL 层自身开销:解析 + coerce + 缓存)
589
- ⚠️ 不做 Schema → 静态类型推断(如需此能力仍推荐 Zod)
590
-
591
- 定位:
592
- 性能、易用、功能三角均衡的现代 TypeScript 验证库
593
- 动态规则场景的最优选择
594
- ```
595
-
596
- ---
597
-
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 → 序列化 → 反序列化 → 再验证”的完整闭环,展示运行时解析和可序列化这两个核心设计点。
606
-
1
+ # Schema-DSL 设计理念与架构
2
+
3
+ > **更新时间**: 2026-05-07
4
+ > **目的**: 阐述 Schema-DSL 的设计理念、架构优势与性能定位
5
+
6
+ ---
7
+
8
+ ## 📑 目录
9
+
10
+ - [核心设计理念](#核心设计理念)
11
+ - [为什么选择运行时解析](#为什么选择运行时解析)
12
+ - [编译时构建的局限性](#编译时构建的局限性)
13
+ - [性能对比与权衡](#性能对比与权衡)
14
+ - [架构设计](#架构设计)
15
+ - [适用场景](#适用场景)
16
+ - [与其他库对比](#与其他库对比)
17
+
18
+ ---
19
+
20
+ ## 核心设计理念
21
+
22
+ ### 设计优先级
23
+
24
+ ```text
25
+ 性能强劲 · 简单易学 · 功能强大
26
+ ```
27
+
28
+ Schema-DSL v2 完成全量 TypeScript 重构,在三个维度上均达到行业领先水平:
29
+
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
+
34
+ ---
35
+
36
+ ## 为什么选择运行时解析?
37
+
38
+ ### 关键决策:运行时 vs 编译时
39
+
40
+ Schema-DSL 选择**运行时解析 DSL**,而非**编译时构建**(如 Zod),这是有意为之的设计选择。
41
+
42
+ ### ✅ 运行时解析的 5 大优势
43
+
44
+ #### 1. 完全动态性
45
+
46
+ **问题**: 编译时构建的 Schema 在运行时无法修改
47
+
48
+ **Schema-DSL 的解决方案**:
49
+ ```javascript
50
+ // ✅ 从配置文件读取验证规则
51
+ const config = require('./validation-config.json');
52
+ const schema = dsl({
53
+ username: `string:${config.username.min}-${config.username.max}!`
54
+ });
55
+
56
+ // ✅ 从数据库读取验证规则
57
+ const rules = await db.collection('validation_rules').findOne({
58
+ entity: 'user'
59
+ });
60
+ const schema = dsl({
61
+ username: `string:${rules.username.min}-${rules.username.max}!`,
62
+ email: 'email!',
63
+ age: `number:${rules.age.min}-${rules.age.max}`
64
+ });
65
+
66
+ // ✅ 根据环境动态调整
67
+ const maxLength = process.env.NODE_ENV === 'development' ? 100 : 32;
68
+ const schema = dsl({
69
+ username: `string:3-${maxLength}!`
70
+ });
71
+
72
+ // ✅ 根据用户角色动态调整
73
+ function getUserSchema(userRole) {
74
+ const maxLength = userRole === 'admin' ? 100 : 32;
75
+ return dsl({
76
+ username: `string:3-${maxLength}!`
77
+ });
78
+ }
79
+ ```
80
+
81
+ **Zod 的限制**:
82
+ ```typescript
83
+ // ❌ Schema 必须在编译时确定
84
+ const schema = z.object({
85
+ username: z.string().min(3).max(32) // 固定值
86
+ });
87
+
88
+ // ❌ 无法运行时动态调整
89
+ ```
90
+
91
+ ---
92
+
93
+ #### 2. 多租户 SaaS 系统支持
94
+
95
+ **真实场景**: 每个租户有不同的验证规则
96
+
97
+ **Schema-DSL 的解决方案**:
98
+ ```javascript
99
+ // ✅ 租户配置存储在数据库
100
+ const tenantRules = {
101
+ 'tenant-a': { username: { min: 3, max: 32 } },
102
+ 'tenant-b': { username: { min: 5, max: 50 } },
103
+ 'tenant-c': { username: { min: 2, max: 20 } }
104
+ };
105
+
106
+ // ✅ 动态生成 Schema
107
+ function getTenantSchema(tenantId) {
108
+ const rules = tenantRules[tenantId];
109
+ return dsl({
110
+ username: `string:${rules.username.min}-${rules.username.max}!`,
111
+ email: 'email!'
112
+ });
113
+ }
114
+
115
+ // ✅ 新增租户 = 插入数据库记录,零代码修改
116
+ ```
117
+
118
+ **Zod 的限制**:
119
+ ```typescript
120
+ // ❌ 必须为每个租户硬编码 Schema
121
+ const tenantASchema = z.object({ username: z.string().min(3).max(32) });
122
+ const tenantBSchema = z.object({ username: z.string().min(5).max(50) });
123
+ // ... 新增租户 = 修改代码 = 重新部署
124
+ ```
125
+
126
+ ---
127
+
128
+ #### 3. 可序列化(存储、传输、共享)
129
+
130
+ **问题**: 编译时构建的 Schema 是 JavaScript 对象,无法序列化
131
+
132
+ **Schema-DSL 的解决方案**:
133
+ ```javascript
134
+ // ✅ DSL 是字符串,可以序列化
135
+ const schemaConfig = {
136
+ username: 'string:3-32!',
137
+ email: 'email!',
138
+ age: 'number:18-120'
139
+ };
140
+
141
+ // ✅ 可以存储到:
142
+ // - JSON 文件
143
+ fs.writeFileSync('schema.json', JSON.stringify(schemaConfig));
144
+
145
+ // - 数据库
146
+ await db.collection('schemas').insert({
147
+ entity: 'user',
148
+ rules: schemaConfig
149
+ });
150
+
151
+ // - Redis
152
+ redis.set('user:schema', JSON.stringify(schemaConfig));
153
+
154
+ // - 配置中心(Nacos/Apollo)
155
+ await nacos.publishConfig({
156
+ dataId: 'user-validation',
157
+ group: 'DEFAULT_GROUP',
158
+ content: JSON.stringify(schemaConfig)
159
+ });
160
+
161
+ // ✅ 可以通过 HTTP API 传输
162
+ app.get('/api/validation-rules/:entity', async (req, res) => {
163
+ const rules = await db.findOne({ entity: req.params.entity });
164
+ res.json(rules); // 直接返回 DSL
165
+ });
166
+
167
+ // ✅ 前后端共享规则
168
+ // 后端定义规则 → API 传输 → 前端使用相同的 DSL
169
+ fetch('/api/validation-rules/user')
170
+ .then(res => res.json())
171
+ .then(rules => {
172
+ const schema = dsl(rules); // 前后端验证规则完全一致
173
+ });
174
+ ```
175
+
176
+ **Zod 的限制**:
177
+ ```typescript
178
+ // ❌ Schema 是对象,无法序列化
179
+ const schema = z.object({
180
+ username: z.string().min(3).max(32)
181
+ });
182
+
183
+ // ❌ JSON.stringify(schema) → 无法正确序列化
184
+ // ❌ 无法存储到数据库
185
+ // ❌ 无法通过 API 传输
186
+ ```
187
+
188
+ ---
189
+
190
+ #### 4. 数据库驱动的验证规则
191
+
192
+ **真实场景**: 后台管理系统,管理员可配置表单验证规则
193
+
194
+ **Schema-DSL 的解决方案**:
195
+ ```javascript
196
+ // ✅ 管理员在后台界面配置验证规则
197
+ // 后台界面:
198
+ // - 字段名:username
199
+ // - 类型:string
200
+ // - 最小长度:3
201
+ // - 最大长度:32
202
+ // - 必填:是
203
+
204
+ // ✅ 规则存储到数据库
205
+ await db.collection('form_rules').insert({
206
+ formId: 'user_registration',
207
+ fields: {
208
+ username: 'string:3-32!',
209
+ email: 'email!',
210
+ age: 'number:18-120'
211
+ }
212
+ });
213
+
214
+ // ✅ 应用使用最新规则(无需重启)
215
+ app.post('/api/users', async (req, res) => {
216
+ // 从数据库读取最新规则
217
+ const formRules = await db.collection('form_rules').findOne({
218
+ formId: 'user_registration'
219
+ });
220
+
221
+ // 动态生成 Schema
222
+ const schema = dsl(formRules.fields);
223
+
224
+ // 验证
225
+ const result = validate(schema, req.body);
226
+ if (!result.valid) {
227
+ return res.status(400).json({ errors: result.errors });
228
+ }
229
+
230
+ // ... 业务逻辑
231
+ });
232
+
233
+ // ✅ 管理员修改规则后,立即生效,无需重启服务
234
+ ```
235
+
236
+ **Zod 的限制**:
237
+ ```typescript
238
+ // ❌ 无法从数据库动态加载规则
239
+ // ❌ 验证规则必须硬编码在代码中
240
+ // ❌ 修改规则 = 修改代码 = 重新部署
241
+ ```
242
+
243
+ ---
244
+
245
+ #### 5. 低代码/无代码平台基础
246
+
247
+ **真实场景**: 可视化表单构建器
248
+
249
+ **Schema-DSL 的解决方案**:
250
+ ```javascript
251
+ // ✅ 可视化表单构建器配置
252
+ const formBuilder = {
253
+ formId: 'contact',
254
+ title: '联系我们',
255
+ fields: [
256
+ {
257
+ name: 'name',
258
+ label: '姓名',
259
+ type: 'text',
260
+ validation: 'string:2-50!', // ← 在 UI 中配置
261
+ placeholder: '请输入您的姓名'
262
+ },
263
+ {
264
+ name: 'email',
265
+ label: '邮箱',
266
+ type: 'email',
267
+ validation: 'email!',
268
+ placeholder: '请输入您的邮箱'
269
+ },
270
+ {
271
+ name: 'message',
272
+ label: '留言',
273
+ type: 'textarea',
274
+ validation: 'string:10-500!',
275
+ placeholder: '请输入您的留言'
276
+ }
277
+ ]
278
+ };
279
+
280
+ // ✅ 自动生成验证 Schema
281
+ const schema = dsl(
282
+ formBuilder.fields.reduce((acc, field) => {
283
+ acc[field.name] = field.validation;
284
+ return acc;
285
+ }, {})
286
+ );
287
+
288
+ // ✅ 自动生成前端表单
289
+ function renderForm(formBuilder) {
290
+ return formBuilder.fields.map(field => (
291
+ `<div>
292
+ <label>${field.label}</label>
293
+ <input name="${field.name}" placeholder="${field.placeholder}" />
294
+ </div>`
295
+ ));
296
+ }
297
+
298
+ // ✅ 这是低代码平台的基础能力
299
+ // - 用户在界面拖拽表单
300
+ // - 配置验证规则(无需写代码)
301
+ // - 自动生成前后端代码
302
+ ```
303
+
304
+ ---
305
+
306
+ ### ⚠️ 其他场景
307
+
308
+ #### A/B 测试验证规则
309
+
310
+ ```javascript
311
+ // ✅ 从配置中心读取 A/B 测试配置
312
+ const abTestConfig = await configCenter.get('user_validation_ab_test');
313
+
314
+ const schema = dsl({
315
+ username: abTestConfig.userInGroupA
316
+ ? 'string:2-50!' // A 组:宽松规则
317
+ : 'string:5-20!' // B 组:严格规则
318
+ });
319
+
320
+ // 修改配置中心的值,立即生效,无需重新部署
321
+ ```
322
+
323
+ #### 灰度发布
324
+
325
+ ```javascript
326
+ // ✅ 根据灰度比例动态选择规则
327
+ const grayConfig = await configCenter.get('validation_gray_config');
328
+ const useNewRules = Math.random() < grayConfig.grayRatio;
329
+
330
+ const schema = dsl(useNewRules ? newRules : oldRules);
331
+ ```
332
+
333
+ ---
334
+
335
+ ## 编译时构建的局限性
336
+
337
+ ### Zod 等编译时库的限制
338
+
339
+ | 限制 | 说明 | 影响 |
340
+ |------|------|------|
341
+ | **无法动态调整** | Schema 在编译时固定 | 无法根据配置/环境/用户动态生成 |
342
+ | **无法序列化** | Schema 是 JavaScript 对象 | 无法存储、传输、共享 |
343
+ | **多租户困难** | 必须为每个租户写代码 | 新增租户 = 修改代码 = 重新部署 |
344
+ | **数据库驱动困难** | 无法从数据库读取规则 | 后台配置表单验证无法实现 |
345
+ | **配置驱动困难** | 必须硬编码 Schema | 无法从配置文件/API 动态生成 |
346
+ | **前后端共享困难** | 无法通过 API 传输 | 前后端验证规则容易不一致 |
347
+ | **低代码平台不适合** | 无法可视化配置 | 不适合低代码/无代码场景 |
348
+
349
+ ---
350
+
351
+ ## 性能对比与权衡
352
+
353
+ ### 真实性能测试结果(v2 基准,分场景对比)
354
+
355
+ **测试环境**: Node.js v20.20.2, tinybench,JSON Schema 同维度对比
356
+
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 |
362
+
363
+ > ℹ️ 绝对 ops/s 数值随测试机器 CPU 性能而变化;**相对倍数(vs Zod 列)是稳定的跨机器指标**,以下分析均基于倍数。
364
+ > ℹ️ S2 使用 `validate(schema, data, { format: false })` 关闭 i18n 格式化,与其他库保持相同条件(均不做 i18n 模板渲染),是真正的苹果对苹果比较。
365
+ > ℹ️ Ajv (raw) 是 schema-dsl 的底层引擎,差值即为 schema-dsl 自身层(DSL 解析 + coerce + 缓存)的开销。
366
+
367
+ ### 性能分析
368
+
369
+ **Schema-DSL vs Zod 对比结论**
370
+
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 的执行流程(含内置缓存):
378
+ DSL 字符串
379
+ ↓ 缓存命中(热路径,无解析开销)
380
+ 验证函数
381
+ ↓ 执行验证 (~0.5-1μs)
382
+ 结果
383
+
384
+ 冷路径(首次):
385
+ DSL 字符串 → 解析 → JSON Schema → Ajv 编译 → 缓存并执行
386
+ ```
387
+
388
+ **性能瓶颈分布(冷启动)**:
389
+ 1. DSL 解析(40-50%)
390
+ 2. JSON Schema 转换(20-30%)
391
+ 3. 多语言处理(10-20%)
392
+ 4. Ajv 编译(10-15%)
393
+
394
+ ---
395
+
396
+ ### 性能权衡分析
397
+
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 功能
403
+ ```
404
+
405
+ **换来的价值**:
406
+ ```text
407
+ ✅ 代码量减少 65%
408
+ 'string:3-32!' vs z.string().min(3).max(32)
409
+
410
+ ✅ 完全动态的验证规则
411
+ 可从配置/数据库/API 动态生成
412
+
413
+ ✅ 多租户支持
414
+ 每个租户不同规则,零代码修改
415
+
416
+ ✅ 可序列化
417
+ 可存储、传输、共享
418
+
419
+ ✅ 前后端共享规则
420
+ 一套规则,两端使用
421
+
422
+ ✅ 低代码平台基础
423
+ 可视化配置表单验证
424
+
425
+ ✅ 数据库驱动
426
+ 管理员后台配置,立即生效
427
+ ```
428
+
429
+ ### 性能优化措施
430
+
431
+ ### 缓存优化
432
+ ```javascript
433
+ // Schema 缓存:5000条(提升 5倍)
434
+ // 正则缓存:500条(提升 2.5倍)
435
+ // LRU 驱逐机制
436
+
437
+ // 效果:
438
+ // - 大型项目(3000 Schema):3倍提升
439
+ // - 超大型项目(10000 Schema):5-10倍提升
440
+ ```
441
+
442
+ ---
443
+
444
+ ## 架构设计
445
+
446
+ ### 核心组件
447
+
448
+ ```text
449
+ ┌─────────────────────────────────────┐
450
+ │ DSL 字符串 │
451
+ │ 'string:3-32!', 'email!' │
452
+ └──────────────┬──────────────────────┘
453
+
454
+
455
+ ┌─────────────────────────────────────┐
456
+ │ DslAdapter (解析器) │
457
+ │ 正则解析 → DSL 对象 │
458
+ └──────────────┬──────────────────────┘
459
+
460
+
461
+ ┌─────────────────────────────────────┐
462
+ │ JSONSchemaCore (转换器) │
463
+ │ DSL 对象 → JSON Schema │
464
+ └──────────────┬──────────────────────┘
465
+
466
+
467
+ ┌─────────────────────────────────────┐
468
+ │ Ajv (验证引擎) │
469
+ │ JSON Schema → 验证函数 │
470
+ └──────────────┬──────────────────────┘
471
+
472
+
473
+ ┌─────────────────────────────────────┐
474
+ │ ErrorFormatter (错误格式化) │
475
+ │ Ajv 错误 → 友好消息 → 多语言 │
476
+ └──────────────┬──────────────────────┘
477
+
478
+
479
+ ┌─────────────────────────────────────┐
480
+ │ ValidationResult │
481
+ │ { valid, errors, data } │
482
+ └─────────────────────────────────────┘
483
+ ```
484
+
485
+ ### 缓存机制
486
+
487
+ ```javascript
488
+ // Schema 缓存
489
+ SCHEMA_CACHE: LRU(5000) // DSL → JSONSchema
490
+ REGEX_CACHE: LRU(500) // 正则表达式
491
+
492
+ // 缓存命中:0μs 开销
493
+ // 缓存未命中:12-21μs 开销
494
+ ```
495
+
496
+ ---
497
+
498
+ ## 适用场景
499
+
500
+ ### ✅ 选择 Schema-DSL
501
+
502
+ **最适合的场景**:
503
+
504
+ 1. **多租户 SaaS 系统**
505
+ - 每个租户不同验证规则
506
+ - 新增租户零代码修改
507
+
508
+ 2. **后台管理系统**
509
+ - 管理员配置表单验证
510
+ - 规则立即生效,无需重启
511
+
512
+ 3. **配置驱动开发**
513
+ - 验证规则存储在配置文件/数据库
514
+ - 可通过 API 动态获取
515
+
516
+ 4. **低代码/无代码平台**
517
+ - 可视化表单构建器
518
+ - 拖拽配置验证规则
519
+
520
+ 5. **快速原型开发**
521
+ - 5分钟上手
522
+ - 代码量最少
523
+
524
+ 6. **前后端共享验证**
525
+ - 一套规则,两端使用
526
+ - 通过 API 传输
527
+
528
+ 7. **A/B 测试/灰度发布**
529
+ - 动态切换验证规则
530
+ - 配置驱动
531
+
532
+ ### ⚠️ 以下场景可能有更优选择
533
+
534
+ 1. **追求代码生成级极致吞吐量**
535
+ - 需要 fastest-validator 级别性能(compile 为原生 JS 函数)
536
+ - 推荐:**fastest-validator**(但需放弃 JSON Schema 标准兼容)
537
+
538
+ 2. **以 Schema → 静态类型推断为核心目标**
539
+ - 需要从 Schema 自动导出精确的 TypeScript 类型(如 `z.infer<typeof schema>`)
540
+ - 推荐:**Zod**(schema-dsl 提供完整 TypeScript API 类型安全,但不做 Schema → 类型推断)
541
+
542
+ 3. **静态规则 + 团队已深度投入 Zod**
543
+ - 迁移成本大于收益时,保持现状即可
544
+
545
+ ---
546
+
547
+ ## 与其他库对比
548
+
549
+ ### 综合对比
550
+
551
+ | 维度 | Schema-DSL | Zod | Ajv | Joi |
552
+ |------|-----------|-----|-----|-----|
553
+ | **有效路径性能** | ✅ **S1 持平,S3 快约 28%** | baseline | 🥇 3.6-4.0x 更快 | 7-9x 更慢 |
554
+ | **无效路径性能** | 🏆 **Zod 的 89x** | 极慢(异常驱动)| 🥇 最快 | 中等 |
555
+ | **动态性** | ✅✅ 完全动态 | ❌ 编译时固定 | ⚠️ 部分动态 | ⚠️ 部分动态 |
556
+ | **语法简洁性** | ✅✅ 最简洁 | ⚠️ 较冗长 | ❌ 最冗长 | ⚠️ 较冗长 |
557
+ | **TypeScript** | ✅ 完整(v2 全量 TS 重构)| ✅✅ 强(Schema→类型推断)| ⚠️ 基础 | ⚠️ 基础 |
558
+ | **序列化** | ✅✅ 支持 | ❌ 不支持 | ⚠️ 部分支持 | ❌ 不支持 |
559
+ | **多租户** | ✅✅ 容易 | ❌ 困难 | ⚠️ 可以 | ⚠️ 可以 |
560
+ | **配置驱动** | ✅✅ 完美 | ❌ 不支持 | ⚠️ 可以 | ⚠️ 可以 |
561
+ | **数据库导出** | ✅✅ 唯一 | ❌ | ❌ | ❌ |
562
+ | **学习曲线** | ✅✅ 5分钟 | ⚠️ 30分钟 | ❌ 1小时 | ⚠️ 30分钟 |
563
+
564
+ ---
565
+
566
+ ## 结论
567
+
568
+ ### Schema-DSL 的价值主张
569
+
570
+ **性能强劲 · 简单易学 · 功能强大**:
571
+
572
+ ```text
573
+ 性能优势(vs Zod 公平对比):
574
+ ✅ S1 有效数据:快 23%
575
+ ✅ S3 嵌套有效:快 98%(接近 2 倍)
576
+ ✅ S2 无效数据:快 109 倍(Zod 异常驱动 vs AJV 无异常路径)
577
+
578
+ 易用性优势:
579
+ ✅ 语法最简洁(代码量减少 65%)
580
+ ✅ 5 分钟上手,学习曲线最平
581
+ ✅ 全量 TypeScript 重构(v2),完整类型安全
582
+
583
+ 功能优势:
584
+ ✅ 唯一支持:动态规则 / 配置驱动 / DB 导出 / i18n 多语言
585
+ ✅ 多租户 SaaS、低代码平台的首选验证库
586
+
587
+ 理性权衡:
588
+ ⚠️ 比 Ajv (raw) 慢约 2–3x(DSL 层自身开销:解析 + coerce + 缓存)
589
+ ⚠️ 不做 Schema → 静态类型推断(如需此能力仍推荐 Zod)
590
+
591
+ 定位:
592
+ 性能、易用、功能三角均衡的现代 TypeScript 验证库
593
+ 动态规则场景的最优选择
594
+ ```
595
+
596
+ ---
597
+
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 → 序列化 → 反序列化 → 再验证”的完整闭环,展示运行时解析和可序列化这两个核心设计点。
606
+