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,578 +1,578 @@
1
- # validate() 函数支持 DSL 对象说明
2
-
3
- ## 问题
4
-
5
- 用户问:`validate(schema, { email: 'test@example.com', age: 25 })` 中的 `schema` 能否直接是个对象,为什么必须是 schema?
6
-
7
- ## 答案
8
-
9
- **现在可以了!** 🎉 当前 TypeScript 重构版中,顶层 `validate()` 和 `validateAsync()` 都支持直接传入 DSL 对象。
10
-
11
- ---
12
-
13
- ## 支持的三种方式
14
-
15
- ### 方式1:传入 DSL 对象(✅ 当前版本支持)
16
-
17
- ```javascript
18
- const { validate } = require('schema-dsl');
19
-
20
- // ✅ 直接传入 DSL 对象,无需 dsl() 包裹
21
- const result = validate(
22
- { email: 'email!', age: 'number:18-120' }, // DSL 对象
23
- { email: 'test@example.com', age: 25 }
24
- );
25
-
26
- console.log(result.valid); // true
27
- ```
28
-
29
- **优点**:
30
- - ✅ 最简洁,无需 `dsl()` 包裹
31
- - ✅ 代码更直观,适合简单场景
32
-
33
- **⚠️ 注意**:DSL 对象也支持混合使用 DslBuilder 实例:
34
-
35
- ```javascript
36
- const { dsl, validate } = require('schema-dsl');
37
-
38
- // ✅ 混合使用:DslBuilder + DSL 字符串
39
- const result = validate(
40
- {
41
- username: dsl('string:3-32!')
42
- .pattern(/^[a-zA-Z0-9_]+$/)
43
- .messages({ 'string.pattern': '只能包含字母、数字和下划线' }),
44
- email: 'email!', // 纯 DSL 字符串
45
- age: 'number:18-'
46
- },
47
- data
48
- );
49
- ```
50
-
51
- ### 方式2:使用 dsl() 包裹(推荐)
52
-
53
- ```javascript
54
- const { dsl, validate } = require('schema-dsl');
55
-
56
- // ✅ 先转换为 JSON Schema,再验证
57
- const schema = dsl({
58
- email: 'email!',
59
- age: 'number:18-120'
60
- });
61
-
62
- const result = validate(schema, { email: 'test@example.com', age: 25 });
63
- ```
64
-
65
- **优点**:
66
- - ✅ 更明确,意图清晰
67
- - ✅ 可复用 schema
68
- - ✅ 支持链式调用扩展
69
-
70
- ### 方式3:传入标准 JSON Schema
71
-
72
- ```javascript
73
- const { validate } = require('schema-dsl');
74
-
75
- // ✅ 传入标准 JSON Schema
76
- const result = validate(
77
- {
78
- type: 'object',
79
- properties: {
80
- email: { type: 'string', format: 'email' },
81
- age: { type: 'number', minimum: 18, maximum: 120 }
82
- },
83
- required: ['email']
84
- },
85
- { email: 'test@example.com', age: 25 }
86
- );
87
- ```
88
-
89
- **优点**:
90
- - ✅ 兼容标准 JSON Schema
91
- - ✅ 可与其他 JSON Schema 工具互操作
92
-
93
- ---
94
-
95
- ## 实现原理
96
-
97
- ### 自动检测逻辑
98
-
99
- 顶层 `validate()` / `validateAsync()` 会先归一化传入的 schema:
100
-
101
- ```javascript
102
- function validate(schema, data, options = {}) {
103
- const normalizedSchema = _normalizeSchemaInput(schema);
104
- const validator = getDefaultValidator();
105
- return validator.validate(normalizedSchema, data, options);
106
- }
107
- ```
108
-
109
- ### 检测规则
110
-
111
- 判断是否为 DSL 对象的逻辑(`_isDslObject()`):
112
-
113
- 1. **排除非对象**:不是普通对象返回 false
114
- 2. **排除 DslBuilder**:有 `toSchema()` 方法返回 false
115
- 3. **排除 ConditionalBuilder**:有 `_isConditional` 标记返回 false
116
- 4. **排除标准 JSON Schema**:
117
- - 有 `type` 字段且值为标准类型(string/number/object等)
118
- - `properties` 的所有值都包含 `type` 字段
119
- 5. **识别 DSL 对象**:
120
- - 属性值包含 DSL 字符串(如 `'email!'`, `'string:3-32'`)
121
- - 属性值包含嵌套的 DSL 对象
122
-
123
- ---
124
-
125
- ## 为什么之前必须是 schema?
126
-
127
- ### 背景
128
-
129
- 早期实现中,顶层 `validate()` 不会自动转换 DSL 对象:
130
-
131
- ```javascript
132
- // ❌ v1.1.6 及之前版本会失败
133
- const result = validate(
134
- { email: 'email!', age: 'number!' }, // 被当作 JSON Schema
135
- { email: 'test@example.com', age: 25 }
136
- );
137
- // 错误:Schema compilation failed: unknown keyword: "email"
138
- ```
139
-
140
- **原因**:`validate()` 会把 DSL 对象当作标准 JSON Schema,而 `"email!"` 不是有效的 JSON Schema 关键字。
141
-
142
- ### 当前方案
143
-
144
- 当前 TypeScript 重构版已补齐自动检测和转换逻辑:
145
-
146
- 1. **检测 DSL 对象**:识别对象中的 DSL 字符串
147
- 2. **自动转换**:调用 `DslAdapter.parseObject()` 转换为 JSON Schema
148
- 3. **透明处理**:用户无需关心内部转换
149
-
150
- ---
151
-
152
- ## 使用建议
153
-
154
- ### 简单场景:直接用 DSL 对象
155
-
156
- 适用于:脚本、原型开发、测试代码、一次性验证
157
-
158
- ```javascript
159
- // ✅ 简单验证,直接传 DSL 对象
160
- app.post('/api/user', (req, res) => {
161
- const result = validate(
162
- { email: 'email!', age: 'number:18-' },
163
- req.body
164
- );
165
-
166
- if (!result.valid) {
167
- return res.status(400).json({ errors: result.errors });
168
- }
169
-
170
- // 处理数据...
171
- });
172
- ```
173
-
174
- ### 复杂场景:项目启动时配置 schema(推荐)
175
-
176
- 适用于:生产环境、高并发服务、需要复用的场景
177
-
178
- ```javascript
179
- // ✅ 最佳实践:在单独的文件中定义所有 schema
180
-
181
- // schemas/user.js - 项目启动时加载,转换一次
182
- const { dsl } = require('schema-dsl');
183
-
184
- module.exports = {
185
- register: dsl({
186
- username: dsl('string:3-32!')
187
- .pattern(/^[a-zA-Z0-9_]+$/)
188
- .messages({ 'string.pattern': '只能包含字母、数字和下划线' }),
189
- email: 'email!',
190
- password: dsl('string!').password('strong'),
191
- age: 'number:18-120'
192
- }),
193
-
194
- login: dsl({
195
- username: 'string!',
196
- password: 'string!'
197
- }),
198
-
199
- updateProfile: dsl({
200
- nickname: 'string:2-20',
201
- avatar: 'url',
202
- bio: 'string:0-500'
203
- })
204
- };
205
-
206
- // routes/user.js - 路由中直接使用,不再转换
207
- const userSchemas = require('../schemas/user');
208
- const { validate } = require('schema-dsl');
209
-
210
- app.post('/api/register', (req, res) => {
211
- const result = validate(userSchemas.register, req.body); // ✅ 直接使用
212
- // ...
213
- });
214
-
215
- app.post('/api/login', (req, res) => {
216
- const result = validate(userSchemas.login, req.body); // ✅ 直接使用
217
- // ...
218
- });
219
-
220
- app.put('/api/user/profile', (req, res) => {
221
- const result = validate(userSchemas.updateProfile, req.body); // ✅ 直接使用
222
- // ...
223
- });
224
- ```
225
-
226
- **性能优势**:
227
- - ✅ 避免每次请求都转换 DSL 对象
228
- - ✅ schema 只在项目启动时创建一次
229
- - ✅ 适合高并发场景
230
-
231
- ### 需要链式调用:混合使用 DslBuilder
232
-
233
- 适用于:需要自定义错误消息、复杂验证规则
234
-
235
- ```javascript
236
- // ✅ 需要自定义消息
237
- const schema = dsl({
238
- email: dsl('email!')
239
- .label('邮箱地址')
240
- .messages({ 'string.email': '请输入有效的邮箱' }),
241
-
242
- username: dsl('string:3-32!')
243
- .pattern(/^[a-zA-Z0-9_]+$/)
244
- .messages({ 'string.pattern': '只能包含字母、数字和下划线' })
245
- });
246
-
247
- const result = validate(schema, data);
248
- ```
249
-
250
- ---
251
-
252
- ## 对比总结
253
-
254
- | 方式 | 简洁性 | 灵活性 | 复用性 | 适用场景 |
255
- |------|-------|-------|-------|---------|
256
- | DSL 对象 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | 简单验证、一次性使用 |
257
- | dsl() 包裹 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 复杂验证、需要复用 |
258
- | JSON Schema | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 与其他工具互操作 |
259
-
260
- ---
261
-
262
- ## 注意事项
263
-
264
- ### 1. 性能考虑
265
-
266
- DSL 对象会在每次 `validate()` 调用时转换,如果需要高性能:
267
-
268
- ```javascript
269
- // ❌ 不推荐:每次请求都转换
270
- app.post('/api/user', (req, res) => {
271
- const result = validate(
272
- { email: 'email!', age: 'number!' }, // 每次都转换
273
- req.body
274
- );
275
- });
276
-
277
- // ✅ 推荐:提前转换,复用 schema
278
- const userSchema = dsl({ email: 'email!', age: 'number!' });
279
-
280
- app.post('/api/user', (req, res) => {
281
- const result = validate(userSchema, req.body); // 直接使用
282
- });
283
- ```
284
-
285
- ### 2. 类型混淆
286
-
287
- 确保 DSL 对象不会被误识别为 JSON Schema:
288
-
289
- ```javascript
290
- // ✅ 明确的 DSL 对象
291
- { email: 'email!', age: 'number!' } // 自动识别
292
-
293
- // ⚠️ 可能混淆
294
- {
295
- type: 'object', // 有 type 字段
296
- email: 'email!' // 但还有 DSL 字符串
297
- }
298
- // 会被识别为 JSON Schema(type 优先级高)
299
- ```
300
-
301
- ### 3. 嵌套对象
302
-
303
- 嵌套的 DSL 对象会被正确处理:
304
-
305
- ```javascript
306
- // ✅ 支持嵌套
307
- const result = validate(
308
- {
309
- user: {
310
- profile: {
311
- name: 'string!',
312
- age: 'number!'
313
- }
314
- }
315
- },
316
- data
317
- );
318
- ```
319
-
320
- ---
321
-
322
- ## 完整示例
323
-
324
- ```javascript
325
- const { dsl, validate, validateAsync } = require('schema-dsl');
326
-
327
- // 示例1:同步验证
328
- const result = validate(
329
- {
330
- email: 'email!',
331
- password: dsl('string!').password('strong'),
332
- age: 'number:18-120',
333
- username: 'string:3-32!'
334
- },
335
- {
336
- email: 'test@example.com',
337
- password: 'MyP@ssw0rd!',
338
- age: 25,
339
- username: 'john_doe'
340
- }
341
- );
342
-
343
- if (result.valid) {
344
- console.log('验证通过');
345
- } else {
346
- console.log('验证失败:', result.errors);
347
- }
348
-
349
- // 示例2:异步验证
350
- (async () => {
351
- try {
352
- const data = await validateAsync(
353
- { email: 'email!', age: 'number!' },
354
- { email: 'test@example.com', age: 25 }
355
- );
356
- console.log('验证通过:', data);
357
- } catch (error) {
358
- console.error('验证失败:', error.errors);
359
- }
360
- })();
361
- ```
362
-
363
- ---
364
-
365
- ## 总结
366
-
367
- **问:为什么必须是 schema?**
368
-
369
- **答:现在不必了!**
370
-
371
- - ✅ 当前版本支持直接传入 DSL 对象
372
- - ✅ 自动检测并转换,无需手动包裹
373
- - ✅ 完全向后兼容,不影响原有功能
374
- - ✅ 同时支持 JSON Schema、DslBuilder、DSL 对象三种方式
375
-
376
- **推荐使用**:
377
- - 简单场景:直接用 DSL 对象
378
- - 复杂场景:先用 `dsl()` 转换,便于复用和扩展
379
-
380
- ---
381
-
382
- ## 常见问题
383
-
384
- ### Q1: DSL 对象中可以使用链式调用吗?
385
-
386
- **A: 可以!** 支持混合使用 DslBuilder 实例和 DSL 字符串:
387
-
388
- ```javascript
389
- const result = validate(
390
- {
391
- username: dsl('string:3-32!')
392
- .pattern(/^[a-zA-Z0-9_]+$/)
393
- .messages({ 'string.pattern': '只能包含字母、数字和下划线' }),
394
- email: 'email!', // 纯 DSL 字符串
395
- age: 'number:18-'
396
- },
397
- data
398
- );
399
- ```
400
-
401
- 嵌套对象中也支持:
402
-
403
- ```javascript
404
- const result = validate(
405
- {
406
- user: {
407
- name: dsl('string:3-32!').messages({ 'string.min': '名字太短了' }),
408
- email: 'email!'
409
- }
410
- },
411
- data
412
- );
413
- ```
414
-
415
- ### Q2: 直接用对象会有什么影响?
416
-
417
- **性能影响**:
418
-
419
- 每次调用 `validate()` 时,DSL 对象都会被转换为 JSON Schema:
420
-
421
- ```javascript
422
- // ❌ 性能较差:每次请求都重复转换
423
- app.post('/api/user', (req, res) => {
424
- const result = validate(
425
- { email: 'email!', age: 'number!' }, // ❌ 每次请求都会执行 DSL → JSON Schema 转换
426
- req.body
427
- );
428
- });
429
-
430
- // ✅ 性能最优:项目启动时转换一次,复用 schema
431
- const userSchema = dsl({ email: 'email!', age: 'number!' }); // ✅ 启动时转换一次
432
-
433
- app.post('/api/user', (req, res) => {
434
- const result = validate(userSchema, req.body); // ✅ 直接使用,不再转换
435
- });
436
- ```
437
-
438
- > ℹ️ 具体耗时取决于机器性能、Node 版本、schema 复杂度和命中率;这里强调的是“预先转换后复用通常显著快于每次请求都重新转换”的相对结论,而不是固定秒数。
439
-
440
- **性能差异**:约 3-5%(对于简单 schema)
441
-
442
- **✅ 您的理解完全正确!**
443
-
444
- **最佳实践**:在项目启动时配置好所有 schema
445
-
446
- ```javascript
447
- // ✅ 推荐:在单独的文件中定义所有 schema(schemas/user.js)
448
- const { dsl } = require('schema-dsl');
449
-
450
- // 项目启动时转换一次,后续直接复用
451
- const userSchemas = {
452
- register: dsl({
453
- username: dsl('string:3-32!')
454
- .pattern(/^[a-zA-Z0-9_]+$/)
455
- .messages({ 'string.pattern': '只能包含字母、数字和下划线' }),
456
- email: 'email!',
457
- password: dsl('string!').password('strong'),
458
- age: 'number:18-120'
459
- }),
460
-
461
- login: dsl({
462
- username: 'string!',
463
- password: 'string!'
464
- }),
465
-
466
- updateProfile: dsl({
467
- nickname: 'string:2-20',
468
- avatar: 'url',
469
- bio: 'string:0-500'
470
- })
471
- };
472
-
473
- module.exports = userSchemas;
474
-
475
- // 在路由中使用(routes/user.js)
476
- const userSchemas = require('../schemas/user');
477
-
478
- app.post('/api/register', (req, res) => {
479
- const result = validate(userSchemas.register, req.body); // ✅ 直接使用
480
- // ...
481
- });
482
-
483
- app.post('/api/login', (req, res) => {
484
- const result = validate(userSchemas.login, req.body); // ✅ 直接使用
485
- // ...
486
- });
487
- ```
488
-
489
- **场景建议**:
490
-
491
- | 场景 | 推荐方式 | 原因 |
492
- |------|---------|------|
493
- | **生产环境 API** | ✅ 项目启动时配置 schema | 避免每次请求都转换,性能最优 |
494
- | **高并发服务** | ✅ 项目启动时配置 schema | 3-5% 的性能损失会被放大 |
495
- | **单次脚本** | ✅ 直接用 DSL 对象 | 只执行一次,性能影响可忽略 |
496
- | **原型开发** | ✅ 直接用 DSL 对象 | 快速迭代,无需在意性能 |
497
- | **测试代码** | ✅ 直接用 DSL 对象 | 简洁清晰,易于维护 |
498
-
499
- ### Q3: 为什么复杂场景仍然建议先用 `dsl()` 转换?
500
-
501
- **历史原因**:
502
-
503
- 1. **明确的职责分离**(设计哲学)
504
- ```javascript
505
- // 转换阶段:DSL → JSON Schema
506
- const schema = dsl({ email: 'email!', age: 'number!' });
507
-
508
- // 验证阶段:JSON Schema + data → result
509
- const result = validate(schema, data);
510
- ```
511
- 这种设计让每个步骤的职责更清晰。
512
-
513
- 2. **避免在高频路径里滥用隐式转换**(最小惊喜原则)
514
- ```javascript
515
- // 用户传入什么,就是什么
516
- validate(jsonSchema, data); // JSON Schema
517
- validate(dslBuilder, data); // DslBuilder
518
-
519
- // ⚠️ 当前虽然支持隐式转换,但高频场景仍建议预先转换后复用
520
- validate({ email: 'email!' }, data);
521
- ```
522
-
523
- 3. **类型安全考虑**(TypeScript)
524
- ```typescript
525
- // 明确的类型定义
526
- function validate(
527
- schema: JSONSchema | DslBuilder, // 明确的类型
528
- data: any
529
- ): ValidationResult;
530
-
531
- // 如果支持任意对象,类型推断会变复杂
532
- function validate(
533
- schema: JSONSchema | DslBuilder | Record<string, any>, // 太宽泛
534
- data: any
535
- ): ValidationResult;
536
- ```
537
-
538
- 4. **性能考虑**(避免重复转换)
539
- ```javascript
540
- // 避免用户不经意间写出性能差的代码
541
- for (let i = 0; i < 10000; i++) {
542
- validate({ email: 'email!' }, data); // 每次都转换
543
- }
544
- ```
545
-
546
- **为什么当前版本要补齐这个能力?**
547
-
548
- 1. **用户反馈**:很多用户期望更简洁的 API
549
- 2. **智能检测**:通过 `_isDslObject()` 准确区分 DSL 对象和 JSON Schema
550
- 3. **性能可接受**:转换开销很小(~3-5%)
551
- 4. **向后兼容**:不影响现有代码
552
- 5. **使用体验优先**:简化常见场景的使用
553
-
554
- **设计权衡**:
555
-
556
- | 设计方案 | 优点 | 缺点 |
557
- |---------|------|------|
558
- | **显式转换** | 职责清晰、类型安全、性能最优 | 代码稍长 |
559
- | **自动转换**(当前顶层便捷函数) | 简洁直观、学习成本低 | 在高频路径里有额外转换开销 |
560
-
561
- **最终选择**:两者都支持,让用户自由选择!
562
-
563
- ```javascript
564
- // ✅ 简单场景:直接用 DSL 对象
565
- validate({ email: 'email!' }, data);
566
-
567
- // ✅ 复杂场景:显式转换
568
- const schema = dsl({ email: 'email!' });
569
- validate(schema, data);
570
- ```
571
-
572
- ---
573
-
574
- ## 对应示例文件
575
-
576
- **示例入口**: [validate-dsl-object-support.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/validate-dsl-object-support.ts)
577
- **说明**: 覆盖直接传入 DSL 对象、混合使用 `DslBuilder` 与 DSL 字符串,以及顶层 `validate()` / `validateAsync()` 的真实支持边界。
578
-
1
+ # validate() 函数支持 DSL 对象说明
2
+
3
+ ## 问题
4
+
5
+ 用户问:`validate(schema, { email: 'test@example.com', age: 25 })` 中的 `schema` 能否直接是个对象,为什么必须是 schema?
6
+
7
+ ## 答案
8
+
9
+ **现在可以了!** 🎉 当前 TypeScript 重构版中,顶层 `validate()` 和 `validateAsync()` 都支持直接传入 DSL 对象。
10
+
11
+ ---
12
+
13
+ ## 支持的三种方式
14
+
15
+ ### 方式1:传入 DSL 对象(✅ 当前版本支持)
16
+
17
+ ```javascript
18
+ const { validate } = require('schema-dsl');
19
+
20
+ // ✅ 直接传入 DSL 对象,无需 dsl() 包裹
21
+ const result = validate(
22
+ { email: 'email!', age: 'number:18-120' }, // DSL 对象
23
+ { email: 'test@example.com', age: 25 }
24
+ );
25
+
26
+ console.log(result.valid); // true
27
+ ```
28
+
29
+ **优点**:
30
+ - ✅ 最简洁,无需 `dsl()` 包裹
31
+ - ✅ 代码更直观,适合简单场景
32
+
33
+ **⚠️ 注意**:DSL 对象也支持混合使用 DslBuilder 实例:
34
+
35
+ ```javascript
36
+ const { dsl, validate } = require('schema-dsl');
37
+
38
+ // ✅ 混合使用:DslBuilder + DSL 字符串
39
+ const result = validate(
40
+ {
41
+ username: dsl('string:3-32!')
42
+ .pattern(/^[a-zA-Z0-9_]+$/)
43
+ .messages({ 'string.pattern': '只能包含字母、数字和下划线' }),
44
+ email: 'email!', // 纯 DSL 字符串
45
+ age: 'number:18-'
46
+ },
47
+ data
48
+ );
49
+ ```
50
+
51
+ ### 方式2:使用 dsl() 包裹(推荐)
52
+
53
+ ```javascript
54
+ const { dsl, validate } = require('schema-dsl');
55
+
56
+ // ✅ 先转换为 JSON Schema,再验证
57
+ const schema = dsl({
58
+ email: 'email!',
59
+ age: 'number:18-120'
60
+ });
61
+
62
+ const result = validate(schema, { email: 'test@example.com', age: 25 });
63
+ ```
64
+
65
+ **优点**:
66
+ - ✅ 更明确,意图清晰
67
+ - ✅ 可复用 schema
68
+ - ✅ 支持链式调用扩展
69
+
70
+ ### 方式3:传入标准 JSON Schema
71
+
72
+ ```javascript
73
+ const { validate } = require('schema-dsl');
74
+
75
+ // ✅ 传入标准 JSON Schema
76
+ const result = validate(
77
+ {
78
+ type: 'object',
79
+ properties: {
80
+ email: { type: 'string', format: 'email' },
81
+ age: { type: 'number', minimum: 18, maximum: 120 }
82
+ },
83
+ required: ['email']
84
+ },
85
+ { email: 'test@example.com', age: 25 }
86
+ );
87
+ ```
88
+
89
+ **优点**:
90
+ - ✅ 兼容标准 JSON Schema
91
+ - ✅ 可与其他 JSON Schema 工具互操作
92
+
93
+ ---
94
+
95
+ ## 实现原理
96
+
97
+ ### 自动检测逻辑
98
+
99
+ 顶层 `validate()` / `validateAsync()` 会先归一化传入的 schema:
100
+
101
+ ```javascript
102
+ function validate(schema, data, options = {}) {
103
+ const normalizedSchema = _normalizeSchemaInput(schema);
104
+ const validator = getDefaultValidator();
105
+ return validator.validate(normalizedSchema, data, options);
106
+ }
107
+ ```
108
+
109
+ ### 检测规则
110
+
111
+ 判断是否为 DSL 对象的逻辑(`_isDslObject()`):
112
+
113
+ 1. **排除非对象**:不是普通对象返回 false
114
+ 2. **排除 DslBuilder**:有 `toSchema()` 方法返回 false
115
+ 3. **排除 ConditionalBuilder**:有 `_isConditional` 标记返回 false
116
+ 4. **排除标准 JSON Schema**:
117
+ - 有 `type` 字段且值为标准类型(string/number/object等)
118
+ - `properties` 的所有值都包含 `type` 字段
119
+ 5. **识别 DSL 对象**:
120
+ - 属性值包含 DSL 字符串(如 `'email!'`, `'string:3-32'`)
121
+ - 属性值包含嵌套的 DSL 对象
122
+
123
+ ---
124
+
125
+ ## 为什么之前必须是 schema?
126
+
127
+ ### 背景
128
+
129
+ 早期实现中,顶层 `validate()` 不会自动转换 DSL 对象:
130
+
131
+ ```javascript
132
+ // ❌ v1.1.6 及之前版本会失败
133
+ const result = validate(
134
+ { email: 'email!', age: 'number!' }, // 被当作 JSON Schema
135
+ { email: 'test@example.com', age: 25 }
136
+ );
137
+ // 错误:Schema compilation failed: unknown keyword: "email"
138
+ ```
139
+
140
+ **原因**:`validate()` 会把 DSL 对象当作标准 JSON Schema,而 `"email!"` 不是有效的 JSON Schema 关键字。
141
+
142
+ ### 当前方案
143
+
144
+ 当前 TypeScript 重构版已补齐自动检测和转换逻辑:
145
+
146
+ 1. **检测 DSL 对象**:识别对象中的 DSL 字符串
147
+ 2. **自动转换**:调用 `DslAdapter.parseObject()` 转换为 JSON Schema
148
+ 3. **透明处理**:用户无需关心内部转换
149
+
150
+ ---
151
+
152
+ ## 使用建议
153
+
154
+ ### 简单场景:直接用 DSL 对象
155
+
156
+ 适用于:脚本、原型开发、测试代码、一次性验证
157
+
158
+ ```javascript
159
+ // ✅ 简单验证,直接传 DSL 对象
160
+ app.post('/api/user', (req, res) => {
161
+ const result = validate(
162
+ { email: 'email!', age: 'number:18-' },
163
+ req.body
164
+ );
165
+
166
+ if (!result.valid) {
167
+ return res.status(400).json({ errors: result.errors });
168
+ }
169
+
170
+ // 处理数据...
171
+ });
172
+ ```
173
+
174
+ ### 复杂场景:项目启动时配置 schema(推荐)
175
+
176
+ 适用于:生产环境、高并发服务、需要复用的场景
177
+
178
+ ```javascript
179
+ // ✅ 最佳实践:在单独的文件中定义所有 schema
180
+
181
+ // schemas/user.js - 项目启动时加载,转换一次
182
+ const { dsl } = require('schema-dsl');
183
+
184
+ module.exports = {
185
+ register: dsl({
186
+ username: dsl('string:3-32!')
187
+ .pattern(/^[a-zA-Z0-9_]+$/)
188
+ .messages({ 'string.pattern': '只能包含字母、数字和下划线' }),
189
+ email: 'email!',
190
+ password: dsl('string!').password('strong'),
191
+ age: 'number:18-120'
192
+ }),
193
+
194
+ login: dsl({
195
+ username: 'string!',
196
+ password: 'string!'
197
+ }),
198
+
199
+ updateProfile: dsl({
200
+ nickname: 'string:2-20',
201
+ avatar: 'url',
202
+ bio: 'string:0-500'
203
+ })
204
+ };
205
+
206
+ // routes/user.js - 路由中直接使用,不再转换
207
+ const userSchemas = require('../schemas/user');
208
+ const { validate } = require('schema-dsl');
209
+
210
+ app.post('/api/register', (req, res) => {
211
+ const result = validate(userSchemas.register, req.body); // ✅ 直接使用
212
+ // ...
213
+ });
214
+
215
+ app.post('/api/login', (req, res) => {
216
+ const result = validate(userSchemas.login, req.body); // ✅ 直接使用
217
+ // ...
218
+ });
219
+
220
+ app.put('/api/user/profile', (req, res) => {
221
+ const result = validate(userSchemas.updateProfile, req.body); // ✅ 直接使用
222
+ // ...
223
+ });
224
+ ```
225
+
226
+ **性能优势**:
227
+ - ✅ 避免每次请求都转换 DSL 对象
228
+ - ✅ schema 只在项目启动时创建一次
229
+ - ✅ 适合高并发场景
230
+
231
+ ### 需要链式调用:混合使用 DslBuilder
232
+
233
+ 适用于:需要自定义错误消息、复杂验证规则
234
+
235
+ ```javascript
236
+ // ✅ 需要自定义消息
237
+ const schema = dsl({
238
+ email: dsl('email!')
239
+ .label('邮箱地址')
240
+ .messages({ 'string.email': '请输入有效的邮箱' }),
241
+
242
+ username: dsl('string:3-32!')
243
+ .pattern(/^[a-zA-Z0-9_]+$/)
244
+ .messages({ 'string.pattern': '只能包含字母、数字和下划线' })
245
+ });
246
+
247
+ const result = validate(schema, data);
248
+ ```
249
+
250
+ ---
251
+
252
+ ## 对比总结
253
+
254
+ | 方式 | 简洁性 | 灵活性 | 复用性 | 适用场景 |
255
+ |------|-------|-------|-------|---------|
256
+ | DSL 对象 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ | 简单验证、一次性使用 |
257
+ | dsl() 包裹 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | 复杂验证、需要复用 |
258
+ | JSON Schema | ⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | 与其他工具互操作 |
259
+
260
+ ---
261
+
262
+ ## 注意事项
263
+
264
+ ### 1. 性能考虑
265
+
266
+ DSL 对象会在每次 `validate()` 调用时转换,如果需要高性能:
267
+
268
+ ```javascript
269
+ // ❌ 不推荐:每次请求都转换
270
+ app.post('/api/user', (req, res) => {
271
+ const result = validate(
272
+ { email: 'email!', age: 'number!' }, // 每次都转换
273
+ req.body
274
+ );
275
+ });
276
+
277
+ // ✅ 推荐:提前转换,复用 schema
278
+ const userSchema = dsl({ email: 'email!', age: 'number!' });
279
+
280
+ app.post('/api/user', (req, res) => {
281
+ const result = validate(userSchema, req.body); // 直接使用
282
+ });
283
+ ```
284
+
285
+ ### 2. 类型混淆
286
+
287
+ 确保 DSL 对象不会被误识别为 JSON Schema:
288
+
289
+ ```javascript
290
+ // ✅ 明确的 DSL 对象
291
+ { email: 'email!', age: 'number!' } // 自动识别
292
+
293
+ // ⚠️ 可能混淆
294
+ {
295
+ type: 'object', // 有 type 字段
296
+ email: 'email!' // 但还有 DSL 字符串
297
+ }
298
+ // 会被识别为 JSON Schema(type 优先级高)
299
+ ```
300
+
301
+ ### 3. 嵌套对象
302
+
303
+ 嵌套的 DSL 对象会被正确处理:
304
+
305
+ ```javascript
306
+ // ✅ 支持嵌套
307
+ const result = validate(
308
+ {
309
+ user: {
310
+ profile: {
311
+ name: 'string!',
312
+ age: 'number!'
313
+ }
314
+ }
315
+ },
316
+ data
317
+ );
318
+ ```
319
+
320
+ ---
321
+
322
+ ## 完整示例
323
+
324
+ ```javascript
325
+ const { dsl, validate, validateAsync } = require('schema-dsl');
326
+
327
+ // 示例1:同步验证
328
+ const result = validate(
329
+ {
330
+ email: 'email!',
331
+ password: dsl('string!').password('strong'),
332
+ age: 'number:18-120',
333
+ username: 'string:3-32!'
334
+ },
335
+ {
336
+ email: 'test@example.com',
337
+ password: 'MyP@ssw0rd!',
338
+ age: 25,
339
+ username: 'john_doe'
340
+ }
341
+ );
342
+
343
+ if (result.valid) {
344
+ console.log('验证通过');
345
+ } else {
346
+ console.log('验证失败:', result.errors);
347
+ }
348
+
349
+ // 示例2:异步验证
350
+ (async () => {
351
+ try {
352
+ const data = await validateAsync(
353
+ { email: 'email!', age: 'number!' },
354
+ { email: 'test@example.com', age: 25 }
355
+ );
356
+ console.log('验证通过:', data);
357
+ } catch (error) {
358
+ console.error('验证失败:', error.errors);
359
+ }
360
+ })();
361
+ ```
362
+
363
+ ---
364
+
365
+ ## 总结
366
+
367
+ **问:为什么必须是 schema?**
368
+
369
+ **答:现在不必了!**
370
+
371
+ - ✅ 当前版本支持直接传入 DSL 对象
372
+ - ✅ 自动检测并转换,无需手动包裹
373
+ - ✅ 完全向后兼容,不影响原有功能
374
+ - ✅ 同时支持 JSON Schema、DslBuilder、DSL 对象三种方式
375
+
376
+ **推荐使用**:
377
+ - 简单场景:直接用 DSL 对象
378
+ - 复杂场景:先用 `dsl()` 转换,便于复用和扩展
379
+
380
+ ---
381
+
382
+ ## 常见问题
383
+
384
+ ### Q1: DSL 对象中可以使用链式调用吗?
385
+
386
+ **A: 可以!** 支持混合使用 DslBuilder 实例和 DSL 字符串:
387
+
388
+ ```javascript
389
+ const result = validate(
390
+ {
391
+ username: dsl('string:3-32!')
392
+ .pattern(/^[a-zA-Z0-9_]+$/)
393
+ .messages({ 'string.pattern': '只能包含字母、数字和下划线' }),
394
+ email: 'email!', // 纯 DSL 字符串
395
+ age: 'number:18-'
396
+ },
397
+ data
398
+ );
399
+ ```
400
+
401
+ 嵌套对象中也支持:
402
+
403
+ ```javascript
404
+ const result = validate(
405
+ {
406
+ user: {
407
+ name: dsl('string:3-32!').messages({ 'string.min': '名字太短了' }),
408
+ email: 'email!'
409
+ }
410
+ },
411
+ data
412
+ );
413
+ ```
414
+
415
+ ### Q2: 直接用对象会有什么影响?
416
+
417
+ **性能影响**:
418
+
419
+ 每次调用 `validate()` 时,DSL 对象都会被转换为 JSON Schema:
420
+
421
+ ```javascript
422
+ // ❌ 性能较差:每次请求都重复转换
423
+ app.post('/api/user', (req, res) => {
424
+ const result = validate(
425
+ { email: 'email!', age: 'number!' }, // ❌ 每次请求都会执行 DSL → JSON Schema 转换
426
+ req.body
427
+ );
428
+ });
429
+
430
+ // ✅ 性能最优:项目启动时转换一次,复用 schema
431
+ const userSchema = dsl({ email: 'email!', age: 'number!' }); // ✅ 启动时转换一次
432
+
433
+ app.post('/api/user', (req, res) => {
434
+ const result = validate(userSchema, req.body); // ✅ 直接使用,不再转换
435
+ });
436
+ ```
437
+
438
+ > ℹ️ 具体耗时取决于机器性能、Node 版本、schema 复杂度和命中率;这里强调的是“预先转换后复用通常显著快于每次请求都重新转换”的相对结论,而不是固定秒数。
439
+
440
+ **性能差异**:约 3-5%(对于简单 schema)
441
+
442
+ **✅ 您的理解完全正确!**
443
+
444
+ **最佳实践**:在项目启动时配置好所有 schema
445
+
446
+ ```javascript
447
+ // ✅ 推荐:在单独的文件中定义所有 schema(schemas/user.js)
448
+ const { dsl } = require('schema-dsl');
449
+
450
+ // 项目启动时转换一次,后续直接复用
451
+ const userSchemas = {
452
+ register: dsl({
453
+ username: dsl('string:3-32!')
454
+ .pattern(/^[a-zA-Z0-9_]+$/)
455
+ .messages({ 'string.pattern': '只能包含字母、数字和下划线' }),
456
+ email: 'email!',
457
+ password: dsl('string!').password('strong'),
458
+ age: 'number:18-120'
459
+ }),
460
+
461
+ login: dsl({
462
+ username: 'string!',
463
+ password: 'string!'
464
+ }),
465
+
466
+ updateProfile: dsl({
467
+ nickname: 'string:2-20',
468
+ avatar: 'url',
469
+ bio: 'string:0-500'
470
+ })
471
+ };
472
+
473
+ module.exports = userSchemas;
474
+
475
+ // 在路由中使用(routes/user.js)
476
+ const userSchemas = require('../schemas/user');
477
+
478
+ app.post('/api/register', (req, res) => {
479
+ const result = validate(userSchemas.register, req.body); // ✅ 直接使用
480
+ // ...
481
+ });
482
+
483
+ app.post('/api/login', (req, res) => {
484
+ const result = validate(userSchemas.login, req.body); // ✅ 直接使用
485
+ // ...
486
+ });
487
+ ```
488
+
489
+ **场景建议**:
490
+
491
+ | 场景 | 推荐方式 | 原因 |
492
+ |------|---------|------|
493
+ | **生产环境 API** | ✅ 项目启动时配置 schema | 避免每次请求都转换,性能最优 |
494
+ | **高并发服务** | ✅ 项目启动时配置 schema | 3-5% 的性能损失会被放大 |
495
+ | **单次脚本** | ✅ 直接用 DSL 对象 | 只执行一次,性能影响可忽略 |
496
+ | **原型开发** | ✅ 直接用 DSL 对象 | 快速迭代,无需在意性能 |
497
+ | **测试代码** | ✅ 直接用 DSL 对象 | 简洁清晰,易于维护 |
498
+
499
+ ### Q3: 为什么复杂场景仍然建议先用 `dsl()` 转换?
500
+
501
+ **历史原因**:
502
+
503
+ 1. **明确的职责分离**(设计哲学)
504
+ ```javascript
505
+ // 转换阶段:DSL → JSON Schema
506
+ const schema = dsl({ email: 'email!', age: 'number!' });
507
+
508
+ // 验证阶段:JSON Schema + data → result
509
+ const result = validate(schema, data);
510
+ ```
511
+ 这种设计让每个步骤的职责更清晰。
512
+
513
+ 2. **避免在高频路径里滥用隐式转换**(最小惊喜原则)
514
+ ```javascript
515
+ // 用户传入什么,就是什么
516
+ validate(jsonSchema, data); // JSON Schema
517
+ validate(dslBuilder, data); // DslBuilder
518
+
519
+ // ⚠️ 当前虽然支持隐式转换,但高频场景仍建议预先转换后复用
520
+ validate({ email: 'email!' }, data);
521
+ ```
522
+
523
+ 3. **类型安全考虑**(TypeScript)
524
+ ```typescript
525
+ // 明确的类型定义
526
+ function validate(
527
+ schema: JSONSchema | DslBuilder, // 明确的类型
528
+ data: any
529
+ ): ValidationResult;
530
+
531
+ // 如果支持任意对象,类型推断会变复杂
532
+ function validate(
533
+ schema: JSONSchema | DslBuilder | Record<string, any>, // 太宽泛
534
+ data: any
535
+ ): ValidationResult;
536
+ ```
537
+
538
+ 4. **性能考虑**(避免重复转换)
539
+ ```javascript
540
+ // 避免用户不经意间写出性能差的代码
541
+ for (let i = 0; i < 10000; i++) {
542
+ validate({ email: 'email!' }, data); // 每次都转换
543
+ }
544
+ ```
545
+
546
+ **为什么当前版本要补齐这个能力?**
547
+
548
+ 1. **用户反馈**:很多用户期望更简洁的 API
549
+ 2. **智能检测**:通过 `_isDslObject()` 准确区分 DSL 对象和 JSON Schema
550
+ 3. **性能可接受**:转换开销很小(~3-5%)
551
+ 4. **向后兼容**:不影响现有代码
552
+ 5. **使用体验优先**:简化常见场景的使用
553
+
554
+ **设计权衡**:
555
+
556
+ | 设计方案 | 优点 | 缺点 |
557
+ |---------|------|------|
558
+ | **显式转换** | 职责清晰、类型安全、性能最优 | 代码稍长 |
559
+ | **自动转换**(当前顶层便捷函数) | 简洁直观、学习成本低 | 在高频路径里有额外转换开销 |
560
+
561
+ **最终选择**:两者都支持,让用户自由选择!
562
+
563
+ ```javascript
564
+ // ✅ 简单场景:直接用 DSL 对象
565
+ validate({ email: 'email!' }, data);
566
+
567
+ // ✅ 复杂场景:显式转换
568
+ const schema = dsl({ email: 'email!' });
569
+ validate(schema, data);
570
+ ```
571
+
572
+ ---
573
+
574
+ ## 对应示例文件
575
+
576
+ **示例入口**: [validate-dsl-object-support.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/validate-dsl-object-support.ts)
577
+ **说明**: 覆盖直接传入 DSL 对象、混合使用 `DslBuilder` 与 DSL 字符串,以及顶层 `validate()` / `validateAsync()` 的真实支持边界。
578
+