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,714 +1,714 @@
1
- # DSL 语法完整指南
2
-
3
- > **更新时间**: 2026-05-22
4
-
5
- ---
6
-
7
- ## 📑 目录
8
-
9
- - [快速开始](#快速开始)
10
- - [完整类型列表](#完整类型列表)
11
- - [基础语法](#基础语法)
12
- - [约束语法](#约束语法)
13
- - [数组语法](#数组语法)
14
- - [对象语法](#对象语法)
15
- - [条件验证 (Match)](#条件验证-match)
16
- - [高级用法](#高级用法)
17
- - [实现方案对比](#实现方案对比)
18
- - [完整示例](#完整示例)
19
-
20
- ---
21
-
22
- ## 快速开始
23
-
24
- ```javascript
25
- const { dsl } = require('schema-dsl');
26
-
27
- // 基本类型
28
- const schema = dsl({
29
- name: 'string!', // 必填字符串
30
- age: 'number', // 可选数字
31
- email: 'email!', // 必填邮箱
32
- active: 'boolean', // 布尔值
33
- tags: 'array<string>' // 字符串数组
34
- });
35
- ```
36
-
37
- ---
38
-
39
- ## 完整类型列表
40
-
41
- ### 基本类型
42
-
43
- | 类型 | DSL | 说明 |
44
- |------|-----|------|
45
- | 字符串 | `string` | 文本类型 |
46
- | 数字 | `number` | 浮点数 |
47
- | 整数 | `integer` | 整数 |
48
- | 布尔 | `boolean` | true/false |
49
- | 对象 | `object` | 嵌套对象 |
50
- | 数组 | `array` | 数组类型 |
51
- | 空值 | `null` | null值 |
52
- | 任意 | `any` | 任意类型 |
53
-
54
- ### 格式类型
55
-
56
- | 类型 | DSL | 说明 |
57
- |------|-----|------|
58
- | 邮箱 | `email` | 邮箱地址 |
59
- | URL | `url` | 网址 |
60
- | URI | `uri` | URI 地址 |
61
- | UUID | `uuid` | UUID格式 |
62
- | 日期 | `date` | YYYY-MM-DD |
63
- | 日期时间 | `datetime` | ISO 8601 |
64
- | 时间 | `time` | HH:mm:ss |
65
- | 主机名 | `hostname` | 主机名 |
66
- | IP(IPv4 / IPv6) | `ip` | 自动接受 IPv4 或 IPv6 |
67
- | IPv4 | `ipv4` | IPv4地址 |
68
- | IPv6 | `ipv6` | IPv6地址 |
69
- | 二进制 | `binary` | Base64编码 |
70
-
71
- ### 特殊类型
72
-
73
- | 类型 | DSL | 说明 |
74
- |------|-----|------|
75
- | ObjectId | `objectId` | MongoDB ObjectId |
76
- | 十六进制颜色 | `hexColor` | CSS 十六进制颜色 |
77
- | MAC 地址 | `macAddress` | MAC 地址 |
78
- | Cron 表达式 | `cron` | 标准 Cron 表达式 |
79
- | URL Slug | `slug` | 小写字母/数字/中横线组成的 URL 友好标识 |
80
- | 中文姓名 | `chineseName` | 2 到 10 个中文字符 |
81
- | 纯中文文本 | `chinese` | 仅允许中文字符 |
82
- | 邮箱域名校验 | `emailDomain` | 邮箱格式基础上的域名约束类型 |
83
- | 字母数字 | `alphanum` | 仅字母与数字 |
84
- | 全小写字符串 | `lower` | 自动约束为小写字符串 |
85
- | 全大写字符串 | `upper` | 自动约束为大写字符串 |
86
- | JSON 字符串 | `json` | 内容需为合法 JSON 字符串 |
87
- | 端口号 | `port` | 整数端口号 |
88
-
89
-
90
- ---
91
-
92
- ## 基础语法
93
-
94
- ### 1. 类型定义
95
-
96
- ```javascript
97
- // 基本类型
98
- 'string' // 字符串
99
- 'number' // 数字
100
- 'integer' // 整数
101
- 'boolean' // 布尔
102
-
103
- // 格式类型
104
- 'email' // 邮箱
105
- 'url' // URL
106
- 'date' // 日期
107
- 'uuid' // UUID
108
- ```
109
-
110
- ### 2. 必填与可选标记
111
-
112
- 使用 `!` 标记必填字段,使用 `?` 显式标记可选字段:
113
-
114
- ```javascript
115
- const schema = dsl({
116
- username: 'string!', // 必填
117
- nickname: 'string', // 可选(默认)
118
- bio: 'string?', // 显式可选(等价于 string)
119
- email: 'email?' // 可选邮箱
120
- });
121
- ```
122
-
123
- **说明**:
124
- - `!` - 必填标记,字段必须存在
125
- - `?` - 可选标记,字段可省略(显式表达)
126
- - 不加标记 - 默认可选(字段可省略)
127
-
128
- **推荐**:
129
- - 使用 `!` 明确标记必填字段
130
- - 使用 `?` 在需要明确表达"可选"时增强代码可读性
131
-
132
- ### 3. 对象必填
133
-
134
- 支持两种方式:
135
-
136
- ```javascript
137
- // 方式1: 字段内部必填
138
- const schema1 = dsl({
139
- user: {
140
- name: 'string!', // name 必填(user 可选)
141
- email: 'email!' // email 必填
142
- }
143
- });
144
-
145
- // 方式2: 对象本身必填 ✅ 推荐
146
- const schema2 = dsl({
147
- 'user!': { // user 本身必填
148
- name: 'string', // name 可选
149
- email: 'email' // email 可选
150
- }
151
- });
152
- ```
153
-
154
- ---
155
-
156
- ## 约束语法
157
-
158
- ### 1. 字符串长度
159
-
160
- ```javascript
161
- 'string:10' // 精确长度10(exactLength:minLength=10, maxLength=10)
162
- 'string:-10' // 最大长度10
163
- 'string:3-32' // 长度范围3-32
164
- 'string:10-' // 最小长度10(无最大限制)
165
- ```
166
-
167
- **示例**:
168
- ```javascript
169
- const schema = dsl({
170
- username: 'string:3-32!', // 3-32字符,必填
171
- bio: 'string:500', // 最大500字符
172
- password: 'string:8-' // 最少8字符
173
- });
174
- ```
175
-
176
- ### 2. 数字范围
177
-
178
- ```javascript
179
- 'number:100' // 最大值100
180
- 'number:0-100' // 范围0-100
181
- 'number:18-' // 最小值18
182
- ```
183
-
184
- **示例**:
185
- ```javascript
186
- const schema = dsl({
187
- age: 'number:18-120', // 18-120
188
- score: 'number:100', // 0-100
189
- price: 'number:0-' // ≥0
190
- });
191
- ```
192
-
193
- ### 3. 枚举值
194
-
195
- 使用 `|` 分隔枚举值:
196
-
197
- ```javascript
198
- const schema = dsl({
199
- status: 'active|inactive|pending',
200
- gender: 'male|female|other!',
201
- role: 'admin|user|guest'
202
- });
203
- ```
204
-
205
- ### 4. `types:` 联合类型
206
-
207
- 当一个字段需要接受多种不同类型时,可以使用 `types:` 前缀生成联合类型:
208
-
209
- ```javascript
210
- const schema = dsl({
211
- contact: 'types:email|phone',
212
- price: 'types:number:0-|string:1-20',
213
- payload: 'types:object|array<object>'
214
- });
215
- ```
216
-
217
- 这个语法会被编译为 `oneOf` 结构,适合表达“满足其中任意一种类型即可”的场景。
218
-
219
- **适用场景**:
220
- - 联系方式允许邮箱或手机号
221
- - 价格字段允许数值或说明字符串
222
- - 兼容历史接口中同字段的多种输入格式
223
-
224
- ### 5. 特殊约束
225
-
226
- 支持特定格式的约束:
227
-
228
- ```javascript
229
- 'phone:cn' // 中国手机号
230
- 'idCard:cn' // 中国身份证
231
- 'creditCard:visa' // Visa信用卡
232
- 'licensePlate:cn' // 中国车牌
233
- 'postalCode:cn' // 中国邮编
234
- 'passport:cn' // 中国护照
235
- ```
236
-
237
- **示例**:
238
- ```javascript
239
- const schema = dsl({
240
- mobile: 'phone:cn!',
241
- id: 'idCard:cn',
242
- card: 'creditCard:mastercard'
243
- });
244
- ```
245
-
246
- ---
247
-
248
- ## 数组语法
249
-
250
- ### 1. 基础数组
251
-
252
- ```javascript
253
- 'array' // 任意类型数组
254
- 'array<string>' // 字符串数组
255
- 'array<number>' // 数字数组
256
- 'array<integer>' // 整数数组
257
- ```
258
-
259
- ### 2. 数组长度约束
260
-
261
- ```javascript
262
- 'array:1-10' // 1-10个元素
263
- 'array!1-10' // 1-10个元素,必填
264
- 'array:1-' // 至少1个元素
265
- 'array:-10' // 最多10个元素
266
- 'array:1-10<string>' // 1-10个字符串元素
267
- ```
268
-
269
- **示例**:
270
- ```javascript
271
- const schema = dsl({
272
- tags: 'array!1-10<string>', // 必填,1-10个字符串
273
- scores: 'array:1-5<number>', // 可选,1-5个数字
274
- items: 'array:1-<string>' // 至少1个字符串
275
- });
276
- ```
277
-
278
- ### 3. 数组元素约束
279
-
280
- ```javascript
281
- const schema = dsl({
282
- tags: 'array<string:1-20>', // 每个字符串1-20字符
283
- scores: 'array<number:0-100>', // 每个数字0-100
284
- ids: 'array<integer:1->' // 每个整数≥1
285
- });
286
- ```
287
-
288
- ### 4. 嵌套数组
289
-
290
- ```javascript
291
- // 二维数组
292
- const schema = dsl({
293
- matrix: 'array<array<number>>'
294
- });
295
-
296
- // 对象数组
297
- const schema = dsl({
298
- users: 'array<object>',
299
- // 或更详细定义
300
- items: {
301
- type: 'array',
302
- items: {
303
- name: 'string!',
304
- age: 'number'
305
- }
306
- }
307
- });
308
- ```
309
-
310
- ---
311
-
312
- ## 对象语法
313
-
314
- ### 1. 基础对象
315
-
316
- ```javascript
317
- const schema = dsl({
318
- user: {
319
- name: 'string!',
320
- email: 'email!',
321
- age: 'number'
322
- }
323
- });
324
- ```
325
-
326
- ### 2. 嵌套对象
327
-
328
- ```javascript
329
- const schema = dsl({
330
- user: {
331
- profile: {
332
- bio: 'string:500',
333
- social: {
334
- twitter: 'url',
335
- github: 'url'
336
- }
337
- }
338
- }
339
- });
340
- ```
341
-
342
- ### 3. 混合嵌套
343
-
344
- ```javascript
345
- const schema = dsl({
346
- 'user!': { // user 必填
347
- name: 'string!', // name 必填
348
- contacts: 'array!1-5<object>', // 1-5个联系方式
349
- tags: 'array<string:1-20>' // 字符串数组
350
- }
351
- });
352
- ```
353
-
354
- ---
355
-
356
- ## 条件验证 (Match)
357
-
358
- 支持更优雅的条件验证语法 `dsl.match` 和 `dsl.if`。
359
-
360
- ### 1. dsl.match (推荐)
361
-
362
- 类似于 `switch-case`,根据某个字段的值决定当前字段的验证规则。
363
-
364
- **语法**:
365
- ```javascript
366
- dsl.match(field, {
367
- value1: 'schema1',
368
- value2: 'schema2',
369
- _default: 'defaultSchema' // 可选
370
- })
371
- ```
372
-
373
- **示例**:
374
- ```javascript
375
- const schema = dsl({
376
- contactType: 'email|phone',
377
-
378
- // 根据 contactType 的值决定 contact 的规则
379
- contact: dsl.match('contactType', {
380
- email: 'email!', // contactType=email 时
381
- phone: 'string:11!', // contactType=phone 时
382
- _default: 'string' // 其他情况
383
- })
384
- });
385
- ```
386
-
387
- **处理非英文值**:
388
- 如果条件值包含中文、数字或特殊字符,给键名加上引号即可:
389
-
390
- ```javascript
391
- discount: dsl.match('level', {
392
- '普通用户': 'number:0-5',
393
- 'VIP-1': 'number:0-20',
394
- '100': 'number:0-50'
395
- })
396
- ```
397
-
398
- ### 2. dsl.if (简单条件)
399
-
400
- 适用于简单的二选一场景。
401
-
402
- **语法**:
403
- ```javascript
404
- dsl.if(conditionField, thenSchema, elseSchema)
405
- ```
406
-
407
- **示例**:
408
- ```javascript
409
- const schema = dsl({
410
- isVip: 'boolean',
411
-
412
- // 如果是VIP,折扣0-50,否则0-10
413
- discount: dsl.if('isVip', 'number:0-50', 'number:0-10')
414
- });
415
- ```
416
-
417
- ---
418
-
419
- ## 高级用法
420
-
421
- ### 1. 链式调用
422
-
423
- > ⚠️ `.custom()` 当前仅支持同步自定义逻辑;异步业务校验请在验证通过后单独执行。
424
-
425
- ```javascript
426
- const schema = dsl({
427
- username: 'string:3-32!'
428
- .pattern(/^[a-zA-Z0-9_]+$/)
429
- .label('用户名')
430
- .messages({
431
- 'pattern': '只能包含字母、数字和下划线'
432
- }),
433
-
434
- email: 'email!'
435
- .label('邮箱地址')
436
- .description('用于登录和接收通知')
437
- .custom((value) => {
438
- if (value.endsWith('@blocked.example')) return '该邮箱域名不允许注册';
439
- })
440
- });
441
- ```
442
-
443
- ### 2. 默认验证器
444
-
445
- ```javascript
446
- const schema = dsl({
447
- username: 'string!'.username('5-20'), // 自动正则+长度
448
- phone: 'string!'.phone('cn'), // 中国手机号
449
- password: 'string!'.password('strong') // 强密码
450
- });
451
- ```
452
-
453
- ---
454
-
455
- ## 注意事项
456
-
457
- ### 1. 条件验证
458
-
459
- ⚠️ **注意**: DSL 字符串不支持直接写条件逻辑
460
-
461
- ```javascript
462
- 'string | number' // ❌ 不支持
463
- ```
464
-
465
- **解决方案**: 使用 `dsl.match` (推荐)
466
-
467
- ```javascript
468
- // ✅ 推荐:使用 dsl.match
469
- const schema = dsl({
470
- vipLevel: 'string',
471
- discount: dsl.match('vipLevel', {
472
- gold: 'number:0-50',
473
- silver: 'number:0-20',
474
- normal: 'number:0-5'
475
- })
476
- });
477
- ```
478
-
479
- ---
480
-
481
- ### 2. 数组约束
482
-
483
- ✅ **推荐**: 使用简洁的 DSL 语法
484
- ```javascript
485
- 'array!1-10<string:1-20>' // 1-10个元素,每个1-20字符
486
- ```
487
-
488
- ⚠️ **也可以**: 使用完整 JSON Schema 格式(不推荐,太繁琐)
489
- ```javascript
490
- {
491
- type: 'array',
492
- items: { type: 'string' },
493
- minItems: 1,
494
- maxItems: 10
495
- }
496
- ```
497
-
498
- ---
499
-
500
- ### 3. 正则验证
501
-
502
- ⚠️ **注意**: DSL 字符串不支持直接写正则
503
-
504
- ```javascript
505
- 'string:/^[a-z]+$/' // ❌ 不支持
506
- ```
507
-
508
- **解决方案**: 使用 `.pattern()` 方法
509
- ```javascript
510
- 'string!'.pattern(/^[a-z]+$/) // ✅ 推荐
511
- ```
512
-
513
- ---
514
-
515
- ### 4. 自定义验证
516
-
517
- ⚠️ **注意**: DSL 字符串不支持自定义逻辑
518
-
519
- ```javascript
520
- 'string!@custom' // ❌ 不支持
521
- ```
522
-
523
- **解决方案**: 使用 `.custom()` 方法承载**同步**自定义逻辑
524
- ```javascript
525
- 'string!'.custom((value) => {
526
- // 自定义同步逻辑
527
- if (value === 'reserved') {
528
- return '该值不可用';
529
- }
530
- })
531
- ```
532
-
533
- 异步校验(如数据库查重)请在 `validate()` / `validateAsync()` 通过后于业务层单独执行。
534
-
535
- ---
536
-
537
- ### 5. 对象数组详细定义
538
-
539
- ⚠️ **注意**: DSL 简写不支持对象数组的详细定义
540
-
541
- ```javascript
542
- 'array<object{name:string,age:number}>' // ❌ 不支持
543
- ```
544
-
545
- **解决方案**: 使用完整对象定义
546
- ```javascript
547
- const schema = dsl({
548
- users: {
549
- type: 'array',
550
- items: {
551
- name: 'string!',
552
- age: 'number:18-'
553
- }
554
- }
555
- });
556
- ```
557
-
558
- ---
559
-
560
- ## 完整示例
561
-
562
- ### 用户注册表单
563
-
564
- ```javascript
565
- const { dsl } = require('schema-dsl');
566
-
567
- const schema = dsl({
568
- // 基本信息
569
- username: 'string:3-32!'.username().label('用户名'),
570
- password: 'string!'.password('strong').label('密码'),
571
- email: 'email!'.label('邮箱'),
572
- phone: 'string!'.phone('cn').label('手机号'),
573
-
574
- // 个人资料
575
- 'profile!': {
576
- realName: 'string:2-50',
577
- gender: 'male|female|other',
578
- birthday: 'date',
579
- bio: 'string:500'
580
- },
581
-
582
- // 地址信息
583
- addresses: 'array:1-5<object>', // 1-5个地址
584
-
585
- // 标签
586
- tags: 'array:1-10<string:1-20>', // 1-10个标签,每个1-20字符
587
-
588
- // 同意条款
589
- agree: 'boolean!'
590
- });
591
- ```
592
-
593
- ### 电商商品 Schema
594
-
595
- ```javascript
596
- const schema = dsl({
597
- // 商品基本信息
598
- title: 'string:1-100!',
599
- price: 'number:0-!',
600
- stock: 'integer:0-',
601
- status: 'on_sale|off_sale|sold_out!',
602
-
603
- // 商品详情
604
- 'details!': {
605
- description: 'string:10000',
606
- images: 'array!1-10<url>',
607
- specs: 'array<object>',
608
- tags: 'array:1-20<string:1-30>'
609
- },
610
-
611
- // SKU信息
612
- skus: {
613
- type: 'array',
614
- minItems: 1,
615
- items: {
616
- sku_code: 'string!',
617
- price: 'number!',
618
- stock: 'integer!'
619
- }
620
- }
621
- });
622
- ```
623
-
624
- ### API 请求验证
625
-
626
- ```javascript
627
- const schema = dsl({
628
- // 查询参数
629
- page: 'integer:1-',
630
- pageSize: 'integer:10-100',
631
- keyword: 'string:1-50',
632
-
633
- // 筛选条件
634
- filters: {
635
- category: 'array<string>',
636
- priceRange: {
637
- min: 'number:0-',
638
- max: 'number:0-'
639
- },
640
- status: 'active|inactive'
641
- },
642
-
643
- // 排序
644
- sort: {
645
- field: 'price|created_at|sales',
646
- order: 'asc|desc'
647
- }
648
- });
649
- ```
650
-
651
- ---
652
-
653
- ## 常见问题
654
-
655
- ### Q1: 为什么移除了简写功能?
656
-
657
- **A**: 为了降低学习成本和减少歧义。使用完整类型名更清晰,特别是对新手更友好。
658
-
659
- ### Q2: 数组长度约束怎么写?
660
-
661
- **A**: 支持直接在DSL中写:
662
- ```javascript
663
- 'array!1-10<string>' // 推荐
664
- ```
665
-
666
- ### Q3: 如何定义对象数组?
667
-
668
- **A**: 使用完整对象定义:
669
- ```javascript
670
- const schema = dsl({
671
- users: {
672
- type: 'array',
673
- items: {
674
- name: 'string!',
675
- email: 'email!'
676
- }
677
- }
678
- });
679
- ```
680
-
681
- ### Q4: 不支持条件验证吗?
682
-
683
- **A**: 支持。推荐使用 `dsl.match`:
684
- ```javascript
685
- dsl.match('vipLevel', { gold: 'number:0-50', silver: 'number:0-20' })
686
- ```
687
-
688
- ### Q5: 能用正则验证吗?
689
-
690
- **A**: 能,使用 `.pattern()` 方法:
691
- ```javascript
692
- 'string!'.pattern(/^[a-z]+$/)
693
- ```
694
-
695
- ---
696
-
697
- ## 相关文档
698
-
699
- - [类型参考](./type-reference.md) - 完整类型列表
700
- - [String 扩展](./string-extensions.md) - 链式调用
701
- - [快速开始](./quick-start.md) - 5分钟上手
702
-
703
- ---
704
-
705
- ## 对应示例文件
706
-
707
- **示例入口**: [dsl-syntax.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/dsl-syntax.ts)
708
- **说明**: 覆盖 Batch 1 中 DSL 语法的基础类型、约束、枚举、数组和嵌套对象写法,可直接运行参考。
709
-
710
- ---
711
-
712
- **最后更新**: 2026-05-08
713
- **作者**: schema-dsl Team
714
-
1
+ # DSL 语法完整指南
2
+
3
+ > **更新时间**: 2026-05-22
4
+
5
+ ---
6
+
7
+ ## 📑 目录
8
+
9
+ - [快速开始](#快速开始)
10
+ - [完整类型列表](#完整类型列表)
11
+ - [基础语法](#基础语法)
12
+ - [约束语法](#约束语法)
13
+ - [数组语法](#数组语法)
14
+ - [对象语法](#对象语法)
15
+ - [条件验证 (Match)](#条件验证-match)
16
+ - [高级用法](#高级用法)
17
+ - [实现方案对比](#实现方案对比)
18
+ - [完整示例](#完整示例)
19
+
20
+ ---
21
+
22
+ ## 快速开始
23
+
24
+ ```javascript
25
+ const { dsl } = require('schema-dsl');
26
+
27
+ // 基本类型
28
+ const schema = dsl({
29
+ name: 'string!', // 必填字符串
30
+ age: 'number', // 可选数字
31
+ email: 'email!', // 必填邮箱
32
+ active: 'boolean', // 布尔值
33
+ tags: 'array<string>' // 字符串数组
34
+ });
35
+ ```
36
+
37
+ ---
38
+
39
+ ## 完整类型列表
40
+
41
+ ### 基本类型
42
+
43
+ | 类型 | DSL | 说明 |
44
+ |------|-----|------|
45
+ | 字符串 | `string` | 文本类型 |
46
+ | 数字 | `number` | 浮点数 |
47
+ | 整数 | `integer` | 整数 |
48
+ | 布尔 | `boolean` | true/false |
49
+ | 对象 | `object` | 嵌套对象 |
50
+ | 数组 | `array` | 数组类型 |
51
+ | 空值 | `null` | null值 |
52
+ | 任意 | `any` | 任意类型 |
53
+
54
+ ### 格式类型
55
+
56
+ | 类型 | DSL | 说明 |
57
+ |------|-----|------|
58
+ | 邮箱 | `email` | 邮箱地址 |
59
+ | URL | `url` | 网址 |
60
+ | URI | `uri` | URI 地址 |
61
+ | UUID | `uuid` | UUID格式 |
62
+ | 日期 | `date` | YYYY-MM-DD |
63
+ | 日期时间 | `datetime` | ISO 8601 |
64
+ | 时间 | `time` | HH:mm:ss |
65
+ | 主机名 | `hostname` | 主机名 |
66
+ | IP(IPv4 / IPv6) | `ip` | 自动接受 IPv4 或 IPv6 |
67
+ | IPv4 | `ipv4` | IPv4地址 |
68
+ | IPv6 | `ipv6` | IPv6地址 |
69
+ | 二进制 | `binary` | Base64编码 |
70
+
71
+ ### 特殊类型
72
+
73
+ | 类型 | DSL | 说明 |
74
+ |------|-----|------|
75
+ | ObjectId | `objectId` | MongoDB ObjectId |
76
+ | 十六进制颜色 | `hexColor` | CSS 十六进制颜色 |
77
+ | MAC 地址 | `macAddress` | MAC 地址 |
78
+ | Cron 表达式 | `cron` | 标准 Cron 表达式 |
79
+ | URL Slug | `slug` | 小写字母/数字/中横线组成的 URL 友好标识 |
80
+ | 中文姓名 | `chineseName` | 2 到 10 个中文字符 |
81
+ | 纯中文文本 | `chinese` | 仅允许中文字符 |
82
+ | 邮箱域名校验 | `emailDomain` | 邮箱格式基础上的域名约束类型 |
83
+ | 字母数字 | `alphanum` | 仅字母与数字 |
84
+ | 全小写字符串 | `lower` | 自动约束为小写字符串 |
85
+ | 全大写字符串 | `upper` | 自动约束为大写字符串 |
86
+ | JSON 字符串 | `json` | 内容需为合法 JSON 字符串 |
87
+ | 端口号 | `port` | 整数端口号 |
88
+
89
+
90
+ ---
91
+
92
+ ## 基础语法
93
+
94
+ ### 1. 类型定义
95
+
96
+ ```javascript
97
+ // 基本类型
98
+ 'string' // 字符串
99
+ 'number' // 数字
100
+ 'integer' // 整数
101
+ 'boolean' // 布尔
102
+
103
+ // 格式类型
104
+ 'email' // 邮箱
105
+ 'url' // URL
106
+ 'date' // 日期
107
+ 'uuid' // UUID
108
+ ```
109
+
110
+ ### 2. 必填与可选标记
111
+
112
+ 使用 `!` 标记必填字段,使用 `?` 显式标记可选字段:
113
+
114
+ ```javascript
115
+ const schema = dsl({
116
+ username: 'string!', // 必填
117
+ nickname: 'string', // 可选(默认)
118
+ bio: 'string?', // 显式可选(等价于 string)
119
+ email: 'email?' // 可选邮箱
120
+ });
121
+ ```
122
+
123
+ **说明**:
124
+ - `!` - 必填标记,字段必须存在
125
+ - `?` - 可选标记,字段可省略(显式表达)
126
+ - 不加标记 - 默认可选(字段可省略)
127
+
128
+ **推荐**:
129
+ - 使用 `!` 明确标记必填字段
130
+ - 使用 `?` 在需要明确表达"可选"时增强代码可读性
131
+
132
+ ### 3. 对象必填
133
+
134
+ 支持两种方式:
135
+
136
+ ```javascript
137
+ // 方式1: 字段内部必填
138
+ const schema1 = dsl({
139
+ user: {
140
+ name: 'string!', // name 必填(user 可选)
141
+ email: 'email!' // email 必填
142
+ }
143
+ });
144
+
145
+ // 方式2: 对象本身必填 ✅ 推荐
146
+ const schema2 = dsl({
147
+ 'user!': { // user 本身必填
148
+ name: 'string', // name 可选
149
+ email: 'email' // email 可选
150
+ }
151
+ });
152
+ ```
153
+
154
+ ---
155
+
156
+ ## 约束语法
157
+
158
+ ### 1. 字符串长度
159
+
160
+ ```javascript
161
+ 'string:10' // 精确长度10(exactLength:minLength=10, maxLength=10)
162
+ 'string:-10' // 最大长度10
163
+ 'string:3-32' // 长度范围3-32
164
+ 'string:10-' // 最小长度10(无最大限制)
165
+ ```
166
+
167
+ **示例**:
168
+ ```javascript
169
+ const schema = dsl({
170
+ username: 'string:3-32!', // 3-32字符,必填
171
+ bio: 'string:500', // 最大500字符
172
+ password: 'string:8-' // 最少8字符
173
+ });
174
+ ```
175
+
176
+ ### 2. 数字范围
177
+
178
+ ```javascript
179
+ 'number:100' // 最大值100
180
+ 'number:0-100' // 范围0-100
181
+ 'number:18-' // 最小值18
182
+ ```
183
+
184
+ **示例**:
185
+ ```javascript
186
+ const schema = dsl({
187
+ age: 'number:18-120', // 18-120
188
+ score: 'number:100', // 0-100
189
+ price: 'number:0-' // ≥0
190
+ });
191
+ ```
192
+
193
+ ### 3. 枚举值
194
+
195
+ 使用 `|` 分隔枚举值:
196
+
197
+ ```javascript
198
+ const schema = dsl({
199
+ status: 'active|inactive|pending',
200
+ gender: 'male|female|other!',
201
+ role: 'admin|user|guest'
202
+ });
203
+ ```
204
+
205
+ ### 4. `types:` 联合类型
206
+
207
+ 当一个字段需要接受多种不同类型时,可以使用 `types:` 前缀生成联合类型:
208
+
209
+ ```javascript
210
+ const schema = dsl({
211
+ contact: 'types:email|phone',
212
+ price: 'types:number:0-|string:1-20',
213
+ payload: 'types:object|array<object>'
214
+ });
215
+ ```
216
+
217
+ 这个语法会被编译为 `oneOf` 结构,适合表达“满足其中任意一种类型即可”的场景。
218
+
219
+ **适用场景**:
220
+ - 联系方式允许邮箱或手机号
221
+ - 价格字段允许数值或说明字符串
222
+ - 兼容历史接口中同字段的多种输入格式
223
+
224
+ ### 5. 特殊约束
225
+
226
+ 支持特定格式的约束:
227
+
228
+ ```javascript
229
+ 'phone:cn' // 中国手机号
230
+ 'idCard:cn' // 中国身份证
231
+ 'creditCard:visa' // Visa信用卡
232
+ 'licensePlate:cn' // 中国车牌
233
+ 'postalCode:cn' // 中国邮编
234
+ 'passport:cn' // 中国护照
235
+ ```
236
+
237
+ **示例**:
238
+ ```javascript
239
+ const schema = dsl({
240
+ mobile: 'phone:cn!',
241
+ id: 'idCard:cn',
242
+ card: 'creditCard:mastercard'
243
+ });
244
+ ```
245
+
246
+ ---
247
+
248
+ ## 数组语法
249
+
250
+ ### 1. 基础数组
251
+
252
+ ```javascript
253
+ 'array' // 任意类型数组
254
+ 'array<string>' // 字符串数组
255
+ 'array<number>' // 数字数组
256
+ 'array<integer>' // 整数数组
257
+ ```
258
+
259
+ ### 2. 数组长度约束
260
+
261
+ ```javascript
262
+ 'array:1-10' // 1-10个元素
263
+ 'array!1-10' // 1-10个元素,必填
264
+ 'array:1-' // 至少1个元素
265
+ 'array:-10' // 最多10个元素
266
+ 'array:1-10<string>' // 1-10个字符串元素
267
+ ```
268
+
269
+ **示例**:
270
+ ```javascript
271
+ const schema = dsl({
272
+ tags: 'array!1-10<string>', // 必填,1-10个字符串
273
+ scores: 'array:1-5<number>', // 可选,1-5个数字
274
+ items: 'array:1-<string>' // 至少1个字符串
275
+ });
276
+ ```
277
+
278
+ ### 3. 数组元素约束
279
+
280
+ ```javascript
281
+ const schema = dsl({
282
+ tags: 'array<string:1-20>', // 每个字符串1-20字符
283
+ scores: 'array<number:0-100>', // 每个数字0-100
284
+ ids: 'array<integer:1->' // 每个整数≥1
285
+ });
286
+ ```
287
+
288
+ ### 4. 嵌套数组
289
+
290
+ ```javascript
291
+ // 二维数组
292
+ const schema = dsl({
293
+ matrix: 'array<array<number>>'
294
+ });
295
+
296
+ // 对象数组
297
+ const schema = dsl({
298
+ users: 'array<object>',
299
+ // 或更详细定义
300
+ items: {
301
+ type: 'array',
302
+ items: {
303
+ name: 'string!',
304
+ age: 'number'
305
+ }
306
+ }
307
+ });
308
+ ```
309
+
310
+ ---
311
+
312
+ ## 对象语法
313
+
314
+ ### 1. 基础对象
315
+
316
+ ```javascript
317
+ const schema = dsl({
318
+ user: {
319
+ name: 'string!',
320
+ email: 'email!',
321
+ age: 'number'
322
+ }
323
+ });
324
+ ```
325
+
326
+ ### 2. 嵌套对象
327
+
328
+ ```javascript
329
+ const schema = dsl({
330
+ user: {
331
+ profile: {
332
+ bio: 'string:500',
333
+ social: {
334
+ twitter: 'url',
335
+ github: 'url'
336
+ }
337
+ }
338
+ }
339
+ });
340
+ ```
341
+
342
+ ### 3. 混合嵌套
343
+
344
+ ```javascript
345
+ const schema = dsl({
346
+ 'user!': { // user 必填
347
+ name: 'string!', // name 必填
348
+ contacts: 'array!1-5<object>', // 1-5个联系方式
349
+ tags: 'array<string:1-20>' // 字符串数组
350
+ }
351
+ });
352
+ ```
353
+
354
+ ---
355
+
356
+ ## 条件验证 (Match)
357
+
358
+ 支持更优雅的条件验证语法 `dsl.match` 和 `dsl.if`。
359
+
360
+ ### 1. dsl.match (推荐)
361
+
362
+ 类似于 `switch-case`,根据某个字段的值决定当前字段的验证规则。
363
+
364
+ **语法**:
365
+ ```javascript
366
+ dsl.match(field, {
367
+ value1: 'schema1',
368
+ value2: 'schema2',
369
+ _default: 'defaultSchema' // 可选
370
+ })
371
+ ```
372
+
373
+ **示例**:
374
+ ```javascript
375
+ const schema = dsl({
376
+ contactType: 'email|phone',
377
+
378
+ // 根据 contactType 的值决定 contact 的规则
379
+ contact: dsl.match('contactType', {
380
+ email: 'email!', // contactType=email 时
381
+ phone: 'string:11!', // contactType=phone 时
382
+ _default: 'string' // 其他情况
383
+ })
384
+ });
385
+ ```
386
+
387
+ **处理非英文值**:
388
+ 如果条件值包含中文、数字或特殊字符,给键名加上引号即可:
389
+
390
+ ```javascript
391
+ discount: dsl.match('level', {
392
+ '普通用户': 'number:0-5',
393
+ 'VIP-1': 'number:0-20',
394
+ '100': 'number:0-50'
395
+ })
396
+ ```
397
+
398
+ ### 2. dsl.if (简单条件)
399
+
400
+ 适用于简单的二选一场景。
401
+
402
+ **语法**:
403
+ ```javascript
404
+ dsl.if(conditionField, thenSchema, elseSchema)
405
+ ```
406
+
407
+ **示例**:
408
+ ```javascript
409
+ const schema = dsl({
410
+ isVip: 'boolean',
411
+
412
+ // 如果是VIP,折扣0-50,否则0-10
413
+ discount: dsl.if('isVip', 'number:0-50', 'number:0-10')
414
+ });
415
+ ```
416
+
417
+ ---
418
+
419
+ ## 高级用法
420
+
421
+ ### 1. 链式调用
422
+
423
+ > ⚠️ `.custom()` 当前仅支持同步自定义逻辑;异步业务校验请在验证通过后单独执行。
424
+
425
+ ```javascript
426
+ const schema = dsl({
427
+ username: 'string:3-32!'
428
+ .pattern(/^[a-zA-Z0-9_]+$/)
429
+ .label('用户名')
430
+ .messages({
431
+ 'pattern': '只能包含字母、数字和下划线'
432
+ }),
433
+
434
+ email: 'email!'
435
+ .label('邮箱地址')
436
+ .description('用于登录和接收通知')
437
+ .custom((value) => {
438
+ if (value.endsWith('@blocked.example')) return '该邮箱域名不允许注册';
439
+ })
440
+ });
441
+ ```
442
+
443
+ ### 2. 默认验证器
444
+
445
+ ```javascript
446
+ const schema = dsl({
447
+ username: 'string!'.username('5-20'), // 自动正则+长度
448
+ phone: 'string!'.phone('cn'), // 中国手机号
449
+ password: 'string!'.password('strong') // 强密码
450
+ });
451
+ ```
452
+
453
+ ---
454
+
455
+ ## 注意事项
456
+
457
+ ### 1. 条件验证
458
+
459
+ ⚠️ **注意**: DSL 字符串不支持直接写条件逻辑
460
+
461
+ ```javascript
462
+ 'string | number' // ❌ 不支持
463
+ ```
464
+
465
+ **解决方案**: 使用 `dsl.match` (推荐)
466
+
467
+ ```javascript
468
+ // ✅ 推荐:使用 dsl.match
469
+ const schema = dsl({
470
+ vipLevel: 'string',
471
+ discount: dsl.match('vipLevel', {
472
+ gold: 'number:0-50',
473
+ silver: 'number:0-20',
474
+ normal: 'number:0-5'
475
+ })
476
+ });
477
+ ```
478
+
479
+ ---
480
+
481
+ ### 2. 数组约束
482
+
483
+ ✅ **推荐**: 使用简洁的 DSL 语法
484
+ ```javascript
485
+ 'array!1-10<string:1-20>' // 1-10个元素,每个1-20字符
486
+ ```
487
+
488
+ ⚠️ **也可以**: 使用完整 JSON Schema 格式(不推荐,太繁琐)
489
+ ```javascript
490
+ {
491
+ type: 'array',
492
+ items: { type: 'string' },
493
+ minItems: 1,
494
+ maxItems: 10
495
+ }
496
+ ```
497
+
498
+ ---
499
+
500
+ ### 3. 正则验证
501
+
502
+ ⚠️ **注意**: DSL 字符串不支持直接写正则
503
+
504
+ ```javascript
505
+ 'string:/^[a-z]+$/' // ❌ 不支持
506
+ ```
507
+
508
+ **解决方案**: 使用 `.pattern()` 方法
509
+ ```javascript
510
+ 'string!'.pattern(/^[a-z]+$/) // ✅ 推荐
511
+ ```
512
+
513
+ ---
514
+
515
+ ### 4. 自定义验证
516
+
517
+ ⚠️ **注意**: DSL 字符串不支持自定义逻辑
518
+
519
+ ```javascript
520
+ 'string!@custom' // ❌ 不支持
521
+ ```
522
+
523
+ **解决方案**: 使用 `.custom()` 方法承载**同步**自定义逻辑
524
+ ```javascript
525
+ 'string!'.custom((value) => {
526
+ // 自定义同步逻辑
527
+ if (value === 'reserved') {
528
+ return '该值不可用';
529
+ }
530
+ })
531
+ ```
532
+
533
+ 异步校验(如数据库查重)请在 `validate()` / `validateAsync()` 通过后于业务层单独执行。
534
+
535
+ ---
536
+
537
+ ### 5. 对象数组详细定义
538
+
539
+ ⚠️ **注意**: DSL 简写不支持对象数组的详细定义
540
+
541
+ ```javascript
542
+ 'array<object{name:string,age:number}>' // ❌ 不支持
543
+ ```
544
+
545
+ **解决方案**: 使用完整对象定义
546
+ ```javascript
547
+ const schema = dsl({
548
+ users: {
549
+ type: 'array',
550
+ items: {
551
+ name: 'string!',
552
+ age: 'number:18-'
553
+ }
554
+ }
555
+ });
556
+ ```
557
+
558
+ ---
559
+
560
+ ## 完整示例
561
+
562
+ ### 用户注册表单
563
+
564
+ ```javascript
565
+ const { dsl } = require('schema-dsl');
566
+
567
+ const schema = dsl({
568
+ // 基本信息
569
+ username: 'string:3-32!'.username().label('用户名'),
570
+ password: 'string!'.password('strong').label('密码'),
571
+ email: 'email!'.label('邮箱'),
572
+ phone: 'string!'.phone('cn').label('手机号'),
573
+
574
+ // 个人资料
575
+ 'profile!': {
576
+ realName: 'string:2-50',
577
+ gender: 'male|female|other',
578
+ birthday: 'date',
579
+ bio: 'string:500'
580
+ },
581
+
582
+ // 地址信息
583
+ addresses: 'array:1-5<object>', // 1-5个地址
584
+
585
+ // 标签
586
+ tags: 'array:1-10<string:1-20>', // 1-10个标签,每个1-20字符
587
+
588
+ // 同意条款
589
+ agree: 'boolean!'
590
+ });
591
+ ```
592
+
593
+ ### 电商商品 Schema
594
+
595
+ ```javascript
596
+ const schema = dsl({
597
+ // 商品基本信息
598
+ title: 'string:1-100!',
599
+ price: 'number:0-!',
600
+ stock: 'integer:0-',
601
+ status: 'on_sale|off_sale|sold_out!',
602
+
603
+ // 商品详情
604
+ 'details!': {
605
+ description: 'string:10000',
606
+ images: 'array!1-10<url>',
607
+ specs: 'array<object>',
608
+ tags: 'array:1-20<string:1-30>'
609
+ },
610
+
611
+ // SKU信息
612
+ skus: {
613
+ type: 'array',
614
+ minItems: 1,
615
+ items: {
616
+ sku_code: 'string!',
617
+ price: 'number!',
618
+ stock: 'integer!'
619
+ }
620
+ }
621
+ });
622
+ ```
623
+
624
+ ### API 请求验证
625
+
626
+ ```javascript
627
+ const schema = dsl({
628
+ // 查询参数
629
+ page: 'integer:1-',
630
+ pageSize: 'integer:10-100',
631
+ keyword: 'string:1-50',
632
+
633
+ // 筛选条件
634
+ filters: {
635
+ category: 'array<string>',
636
+ priceRange: {
637
+ min: 'number:0-',
638
+ max: 'number:0-'
639
+ },
640
+ status: 'active|inactive'
641
+ },
642
+
643
+ // 排序
644
+ sort: {
645
+ field: 'price|created_at|sales',
646
+ order: 'asc|desc'
647
+ }
648
+ });
649
+ ```
650
+
651
+ ---
652
+
653
+ ## 常见问题
654
+
655
+ ### Q1: 为什么移除了简写功能?
656
+
657
+ **A**: 为了降低学习成本和减少歧义。使用完整类型名更清晰,特别是对新手更友好。
658
+
659
+ ### Q2: 数组长度约束怎么写?
660
+
661
+ **A**: 支持直接在DSL中写:
662
+ ```javascript
663
+ 'array!1-10<string>' // 推荐
664
+ ```
665
+
666
+ ### Q3: 如何定义对象数组?
667
+
668
+ **A**: 使用完整对象定义:
669
+ ```javascript
670
+ const schema = dsl({
671
+ users: {
672
+ type: 'array',
673
+ items: {
674
+ name: 'string!',
675
+ email: 'email!'
676
+ }
677
+ }
678
+ });
679
+ ```
680
+
681
+ ### Q4: 不支持条件验证吗?
682
+
683
+ **A**: 支持。推荐使用 `dsl.match`:
684
+ ```javascript
685
+ dsl.match('vipLevel', { gold: 'number:0-50', silver: 'number:0-20' })
686
+ ```
687
+
688
+ ### Q5: 能用正则验证吗?
689
+
690
+ **A**: 能,使用 `.pattern()` 方法:
691
+ ```javascript
692
+ 'string!'.pattern(/^[a-z]+$/)
693
+ ```
694
+
695
+ ---
696
+
697
+ ## 相关文档
698
+
699
+ - [类型参考](./type-reference.md) - 完整类型列表
700
+ - [String 扩展](./string-extensions.md) - 链式调用
701
+ - [快速开始](./quick-start.md) - 5分钟上手
702
+
703
+ ---
704
+
705
+ ## 对应示例文件
706
+
707
+ **示例入口**: [dsl-syntax.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/dsl-syntax.ts)
708
+ **说明**: 覆盖 Batch 1 中 DSL 语法的基础类型、约束、枚举、数组和嵌套对象写法,可直接运行参考。
709
+
710
+ ---
711
+
712
+ **最后更新**: 2026-05-08
713
+ **作者**: schema-dsl Team
714
+