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,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
+