schema-dsl 1.2.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +87 -210
- package/README.md +391 -2249
- package/dist/DslBuilder-DQDN0ZxZ.d.cts +341 -0
- package/dist/DslBuilder-DkLaOo9Q.d.ts +341 -0
- package/dist/Validator-C7GsVQOH.d.cts +192 -0
- package/dist/Validator-hFWKGxir.d.ts +192 -0
- package/dist/index.cjs +6594 -0
- package/dist/index.d.cts +1145 -0
- package/dist/index.d.ts +1145 -0
- package/dist/index.js +6528 -0
- package/dist/plugin-CIKtTMtS.d.cts +246 -0
- package/dist/plugin-CIKtTMtS.d.ts +246 -0
- package/dist/plugins/custom-format.cjs +3802 -0
- package/dist/plugins/custom-format.d.cts +12 -0
- package/dist/plugins/custom-format.d.ts +12 -0
- package/dist/plugins/custom-format.js +3772 -0
- package/dist/plugins/custom-type-example.cjs +3795 -0
- package/dist/plugins/custom-type-example.d.cts +8 -0
- package/dist/plugins/custom-type-example.d.ts +8 -0
- package/dist/plugins/custom-type-example.js +3765 -0
- package/dist/plugins/custom-validator.cjs +146 -0
- package/dist/plugins/custom-validator.d.cts +10 -0
- package/dist/plugins/custom-validator.d.ts +10 -0
- package/dist/plugins/custom-validator.js +121 -0
- package/docs/FEATURE-INDEX.md +102 -68
- package/docs/add-custom-locale.md +48 -35
- package/docs/add-keyword.md +24 -0
- package/docs/api-reference.md +396 -154
- package/docs/api.md +13 -0
- package/docs/best-practices-project-structure.md +19 -10
- package/docs/best-practices.md +93 -53
- package/docs/cache-manager.md +23 -15
- package/docs/compile.md +45 -0
- package/docs/conditional-api.md +40 -11
- package/docs/custom-extensions-guide.md +80 -152
- package/docs/design-philosophy.md +76 -71
- package/docs/doc-index.md +324 -0
- package/docs/dsl-syntax.md +69 -19
- package/docs/dynamic-locale.md +24 -14
- package/docs/enum.md +12 -5
- package/docs/error-handling.md +53 -44
- package/docs/export-guide.md +47 -8
- package/docs/export-limitations.md +27 -11
- package/docs/faq.md +86 -67
- package/docs/frontend-i18n-guide.md +26 -12
- package/docs/i18n-user-guide.md +60 -47
- package/docs/i18n.md +51 -32
- package/docs/index.md +48 -0
- package/docs/json-schema-basics.md +40 -0
- package/docs/label-vs-description.md +12 -3
- package/docs/markdown-exporter.md +15 -6
- package/docs/mongodb-exporter.md +11 -4
- package/docs/multi-language.md +26 -0
- package/docs/multi-type-support.md +26 -33
- package/docs/mysql-exporter.md +9 -2
- package/docs/number-operators.md +12 -5
- package/docs/optional-marker-guide.md +28 -23
- package/docs/performance-guide.md +49 -0
- package/docs/plugin-system.md +205 -366
- package/docs/plugin-type-registration.md +34 -0
- package/docs/postgresql-exporter.md +9 -2
- package/docs/public/favicon.svg +5 -0
- package/docs/quick-start.md +37 -363
- package/docs/runtime-locale-support.md +20 -9
- package/docs/schema-helper.md +10 -5
- package/docs/schema-utils-advanced-issues.md +23 -0
- package/docs/schema-utils-best-practices.md +20 -0
- package/docs/schema-utils-chaining.md +7 -0
- package/docs/schema-utils.md +76 -42
- package/docs/security-checklist.md +20 -0
- package/docs/string-extensions.md +17 -9
- package/docs/troubleshooting.md +36 -21
- package/docs/type-converter.md +41 -50
- package/docs/type-reference.md +38 -15
- package/docs/typescript-guide.md +53 -42
- package/docs/union-type-guide.md +11 -1
- package/docs/union-types.md +10 -3
- package/docs/validate-async.md +36 -25
- package/docs/validate-batch.md +49 -0
- package/docs/validate-dsl-object-support.md +33 -28
- package/docs/validate.md +36 -16
- package/docs/validation-guide.md +25 -7
- package/docs/validator.md +39 -0
- package/package.json +85 -27
- package/plugins/custom-format.cjs +8 -0
- package/plugins/custom-type-example.cjs +8 -0
- package/plugins/custom-validator.cjs +8 -0
- package/src/adapters/DslAdapter.ts +111 -0
- package/src/adapters/index.ts +1 -0
- package/src/config/constants.ts +83 -0
- package/src/config/index.ts +2 -0
- package/src/config/patterns.ts +77 -0
- package/src/core/CacheManager.ts +159 -0
- package/src/core/ConditionalBuilder.ts +382 -0
- package/src/core/ConditionalRuntime.ts +28 -0
- package/src/core/ConditionalValidator.ts +255 -0
- package/src/core/DslBuilder.ts +677 -0
- package/src/core/ErrorCodes.ts +38 -0
- package/src/core/ErrorFormatter.ts +271 -0
- package/src/core/JSONSchemaCore.ts +65 -0
- package/src/core/Locale.ts +187 -0
- package/src/core/MessageTemplate.ts +42 -0
- package/src/core/ObjectDslBuilder.ts +64 -0
- package/src/core/PluginManager.ts +326 -0
- package/src/core/StringExtensions.ts +140 -0
- package/src/core/TemplateEngine.ts +44 -0
- package/src/core/Validator.ts +448 -0
- package/src/errors/I18nError.ts +159 -0
- package/src/errors/ValidationError.ts +105 -0
- package/src/exporters/BaseExporter.ts +60 -0
- package/src/exporters/MarkdownExporter.ts +305 -0
- package/src/exporters/MongoDBExporter.ts +126 -0
- package/src/exporters/MySQLExporter.ts +155 -0
- package/src/exporters/PostgreSQLExporter.ts +222 -0
- package/src/exporters/index.ts +18 -0
- package/src/index.ts +633 -0
- package/{lib/locales/en-US.js → src/locales/en-US.ts} +21 -37
- package/{lib/locales/es-ES.js → src/locales/es-ES.ts} +63 -16
- package/{lib/locales/fr-FR.js → src/locales/fr-FR.ts} +74 -27
- package/src/locales/index.ts +103 -0
- package/{lib/locales/ja-JP.js → src/locales/ja-JP.ts} +59 -17
- package/src/locales/types.ts +156 -0
- package/{lib/locales/zh-CN.js → src/locales/zh-CN.ts} +21 -38
- package/src/parser/ConstraintParser.ts +101 -0
- package/src/parser/DslParser.ts +470 -0
- package/src/parser/SchemaCompiler.ts +66 -0
- package/src/parser/TypeRegistry.ts +250 -0
- package/src/parser/index.ts +6 -0
- package/src/plugins/custom-format.ts +126 -0
- package/src/plugins/custom-type-example.ts +108 -0
- package/src/plugins/custom-validator.ts +140 -0
- package/src/types/conditional.ts +28 -0
- package/src/types/config.ts +59 -0
- package/src/types/dsl.ts +131 -0
- package/src/types/error.ts +60 -0
- package/src/types/index.ts +17 -0
- package/src/types/infer.ts +128 -0
- package/src/types/plugin.ts +58 -0
- package/src/types/safe-regex.d.ts +9 -0
- package/src/types/schema.ts +66 -0
- package/src/types/validate.ts +71 -0
- package/src/utils/SchemaHelper.ts +196 -0
- package/src/utils/SchemaUtils.ts +346 -0
- package/src/utils/TypeConverter.ts +215 -0
- package/src/utils/index.ts +10 -0
- package/src/validators/CustomKeywords.ts +477 -0
- package/.eslintignore +0 -11
- package/.eslintrc.json +0 -27
- package/CONTRIBUTING.md +0 -368
- package/STATUS.md +0 -491
- package/changelogs/v1.0.0.md +0 -328
- package/changelogs/v1.0.9.md +0 -367
- package/changelogs/v1.1.0.md +0 -389
- package/changelogs/v1.1.1.md +0 -308
- package/changelogs/v1.1.2.md +0 -183
- package/changelogs/v1.1.3.md +0 -161
- package/changelogs/v1.1.4.md +0 -432
- package/changelogs/v1.1.5.md +0 -493
- package/changelogs/v1.1.6.md +0 -211
- package/changelogs/v1.1.8.md +0 -376
- package/changelogs/v1.2.3.md +0 -124
- package/docs/INDEX.md +0 -252
- package/docs/issues-resolved-summary.md +0 -196
- package/docs/performance-benchmark-report.md +0 -179
- package/docs/performance-quick-reference.md +0 -123
- package/docs/user-questions-answered.md +0 -353
- package/docs/validation-rules-v1.0.2.md +0 -1608
- package/examples/README.md +0 -81
- package/examples/array-dsl-example.js +0 -227
- package/examples/conditional-example.js +0 -288
- package/examples/conditional-non-object.js +0 -129
- package/examples/conditional-validate-example.js +0 -321
- package/examples/custom-extension.js +0 -85
- package/examples/dsl-match-example.js +0 -74
- package/examples/dsl-style.js +0 -118
- package/examples/dynamic-locale-configuration.js +0 -348
- package/examples/dynamic-locale-example.js +0 -287
- package/examples/enum.examples.js +0 -324
- package/examples/export-demo.js +0 -130
- package/examples/express-integration.js +0 -376
- package/examples/i18n-error-handling-complete.js +0 -381
- package/examples/i18n-error-handling-quickstart.md +0 -0
- package/examples/i18n-error.examples.js +0 -181
- package/examples/i18n-full-demo.js +0 -301
- package/examples/i18n-memory-safety.examples.js +0 -268
- package/examples/markdown-export.js +0 -71
- package/examples/middleware-usage.js +0 -93
- package/examples/new-features-comparison.js +0 -315
- package/examples/password-reset/README.md +0 -153
- package/examples/password-reset/schema.js +0 -26
- package/examples/password-reset/test.js +0 -101
- package/examples/plugin-system.examples.js +0 -205
- package/examples/schema-utils-chaining.examples.js +0 -250
- package/examples/simple-example.js +0 -122
- package/examples/slug.examples.js +0 -179
- package/examples/string-extensions.js +0 -297
- package/examples/union-type-example.js +0 -127
- package/examples/union-types-example.js +0 -77
- package/examples/user-registration/README.md +0 -156
- package/examples/user-registration/routes.js +0 -92
- package/examples/user-registration/schema.js +0 -150
- package/examples/user-registration/server.js +0 -74
- package/index.d.ts +0 -3540
- package/index.js +0 -457
- package/index.mjs +0 -60
- package/lib/adapters/DslAdapter.js +0 -871
- package/lib/adapters/index.js +0 -20
- package/lib/config/constants.js +0 -286
- package/lib/config/patterns/common.js +0 -47
- package/lib/config/patterns/creditCard.js +0 -9
- package/lib/config/patterns/idCard.js +0 -9
- package/lib/config/patterns/index.js +0 -9
- package/lib/config/patterns/licensePlate.js +0 -4
- package/lib/config/patterns/passport.js +0 -4
- package/lib/config/patterns/phone.js +0 -9
- package/lib/config/patterns/postalCode.js +0 -5
- package/lib/core/CacheManager.js +0 -376
- package/lib/core/ConditionalBuilder.js +0 -503
- package/lib/core/DslBuilder.js +0 -1400
- package/lib/core/ErrorCodes.js +0 -233
- package/lib/core/ErrorFormatter.js +0 -445
- package/lib/core/JSONSchemaCore.js +0 -347
- package/lib/core/Locale.js +0 -130
- package/lib/core/MessageTemplate.js +0 -98
- package/lib/core/PluginManager.js +0 -448
- package/lib/core/StringExtensions.js +0 -240
- package/lib/core/Validator.js +0 -654
- package/lib/errors/I18nError.js +0 -328
- package/lib/errors/ValidationError.js +0 -191
- package/lib/exporters/MarkdownExporter.js +0 -420
- package/lib/exporters/MongoDBExporter.js +0 -162
- package/lib/exporters/MySQLExporter.js +0 -212
- package/lib/exporters/PostgreSQLExporter.js +0 -289
- package/lib/exporters/index.js +0 -24
- package/lib/locales/index.js +0 -8
- package/lib/utils/LRUCache.js +0 -174
- package/lib/utils/SchemaHelper.js +0 -240
- package/lib/utils/SchemaUtils.js +0 -445
- package/lib/utils/TypeConverter.js +0 -245
- package/lib/utils/index.js +0 -13
- package/lib/validators/CustomKeywords.js +0 -616
- package/lib/validators/index.js +0 -11
package/docs/api.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# API 参考入口
|
|
2
|
+
|
|
3
|
+
完整 API 参考请见:[api-reference.md](./api-reference.md)。
|
|
4
|
+
|
|
5
|
+
本文件用于兼容历史文档中的 `./api.md` 链接。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 对应示例文件
|
|
10
|
+
|
|
11
|
+
**示例入口**: [api.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/api.ts)
|
|
12
|
+
**说明**: 以最小入口串起 `dsl()`、`validate()`、`Validator.validateAsync()` 和 `TypeConverter` 这些最常用公开 API。
|
|
13
|
+
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## 推荐的项目结构
|
|
4
4
|
|
|
5
|
-
```
|
|
5
|
+
```text
|
|
6
6
|
your-project/
|
|
7
7
|
├── schemas/ # ✅ 所有 schema 定义(项目启动时加载)
|
|
8
8
|
│ ├── index.js # 统一导出
|
|
@@ -49,7 +49,7 @@ const userSchemas = {
|
|
|
49
49
|
'string.email': '请输入有效的邮箱地址'
|
|
50
50
|
}),
|
|
51
51
|
|
|
52
|
-
password: dsl('password
|
|
52
|
+
password: dsl('string!').password('strong')
|
|
53
53
|
.label('密码')
|
|
54
54
|
.messages({
|
|
55
55
|
'string.password': '密码必须包含大小写字母、数字和特殊字符'
|
|
@@ -82,7 +82,7 @@ const userSchemas = {
|
|
|
82
82
|
// 修改密码 schema
|
|
83
83
|
changePassword: dsl({
|
|
84
84
|
oldPassword: 'string!',
|
|
85
|
-
newPassword: 'password
|
|
85
|
+
newPassword: dsl('string!').password('strong')
|
|
86
86
|
})
|
|
87
87
|
};
|
|
88
88
|
|
|
@@ -236,7 +236,7 @@ app.use('/api/product', require('./routes/product'));
|
|
|
236
236
|
const PORT = process.env.PORT || 3000;
|
|
237
237
|
app.listen(PORT, () => {
|
|
238
238
|
console.log(`✅ Server started on port ${PORT}`);
|
|
239
|
-
console.log('✅ All schemas are
|
|
239
|
+
console.log('✅ All schemas are loaded and ready to validate');
|
|
240
240
|
});
|
|
241
241
|
|
|
242
242
|
module.exports = app;
|
|
@@ -255,7 +255,7 @@ router.post('/register', (req, res) => {
|
|
|
255
255
|
{ // ❌ 每次请求都转换
|
|
256
256
|
username: 'string:3-32!',
|
|
257
257
|
email: 'email!',
|
|
258
|
-
password: 'password
|
|
258
|
+
password: dsl('string!').password('strong')
|
|
259
259
|
},
|
|
260
260
|
req.body
|
|
261
261
|
);
|
|
@@ -297,9 +297,9 @@ router.post('/register', (req, res) => {
|
|
|
297
297
|
| **生产环境 API** | ✅ 项目启动时配置 | `const schemas = require('./schemas')` | 避免每次请求都转换 |
|
|
298
298
|
| **高并发服务** | ✅ 项目启动时配置 | 同上 | 3-5% 的性能损失会被放大 |
|
|
299
299
|
| **微服务** | ✅ 项目启动时配置 | 同上 | 保证响应时间稳定 |
|
|
300
|
-
| **单次脚本** | ✅ 直接用 DSL
|
|
301
|
-
| **原型开发** | ✅ 直接用 DSL
|
|
302
|
-
| **测试代码** | ✅ 直接用 DSL
|
|
300
|
+
| **单次脚本** | ✅ 直接用 DSL 对象(当前版便捷函数支持) | `validate({ email: 'email!' }, data)` | 只执行一次,性能影响可忽略 |
|
|
301
|
+
| **原型开发** | ✅ 直接用 DSL 对象(当前版便捷函数支持) | 同上 | 快速迭代,无需在意性能 |
|
|
302
|
+
| **测试代码** | ✅ 直接用 DSL 对象(当前版便捷函数支持) | 同上 | 简洁清晰,易于维护 |
|
|
303
303
|
|
|
304
304
|
---
|
|
305
305
|
|
|
@@ -365,9 +365,11 @@ export const userSchemas = {
|
|
|
365
365
|
register: dsl({
|
|
366
366
|
username: dsl('string:3-32!')
|
|
367
367
|
.pattern(/^[a-zA-Z0-9_]+$/)
|
|
368
|
-
.
|
|
368
|
+
.error({ pattern: '只能包含字母、数字和下划线' }),
|
|
369
369
|
email: 'email!',
|
|
370
|
-
password: '
|
|
370
|
+
password: dsl('string:8-64!')
|
|
371
|
+
.pattern(/^(?=.*[A-Za-z])(?=.*\d).{8,}$/)
|
|
372
|
+
.error({ pattern: '密码至少 8 位且必须包含字母和数字' }),
|
|
371
373
|
age: 'number:18-120'
|
|
372
374
|
}),
|
|
373
375
|
|
|
@@ -406,3 +408,10 @@ router.post('/register', (req, res) => {
|
|
|
406
408
|
- 集中管理所有验证规则
|
|
407
409
|
- 易于维护和修改
|
|
408
410
|
- 类型安全(TypeScript)
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## 对应示例文件
|
|
415
|
+
|
|
416
|
+
**示例入口**: [best-practices-project-structure.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/best-practices-project-structure.ts)
|
|
417
|
+
**说明**: 用一个最小的 `userSchemas` 对象模拟集中定义 / 路由复用结构,直接验证注册与登录两条路径。
|
package/docs/best-practices.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# schema-dsl 最佳实践
|
|
2
2
|
|
|
3
3
|
> **用途**: 帮助你写出高质量、高性能的 Schema 代码
|
|
4
|
-
> **更新**:
|
|
4
|
+
> **更新**: 2026-05-08
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -33,7 +33,7 @@ const schema = dsl({
|
|
|
33
33
|
**不推荐**(过度复杂):
|
|
34
34
|
```javascript
|
|
35
35
|
const schema = dsl({
|
|
36
|
-
username: dsl('string').
|
|
36
|
+
username: dsl('string').min(3).max(32).required(),
|
|
37
37
|
// 太冗长了!
|
|
38
38
|
});
|
|
39
39
|
```
|
|
@@ -67,9 +67,8 @@ const schema = dsl({
|
|
|
67
67
|
}),
|
|
68
68
|
|
|
69
69
|
email: 'email!'
|
|
70
|
-
.custom(
|
|
71
|
-
|
|
72
|
-
if (exists) return '邮箱已被占用';
|
|
70
|
+
.custom((value) => {
|
|
71
|
+
if (value.endsWith('@blocked.example')) return '该邮箱域名不允许注册';
|
|
73
72
|
})
|
|
74
73
|
.label('邮箱地址')
|
|
75
74
|
});
|
|
@@ -79,7 +78,7 @@ const schema = dsl({
|
|
|
79
78
|
|
|
80
79
|
### 3. 使用预设验证器
|
|
81
80
|
|
|
82
|
-
|
|
81
|
+
schema-dsl 提供了常用的预设验证器,开箱即用:
|
|
83
82
|
|
|
84
83
|
```javascript
|
|
85
84
|
const schema = dsl({
|
|
@@ -164,6 +163,7 @@ app.post('/api/user', (req, res) => {
|
|
|
164
163
|
**推荐**(预编译):
|
|
165
164
|
```javascript
|
|
166
165
|
// 在应用启动时编译一次
|
|
166
|
+
const validator = new Validator();
|
|
167
167
|
const userSchema = dsl({ username: 'string!' });
|
|
168
168
|
const validateUser = validator.compile(userSchema);
|
|
169
169
|
|
|
@@ -172,15 +172,24 @@ app.post('/api/user', (req, res) => {
|
|
|
172
172
|
});
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
**收益**: 复用已编译结果可以显著减少重复编译成本,尤其适合热点路由和高频校验路径。
|
|
176
176
|
|
|
177
177
|
---
|
|
178
178
|
|
|
179
179
|
### 2. 启用缓存
|
|
180
180
|
|
|
181
181
|
```javascript
|
|
182
|
-
const validator = new Validator({
|
|
183
|
-
cache: true //
|
|
182
|
+
const validator = new Validator({
|
|
183
|
+
cache: true // ✅ 简写:启用默认编译缓存配置
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// 需要更细粒度时,使用对象配置
|
|
187
|
+
const tunedValidator = new Validator({
|
|
188
|
+
cache: {
|
|
189
|
+
enabled: true,
|
|
190
|
+
maxSize: 500,
|
|
191
|
+
ttl: 60 * 60 * 1000
|
|
192
|
+
}
|
|
184
193
|
});
|
|
185
194
|
|
|
186
195
|
// 或者使用全局单例(默认启用缓存)
|
|
@@ -205,10 +214,15 @@ records.forEach(record => {
|
|
|
205
214
|
|
|
206
215
|
**推荐**(批量验证):
|
|
207
216
|
```javascript
|
|
208
|
-
const
|
|
209
|
-
|
|
217
|
+
const { SchemaUtils, Validator } = require('schema-dsl');
|
|
218
|
+
|
|
219
|
+
const validator = new Validator();
|
|
220
|
+
const result = SchemaUtils.validateBatch(schema, records, validator.getAjv());
|
|
221
|
+
// 当你已经复用 Validator 底层 Ajv 实例时,这条路径适合批量校验
|
|
210
222
|
```
|
|
211
223
|
|
|
224
|
+
> ℹ️ 如果你确实要直接传入自己创建的 Ajv 实例,请先确保它已经注册了与 schema-dsl 生成 schema 匹配的格式和关键字;对大多数项目来说,直接复用 `validator.getAjv()` 更稳妥。
|
|
225
|
+
|
|
212
226
|
---
|
|
213
227
|
|
|
214
228
|
### 4. 优化正则表达式
|
|
@@ -312,13 +326,17 @@ return res.status(400).json({
|
|
|
312
326
|
### 3. 限制 Schema 复杂度
|
|
313
327
|
|
|
314
328
|
```javascript
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
329
|
+
const MAX_SCHEMA_SIZE = 10000;
|
|
330
|
+
|
|
331
|
+
if (JSON.stringify(schema).length > MAX_SCHEMA_SIZE) {
|
|
332
|
+
throw new Error('Schema 体积过大,建议拆分');
|
|
333
|
+
}
|
|
319
334
|
|
|
320
335
|
// 在 validate 前检查
|
|
321
|
-
DslBuilder.validateNestingDepth(schema, 10);
|
|
336
|
+
const depthCheck = DslBuilder.validateNestingDepth(schema, 10);
|
|
337
|
+
if (!depthCheck.valid) {
|
|
338
|
+
throw new Error(depthCheck.message);
|
|
339
|
+
}
|
|
322
340
|
```
|
|
323
341
|
|
|
324
342
|
---
|
|
@@ -394,7 +412,7 @@ const schema = dsl({
|
|
|
394
412
|
```
|
|
395
413
|
|
|
396
414
|
**效果**:
|
|
397
|
-
```
|
|
415
|
+
```text
|
|
398
416
|
❌ 用户名不能为空
|
|
399
417
|
❌ 用户名至少需要3个字符
|
|
400
418
|
✅ 清晰明了,用户友好
|
|
@@ -402,22 +420,33 @@ const schema = dsl({
|
|
|
402
420
|
|
|
403
421
|
---
|
|
404
422
|
|
|
405
|
-
### 3.
|
|
423
|
+
### 3. 处理外部异步校验错误
|
|
424
|
+
|
|
425
|
+
> `.custom()` 当前仅支持同步函数;涉及数据库、RPC、HTTP 等异步检查时,请在基础校验通过后于业务层单独执行。
|
|
406
426
|
|
|
407
427
|
```javascript
|
|
408
428
|
const schema = dsl({
|
|
409
|
-
email: 'email!'.
|
|
410
|
-
try {
|
|
411
|
-
const exists = await checkEmailExists(value);
|
|
412
|
-
if (exists) return '邮箱已被占用';
|
|
413
|
-
} catch (error) {
|
|
414
|
-
// 记录错误但不阻止验证
|
|
415
|
-
console.error('Email check failed:', error);
|
|
416
|
-
// 可以选择跳过此验证或返回提示
|
|
417
|
-
return; // 跳过
|
|
418
|
-
}
|
|
419
|
-
})
|
|
429
|
+
email: 'email!'.label('邮箱地址')
|
|
420
430
|
});
|
|
431
|
+
|
|
432
|
+
async function validateUser(data) {
|
|
433
|
+
const result = validate(schema, data);
|
|
434
|
+
if (!result.valid) return result;
|
|
435
|
+
|
|
436
|
+
try {
|
|
437
|
+
const exists = await checkEmailExists(data.email);
|
|
438
|
+
if (exists) {
|
|
439
|
+
return {
|
|
440
|
+
valid: false,
|
|
441
|
+
errors: [{ field: 'email', keyword: 'business', message: '邮箱已被占用' }]
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
} catch (error) {
|
|
445
|
+
console.error('Email check failed:', error);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return result;
|
|
449
|
+
}
|
|
421
450
|
```
|
|
422
451
|
|
|
423
452
|
---
|
|
@@ -427,7 +456,7 @@ const schema = dsl({
|
|
|
427
456
|
### 1. 集中管理 Schema
|
|
428
457
|
|
|
429
458
|
**推荐的项目结构**:
|
|
430
|
-
```
|
|
459
|
+
```text
|
|
431
460
|
src/
|
|
432
461
|
├── schemas/
|
|
433
462
|
│ ├── index.js # 导出所有 Schema
|
|
@@ -498,25 +527,27 @@ router.post('/register', (req, res) => {
|
|
|
498
527
|
|
|
499
528
|
### 2. Schema 复用
|
|
500
529
|
|
|
501
|
-
**使用
|
|
530
|
+
**使用 SchemaUtils**:
|
|
502
531
|
```javascript
|
|
503
|
-
const {
|
|
532
|
+
const { SchemaUtils, dsl } = require('schema-dsl');
|
|
504
533
|
|
|
505
534
|
// 创建可复用字段库
|
|
506
|
-
const fields =
|
|
507
|
-
email: 'email!',
|
|
508
|
-
phone: dsl('string!').phone('cn'),
|
|
509
|
-
password: dsl('string!').password('strong')
|
|
535
|
+
const fields = SchemaUtils.createLibrary({
|
|
536
|
+
email: () => 'email!',
|
|
537
|
+
phone: () => dsl('string!').phone('cn'),
|
|
538
|
+
password: () => dsl('string!').password('strong')
|
|
510
539
|
});
|
|
511
540
|
|
|
512
541
|
// 在多个 Schema 中复用
|
|
513
542
|
const registerSchema = dsl({
|
|
514
|
-
|
|
543
|
+
email: fields.email(),
|
|
544
|
+
password: fields.password(),
|
|
515
545
|
username: 'string:3-32!'
|
|
516
546
|
});
|
|
517
547
|
|
|
518
548
|
const profileSchema = dsl({
|
|
519
|
-
|
|
549
|
+
email: fields.email(),
|
|
550
|
+
phone: fields.phone(),
|
|
520
551
|
bio: 'string:500'
|
|
521
552
|
});
|
|
522
553
|
```
|
|
@@ -535,12 +566,16 @@ const config = {
|
|
|
535
566
|
development: {
|
|
536
567
|
verbose: true,
|
|
537
568
|
allErrors: true,
|
|
538
|
-
cache: false //
|
|
569
|
+
cache: false // ✅ 简写:关闭缓存,便于调试
|
|
539
570
|
},
|
|
540
571
|
production: {
|
|
541
572
|
verbose: false,
|
|
542
573
|
allErrors: false, // 只返回第一个错误
|
|
543
|
-
cache:
|
|
574
|
+
cache: {
|
|
575
|
+
enabled: true,
|
|
576
|
+
maxSize: 1000,
|
|
577
|
+
ttl: 60 * 60 * 1000
|
|
578
|
+
}
|
|
544
579
|
}
|
|
545
580
|
};
|
|
546
581
|
|
|
@@ -601,7 +636,7 @@ app.get('/health', (req, res) => {
|
|
|
601
636
|
res.json({
|
|
602
637
|
status: 'ok',
|
|
603
638
|
validator: 'operational',
|
|
604
|
-
|
|
639
|
+
cacheStats: validator.getCacheStats()
|
|
605
640
|
});
|
|
606
641
|
} catch (error) {
|
|
607
642
|
res.status(500).json({
|
|
@@ -639,23 +674,21 @@ setInterval(() => {
|
|
|
639
674
|
|
|
640
675
|
## 性能基准参考
|
|
641
676
|
|
|
642
|
-
|
|
677
|
+
缓存命中前后通常能显著降低重复编译开销,但绝对耗时会受到机器性能、Node 版本、schema 复杂度、数据规模和命中率影响,不建议把某组固定毫秒数当成通用基准。
|
|
678
|
+
|
|
679
|
+
**更稳定的结论**:
|
|
643
680
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
| 简单验证(已缓存) | ~0.01ms |
|
|
648
|
-
| 复杂嵌套(未缓存) | ~1ms |
|
|
649
|
-
| 复杂嵌套(已缓存) | ~0.1ms |
|
|
650
|
-
| 批量验证(1000条) | ~100ms |
|
|
681
|
+
- 复用同一个 schema 对象或 `Validator` 实例,通常比每次请求都重新编译更快
|
|
682
|
+
- schema 越复杂、重复验证次数越多,缓存收益通常越明显
|
|
683
|
+
- 批量验证总耗时主要取决于单条 schema 复杂度和数据规模,不应使用固定毫秒数做容量承诺
|
|
651
684
|
|
|
652
|
-
|
|
685
|
+
如需当前可复查的吞吐量对比,请以维护中的 benchmark 结果和 FAQ 中同步的性能数据为准。
|
|
653
686
|
|
|
654
687
|
---
|
|
655
688
|
|
|
656
689
|
## 总结
|
|
657
690
|
|
|
658
|
-
遵循这些最佳实践,你的
|
|
691
|
+
遵循这些最佳实践,你的 schema-dsl 代码将具备:
|
|
659
692
|
|
|
660
693
|
✅ **高性能** - 通过预编译和缓存
|
|
661
694
|
✅ **高安全性** - 避免常见安全陷阱
|
|
@@ -666,7 +699,14 @@ setInterval(() => {
|
|
|
666
699
|
|
|
667
700
|
## 延伸阅读
|
|
668
701
|
|
|
669
|
-
- [性能优化指南](performance-guide.md)
|
|
670
|
-
- [安全检查清单](security-checklist.md)
|
|
702
|
+
- [性能优化指南](performance-guide.md)
|
|
703
|
+
- [安全检查清单](security-checklist.md)
|
|
671
704
|
- [故障排查指南](troubleshooting.md)
|
|
672
705
|
|
|
706
|
+
---
|
|
707
|
+
|
|
708
|
+
## 对应示例文件
|
|
709
|
+
|
|
710
|
+
**示例入口**: [best-practices.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/best-practices.ts)
|
|
711
|
+
**说明**: 展示“简单字段用纯 DSL、复杂字段局部使用 Builder、字段库复用”的推荐组合,以及成功 / 失败两条验证路径。
|
|
712
|
+
|
package/docs/cache-manager.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CacheManager 缓存管理器
|
|
2
2
|
|
|
3
|
-
> **模块**: `
|
|
3
|
+
> **模块**: `src/core/CacheManager.ts`(公开导出:`require('schema-dsl').CacheManager`)
|
|
4
4
|
|
|
5
5
|
> **用途**: 高性能 Schema 编译缓存,支持 LRU 淘汰和 TTL 过期
|
|
6
6
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
## 概述
|
|
21
21
|
|
|
22
|
-
`CacheManager` 是
|
|
22
|
+
`CacheManager` 是 schema-dsl 的内部缓存系统,用于缓存编译后的 Schema 验证函数,避免重复编译带来的性能开销。
|
|
23
23
|
|
|
24
24
|
### 核心功能
|
|
25
25
|
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
## 快速开始
|
|
35
35
|
|
|
36
36
|
```javascript
|
|
37
|
-
const CacheManager = require('schema-dsl
|
|
37
|
+
const { CacheManager } = require('schema-dsl');
|
|
38
38
|
|
|
39
39
|
// 创建缓存实例
|
|
40
40
|
const cache = new CacheManager({
|
|
41
|
-
maxSize:
|
|
41
|
+
maxSize: 5000, // 默认最大缓存数量
|
|
42
42
|
ttl: 3600000 // 1小时过期
|
|
43
43
|
});
|
|
44
44
|
|
|
@@ -71,7 +71,7 @@ new CacheManager(options)
|
|
|
71
71
|
|
|
72
72
|
| 参数 | 类型 | 默认值 | 说明 |
|
|
73
73
|
|------|------|--------|------|
|
|
74
|
-
| `options.maxSize` | number | `
|
|
74
|
+
| `options.maxSize` | number | `5000` | 最大缓存条目数 |
|
|
75
75
|
| `options.ttl` | number | `3600000` | 缓存生存时间(毫秒) |
|
|
76
76
|
| `options.enabled` | boolean | `true` | 是否启用缓存 |
|
|
77
77
|
| `options.statsEnabled` | boolean | `true` | 是否启用统计 |
|
|
@@ -162,9 +162,10 @@ console.log(stats);
|
|
|
162
162
|
// sets: 100, // 设置次数
|
|
163
163
|
// deletes: 5, // 删除次数
|
|
164
164
|
// clears: 1, // 清空次数
|
|
165
|
-
// hitRate:
|
|
165
|
+
// hitRate: '83.33', // 命中率百分比字符串
|
|
166
166
|
// size: 80, // 当前缓存数量
|
|
167
|
-
// maxSize:
|
|
167
|
+
// maxSize: 5000, // 最大容量
|
|
168
|
+
// enabled: true // 是否启用缓存
|
|
168
169
|
// }
|
|
169
170
|
```
|
|
170
171
|
|
|
@@ -180,12 +181,12 @@ cache.resetStats();
|
|
|
180
181
|
|
|
181
182
|
---
|
|
182
183
|
|
|
183
|
-
### `
|
|
184
|
+
### `size()`
|
|
184
185
|
|
|
185
186
|
获取当前缓存条目数量。
|
|
186
187
|
|
|
187
188
|
```javascript
|
|
188
|
-
console.log(`当前缓存: ${cache.
|
|
189
|
+
console.log(`当前缓存: ${cache.size()} 条`);
|
|
189
190
|
```
|
|
190
191
|
|
|
191
192
|
---
|
|
@@ -235,12 +236,12 @@ function analyzeCachePerformance(cache) {
|
|
|
235
236
|
console.log('=== 缓存性能分析 ===');
|
|
236
237
|
console.log(`命中次数: ${stats.hits}`);
|
|
237
238
|
console.log(`未命中次数: ${stats.misses}`);
|
|
238
|
-
console.log(`命中率: ${
|
|
239
|
+
console.log(`命中率: ${stats.hitRate}%`);
|
|
239
240
|
console.log(`缓存使用率: ${(stats.size / stats.maxSize * 100).toFixed(1)}%`);
|
|
240
241
|
console.log(`淘汰次数: ${stats.evictions}`);
|
|
241
242
|
|
|
242
243
|
// 性能建议
|
|
243
|
-
if (stats.hitRate <
|
|
244
|
+
if (Number(stats.hitRate) < 50) {
|
|
244
245
|
console.log('⚠️ 命中率较低,考虑增加缓存大小');
|
|
245
246
|
}
|
|
246
247
|
if (stats.evictions > stats.sets * 0.5) {
|
|
@@ -254,13 +255,13 @@ function analyzeCachePerformance(cache) {
|
|
|
254
255
|
```javascript
|
|
255
256
|
function printCacheDashboard(cache) {
|
|
256
257
|
const stats = cache.getStats();
|
|
257
|
-
const hitRate =
|
|
258
|
+
const hitRate = `${stats.hitRate}%`;
|
|
258
259
|
const usage = (stats.size / stats.maxSize * 100).toFixed(1);
|
|
259
260
|
|
|
260
261
|
console.log('┌─────────────────────────────┐');
|
|
261
262
|
console.log('│ 缓存状态仪表板 │');
|
|
262
263
|
console.log('├─────────────────────────────┤');
|
|
263
|
-
console.log(`│ 命中率:
|
|
264
|
+
console.log(`│ 命中率: ${hitRate.padStart(8)} │`);
|
|
264
265
|
console.log(`│ 使用率: ${usage.padStart(6)}% │`);
|
|
265
266
|
console.log(`│ 当前条目: ${String(stats.size).padStart(6)} │`);
|
|
266
267
|
console.log(`│ 最大容量: ${String(stats.maxSize).padStart(6)} │`);
|
|
@@ -293,7 +294,7 @@ const cache = new CacheManager({
|
|
|
293
294
|
```javascript
|
|
294
295
|
setInterval(() => {
|
|
295
296
|
const stats = cache.getStats();
|
|
296
|
-
if (stats.hitRate <
|
|
297
|
+
if (Number(stats.hitRate) < 80) {
|
|
297
298
|
console.warn('缓存命中率低于80%');
|
|
298
299
|
}
|
|
299
300
|
}, 60000);
|
|
@@ -317,7 +318,7 @@ function updateSchema(name, newSchema) {
|
|
|
317
318
|
|
|
318
319
|
当缓存达到最大容量时,自动淘汰最久未使用的条目:
|
|
319
320
|
|
|
320
|
-
```
|
|
321
|
+
```text
|
|
321
322
|
缓存操作顺序:
|
|
322
323
|
1. set('A', ...) → [A]
|
|
323
324
|
2. set('B', ...) → [A, B]
|
|
@@ -334,3 +335,10 @@ function updateSchema(name, newSchema) {
|
|
|
334
335
|
- [性能优化指南](validation-guide.md#性能优化)
|
|
335
336
|
- [API 参考](api-reference.md)
|
|
336
337
|
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## 对应示例文件
|
|
341
|
+
|
|
342
|
+
**示例入口**: [cache-manager.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/cache-manager.ts)
|
|
343
|
+
**说明**: 覆盖 `set/get/has`、LRU 淘汰、统计信息读取和 `resetStats()` 的实际行为。
|
|
344
|
+
|
package/docs/compile.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# compile 方法
|
|
2
|
+
|
|
3
|
+
`Validator.compile(schema, cacheKey?)` 会将 JSON Schema 编译为 AJV 验证函数,并在传入 `cacheKey` 时复用缓存。
|
|
4
|
+
|
|
5
|
+
## 方法签名
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
validator.compile(schema, cacheKey?)
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 参数
|
|
12
|
+
|
|
13
|
+
- `schema` - JSON Schema 对象
|
|
14
|
+
- `cacheKey` - 可选缓存键;传入后,同一个 `Validator` 实例内可复用已编译结果
|
|
15
|
+
|
|
16
|
+
## 返回值
|
|
17
|
+
|
|
18
|
+
返回 AJV 验证函数,可直接像普通函数一样调用;执行结果为 `true / false`,错误详情挂在 `validate.errors` 上。
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
const { Validator, dsl } = require('schema-dsl');
|
|
22
|
+
const validator = new Validator();
|
|
23
|
+
const schema = dsl({ name: 'string!' });
|
|
24
|
+
const validate = validator.compile(schema, 'user-schema');
|
|
25
|
+
console.log(validate({ name: 'Rocky' }));
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 适用场景
|
|
29
|
+
|
|
30
|
+
- 同一份 schema 需要重复校验多次时,先 `compile()` 再复用编译结果
|
|
31
|
+
- 需要自己控制缓存键,避免重复编译开销
|
|
32
|
+
- 想把编译和执行拆开,接入自定义流程
|
|
33
|
+
|
|
34
|
+
## 注意事项
|
|
35
|
+
|
|
36
|
+
- `cacheKey` 的缓存作用域是当前 `Validator` 实例,不跨实例共享
|
|
37
|
+
- 如果只是对同一份 schema 做批量校验,也可以直接使用 `validator.validateBatch()`
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 对应示例文件
|
|
42
|
+
|
|
43
|
+
**示例入口**: [compile.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/compile.ts)
|
|
44
|
+
**说明**: 覆盖 `compile()` 的编译结果复用、`cacheKey` 命中,以及失败场景下从验证函数读取错误详情。
|
|
45
|
+
|
package/docs/conditional-api.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# 链式条件 API - ConditionalBuilder
|
|
2
2
|
|
|
3
|
-
> **版本**:
|
|
4
|
-
> **更新日期**: 2026-
|
|
3
|
+
> **版本**: schema-dsl v2.0.0-beta.2
|
|
4
|
+
> **更新日期**: 2026-05-08
|
|
5
5
|
> **状态**: ✅ 稳定
|
|
6
6
|
|
|
7
7
|
---
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
|
|
23
23
|
`ConditionalBuilder` 提供流畅的链式条件判断 API,类似 JavaScript 的 if-else 语句,用于在验证时根据实际数据动态调整验证规则。
|
|
24
24
|
|
|
25
|
+
> 关键语义:当你使用 `.message()` / `.assert()` / `.check()` 这类“失败即返回”的模式时,条件函数应该写成**失败条件**,因为条件返回 `true` 才会被判定为失败。
|
|
26
|
+
|
|
25
27
|
### 核心特性
|
|
26
28
|
|
|
27
29
|
- ✅ **链式调用** - 流畅的 API,类似 JavaScript if-else
|
|
@@ -218,21 +220,21 @@ const { dsl, validate } = require('schema-dsl');
|
|
|
218
220
|
// 方式1:传统方式(需要 validate 函数)
|
|
219
221
|
const schema1 = dsl({
|
|
220
222
|
age: 'number!',
|
|
221
|
-
status: dsl.if((data) => data.age
|
|
223
|
+
status: dsl.if((data) => data.age < 18)
|
|
222
224
|
.message('未成年用户不能注册')
|
|
223
225
|
});
|
|
224
226
|
|
|
225
227
|
validate(schema1, { age: 16, status: 'active' });
|
|
226
|
-
// => { valid: false, errors: [{ message: '未成年用户不能注册' }] }
|
|
228
|
+
// => { valid: false, errors: [{ message: '未成年用户不能注册' }], data: { age: 16, status: 'active' } }
|
|
227
229
|
|
|
228
230
|
// ✅ 方式2:快捷方式(一行代码验证)
|
|
229
|
-
const result = dsl.if((data) => data.age
|
|
231
|
+
const result = dsl.if((data) => data.age < 18)
|
|
230
232
|
.message('未成年用户不能注册')
|
|
231
233
|
.validate({ age: 16 });
|
|
232
|
-
// => { valid: false, errors: [{ message: '未成年用户不能注册' }] }
|
|
234
|
+
// => { valid: false, errors: [{ message: '未成年用户不能注册' }], data: { age: 16 } }
|
|
233
235
|
|
|
234
236
|
// ✅ 方式3:.check() 快速判断
|
|
235
|
-
const isValid = dsl.if((data) => data.age
|
|
237
|
+
const isValid = dsl.if((data) => data.age < 18)
|
|
236
238
|
.message('未成年用户不能注册')
|
|
237
239
|
.check({ age: 16 });
|
|
238
240
|
// => false
|
|
@@ -421,6 +423,26 @@ dsl.if(d => d.age < 18)
|
|
|
421
423
|
|
|
422
424
|
---
|
|
423
425
|
|
|
426
|
+
### .build()
|
|
427
|
+
|
|
428
|
+
将当前 `ConditionalBuilder` 输出为可直接交给 `Validator` / `validate()` 使用的 schema 对象。
|
|
429
|
+
|
|
430
|
+
`.build()` 是 `.toSchema()` 的别名,适合在你想显式拿到最终 schema 时使用。
|
|
431
|
+
|
|
432
|
+
```javascript
|
|
433
|
+
const { dsl, validate } = require('schema-dsl');
|
|
434
|
+
|
|
435
|
+
const conditionalSchema = dsl.if(data => data.age >= 18)
|
|
436
|
+
.then('email!')
|
|
437
|
+
.else('email')
|
|
438
|
+
.build();
|
|
439
|
+
|
|
440
|
+
const result = validate(conditionalSchema, 'user@example.com');
|
|
441
|
+
console.log(result.valid);
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
424
446
|
### .elseIf(condition)
|
|
425
447
|
|
|
426
448
|
添加 else-if 分支。
|
|
@@ -458,11 +480,11 @@ dsl.if((data) => data.userType === 'admin')
|
|
|
458
480
|
|
|
459
481
|
**基础示例**:
|
|
460
482
|
```javascript
|
|
461
|
-
dsl.if((data) => data.age
|
|
483
|
+
dsl.if((data) => data.age < 18)
|
|
462
484
|
.message('未成年用户不能注册')
|
|
463
485
|
|
|
464
486
|
// 支持多语言 key
|
|
465
|
-
dsl.if((data) => data.age
|
|
487
|
+
dsl.if((data) => data.age < 18)
|
|
466
488
|
.message('error.underage')
|
|
467
489
|
```
|
|
468
490
|
|
|
@@ -666,7 +688,7 @@ try {
|
|
|
666
688
|
|
|
667
689
|
**返回**: `*` - 验证通过返回数据
|
|
668
690
|
|
|
669
|
-
**抛出**: `
|
|
691
|
+
**抛出**: `ValidationError` - 验证失败时直接抛出 `ValidationError`
|
|
670
692
|
|
|
671
693
|
**特性**: 同步版本的断言验证,适合快速失败场景
|
|
672
694
|
|
|
@@ -1237,7 +1259,7 @@ validate(contactSchema, 'user@example.com'); // ✅ 作为邮箱验证
|
|
|
1237
1259
|
validate(contactSchema, '13800138000'); // ✅ 作为手机号验证
|
|
1238
1260
|
```
|
|
1239
1261
|
|
|
1240
|
-
**完整示例**: 参见 `
|
|
1262
|
+
**完整示例**: 参见 `test/unit/conditional-non-object.test.ts`
|
|
1241
1263
|
|
|
1242
1264
|
---
|
|
1243
1265
|
|
|
@@ -1276,3 +1298,10 @@ validate(contactSchema, '13800138000'); // ✅ 作为手机号验证
|
|
|
1276
1298
|
- [API 参考](./api-reference.md)
|
|
1277
1299
|
- [最佳实践](./best-practices.md)
|
|
1278
1300
|
|
|
1301
|
+
---
|
|
1302
|
+
|
|
1303
|
+
## 对应示例文件
|
|
1304
|
+
|
|
1305
|
+
**示例入口**: [conditional-api.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/conditional-api.ts)
|
|
1306
|
+
**说明**: 同时覆盖失败谓词模式下的 `.check()` / `.assert()`,以及字段名版本 `dsl.if(field, then, else)` 和 `dsl.match()` 映射。
|
|
1307
|
+
|