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.
- package/CHANGELOG.md +130 -113
- package/LICENSE +21 -21
- package/README.md +628 -628
- package/dist/{DslBuilder-DkLaOo9Q.d.ts → DslBuilder-BIgQOAXp.d.ts} +2 -0
- package/dist/{DslBuilder-DQDN0ZxZ.d.cts → DslBuilder-CjHTucNQ.d.cts} +2 -0
- package/dist/{Validator-hFWKGxir.d.ts → Validator-CllRdrY0.d.ts} +1 -1
- package/dist/{Validator-C7GsVQOH.d.cts → Validator-D6okG9tr.d.cts} +1 -1
- package/dist/index.cjs +75 -29
- package/dist/index.d.cts +10 -4
- package/dist/index.d.ts +10 -4
- package/dist/index.js +75 -29
- package/dist/plugins/custom-format.cjs +33 -17
- package/dist/plugins/custom-format.d.cts +1 -1
- package/dist/plugins/custom-format.d.ts +1 -1
- package/dist/plugins/custom-format.js +33 -17
- package/dist/plugins/custom-type-example.cjs +33 -17
- package/dist/plugins/custom-type-example.d.cts +1 -1
- package/dist/plugins/custom-type-example.d.ts +1 -1
- package/dist/plugins/custom-type-example.js +33 -17
- package/dist/plugins/custom-validator.cjs +0 -2
- package/dist/plugins/custom-validator.d.cts +1 -1
- package/dist/plugins/custom-validator.d.ts +1 -1
- package/dist/plugins/custom-validator.js +0 -2
- package/docs/FEATURE-INDEX.md +553 -553
- package/docs/add-custom-locale.md +496 -496
- package/docs/add-keyword.md +24 -24
- package/docs/api-reference.md +1047 -1047
- package/docs/api.md +13 -13
- package/docs/best-practices-project-structure.md +417 -417
- package/docs/best-practices.md +712 -712
- package/docs/cache-manager.md +344 -344
- package/docs/compile.md +45 -45
- package/docs/conditional-api.md +1307 -1307
- package/docs/custom-extensions-guide.md +339 -339
- package/docs/design-philosophy.md +606 -606
- package/docs/doc-index.md +324 -324
- package/docs/dsl-syntax.md +714 -714
- package/docs/dynamic-locale.md +608 -608
- package/docs/enum.md +482 -482
- package/docs/error-handling.md +1975 -1975
- package/docs/export-guide.md +501 -501
- package/docs/export-limitations.md +567 -567
- package/docs/faq.md +596 -596
- package/docs/frontend-i18n-guide.md +307 -307
- package/docs/i18n-user-guide.md +487 -487
- package/docs/i18n.md +476 -476
- package/docs/index.md +48 -48
- package/docs/json-schema-basics.md +40 -40
- package/docs/label-vs-description.md +271 -271
- package/docs/markdown-exporter.md +406 -406
- package/docs/mongodb-exporter.md +302 -302
- package/docs/multi-language.md +26 -26
- package/docs/multi-type-support.md +322 -322
- package/docs/mysql-exporter.md +280 -280
- package/docs/number-operators.md +449 -449
- package/docs/optional-marker-guide.md +326 -326
- package/docs/performance-guide.md +49 -49
- package/docs/plugin-system.md +381 -381
- package/docs/plugin-type-registration.md +34 -34
- package/docs/postgresql-exporter.md +311 -311
- package/docs/public/favicon.svg +4 -4
- package/docs/quick-start.md +435 -435
- package/docs/runtime-locale-support.md +532 -532
- package/docs/schema-helper.md +345 -345
- package/docs/schema-utils-advanced-issues.md +23 -23
- package/docs/schema-utils-best-practices.md +20 -20
- package/docs/schema-utils-chaining.md +150 -150
- package/docs/schema-utils.md +524 -524
- package/docs/security-checklist.md +20 -20
- package/docs/string-extensions.md +488 -488
- package/docs/troubleshooting.md +486 -486
- package/docs/type-converter.md +310 -310
- package/docs/type-reference.md +242 -242
- package/docs/typescript-guide.md +584 -584
- package/docs/union-type-guide.md +157 -157
- package/docs/union-types.md +284 -284
- package/docs/validate-async.md +491 -491
- package/docs/validate-batch.md +49 -49
- package/docs/validate-dsl-object-support.md +578 -578
- package/docs/validate.md +506 -506
- package/docs/validation-guide.md +502 -502
- package/docs/validator.md +39 -39
- package/package.json +131 -131
- package/plugins/custom-format.cjs +8 -8
- package/plugins/custom-type-example.cjs +8 -8
- package/plugins/custom-validator.cjs +8 -8
- package/src/adapters/DslAdapter.ts +111 -111
- package/src/adapters/index.ts +1 -1
- package/src/config/constants.ts +83 -83
- package/src/config/index.ts +2 -2
- package/src/config/patterns.ts +77 -77
- package/src/core/CacheManager.ts +169 -159
- package/src/core/ConditionalBuilder.ts +382 -382
- package/src/core/ConditionalRuntime.ts +27 -27
- package/src/core/ConditionalValidator.ts +254 -254
- package/src/core/DslBuilder.ts +687 -677
- package/src/core/ErrorCodes.ts +38 -38
- package/src/core/ErrorFormatter.ts +271 -271
- package/src/core/JSONSchemaCore.ts +65 -65
- package/src/core/Locale.ts +187 -187
- package/src/core/MessageTemplate.ts +42 -42
- package/src/core/ObjectDslBuilder.ts +64 -64
- package/src/core/PluginManager.ts +326 -326
- package/src/core/StringExtensions.ts +140 -140
- package/src/core/TemplateEngine.ts +44 -44
- package/src/core/Validator.ts +448 -448
- package/src/errors/I18nError.ts +159 -159
- package/src/errors/ValidationError.ts +105 -105
- package/src/exporters/BaseExporter.ts +60 -60
- package/src/exporters/MarkdownExporter.ts +305 -305
- package/src/exporters/MongoDBExporter.ts +126 -126
- package/src/exporters/MySQLExporter.ts +156 -155
- package/src/exporters/PostgreSQLExporter.ts +222 -222
- package/src/exporters/index.ts +18 -18
- package/src/index.ts +651 -633
- package/src/locales/en-US.ts +160 -160
- package/src/locales/es-ES.ts +160 -160
- package/src/locales/fr-FR.ts +160 -160
- package/src/locales/index.ts +103 -103
- package/src/locales/ja-JP.ts +160 -160
- package/src/locales/types.ts +156 -156
- package/src/locales/zh-CN.ts +160 -160
- package/src/parser/ConstraintParser.ts +101 -101
- package/src/parser/DslParser.ts +470 -470
- package/src/parser/SchemaCompiler.ts +66 -66
- package/src/parser/TypeRegistry.ts +250 -250
- package/src/parser/index.ts +6 -6
- package/src/plugins/custom-format.ts +124 -126
- package/src/plugins/custom-type-example.ts +106 -108
- package/src/plugins/custom-validator.ts +138 -140
- package/src/types/conditional.ts +28 -28
- package/src/types/config.ts +59 -59
- package/src/types/dsl.ts +131 -131
- package/src/types/error.ts +60 -60
- package/src/types/index.ts +17 -17
- package/src/types/infer.ts +127 -127
- package/src/types/plugin.ts +58 -58
- package/src/types/safe-regex.d.ts +9 -9
- package/src/types/schema.ts +66 -66
- package/src/types/validate.ts +71 -71
- package/src/utils/SchemaHelper.ts +196 -196
- package/src/utils/SchemaUtils.ts +365 -346
- package/src/utils/TypeConverter.ts +215 -215
- package/src/utils/index.ts +10 -10
- package/src/validators/CustomKeywords.ts +477 -477
package/docs/schema-utils.md
CHANGED
|
@@ -1,524 +1,524 @@
|
|
|
1
|
-
# Schema 工具函数文档
|
|
2
|
-
|
|
3
|
-
> **更新时间**: 2025-12-25
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 📑 目录
|
|
8
|
-
|
|
9
|
-
- [Schema 复用](#schema-复用)
|
|
10
|
-
- [Schema 合并](#schema-合并)
|
|
11
|
-
- [Schema 筛选](#schema-筛选)
|
|
12
|
-
- [Schema 导出](#schema-导出)
|
|
13
|
-
- [性能监控](#性能监控)
|
|
14
|
-
- [完整示例](#完整示例)
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## Schema 复用
|
|
19
|
-
|
|
20
|
-
### 直接复用(最简单)✅
|
|
21
|
-
|
|
22
|
-
```javascript
|
|
23
|
-
const { dsl } = require('schema-dsl');
|
|
24
|
-
|
|
25
|
-
// 定义可复用字段(就是普通对象)
|
|
26
|
-
const commonFields = {
|
|
27
|
-
email: 'email!'.label('邮箱地址'),
|
|
28
|
-
phone: 'string:11!'.phone('cn').label('手机号'),
|
|
29
|
-
username: 'string:3-32!'.username().label('用户名')
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// 直接使用
|
|
33
|
-
const registerSchema = dsl({
|
|
34
|
-
...commonFields, // ✅ 直接展开
|
|
35
|
-
password: 'string:8-64!'.password('strong')
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
const profileSchema = dsl({
|
|
39
|
-
...commonFields, // ✅ 重复使用
|
|
40
|
-
bio: 'string:500',
|
|
41
|
-
avatar: 'url'
|
|
42
|
-
});
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
**优点**: 最简单,直接使用 JavaScript 对象展开
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
### 函数复用(需要参数时)
|
|
50
|
-
|
|
51
|
-
```javascript
|
|
52
|
-
// 定义可复用字段函数
|
|
53
|
-
const createEmailField = (label = '邮箱地址') =>
|
|
54
|
-
'email!'.label(label);
|
|
55
|
-
|
|
56
|
-
const createRangeField = (min, max) =>
|
|
57
|
-
`number:${min}-${max}`.label('数值范围');
|
|
58
|
-
|
|
59
|
-
// 使用
|
|
60
|
-
const schema = dsl({
|
|
61
|
-
email: createEmailField('联系邮箱'),
|
|
62
|
-
workEmail: createEmailField('工作邮箱'),
|
|
63
|
-
age: createRangeField(18, 120),
|
|
64
|
-
score: createRangeField(0, 100)
|
|
65
|
-
});
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
**优点**: 支持参数化,灵活性强
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
### 字段库复用(大型项目)
|
|
73
|
-
|
|
74
|
-
```javascript
|
|
75
|
-
// fields/common.js - 定义字段库
|
|
76
|
-
module.exports = {
|
|
77
|
-
email: () => 'email!'.label('邮箱地址'),
|
|
78
|
-
phone: (country = 'cn') => `string:11!`.phone(country).label('手机号'),
|
|
79
|
-
username: (range = '3-32') => `string:${range}!`.username(range).label('用户名'),
|
|
80
|
-
password: (strength = 'medium') => 'string:8-64!'.password(strength).label('密码'),
|
|
81
|
-
|
|
82
|
-
// 组合字段
|
|
83
|
-
userAuth: () => ({
|
|
84
|
-
username: 'string:3-32!'.username().label('用户名'),
|
|
85
|
-
password: 'string:8-64!'.password('strong').label('密码')
|
|
86
|
-
}),
|
|
87
|
-
|
|
88
|
-
userProfile: () => ({
|
|
89
|
-
nickname: 'string:2-20!'.label('昵称'),
|
|
90
|
-
bio: 'string:500',
|
|
91
|
-
avatar: 'url'
|
|
92
|
-
})
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
// 使用
|
|
96
|
-
const fields = require('./fields/common');
|
|
97
|
-
|
|
98
|
-
const loginSchema = dsl({
|
|
99
|
-
email: fields.email(),
|
|
100
|
-
password: fields.password('strong')
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const registerSchema = dsl({
|
|
104
|
-
...fields.userAuth(), // ✅ 展开组合字段
|
|
105
|
-
email: fields.email(),
|
|
106
|
-
phone: fields.phone('cn')
|
|
107
|
-
});
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
**优点**: 统一管理,易于维护
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## Schema 合并
|
|
115
|
-
|
|
116
|
-
### createLibrary() - 创建片段库
|
|
117
|
-
|
|
118
|
-
```javascript
|
|
119
|
-
const { SchemaUtils, dsl } = require('schema-dsl');
|
|
120
|
-
|
|
121
|
-
const fields = SchemaUtils.createLibrary({
|
|
122
|
-
email: () => 'email!'.label('邮箱地址'),
|
|
123
|
-
phone: () => dsl('string!').phone('cn').label('手机号'),
|
|
124
|
-
profile: () => ({
|
|
125
|
-
bio: 'string:500',
|
|
126
|
-
avatar: 'url'
|
|
127
|
-
})
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
const registerSchema = dsl({
|
|
131
|
-
email: fields.email(),
|
|
132
|
-
phone: fields.phone(),
|
|
133
|
-
password: dsl('string!').password('strong')
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
const profileSchema = dsl({
|
|
137
|
-
...fields.profile(),
|
|
138
|
-
email: fields.email()
|
|
139
|
-
});
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
**说明**: `createLibrary()` 只是返回片段工厂集合,适合在大型项目中集中管理字段和组合片段。
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
### extend() - 扩展Schema(继承)
|
|
147
|
-
|
|
148
|
-
```javascript
|
|
149
|
-
const baseUser = dsl({
|
|
150
|
-
name: 'string!',
|
|
151
|
-
email: 'email!'
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// 扩展基础Schema
|
|
155
|
-
const admin = SchemaUtils.extend(baseUser, {
|
|
156
|
-
role: 'admin|superadmin',
|
|
157
|
-
permissions: 'array<string>'
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
// admin包含所有baseUser字段 + role + permissions
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
**说明**: 类似继承,保留基础Schema的所有字段
|
|
164
|
-
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
## Schema 筛选
|
|
168
|
-
|
|
169
|
-
### pick() - 选择字段
|
|
170
|
-
|
|
171
|
-
```javascript
|
|
172
|
-
const fullUser = dsl({
|
|
173
|
-
name: 'string!',
|
|
174
|
-
email: 'email!',
|
|
175
|
-
password: 'string:8-64!',
|
|
176
|
-
phone: 'string:11!',
|
|
177
|
-
age: 'number:18-120'
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
// 只选择特定字段
|
|
181
|
-
const publicUser = SchemaUtils.pick(fullUser, ['name', 'email']);
|
|
182
|
-
|
|
183
|
-
// publicUser 只包含 name 和 email
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
**用途**: 从完整Schema中提取部分字段(如公开信息)
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
### omit() - 排除字段
|
|
191
|
-
|
|
192
|
-
```javascript
|
|
193
|
-
const fullUser = dsl({
|
|
194
|
-
name: 'string!',
|
|
195
|
-
email: 'email!',
|
|
196
|
-
password: 'string:8-64!',
|
|
197
|
-
phone: 'string:11!'
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
// 排除敏感字段
|
|
201
|
-
const safeUser = SchemaUtils.omit(fullUser, ['password']);
|
|
202
|
-
|
|
203
|
-
// safeUser 包含除 password 外的所有字段
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
**用途**: 移除敏感字段(如密码)
|
|
207
|
-
|
|
208
|
-
---
|
|
209
|
-
|
|
210
|
-
### partial() - 将字段改为可选
|
|
211
|
-
|
|
212
|
-
```javascript
|
|
213
|
-
const updateSchema = SchemaUtils.partial(dsl({
|
|
214
|
-
name: 'string!',
|
|
215
|
-
email: 'email!',
|
|
216
|
-
age: 'number:18-120'
|
|
217
|
-
}));
|
|
218
|
-
|
|
219
|
-
// 结果中 required 会被移除,适合 PATCH / 局部更新场景
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
也可以只对部分字段做可选化:
|
|
223
|
-
|
|
224
|
-
```javascript
|
|
225
|
-
const schema = dsl({
|
|
226
|
-
name: 'string!',
|
|
227
|
-
email: 'email!',
|
|
228
|
-
age: 'number:18-120'
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
const partialContact = SchemaUtils.partial(schema, ['name', 'email']);
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
---
|
|
235
|
-
|
|
236
|
-
## Schema 导出
|
|
237
|
-
|
|
238
|
-
### toMarkdown() - 导出为Markdown文档
|
|
239
|
-
|
|
240
|
-
```javascript
|
|
241
|
-
const schema = dsl({
|
|
242
|
-
username: 'string:3-32!'.label('用户名'),
|
|
243
|
-
email: 'email!'.label('邮箱地址'),
|
|
244
|
-
age: 'number:18-120'
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
const markdown = SchemaUtils.toMarkdown(schema, {
|
|
248
|
-
title: '用户注册Schema'
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
console.log(markdown);
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
**输出**:
|
|
255
|
-
```markdown
|
|
256
|
-
# 用户注册Schema
|
|
257
|
-
|
|
258
|
-
| 字段 | 类型 | 必填 | 约束 | 说明 |
|
|
259
|
-
|------|------|------|------|------|
|
|
260
|
-
| username | string | ✅ | 3-32字符 | 用户名 |
|
|
261
|
-
| email | email | ✅ | - | 邮箱地址 |
|
|
262
|
-
| age | number | ❌ | 18-120 | - |
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
**用途**: 生成API文档
|
|
266
|
-
|
|
267
|
-
---
|
|
268
|
-
|
|
269
|
-
### toHTML() - 导出为HTML表格
|
|
270
|
-
|
|
271
|
-
```javascript
|
|
272
|
-
const html = SchemaUtils.toHTML(schema, {
|
|
273
|
-
title: '用户注册Schema'
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
// 生成HTML表格,可以嵌入文档
|
|
277
|
-
```
|
|
278
|
-
|
|
279
|
-
**用途**: 集成到Web文档
|
|
280
|
-
|
|
281
|
-
---
|
|
282
|
-
|
|
283
|
-
## 性能监控
|
|
284
|
-
|
|
285
|
-
### validateBatch() - 批量验证统计
|
|
286
|
-
|
|
287
|
-
```javascript
|
|
288
|
-
const { SchemaUtils, Validator, dsl } = require('schema-dsl');
|
|
289
|
-
|
|
290
|
-
const schema = dsl({
|
|
291
|
-
email: 'email!',
|
|
292
|
-
age: 'number:18-120'
|
|
293
|
-
});
|
|
294
|
-
|
|
295
|
-
const validator = new Validator();
|
|
296
|
-
|
|
297
|
-
const items = [
|
|
298
|
-
{ email: 'user1@example.com', age: 25 },
|
|
299
|
-
{ email: 'invalid', age: 15 },
|
|
300
|
-
{ email: 'user2@example.com', age: 30 }
|
|
301
|
-
];
|
|
302
|
-
|
|
303
|
-
const batch = SchemaUtils.validateBatch(schema, items, validator.getAjv());
|
|
304
|
-
|
|
305
|
-
console.log(batch);
|
|
306
|
-
// {
|
|
307
|
-
// results: [
|
|
308
|
-
// { index: 0, valid: true, errors: null, data: {...} },
|
|
309
|
-
// { index: 1, valid: false, errors: [...], data: null },
|
|
310
|
-
// { index: 2, valid: true, errors: null, data: {...} }
|
|
311
|
-
// ],
|
|
312
|
-
// summary: {
|
|
313
|
-
// total: 3,
|
|
314
|
-
// valid: 2,
|
|
315
|
-
// invalid: 1,
|
|
316
|
-
// duration: 5,
|
|
317
|
-
// averageTime: 1.67
|
|
318
|
-
// }
|
|
319
|
-
// }
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
**说明**:
|
|
323
|
-
- 如果你只需要“每条是否通过”的结果,可直接使用 `validator.validateBatch(schema, items)`
|
|
324
|
-
- 如果你还需要汇总统计信息,再使用 `SchemaUtils.validateBatch(schema, items, validator.getAjv())`
|
|
325
|
-
|
|
326
|
-
---
|
|
327
|
-
|
|
328
|
-
### withPerformance() - 给 Validator 添加性能包装
|
|
329
|
-
|
|
330
|
-
```javascript
|
|
331
|
-
const validator = SchemaUtils.withPerformance(new Validator());
|
|
332
|
-
|
|
333
|
-
const result = validator.validate(schema, data);
|
|
334
|
-
|
|
335
|
-
console.log(result.performance);
|
|
336
|
-
// {
|
|
337
|
-
// duration: 2,
|
|
338
|
-
// timestamp: '2026-05-06T12:34:56.789Z'
|
|
339
|
-
// }
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
**用途**: 在不改业务调用方式的前提下,为验证结果附加耗时信息
|
|
343
|
-
|
|
344
|
-
---
|
|
345
|
-
|
|
346
|
-
## 其他工具
|
|
347
|
-
|
|
348
|
-
### clone() - 深度克隆Schema
|
|
349
|
-
|
|
350
|
-
```javascript
|
|
351
|
-
const original = dsl({
|
|
352
|
-
user: {
|
|
353
|
-
name: 'string!',
|
|
354
|
-
profile: {
|
|
355
|
-
bio: 'string:500'
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
const cloned = SchemaUtils.clone(original);
|
|
361
|
-
|
|
362
|
-
// cloned 是完全独立的副本
|
|
363
|
-
cloned.properties.user.properties.name.maxLength = 100;
|
|
364
|
-
// original 不会被修改
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
---
|
|
368
|
-
|
|
369
|
-
### validateNestingDepth() - 检查嵌套深度
|
|
370
|
-
|
|
371
|
-
```javascript
|
|
372
|
-
const { dsl, DslBuilder } = require('schema-dsl');
|
|
373
|
-
|
|
374
|
-
const schema = dsl({
|
|
375
|
-
level1: {
|
|
376
|
-
level2: {
|
|
377
|
-
level3: {
|
|
378
|
-
level4: 'string'
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
const result = DslBuilder.validateNestingDepth(schema, 10);
|
|
385
|
-
// 返回: { valid: true, depth: 4, path: 'level1.level2.level3', message: '...' }
|
|
386
|
-
|
|
387
|
-
if (result.depth > 5) {
|
|
388
|
-
console.warn('嵌套层级过深,建议扁平化');
|
|
389
|
-
}
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
**说明**: 这个能力属于 `DslBuilder` 静态方法,不是 `SchemaUtils` 的成员;这里一并列出是因为它常与 Schema 工具链一起使用。
|
|
393
|
-
|
|
394
|
-
---
|
|
395
|
-
|
|
396
|
-
## 完整示例
|
|
397
|
-
|
|
398
|
-
### 企业级字段库
|
|
399
|
-
|
|
400
|
-
```javascript
|
|
401
|
-
// libs/fields/index.js
|
|
402
|
-
module.exports = {
|
|
403
|
-
// 基础字段
|
|
404
|
-
id: () => 'string!'.pattern(/^[a-zA-Z0-9_-]+$/).label('ID'),
|
|
405
|
-
email: () => 'email!'.label('邮箱地址'),
|
|
406
|
-
phone: (country = 'cn') => 'string:11!'.phone(country).label('手机号'),
|
|
407
|
-
|
|
408
|
-
// 认证字段
|
|
409
|
-
auth: {
|
|
410
|
-
username: () => 'string:3-32!'.username().label('用户名'),
|
|
411
|
-
password: (strength = 'strong') =>
|
|
412
|
-
'string:8-64!'.password(strength).label('密码')
|
|
413
|
-
},
|
|
414
|
-
|
|
415
|
-
// 个人信息
|
|
416
|
-
profile: {
|
|
417
|
-
nickname: () => 'string:2-20!'.label('昵称'),
|
|
418
|
-
realName: () => 'string:2-50'.label('真实姓名'),
|
|
419
|
-
bio: () => 'string:500',
|
|
420
|
-
avatar: () => 'url'.label('头像'),
|
|
421
|
-
birthday: () => 'date'
|
|
422
|
-
},
|
|
423
|
-
|
|
424
|
-
// 地址信息
|
|
425
|
-
address: () => ({
|
|
426
|
-
country: 'string:2-50!',
|
|
427
|
-
province: 'string:2-50!',
|
|
428
|
-
city: 'string:2-50!',
|
|
429
|
-
detail: 'string:10-200!'
|
|
430
|
-
}),
|
|
431
|
-
|
|
432
|
-
// 时间戳
|
|
433
|
-
timestamps: () => ({
|
|
434
|
-
created_at: 'datetime!',
|
|
435
|
-
updated_at: 'datetime!'
|
|
436
|
-
})
|
|
437
|
-
};
|
|
438
|
-
|
|
439
|
-
// 使用
|
|
440
|
-
const fields = require('./libs/fields');
|
|
441
|
-
|
|
442
|
-
// 用户注册
|
|
443
|
-
const registerSchema = dsl({
|
|
444
|
-
...fields.auth,
|
|
445
|
-
email: fields.email(),
|
|
446
|
-
phone: fields.phone('cn'),
|
|
447
|
-
agree: 'boolean!'
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
// 用户资料
|
|
451
|
-
const profileSchema = dsl({
|
|
452
|
-
...fields.profile,
|
|
453
|
-
...fields.timestamps()
|
|
454
|
-
});
|
|
455
|
-
|
|
456
|
-
// 完整用户
|
|
457
|
-
const userSchema = SchemaUtils.extend(
|
|
458
|
-
SchemaUtils.extend(registerSchema, profileSchema),
|
|
459
|
-
fields.address()
|
|
460
|
-
);
|
|
461
|
-
```
|
|
462
|
-
|
|
463
|
-
---
|
|
464
|
-
|
|
465
|
-
## 最佳实践
|
|
466
|
-
|
|
467
|
-
### 1. 小项目:直接复用
|
|
468
|
-
|
|
469
|
-
```javascript
|
|
470
|
-
const commonFields = {
|
|
471
|
-
email: 'email!'.label('邮箱'),
|
|
472
|
-
phone: 'string:11!'.phone('cn')
|
|
473
|
-
};
|
|
474
|
-
|
|
475
|
-
const schema1 = dsl({ ...commonFields, ... });
|
|
476
|
-
const schema2 = dsl({ ...commonFields, ... });
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
### 2. 中型项目:函数复用
|
|
480
|
-
|
|
481
|
-
```javascript
|
|
482
|
-
const createUserFields = (options = {}) => ({
|
|
483
|
-
email: 'email!'.label(options.emailLabel || '邮箱'),
|
|
484
|
-
phone: 'string:11!'.phone(options.country || 'cn')
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
const schema = dsl({
|
|
488
|
-
...createUserFields({ emailLabel: '联系邮箱' }),
|
|
489
|
-
...otherFields
|
|
490
|
-
});
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
### 3. 大型项目:字段库
|
|
494
|
-
|
|
495
|
-
```javascript
|
|
496
|
-
// 统一管理在 fields/ 目录
|
|
497
|
-
const fields = require('./fields');
|
|
498
|
-
|
|
499
|
-
const schema = dsl({
|
|
500
|
-
...fields.auth,
|
|
501
|
-
...fields.profile
|
|
502
|
-
});
|
|
503
|
-
```
|
|
504
|
-
|
|
505
|
-
---
|
|
506
|
-
|
|
507
|
-
## 相关文档
|
|
508
|
-
|
|
509
|
-
- [DSL 语法](./dsl-syntax.md)
|
|
510
|
-
- [String 扩展](./string-extensions.md)
|
|
511
|
-
- [API 参考](./api-reference.md)
|
|
512
|
-
|
|
513
|
-
---
|
|
514
|
-
|
|
515
|
-
## 对应示例文件
|
|
516
|
-
|
|
517
|
-
**示例入口**: [schema-utils.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/schema-utils.ts)
|
|
518
|
-
**说明**: 覆盖 `reusable()`、`createLibrary()`、`extend()`、`validateBatch()`、`withPerformance()` 和 `clone()` 的最小工作流。
|
|
519
|
-
|
|
520
|
-
---
|
|
521
|
-
|
|
522
|
-
**最后更新**: 2026-05-08
|
|
523
|
-
|
|
524
|
-
|
|
1
|
+
# Schema 工具函数文档
|
|
2
|
+
|
|
3
|
+
> **更新时间**: 2025-12-25
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 📑 目录
|
|
8
|
+
|
|
9
|
+
- [Schema 复用](#schema-复用)
|
|
10
|
+
- [Schema 合并](#schema-合并)
|
|
11
|
+
- [Schema 筛选](#schema-筛选)
|
|
12
|
+
- [Schema 导出](#schema-导出)
|
|
13
|
+
- [性能监控](#性能监控)
|
|
14
|
+
- [完整示例](#完整示例)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Schema 复用
|
|
19
|
+
|
|
20
|
+
### 直接复用(最简单)✅
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
const { dsl } = require('schema-dsl');
|
|
24
|
+
|
|
25
|
+
// 定义可复用字段(就是普通对象)
|
|
26
|
+
const commonFields = {
|
|
27
|
+
email: 'email!'.label('邮箱地址'),
|
|
28
|
+
phone: 'string:11!'.phone('cn').label('手机号'),
|
|
29
|
+
username: 'string:3-32!'.username().label('用户名')
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// 直接使用
|
|
33
|
+
const registerSchema = dsl({
|
|
34
|
+
...commonFields, // ✅ 直接展开
|
|
35
|
+
password: 'string:8-64!'.password('strong')
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const profileSchema = dsl({
|
|
39
|
+
...commonFields, // ✅ 重复使用
|
|
40
|
+
bio: 'string:500',
|
|
41
|
+
avatar: 'url'
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**优点**: 最简单,直接使用 JavaScript 对象展开
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
### 函数复用(需要参数时)
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
// 定义可复用字段函数
|
|
53
|
+
const createEmailField = (label = '邮箱地址') =>
|
|
54
|
+
'email!'.label(label);
|
|
55
|
+
|
|
56
|
+
const createRangeField = (min, max) =>
|
|
57
|
+
`number:${min}-${max}`.label('数值范围');
|
|
58
|
+
|
|
59
|
+
// 使用
|
|
60
|
+
const schema = dsl({
|
|
61
|
+
email: createEmailField('联系邮箱'),
|
|
62
|
+
workEmail: createEmailField('工作邮箱'),
|
|
63
|
+
age: createRangeField(18, 120),
|
|
64
|
+
score: createRangeField(0, 100)
|
|
65
|
+
});
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**优点**: 支持参数化,灵活性强
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
### 字段库复用(大型项目)
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
// fields/common.js - 定义字段库
|
|
76
|
+
module.exports = {
|
|
77
|
+
email: () => 'email!'.label('邮箱地址'),
|
|
78
|
+
phone: (country = 'cn') => `string:11!`.phone(country).label('手机号'),
|
|
79
|
+
username: (range = '3-32') => `string:${range}!`.username(range).label('用户名'),
|
|
80
|
+
password: (strength = 'medium') => 'string:8-64!'.password(strength).label('密码'),
|
|
81
|
+
|
|
82
|
+
// 组合字段
|
|
83
|
+
userAuth: () => ({
|
|
84
|
+
username: 'string:3-32!'.username().label('用户名'),
|
|
85
|
+
password: 'string:8-64!'.password('strong').label('密码')
|
|
86
|
+
}),
|
|
87
|
+
|
|
88
|
+
userProfile: () => ({
|
|
89
|
+
nickname: 'string:2-20!'.label('昵称'),
|
|
90
|
+
bio: 'string:500',
|
|
91
|
+
avatar: 'url'
|
|
92
|
+
})
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// 使用
|
|
96
|
+
const fields = require('./fields/common');
|
|
97
|
+
|
|
98
|
+
const loginSchema = dsl({
|
|
99
|
+
email: fields.email(),
|
|
100
|
+
password: fields.password('strong')
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const registerSchema = dsl({
|
|
104
|
+
...fields.userAuth(), // ✅ 展开组合字段
|
|
105
|
+
email: fields.email(),
|
|
106
|
+
phone: fields.phone('cn')
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**优点**: 统一管理,易于维护
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Schema 合并
|
|
115
|
+
|
|
116
|
+
### createLibrary() - 创建片段库
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
const { SchemaUtils, dsl } = require('schema-dsl');
|
|
120
|
+
|
|
121
|
+
const fields = SchemaUtils.createLibrary({
|
|
122
|
+
email: () => 'email!'.label('邮箱地址'),
|
|
123
|
+
phone: () => dsl('string!').phone('cn').label('手机号'),
|
|
124
|
+
profile: () => ({
|
|
125
|
+
bio: 'string:500',
|
|
126
|
+
avatar: 'url'
|
|
127
|
+
})
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const registerSchema = dsl({
|
|
131
|
+
email: fields.email(),
|
|
132
|
+
phone: fields.phone(),
|
|
133
|
+
password: dsl('string!').password('strong')
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const profileSchema = dsl({
|
|
137
|
+
...fields.profile(),
|
|
138
|
+
email: fields.email()
|
|
139
|
+
});
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**说明**: `createLibrary()` 只是返回片段工厂集合,适合在大型项目中集中管理字段和组合片段。
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### extend() - 扩展Schema(继承)
|
|
147
|
+
|
|
148
|
+
```javascript
|
|
149
|
+
const baseUser = dsl({
|
|
150
|
+
name: 'string!',
|
|
151
|
+
email: 'email!'
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// 扩展基础Schema
|
|
155
|
+
const admin = SchemaUtils.extend(baseUser, {
|
|
156
|
+
role: 'admin|superadmin',
|
|
157
|
+
permissions: 'array<string>'
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// admin包含所有baseUser字段 + role + permissions
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**说明**: 类似继承,保留基础Schema的所有字段
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Schema 筛选
|
|
168
|
+
|
|
169
|
+
### pick() - 选择字段
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
const fullUser = dsl({
|
|
173
|
+
name: 'string!',
|
|
174
|
+
email: 'email!',
|
|
175
|
+
password: 'string:8-64!',
|
|
176
|
+
phone: 'string:11!',
|
|
177
|
+
age: 'number:18-120'
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// 只选择特定字段
|
|
181
|
+
const publicUser = SchemaUtils.pick(fullUser, ['name', 'email']);
|
|
182
|
+
|
|
183
|
+
// publicUser 只包含 name 和 email
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**用途**: 从完整Schema中提取部分字段(如公开信息)
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
### omit() - 排除字段
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
const fullUser = dsl({
|
|
194
|
+
name: 'string!',
|
|
195
|
+
email: 'email!',
|
|
196
|
+
password: 'string:8-64!',
|
|
197
|
+
phone: 'string:11!'
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// 排除敏感字段
|
|
201
|
+
const safeUser = SchemaUtils.omit(fullUser, ['password']);
|
|
202
|
+
|
|
203
|
+
// safeUser 包含除 password 外的所有字段
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**用途**: 移除敏感字段(如密码)
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
### partial() - 将字段改为可选
|
|
211
|
+
|
|
212
|
+
```javascript
|
|
213
|
+
const updateSchema = SchemaUtils.partial(dsl({
|
|
214
|
+
name: 'string!',
|
|
215
|
+
email: 'email!',
|
|
216
|
+
age: 'number:18-120'
|
|
217
|
+
}));
|
|
218
|
+
|
|
219
|
+
// 结果中 required 会被移除,适合 PATCH / 局部更新场景
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
也可以只对部分字段做可选化:
|
|
223
|
+
|
|
224
|
+
```javascript
|
|
225
|
+
const schema = dsl({
|
|
226
|
+
name: 'string!',
|
|
227
|
+
email: 'email!',
|
|
228
|
+
age: 'number:18-120'
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
const partialContact = SchemaUtils.partial(schema, ['name', 'email']);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Schema 导出
|
|
237
|
+
|
|
238
|
+
### toMarkdown() - 导出为Markdown文档
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
const schema = dsl({
|
|
242
|
+
username: 'string:3-32!'.label('用户名'),
|
|
243
|
+
email: 'email!'.label('邮箱地址'),
|
|
244
|
+
age: 'number:18-120'
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
const markdown = SchemaUtils.toMarkdown(schema, {
|
|
248
|
+
title: '用户注册Schema'
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
console.log(markdown);
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**输出**:
|
|
255
|
+
```markdown
|
|
256
|
+
# 用户注册Schema
|
|
257
|
+
|
|
258
|
+
| 字段 | 类型 | 必填 | 约束 | 说明 |
|
|
259
|
+
|------|------|------|------|------|
|
|
260
|
+
| username | string | ✅ | 3-32字符 | 用户名 |
|
|
261
|
+
| email | email | ✅ | - | 邮箱地址 |
|
|
262
|
+
| age | number | ❌ | 18-120 | - |
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**用途**: 生成API文档
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
### toHTML() - 导出为HTML表格
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
const html = SchemaUtils.toHTML(schema, {
|
|
273
|
+
title: '用户注册Schema'
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// 生成HTML表格,可以嵌入文档
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**用途**: 集成到Web文档
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## 性能监控
|
|
284
|
+
|
|
285
|
+
### validateBatch() - 批量验证统计
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
const { SchemaUtils, Validator, dsl } = require('schema-dsl');
|
|
289
|
+
|
|
290
|
+
const schema = dsl({
|
|
291
|
+
email: 'email!',
|
|
292
|
+
age: 'number:18-120'
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const validator = new Validator();
|
|
296
|
+
|
|
297
|
+
const items = [
|
|
298
|
+
{ email: 'user1@example.com', age: 25 },
|
|
299
|
+
{ email: 'invalid', age: 15 },
|
|
300
|
+
{ email: 'user2@example.com', age: 30 }
|
|
301
|
+
];
|
|
302
|
+
|
|
303
|
+
const batch = SchemaUtils.validateBatch(schema, items, validator.getAjv());
|
|
304
|
+
|
|
305
|
+
console.log(batch);
|
|
306
|
+
// {
|
|
307
|
+
// results: [
|
|
308
|
+
// { index: 0, valid: true, errors: null, data: {...} },
|
|
309
|
+
// { index: 1, valid: false, errors: [...], data: null },
|
|
310
|
+
// { index: 2, valid: true, errors: null, data: {...} }
|
|
311
|
+
// ],
|
|
312
|
+
// summary: {
|
|
313
|
+
// total: 3,
|
|
314
|
+
// valid: 2,
|
|
315
|
+
// invalid: 1,
|
|
316
|
+
// duration: 5,
|
|
317
|
+
// averageTime: 1.67
|
|
318
|
+
// }
|
|
319
|
+
// }
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**说明**:
|
|
323
|
+
- 如果你只需要“每条是否通过”的结果,可直接使用 `validator.validateBatch(schema, items)`
|
|
324
|
+
- 如果你还需要汇总统计信息,再使用 `SchemaUtils.validateBatch(schema, items, validator.getAjv())`
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
### withPerformance() - 给 Validator 添加性能包装
|
|
329
|
+
|
|
330
|
+
```javascript
|
|
331
|
+
const validator = SchemaUtils.withPerformance(new Validator());
|
|
332
|
+
|
|
333
|
+
const result = validator.validate(schema, data);
|
|
334
|
+
|
|
335
|
+
console.log(result.performance);
|
|
336
|
+
// {
|
|
337
|
+
// duration: 2,
|
|
338
|
+
// timestamp: '2026-05-06T12:34:56.789Z'
|
|
339
|
+
// }
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
**用途**: 在不改业务调用方式的前提下,为验证结果附加耗时信息
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## 其他工具
|
|
347
|
+
|
|
348
|
+
### clone() - 深度克隆Schema
|
|
349
|
+
|
|
350
|
+
```javascript
|
|
351
|
+
const original = dsl({
|
|
352
|
+
user: {
|
|
353
|
+
name: 'string!',
|
|
354
|
+
profile: {
|
|
355
|
+
bio: 'string:500'
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
const cloned = SchemaUtils.clone(original);
|
|
361
|
+
|
|
362
|
+
// cloned 是完全独立的副本
|
|
363
|
+
cloned.properties.user.properties.name.maxLength = 100;
|
|
364
|
+
// original 不会被修改
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
### validateNestingDepth() - 检查嵌套深度
|
|
370
|
+
|
|
371
|
+
```javascript
|
|
372
|
+
const { dsl, DslBuilder } = require('schema-dsl');
|
|
373
|
+
|
|
374
|
+
const schema = dsl({
|
|
375
|
+
level1: {
|
|
376
|
+
level2: {
|
|
377
|
+
level3: {
|
|
378
|
+
level4: 'string'
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
const result = DslBuilder.validateNestingDepth(schema, 10);
|
|
385
|
+
// 返回: { valid: true, depth: 4, path: 'level1.level2.level3', message: '...' }
|
|
386
|
+
|
|
387
|
+
if (result.depth > 5) {
|
|
388
|
+
console.warn('嵌套层级过深,建议扁平化');
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
**说明**: 这个能力属于 `DslBuilder` 静态方法,不是 `SchemaUtils` 的成员;这里一并列出是因为它常与 Schema 工具链一起使用。
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## 完整示例
|
|
397
|
+
|
|
398
|
+
### 企业级字段库
|
|
399
|
+
|
|
400
|
+
```javascript
|
|
401
|
+
// libs/fields/index.js
|
|
402
|
+
module.exports = {
|
|
403
|
+
// 基础字段
|
|
404
|
+
id: () => 'string!'.pattern(/^[a-zA-Z0-9_-]+$/).label('ID'),
|
|
405
|
+
email: () => 'email!'.label('邮箱地址'),
|
|
406
|
+
phone: (country = 'cn') => 'string:11!'.phone(country).label('手机号'),
|
|
407
|
+
|
|
408
|
+
// 认证字段
|
|
409
|
+
auth: {
|
|
410
|
+
username: () => 'string:3-32!'.username().label('用户名'),
|
|
411
|
+
password: (strength = 'strong') =>
|
|
412
|
+
'string:8-64!'.password(strength).label('密码')
|
|
413
|
+
},
|
|
414
|
+
|
|
415
|
+
// 个人信息
|
|
416
|
+
profile: {
|
|
417
|
+
nickname: () => 'string:2-20!'.label('昵称'),
|
|
418
|
+
realName: () => 'string:2-50'.label('真实姓名'),
|
|
419
|
+
bio: () => 'string:500',
|
|
420
|
+
avatar: () => 'url'.label('头像'),
|
|
421
|
+
birthday: () => 'date'
|
|
422
|
+
},
|
|
423
|
+
|
|
424
|
+
// 地址信息
|
|
425
|
+
address: () => ({
|
|
426
|
+
country: 'string:2-50!',
|
|
427
|
+
province: 'string:2-50!',
|
|
428
|
+
city: 'string:2-50!',
|
|
429
|
+
detail: 'string:10-200!'
|
|
430
|
+
}),
|
|
431
|
+
|
|
432
|
+
// 时间戳
|
|
433
|
+
timestamps: () => ({
|
|
434
|
+
created_at: 'datetime!',
|
|
435
|
+
updated_at: 'datetime!'
|
|
436
|
+
})
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
// 使用
|
|
440
|
+
const fields = require('./libs/fields');
|
|
441
|
+
|
|
442
|
+
// 用户注册
|
|
443
|
+
const registerSchema = dsl({
|
|
444
|
+
...fields.auth,
|
|
445
|
+
email: fields.email(),
|
|
446
|
+
phone: fields.phone('cn'),
|
|
447
|
+
agree: 'boolean!'
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
// 用户资料
|
|
451
|
+
const profileSchema = dsl({
|
|
452
|
+
...fields.profile,
|
|
453
|
+
...fields.timestamps()
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
// 完整用户
|
|
457
|
+
const userSchema = SchemaUtils.extend(
|
|
458
|
+
SchemaUtils.extend(registerSchema, profileSchema),
|
|
459
|
+
fields.address()
|
|
460
|
+
);
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## 最佳实践
|
|
466
|
+
|
|
467
|
+
### 1. 小项目:直接复用
|
|
468
|
+
|
|
469
|
+
```javascript
|
|
470
|
+
const commonFields = {
|
|
471
|
+
email: 'email!'.label('邮箱'),
|
|
472
|
+
phone: 'string:11!'.phone('cn')
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
const schema1 = dsl({ ...commonFields, ... });
|
|
476
|
+
const schema2 = dsl({ ...commonFields, ... });
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### 2. 中型项目:函数复用
|
|
480
|
+
|
|
481
|
+
```javascript
|
|
482
|
+
const createUserFields = (options = {}) => ({
|
|
483
|
+
email: 'email!'.label(options.emailLabel || '邮箱'),
|
|
484
|
+
phone: 'string:11!'.phone(options.country || 'cn')
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
const schema = dsl({
|
|
488
|
+
...createUserFields({ emailLabel: '联系邮箱' }),
|
|
489
|
+
...otherFields
|
|
490
|
+
});
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
### 3. 大型项目:字段库
|
|
494
|
+
|
|
495
|
+
```javascript
|
|
496
|
+
// 统一管理在 fields/ 目录
|
|
497
|
+
const fields = require('./fields');
|
|
498
|
+
|
|
499
|
+
const schema = dsl({
|
|
500
|
+
...fields.auth,
|
|
501
|
+
...fields.profile
|
|
502
|
+
});
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
---
|
|
506
|
+
|
|
507
|
+
## 相关文档
|
|
508
|
+
|
|
509
|
+
- [DSL 语法](./dsl-syntax.md)
|
|
510
|
+
- [String 扩展](./string-extensions.md)
|
|
511
|
+
- [API 参考](./api-reference.md)
|
|
512
|
+
|
|
513
|
+
---
|
|
514
|
+
|
|
515
|
+
## 对应示例文件
|
|
516
|
+
|
|
517
|
+
**示例入口**: [schema-utils.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/schema-utils.ts)
|
|
518
|
+
**说明**: 覆盖 `reusable()`、`createLibrary()`、`extend()`、`validateBatch()`、`withPerformance()` 和 `clone()` 的最小工作流。
|
|
519
|
+
|
|
520
|
+
---
|
|
521
|
+
|
|
522
|
+
**最后更新**: 2026-05-08
|
|
523
|
+
|
|
524
|
+
|