schema-dsl 1.0.0 → 1.0.4

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 (45) hide show
  1. package/CHANGELOG.md +263 -529
  2. package/README.md +814 -896
  3. package/STATUS.md +135 -2
  4. package/docs/INDEX.md +1 -2
  5. package/docs/api-reference.md +1 -292
  6. package/docs/custom-extensions-guide.md +411 -0
  7. package/docs/enum.md +475 -0
  8. package/docs/i18n.md +394 -0
  9. package/docs/performance-benchmark-report.md +179 -0
  10. package/docs/plugin-system.md +8 -8
  11. package/docs/typescript-guide.md +554 -0
  12. package/docs/validate-async.md +1 -1
  13. package/docs/validation-rules-v1.0.2.md +1601 -0
  14. package/examples/README.md +81 -0
  15. package/examples/enum.examples.js +324 -0
  16. package/examples/express-integration.js +54 -54
  17. package/examples/i18n-full-demo.js +15 -24
  18. package/examples/schema-utils-chaining.examples.js +2 -2
  19. package/examples/slug.examples.js +179 -0
  20. package/index.d.ts +246 -17
  21. package/index.js +30 -34
  22. package/lib/config/constants.js +1 -1
  23. package/lib/config/patterns/common.js +47 -0
  24. package/lib/config/patterns/index.js +2 -1
  25. package/lib/core/DslBuilder.js +500 -8
  26. package/lib/core/StringExtensions.js +31 -0
  27. package/lib/core/Validator.js +42 -15
  28. package/lib/errors/ValidationError.js +3 -3
  29. package/lib/locales/en-US.js +79 -19
  30. package/lib/locales/es-ES.js +60 -19
  31. package/lib/locales/fr-FR.js +84 -43
  32. package/lib/locales/ja-JP.js +83 -42
  33. package/lib/locales/zh-CN.js +32 -0
  34. package/lib/validators/CustomKeywords.js +405 -0
  35. package/package.json +1 -1
  36. package/.github/CODE_OF_CONDUCT.md +0 -45
  37. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -57
  38. package/.github/ISSUE_TEMPLATE/config.yml +0 -11
  39. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -45
  40. package/.github/ISSUE_TEMPLATE/question.md +0 -31
  41. package/.github/PULL_REQUEST_TEMPLATE.md +0 -70
  42. package/.github/SECURITY.md +0 -184
  43. package/.github/workflows/ci.yml +0 -33
  44. package/plugins/custom-format.js +0 -101
  45. package/plugins/custom-validator.js +0 -200
@@ -0,0 +1,1601 @@
1
+ # v1.0.2 新增验证规则
2
+
3
+ **版本**: v1.0.2
4
+ **发布日期**: 2025-12-31
5
+ **新增验证器**: 15 个
6
+
7
+ 本文档详细介绍 v1.0.2 版本新增的 15 个验证规则,包括使用方法、应用场景和完整示例。
8
+
9
+ ---
10
+
11
+ ## 📚 目录
12
+
13
+ - [String 验证器 (6个)](#string-验证器)
14
+ - [exactLength - 精确长度验证](#1-exactlength---精确长度验证)
15
+ - [alphanum - 字母和数字](#2-alphanum---字母和数字)
16
+ - [trim - 前后空格检查](#3-trim---前后空格检查)
17
+ - [lowercase - 小写检查](#4-lowercase---小写检查)
18
+ - [uppercase - 大写检查](#5-uppercase---大写检查)
19
+ - [jsonString - JSON字符串验证](#6-jsonstring---json字符串验证)
20
+ - [Number 验证器 (2个)](#number-验证器)
21
+ - [precision - 小数位数限制](#7-precision---小数位数限制)
22
+ - [port - 端口号验证](#8-port---端口号验证)
23
+ - [Object 验证器 (2个)](#object-验证器)
24
+ - [requiredAll - 要求所有属性](#9-requiredall---要求所有属性)
25
+ - [strictSchema - 严格模式](#10-strictschema---严格模式)
26
+ - [Array 验证器 (2个)](#array-验证器)
27
+ - [noSparse - 禁止稀疏数组](#11-nosparse---禁止稀疏数组)
28
+ - [includesRequired - 必须包含元素](#12-includesrequired---必须包含元素)
29
+ - [Date 验证器 (3个)](#date-验证器)
30
+ - [dateFormat - 日期格式验证](#13-dateformat---日期格式验证)
31
+ - [dateGreater - 日期大于](#14-dategreater---日期大于)
32
+ - [dateLess - 日期小于](#15-dateless---日期小于)
33
+
34
+ ---
35
+
36
+ ## String 验证器
37
+
38
+ ### 1. exactLength - 精确长度验证
39
+
40
+ **用途**: 验证字符串长度必须等于指定值
41
+
42
+ **参数**: `number` - 精确长度
43
+
44
+ **错误消息**:
45
+ - 中文: "{{#label}}长度必须是{{#limit}}个字符"
46
+ - 英文: "{{#label}} length must be exactly {{#limit}} characters"
47
+
48
+ **使用方法**:
49
+
50
+ ```javascript
51
+ const { dsl, validate } = require('schema-dsl');
52
+
53
+ // 方式1: JSON Schema
54
+ const schema = {
55
+ type: 'object',
56
+ properties: {
57
+ code: {
58
+ type: 'string',
59
+ exactLength: 6
60
+ }
61
+ }
62
+ };
63
+
64
+ // 方式2: DSL 语法 (推荐)
65
+ const schema2 = dsl({
66
+ code: 'string!',
67
+ exactLength: 6
68
+ });
69
+ ```
70
+
71
+ **验证示例**:
72
+
73
+ ```javascript
74
+ // ✅ 通过
75
+ validate(schema, { code: 'ABC123' });
76
+ // { valid: true, errors: [], data: { code: 'ABC123' } }
77
+
78
+ // ❌ 失败 - 长度不足
79
+ validate(schema, { code: 'ABC12' });
80
+ // { valid: false, errors: ['code长度必须是6个字符'], ... }
81
+
82
+ // ❌ 失败 - 长度超出
83
+ validate(schema, { code: 'ABC1234' });
84
+ // { valid: false, errors: ['code长度必须是6个字符'], ... }
85
+ ```
86
+
87
+ **应用场景**:
88
+ - ✅ 短信验证码 (6位)
89
+ - ✅ 邀请码 (固定长度)
90
+ - ✅ 产品编码 (固定格式)
91
+ - ✅ 颜色代码 (如 #RRGGBB)
92
+
93
+ **最佳实践**:
94
+
95
+ ```javascript
96
+ // 验证码场景
97
+ const verifyCodeSchema = dsl({
98
+ code: 'string!',
99
+ exactLength: 6,
100
+ alphanum: true // 配合 alphanum 使用
101
+ });
102
+
103
+ // 邀请码场景
104
+ const inviteCodeSchema = dsl({
105
+ inviteCode: 'string!',
106
+ exactLength: 8,
107
+ uppercase: true // 配合 uppercase 使用
108
+ });
109
+ ```
110
+
111
+ ---
112
+
113
+ ### 2. alphanum - 字母和数字
114
+
115
+ **用途**: 验证字符串只能包含字母和数字
116
+
117
+ **参数**: `boolean` - true 表示启用验证
118
+
119
+ **错误消息**:
120
+ - 中文: "{{#label}}只能包含字母和数字"
121
+ - 英文: "{{#label}} must only contain alphanumeric characters"
122
+
123
+ **使用方法**:
124
+
125
+ ```javascript
126
+ // JSON Schema
127
+ const schema = {
128
+ type: 'object',
129
+ properties: {
130
+ username: {
131
+ type: 'string',
132
+ alphanum: true
133
+ }
134
+ }
135
+ };
136
+
137
+ // DSL 语法
138
+ const schema2 = dsl({
139
+ username: 'string!',
140
+ alphanum: true
141
+ });
142
+ ```
143
+
144
+ **验证示例**:
145
+
146
+ ```javascript
147
+ // ✅ 通过
148
+ validate(schema, { username: 'user123' });
149
+ validate(schema, { username: 'ABC' });
150
+ validate(schema, { username: '123' });
151
+
152
+ // ❌ 失败 - 包含特殊字符
153
+ validate(schema, { username: 'user_123' });
154
+ // { valid: false, errors: ['username只能包含字母和数字'], ... }
155
+
156
+ validate(schema, { username: 'user-123' });
157
+ validate(schema, { username: 'user@123' });
158
+ validate(schema, { username: 'user 123' }); // 空格也不允许
159
+ ```
160
+
161
+ **应用场景**:
162
+ - ✅ 用户名验证
163
+ - ✅ 产品编码
164
+ - ✅ 简单标识符
165
+ - ✅ 文件名(无特殊字符)
166
+
167
+ **最佳实践**:
168
+
169
+ ```javascript
170
+ // 用户名场景 - 配合长度验证
171
+ const usernameSchema = dsl({
172
+ username: 'string:3-20!',
173
+ alphanum: true
174
+ });
175
+
176
+ // 产品编码 - 配合大写
177
+ const productCodeSchema = dsl({
178
+ productCode: 'string!',
179
+ alphanum: true,
180
+ uppercase: true,
181
+ exactLength: 10
182
+ });
183
+ ```
184
+
185
+ ---
186
+
187
+ ### 3. trim - 前后空格检查
188
+
189
+ **用途**: 验证字符串不能包含前后空格
190
+
191
+ **参数**: `boolean` - true 表示启用验证
192
+
193
+ **错误消息**:
194
+ - 中文: "{{#label}}不能包含前后空格"
195
+ - 英文: "{{#label}} must not have leading or trailing whitespace"
196
+
197
+ **使用方法**:
198
+
199
+ ```javascript
200
+ // JSON Schema
201
+ const schema = {
202
+ type: 'object',
203
+ properties: {
204
+ keyword: {
205
+ type: 'string',
206
+ trim: true
207
+ }
208
+ }
209
+ };
210
+
211
+ // DSL 语法
212
+ const schema2 = dsl({
213
+ keyword: 'string!',
214
+ trim: true
215
+ });
216
+ ```
217
+
218
+ **验证示例**:
219
+
220
+ ```javascript
221
+ // ✅ 通过
222
+ validate(schema, { keyword: 'search' });
223
+ validate(schema, { keyword: 'hello world' }); // 中间空格允许
224
+
225
+ // ❌ 失败 - 前导空格
226
+ validate(schema, { keyword: ' search' });
227
+ // { valid: false, errors: ['keyword不能包含前后空格'], ... }
228
+
229
+ // ❌ 失败 - 尾随空格
230
+ validate(schema, { keyword: 'search ' });
231
+
232
+ // ❌ 失败 - 前后都有空格
233
+ validate(schema, { keyword: ' search ' });
234
+ ```
235
+
236
+ **应用场景**:
237
+ - ✅ 搜索关键词
238
+ - ✅ 标签名称
239
+ - ✅ 精确匹配场景
240
+ - ✅ API 密钥
241
+ - ✅ Token 验证
242
+
243
+ **最佳实践**:
244
+
245
+ ```javascript
246
+ // 搜索关键词 - 自动修剪
247
+ const searchSchema = dsl({
248
+ keyword: 'string:1-100!',
249
+ trim: true
250
+ });
251
+
252
+ // 标签场景 - 严格验证
253
+ const tagSchema = dsl({
254
+ tag: 'string:2-20!',
255
+ trim: true,
256
+ lowercase: true // 统一小写
257
+ });
258
+ ```
259
+
260
+ **注意事项**:
261
+ - ⚠️ 此验证器只检查前后空格,不会自动去除
262
+ - 💡 如需自动去除,请在业务代码中使用 `String.prototype.trim()`
263
+
264
+ ---
265
+
266
+ ### 4. lowercase - 小写检查
267
+
268
+ **用途**: 验证字符串必须全部是小写
269
+
270
+ **参数**: `boolean` - true 表示启用验证
271
+
272
+ **错误消息**:
273
+ - 中文: "{{#label}}必须是小写"
274
+ - 英文: "{{#label}} must be lowercase"
275
+
276
+ **使用方法**:
277
+
278
+ ```javascript
279
+ // JSON Schema
280
+ const schema = {
281
+ type: 'object',
282
+ properties: {
283
+ email: {
284
+ type: 'string',
285
+ format: 'email',
286
+ lowercase: true
287
+ }
288
+ }
289
+ };
290
+
291
+ // DSL 语法
292
+ const schema2 = dsl({
293
+ email: 'email!',
294
+ lowercase: true
295
+ });
296
+ ```
297
+
298
+ **验证示例**:
299
+
300
+ ```javascript
301
+ // ✅ 通过
302
+ validate(schema, { email: 'user@example.com' });
303
+ validate(schema, { email: 'test123' });
304
+ validate(schema, { email: 'abc' });
305
+
306
+ // ❌ 失败 - 包含大写字母
307
+ validate(schema, { email: 'User@example.com' });
308
+ // { valid: false, errors: ['email必须是小写'], ... }
309
+
310
+ validate(schema, { email: 'TEST' });
311
+ validate(schema, { email: 'Test123' });
312
+ ```
313
+
314
+ **应用场景**:
315
+ - ✅ 邮箱地址(规范化)
316
+ - ✅ 用户名(统一小写)
317
+ - ✅ URL slug
318
+ - ✅ 标签名称
319
+ - ✅ 数据库字段名
320
+
321
+ **最佳实践**:
322
+
323
+ ```javascript
324
+ // 邮箱场景
325
+ const emailSchema = dsl({
326
+ email: 'email!',
327
+ lowercase: true,
328
+ trim: true
329
+ });
330
+
331
+ // URL slug 场景
332
+ const slugSchema = dsl({
333
+ slug: 'string:3-50!',
334
+ lowercase: true,
335
+ alphanum: false, // 允许连字符
336
+ regex: /^[a-z0-9-]+$/
337
+ });
338
+
339
+ // 数据库字段名
340
+ const fieldNameSchema = dsl({
341
+ fieldName: 'string!',
342
+ lowercase: true,
343
+ regex: /^[a-z_][a-z0-9_]*$/ // 下划线命名
344
+ });
345
+ ```
346
+
347
+ ---
348
+
349
+ ### 5. uppercase - 大写检查
350
+
351
+ **用途**: 验证字符串必须全部是大写
352
+
353
+ **参数**: `boolean` - true 表示启用验证
354
+
355
+ **错误消息**:
356
+ - 中文: "{{#label}}必须是大写"
357
+ - 英文: "{{#label}} must be uppercase"
358
+
359
+ **使用方法**:
360
+
361
+ ```javascript
362
+ // JSON Schema
363
+ const schema = {
364
+ type: 'object',
365
+ properties: {
366
+ countryCode: {
367
+ type: 'string',
368
+ uppercase: true,
369
+ exactLength: 2
370
+ }
371
+ }
372
+ };
373
+
374
+ // DSL 语法
375
+ const schema2 = dsl({
376
+ countryCode: 'string!',
377
+ uppercase: true,
378
+ exactLength: 2
379
+ });
380
+ ```
381
+
382
+ **验证示例**:
383
+
384
+ ```javascript
385
+ // ✅ 通过
386
+ validate(schema, { countryCode: 'CN' });
387
+ validate(schema, { countryCode: 'US' });
388
+
389
+ // ❌ 失败 - 包含小写字母
390
+ validate(schema, { countryCode: 'cn' });
391
+ // { valid: false, errors: ['countryCode必须是大写'], ... }
392
+
393
+ validate(schema, { countryCode: 'Cn' });
394
+ ```
395
+
396
+ **应用场景**:
397
+ - ✅ 国家代码 (ISO 3166)
398
+ - ✅ 货币代码 (ISO 4217)
399
+ - ✅ 语言代码 (ISO 639)
400
+ - ✅ 产品系列代码
401
+ - ✅ 常量名称
402
+
403
+ **最佳实践**:
404
+
405
+ ```javascript
406
+ // 国家代码
407
+ const countrySchema = dsl({
408
+ country: 'string!',
409
+ uppercase: true,
410
+ exactLength: 2,
411
+ regex: /^[A-Z]{2}$/
412
+ });
413
+
414
+ // 货币代码
415
+ const currencySchema = dsl({
416
+ currency: 'string!',
417
+ uppercase: true,
418
+ exactLength: 3,
419
+ regex: /^[A-Z]{3}$/ // USD, EUR, CNY
420
+ });
421
+
422
+ // 产品系列代码
423
+ const seriesCodeSchema = dsl({
424
+ seriesCode: 'string!',
425
+ uppercase: true,
426
+ alphanum: true,
427
+ exactLength: 6
428
+ });
429
+ ```
430
+
431
+ ---
432
+
433
+ ### 6. jsonString - JSON字符串验证
434
+
435
+ **用途**: 验证字符串必须是有效的 JSON 格式
436
+
437
+ **参数**: `boolean` - true 表示启用验证
438
+
439
+ **错误消息**:
440
+ - 中文: "{{#label}}必须是有效的JSON字符串"
441
+ - 英文: "{{#label}} must be a valid JSON string"
442
+
443
+ **使用方法**:
444
+
445
+ ```javascript
446
+ // JSON Schema
447
+ const schema = {
448
+ type: 'object',
449
+ properties: {
450
+ config: {
451
+ type: 'string',
452
+ jsonString: true
453
+ }
454
+ }
455
+ };
456
+
457
+ // DSL 语法
458
+ const schema2 = dsl({
459
+ config: 'string!',
460
+ jsonString: true
461
+ });
462
+ ```
463
+
464
+ **验证示例**:
465
+
466
+ ```javascript
467
+ // ✅ 通过 - 有效的 JSON
468
+ validate(schema, { config: '{"key":"value"}' });
469
+ validate(schema, { config: '[1,2,3]' });
470
+ validate(schema, { config: '"string"' });
471
+ validate(schema, { config: '123' });
472
+ validate(schema, { config: 'true' });
473
+ validate(schema, { config: 'null' });
474
+
475
+ // ❌ 失败 - 无效的 JSON
476
+ validate(schema, { config: '{key:value}' }); // 键未加引号
477
+ // { valid: false, errors: ['config必须是有效的JSON字符串'], ... }
478
+
479
+ validate(schema, { config: "{'key':'value'}" }); // 单引号
480
+ validate(schema, { config: '{incomplete' }); // 不完整
481
+ validate(schema, { config: 'undefined' }); // undefined 不是有效 JSON
482
+ ```
483
+
484
+ **应用场景**:
485
+ - ✅ 配置字符串存储
486
+ - ✅ API 参数验证
487
+ - ✅ 数据库 TEXT 字段存储 JSON
488
+ - ✅ 日志记录
489
+ - ✅ 消息队列载荷
490
+
491
+ **最佳实践**:
492
+
493
+ ```javascript
494
+ // 配置存储场景
495
+ const configSchema = dsl({
496
+ config: 'string!',
497
+ jsonString: true
498
+ });
499
+
500
+ // 使用示例
501
+ const result = validate(configSchema, {
502
+ config: JSON.stringify({ theme: 'dark', lang: 'zh' })
503
+ });
504
+
505
+ if (result.valid) {
506
+ const config = JSON.parse(result.data.config);
507
+ console.log(config.theme); // 'dark'
508
+ }
509
+
510
+ // 结合长度限制
511
+ const limitedConfigSchema = dsl({
512
+ config: 'string:1-10000!', // 最大 10KB
513
+ jsonString: true
514
+ });
515
+ ```
516
+
517
+ **注意事项**:
518
+ - ⚠️ 此验证器只检查 JSON 格式有效性,不验证内容结构
519
+ - 💡 如需验证 JSON 内容结构,请解析后再用嵌套 schema 验证
520
+
521
+ ---
522
+
523
+ ## Number 验证器
524
+
525
+ ### 7. precision - 小数位数限制
526
+
527
+ **用途**: 验证数字的小数位数不超过指定值
528
+
529
+ **参数**: `number` - 最大小数位数
530
+
531
+ **错误消息**:
532
+ - 中文: "{{#label}}小数位数不能超过{{#limit}}位"
533
+ - 英文: "{{#label}} must have at most {{#limit}} decimal places"
534
+
535
+ **使用方法**:
536
+
537
+ ```javascript
538
+ // JSON Schema
539
+ const schema = {
540
+ type: 'object',
541
+ properties: {
542
+ price: {
543
+ type: 'number',
544
+ precision: 2
545
+ }
546
+ }
547
+ };
548
+
549
+ // DSL 语法
550
+ const schema2 = dsl({
551
+ price: 'number!',
552
+ precision: 2
553
+ });
554
+ ```
555
+
556
+ **验证示例**:
557
+
558
+ ```javascript
559
+ // ✅ 通过
560
+ validate(schema, { price: 99.99 });
561
+ validate(schema, { price: 100 }); // 整数(0位小数)
562
+ validate(schema, { price: 99.9 }); // 1位小数
563
+
564
+ // ❌ 失败 - 小数位数超出
565
+ validate(schema, { price: 99.999 });
566
+ // { valid: false, errors: ['price小数位数不能超过2位'], ... }
567
+
568
+ validate(schema, { price: 99.1234 });
569
+ ```
570
+
571
+ **应用场景**:
572
+ - ✅ 价格金额 (2位小数)
573
+ - ✅ 百分比 (2位小数)
574
+ - ✅ 坐标精度 (6位小数)
575
+ - ✅ 科学计算精度控制
576
+ - ✅ 财务数据
577
+
578
+ **最佳实践**:
579
+
580
+ ```javascript
581
+ // 价格场景 - 人民币
582
+ const priceSchema = dsl({
583
+ price: 'number:0.01-99999999.99!',
584
+ precision: 2
585
+ });
586
+
587
+ // 百分比场景
588
+ const percentageSchema = dsl({
589
+ percentage: 'number:0-100!',
590
+ precision: 2
591
+ });
592
+
593
+ // GPS 坐标
594
+ const coordinateSchema = dsl({
595
+ latitude: 'number:-90-90!',
596
+ precision: 6,
597
+ longitude: 'number:-180-180!',
598
+ precision: 6
599
+ });
600
+
601
+ // 汇率场景 - 高精度
602
+ const exchangeRateSchema = dsl({
603
+ rate: 'number!',
604
+ precision: 4
605
+ });
606
+ ```
607
+
608
+ **注意事项**:
609
+ - ⚠️ 整数会被识别为 0 位小数(通过验证)
610
+ - ⚠️ JavaScript 浮点数精度问题可能影响验证结果
611
+ - 💡 金融场景建议使用整数存储(如分为单位)
612
+
613
+ ---
614
+
615
+ ### 8. port - 端口号验证
616
+
617
+ **用途**: 验证数字是有效的端口号 (1-65535)
618
+
619
+ **参数**: `boolean` - true 表示启用验证
620
+
621
+ **错误消息**:
622
+ - 中文: "{{#label}}必须是有效的端口号(1-65535)"
623
+ - 英文: "{{#label}} must be a valid port number (1-65535)"
624
+
625
+ **使用方法**:
626
+
627
+ ```javascript
628
+ // JSON Schema
629
+ const schema = {
630
+ type: 'object',
631
+ properties: {
632
+ port: {
633
+ type: 'integer',
634
+ port: true
635
+ }
636
+ }
637
+ };
638
+
639
+ // DSL 语法
640
+ const schema2 = dsl({
641
+ port: 'integer!',
642
+ port: true
643
+ });
644
+ ```
645
+
646
+ **验证示例**:
647
+
648
+ ```javascript
649
+ // ✅ 通过
650
+ validate(schema, { port: 80 });
651
+ validate(schema, { port: 443 });
652
+ validate(schema, { port: 3000 });
653
+ validate(schema, { port: 65535 }); // 最大值
654
+
655
+ // ❌ 失败 - 端口号超出范围
656
+ validate(schema, { port: 0 });
657
+ // { valid: false, errors: ['port必须是有效的端口号(1-65535)'], ... }
658
+
659
+ validate(schema, { port: 65536 }); // 超过最大值
660
+ validate(schema, { port: -1 }); // 负数
661
+
662
+ // ❌ 失败 - 非整数
663
+ validate(schema, { port: 80.5 });
664
+ validate(schema, { port: '80' }); // 字符串(需先类型转换)
665
+ ```
666
+
667
+ **应用场景**:
668
+ - ✅ 服务器配置
669
+ - ✅ 数据库连接配置
670
+ - ✅ 微服务端口分配
671
+ - ✅ 负载均衡配置
672
+ - ✅ 防火墙规则
673
+
674
+ **最佳实践**:
675
+
676
+ ```javascript
677
+ // 服务器配置
678
+ const serverConfigSchema = dsl({
679
+ httpPort: 'integer!',
680
+ port: true,
681
+ httpsPort: 'integer!',
682
+ port: true
683
+ });
684
+
685
+ // 数据库配置
686
+ const dbConfigSchema = dsl({
687
+ host: 'string!',
688
+ port: 'integer!',
689
+ port: true,
690
+ database: 'string!'
691
+ });
692
+
693
+ // 常用端口验证(带默认值)
694
+ const webServerSchema = {
695
+ type: 'object',
696
+ properties: {
697
+ port: {
698
+ type: 'integer',
699
+ port: true,
700
+ default: 3000
701
+ }
702
+ }
703
+ };
704
+ ```
705
+
706
+ **常用端口参考**:
707
+ - HTTP: 80
708
+ - HTTPS: 443
709
+ - SSH: 22
710
+ - FTP: 21
711
+ - MySQL: 3306
712
+ - PostgreSQL: 5432
713
+ - MongoDB: 27017
714
+ - Redis: 6379
715
+
716
+ ---
717
+
718
+ ## Object 验证器
719
+
720
+ ### 9. requiredAll - 要求所有属性
721
+
722
+ **用途**: 要求对象的所有定义属性都必须存在
723
+
724
+ **参数**: `boolean` - true 表示启用验证
725
+
726
+ **错误消息**:
727
+ - 中文: "{{#label}}缺少必需属性"
728
+ - 英文: "{{#label}} is missing required properties"
729
+
730
+ **使用方法**:
731
+
732
+ ```javascript
733
+ // JSON Schema
734
+ const schema = {
735
+ type: 'object',
736
+ properties: {
737
+ name: { type: 'string' },
738
+ age: { type: 'number' },
739
+ email: { type: 'string' }
740
+ },
741
+ requiredAll: true
742
+ };
743
+
744
+ // DSL 语法
745
+ const schema2 = dsl({
746
+ name: 'string',
747
+ age: 'number',
748
+ email: 'string',
749
+ _requiredAll: true
750
+ });
751
+ ```
752
+
753
+ **验证示例**:
754
+
755
+ ```javascript
756
+ // ✅ 通过 - 所有属性都存在
757
+ validate(schema, {
758
+ name: 'John',
759
+ age: 30,
760
+ email: 'john@example.com'
761
+ });
762
+
763
+ // ❌ 失败 - 缺少属性
764
+ validate(schema, {
765
+ name: 'John',
766
+ age: 30
767
+ // 缺少 email
768
+ });
769
+ // { valid: false, errors: ['缺少必需属性'], ... }
770
+
771
+ validate(schema, {
772
+ name: 'John'
773
+ // 缺少 age 和 email
774
+ });
775
+ ```
776
+
777
+ **应用场景**:
778
+ - ✅ 完整性检查
779
+ - ✅ 表单提交验证
780
+ - ✅ API 响应验证
781
+ - ✅ 配置文件验证
782
+ - ✅ 数据导入验证
783
+
784
+ **最佳实践**:
785
+
786
+ ```javascript
787
+ // 用户注册 - 所有字段必填
788
+ const registerSchema = dsl({
789
+ username: 'string:3-20',
790
+ password: 'string:8-32',
791
+ email: 'email',
792
+ phone: 'string',
793
+ _requiredAll: true
794
+ });
795
+
796
+ // 配置文件 - 完整性检查
797
+ const configSchema = dsl({
798
+ host: 'string',
799
+ port: 'integer',
800
+ database: 'string',
801
+ username: 'string',
802
+ password: 'string',
803
+ _requiredAll: true
804
+ });
805
+ ```
806
+
807
+ **与 required 的区别**:
808
+ - `required`: 指定哪些字段必填(灵活)
809
+ - `requiredAll`: 所有定义的字段都必填(严格)
810
+
811
+ ```javascript
812
+ // required 方式(灵活)
813
+ const schema1 = {
814
+ type: 'object',
815
+ properties: {
816
+ name: { type: 'string' },
817
+ age: { type: 'number' },
818
+ email: { type: 'string' }
819
+ },
820
+ required: ['name', 'email'] // 只要求 name 和 email
821
+ };
822
+
823
+ // requiredAll 方式(严格)
824
+ const schema2 = {
825
+ type: 'object',
826
+ properties: {
827
+ name: { type: 'string' },
828
+ age: { type: 'number' },
829
+ email: { type: 'string' }
830
+ },
831
+ requiredAll: true // 要求所有 3 个属性
832
+ };
833
+ ```
834
+
835
+ ---
836
+
837
+ ### 10. strictSchema - 严格模式
838
+
839
+ **用途**: 不允许对象包含未定义的额外属性
840
+
841
+ **参数**: `boolean` - true 表示启用验证
842
+
843
+ **错误消息**:
844
+ - 中文: "{{#label}}包含额外属性"
845
+ - 英文: "{{#label}} contains additional properties"
846
+
847
+ **使用方法**:
848
+
849
+ ```javascript
850
+ // JSON Schema
851
+ const schema = {
852
+ type: 'object',
853
+ properties: {
854
+ name: { type: 'string' },
855
+ age: { type: 'number' }
856
+ },
857
+ strictSchema: true
858
+ };
859
+
860
+ // DSL 语法
861
+ const schema2 = dsl({
862
+ name: 'string',
863
+ age: 'number',
864
+ _strictSchema: true
865
+ });
866
+ ```
867
+
868
+ **验证示例**:
869
+
870
+ ```javascript
871
+ // ✅ 通过 - 只包含定义的属性
872
+ validate(schema, {
873
+ name: 'John',
874
+ age: 30
875
+ });
876
+
877
+ // ❌ 失败 - 包含额外属性
878
+ validate(schema, {
879
+ name: 'John',
880
+ age: 30,
881
+ email: 'john@example.com' // 额外属性
882
+ });
883
+ // { valid: false, errors: ['包含额外属性'], ... }
884
+
885
+ validate(schema, {
886
+ name: 'John',
887
+ age: 30,
888
+ address: '123 Main St',
889
+ phone: '1234567890'
890
+ });
891
+ ```
892
+
893
+ **应用场景**:
894
+ - ✅ API 请求验证(防止恶意字段)
895
+ - ✅ 数据库写入验证(防止污染)
896
+ - ✅ 安全敏感场景
897
+ - ✅ 严格的表单验证
898
+ - ✅ 配置文件验证
899
+
900
+ **最佳实践**:
901
+
902
+ ```javascript
903
+ // API 请求验证 - 严格模式
904
+ const apiRequestSchema = dsl({
905
+ userId: 'string!',
906
+ action: 'string!',
907
+ params: 'object',
908
+ _strictSchema: true // 防止注入额外字段
909
+ });
910
+
911
+ // 数据库更新 - 严格模式
912
+ const updateUserSchema = dsl({
913
+ name: 'string',
914
+ email: 'email',
915
+ age: 'number',
916
+ _strictSchema: true // 只允许更新这3个字段
917
+ });
918
+
919
+ // 支付参数 - 严格模式(安全)
920
+ const paymentSchema = dsl({
921
+ amount: 'number!',
922
+ currency: 'string!',
923
+ orderId: 'string!',
924
+ _strictSchema: true // 防止篡改
925
+ });
926
+ ```
927
+
928
+ **与 additionalProperties 的区别**:
929
+
930
+ ```javascript
931
+ // additionalProperties: false(ajv 标准)
932
+ const schema1 = {
933
+ type: 'object',
934
+ properties: {
935
+ name: { type: 'string' }
936
+ },
937
+ additionalProperties: false
938
+ };
939
+
940
+ // strictSchema: true(schema-dsl 扩展)
941
+ const schema2 = {
942
+ type: 'object',
943
+ properties: {
944
+ name: { type: 'string' }
945
+ },
946
+ strictSchema: true
947
+ };
948
+
949
+ // 功能相同,strictSchema 提供更友好的错误消息
950
+ ```
951
+
952
+ ---
953
+
954
+ ## Array 验证器
955
+
956
+ ### 11. noSparse - 禁止稀疏数组
957
+
958
+ **用途**: 不允许数组包含 undefined 元素(稀疏数组)
959
+
960
+ **参数**: `boolean` - true 表示启用验证
961
+
962
+ **错误消息**:
963
+ - 中文: "{{#label}}不能是稀疏数组"
964
+ - 英文: "{{#label}} must not be a sparse array"
965
+
966
+ **使用方法**:
967
+
968
+ ```javascript
969
+ // JSON Schema
970
+ const schema = {
971
+ type: 'object',
972
+ properties: {
973
+ items: {
974
+ type: 'array',
975
+ noSparse: true
976
+ }
977
+ }
978
+ };
979
+
980
+ // DSL 语法
981
+ const schema2 = dsl({
982
+ items: 'array!',
983
+ noSparse: true
984
+ });
985
+ ```
986
+
987
+ **验证示例**:
988
+
989
+ ```javascript
990
+ // ✅ 通过 - 密集数组
991
+ validate(schema, { items: [1, 2, 3] });
992
+ validate(schema, { items: ['a', 'b', 'c'] });
993
+ validate(schema, { items: [] }); // 空数组
994
+
995
+ // ❌ 失败 - 稀疏数组
996
+ const sparseArray = [1, , 3]; // 注意第2个元素是 empty slot
997
+ validate(schema, { items: sparseArray });
998
+ // { valid: false, errors: ['items不能是稀疏数组'], ... }
999
+
1000
+ // 创建稀疏数组的方式
1001
+ const sparse1 = new Array(5); // [empty × 5]
1002
+ const sparse2 = [1, 2];
1003
+ delete sparse2[1]; // [1, empty]
1004
+ ```
1005
+
1006
+ **应用场景**:
1007
+ - ✅ 数据完整性要求
1008
+ - ✅ 批量处理数据
1009
+ - ✅ 数据库批量插入
1010
+ - ✅ API 批量操作
1011
+ - ✅ 文件上传列表
1012
+
1013
+ **最佳实践**:
1014
+
1015
+ ```javascript
1016
+ // 批量创建用户
1017
+ const batchCreateSchema = dsl({
1018
+ users: 'array:1-100!',
1019
+ noSparse: true,
1020
+ items: {
1021
+ type: 'object',
1022
+ properties: {
1023
+ username: { type: 'string' },
1024
+ email: { type: 'string' }
1025
+ }
1026
+ }
1027
+ });
1028
+
1029
+ // 上传文件列表
1030
+ const uploadSchema = dsl({
1031
+ files: 'array:1-10!',
1032
+ noSparse: true,
1033
+ items: {
1034
+ type: 'object',
1035
+ properties: {
1036
+ name: { type: 'string' },
1037
+ size: { type: 'number' },
1038
+ type: { type: 'string' }
1039
+ }
1040
+ }
1041
+ });
1042
+ ```
1043
+
1044
+ **什么是稀疏数组**:
1045
+
1046
+ ```javascript
1047
+ // 密集数组(正常)
1048
+ const dense = [1, 2, 3];
1049
+ console.log(0 in dense); // true
1050
+ console.log(1 in dense); // true
1051
+ console.log(2 in dense); // true
1052
+
1053
+ // 稀疏数组(异常)
1054
+ const sparse = [1, , 3];
1055
+ console.log(0 in sparse); // true
1056
+ console.log(1 in sparse); // false ❌ empty slot
1057
+ console.log(2 in sparse); // true
1058
+
1059
+ // 影响
1060
+ sparse.forEach(x => console.log(x)); // 只输出 1, 3(跳过空位)
1061
+ console.log(sparse.length); // 3(长度不变)
1062
+ ```
1063
+
1064
+ ---
1065
+
1066
+ ### 12. includesRequired - 必须包含元素
1067
+
1068
+ **用途**: 数组必须包含指定的元素
1069
+
1070
+ **参数**: `array` - 必须包含的元素列表
1071
+
1072
+ **错误消息**:
1073
+ - 中文: "{{#label}}必须包含指定元素"
1074
+ - 英文: "{{#label}} must include required items"
1075
+
1076
+ **使用方法**:
1077
+
1078
+ ```javascript
1079
+ // JSON Schema
1080
+ const schema = {
1081
+ type: 'object',
1082
+ properties: {
1083
+ tags: {
1084
+ type: 'array',
1085
+ includesRequired: ['featured', 'published']
1086
+ }
1087
+ }
1088
+ };
1089
+
1090
+ // DSL 语法
1091
+ const schema2 = dsl({
1092
+ tags: 'array!',
1093
+ includesRequired: ['featured', 'published']
1094
+ });
1095
+ ```
1096
+
1097
+ **验证示例**:
1098
+
1099
+ ```javascript
1100
+ // ✅ 通过 - 包含所有必需元素
1101
+ validate(schema, {
1102
+ tags: ['featured', 'published', 'tech']
1103
+ });
1104
+
1105
+ validate(schema, {
1106
+ tags: ['published', 'featured'] // 顺序无关
1107
+ });
1108
+
1109
+ // ❌ 失败 - 缺少必需元素
1110
+ validate(schema, {
1111
+ tags: ['featured'] // 缺少 'published'
1112
+ });
1113
+ // { valid: false, errors: ['tags必须包含指定元素'], ... }
1114
+
1115
+ validate(schema, {
1116
+ tags: ['tech', 'news'] // 都缺少
1117
+ });
1118
+ ```
1119
+
1120
+ **应用场景**:
1121
+ - ✅ 文章标签验证(必须有分类标签)
1122
+ - ✅ 权限验证(必须包含基础权限)
1123
+ - ✅ 配置验证(必须包含关键配置)
1124
+ - ✅ 功能开关验证
1125
+ - ✅ 环境变量验证
1126
+
1127
+ **最佳实践**:
1128
+
1129
+ ```javascript
1130
+ // 文章发布 - 必须有分类和状态标签
1131
+ const articleSchema = dsl({
1132
+ tags: 'array:2-10!',
1133
+ includesRequired: ['category:*', 'status:published'] // * 表示任意分类
1134
+ });
1135
+
1136
+ // 用户权限 - 必须包含基础权限
1137
+ const userPermissionsSchema = dsl({
1138
+ permissions: 'array!',
1139
+ includesRequired: ['read', 'write'] // 基础权限
1140
+ });
1141
+
1142
+ // 部署环境 - 必须包含关键配置
1143
+ const deployConfigSchema = dsl({
1144
+ requiredEnvVars: 'array!',
1145
+ includesRequired: ['NODE_ENV', 'DATABASE_URL', 'SECRET_KEY']
1146
+ });
1147
+ ```
1148
+
1149
+ **对象元素匹配**:
1150
+
1151
+ ```javascript
1152
+ // 简单类型匹配(字符串、数字等)
1153
+ const schema1 = {
1154
+ items: {
1155
+ type: 'array',
1156
+ includesRequired: ['admin', 'user']
1157
+ }
1158
+ };
1159
+
1160
+ // 对象匹配(使用 JSON.stringify 比较)
1161
+ const schema2 = {
1162
+ items: {
1163
+ type: 'array',
1164
+ includesRequired: [
1165
+ { role: 'admin', level: 1 },
1166
+ { role: 'user', level: 0 }
1167
+ ]
1168
+ }
1169
+ };
1170
+
1171
+ validate(schema2, {
1172
+ items: [
1173
+ { role: 'admin', level: 1 },
1174
+ { role: 'user', level: 0 },
1175
+ { role: 'guest', level: -1 }
1176
+ ]
1177
+ }); // ✅ 通过
1178
+ ```
1179
+
1180
+ ---
1181
+
1182
+ ## Date 验证器
1183
+
1184
+ ### 13. dateFormat - 日期格式验证
1185
+
1186
+ **用途**: 验证字符串符合指定的日期格式
1187
+
1188
+ **参数**: `string` - 日期格式(支持5种)
1189
+
1190
+ **支持的格式**:
1191
+ - `YYYY-MM-DD`: 2025-12-31
1192
+ - `YYYY/MM/DD`: 2025/12/31
1193
+ - `DD-MM-YYYY`: 31-12-2025
1194
+ - `DD/MM/YYYY`: 31/12/2025
1195
+ - `ISO8601`: 2025-12-31T15:30:00.000Z
1196
+
1197
+ **错误消息**:
1198
+ - 中文: "{{#label}}日期格式不正确"
1199
+ - 英文: "{{#label}} date format is invalid"
1200
+
1201
+ **使用方法**:
1202
+
1203
+ ```javascript
1204
+ // JSON Schema
1205
+ const schema = {
1206
+ type: 'object',
1207
+ properties: {
1208
+ birthDate: {
1209
+ type: 'string',
1210
+ dateFormat: 'YYYY-MM-DD'
1211
+ }
1212
+ }
1213
+ };
1214
+
1215
+ // DSL 语法
1216
+ const schema2 = dsl({
1217
+ birthDate: 'string!',
1218
+ dateFormat: 'YYYY-MM-DD'
1219
+ });
1220
+ ```
1221
+
1222
+ **验证示例**:
1223
+
1224
+ ```javascript
1225
+ // ✅ 通过 - YYYY-MM-DD 格式
1226
+ validate(schema, { birthDate: '2025-12-31' });
1227
+ validate(schema, { birthDate: '1990-01-01' });
1228
+
1229
+ // ❌ 失败 - 格式不匹配
1230
+ validate(schema, { birthDate: '2025/12/31' }); // 使用了 /
1231
+ validate(schema, { birthDate: '31-12-2025' }); // DD-MM-YYYY 格式
1232
+ validate(schema, { birthDate: '2025-13-01' }); // 月份无效
1233
+ validate(schema, { birthDate: '2025-12-32' }); // 日期无效
1234
+
1235
+ // ISO8601 格式
1236
+ const isoSchema = dsl({
1237
+ createdAt: 'string!',
1238
+ dateFormat: 'ISO8601'
1239
+ });
1240
+
1241
+ validate(isoSchema, { createdAt: '2025-12-31T15:30:00.000Z' }); // ✅
1242
+ validate(isoSchema, { createdAt: '2025-12-31T15:30:00Z' }); // ✅
1243
+ ```
1244
+
1245
+ **应用场景**:
1246
+ - ✅ 生日验证 (YYYY-MM-DD)
1247
+ - ✅ 预约日期 (DD/MM/YYYY)
1248
+ - ✅ API 时间戳 (ISO8601)
1249
+ - ✅ 日志时间 (ISO8601)
1250
+ - ✅ 数据库日期字段
1251
+
1252
+ **最佳实践**:
1253
+
1254
+ ```javascript
1255
+ // 生日场景 - 带范围验证
1256
+ const birthDateSchema = dsl({
1257
+ birthDate: 'string!',
1258
+ dateFormat: 'YYYY-MM-DD'
1259
+ // 可结合 dateGreater/dateLess 验证年龄范围
1260
+ });
1261
+
1262
+ // API 时间戳 - ISO8601
1263
+ const timestampSchema = dsl({
1264
+ createdAt: 'string!',
1265
+ dateFormat: 'ISO8601',
1266
+ updatedAt: 'string',
1267
+ dateFormat: 'ISO8601'
1268
+ });
1269
+
1270
+ // 国际化日期 - 欧洲格式
1271
+ const europeDateSchema = dsl({
1272
+ date: 'string!',
1273
+ dateFormat: 'DD/MM/YYYY'
1274
+ });
1275
+
1276
+ // 中国日期格式
1277
+ const chinaDateSchema = dsl({
1278
+ date: 'string!',
1279
+ dateFormat: 'YYYY-MM-DD' // 或 YYYY/MM/DD
1280
+ });
1281
+ ```
1282
+
1283
+ **格式选择建议**:
1284
+ - 📅 **YYYY-MM-DD**: 推荐(ISO 8601标准,数据库友好)
1285
+ - 📅 **ISO8601**: API 和日志场景
1286
+ - 📅 **DD/MM/YYYY**: 欧洲用户
1287
+ - 📅 **MM/DD/YYYY**: 美国用户(需自定义)
1288
+
1289
+ ---
1290
+
1291
+ ### 14. dateGreater - 日期大于
1292
+
1293
+ **用途**: 验证日期必须大于(晚于)指定日期
1294
+
1295
+ **参数**: `string` - 对比日期(ISO 8601 格式)
1296
+
1297
+ **错误消息**:
1298
+ - 中文: "{{#label}}必须晚于{{#limit}}"
1299
+ - 英文: "{{#label}} must be after {{#limit}}"
1300
+
1301
+ **使用方法**:
1302
+
1303
+ ```javascript
1304
+ // JSON Schema
1305
+ const schema = {
1306
+ type: 'object',
1307
+ properties: {
1308
+ endDate: {
1309
+ type: 'string',
1310
+ dateGreater: '2025-01-01'
1311
+ }
1312
+ }
1313
+ };
1314
+
1315
+ // DSL 语法
1316
+ const schema2 = dsl({
1317
+ endDate: 'string!',
1318
+ dateGreater: '2025-01-01'
1319
+ });
1320
+ ```
1321
+
1322
+ **验证示例**:
1323
+
1324
+ ```javascript
1325
+ // ✅ 通过 - 日期在指定日期之后
1326
+ validate(schema, { endDate: '2025-12-31' });
1327
+ validate(schema, { endDate: '2026-01-01' });
1328
+
1329
+ // ❌ 失败 - 日期在指定日期之前或相等
1330
+ validate(schema, { endDate: '2025-01-01' }); // 相等
1331
+ // { valid: false, errors: ['endDate必须晚于2025-01-01'], ... }
1332
+
1333
+ validate(schema, { endDate: '2024-12-31' }); // 更早
1334
+
1335
+ // ❌ 失败 - 无效日期
1336
+ validate(schema, { endDate: 'invalid-date' });
1337
+ ```
1338
+
1339
+ **应用场景**:
1340
+ - ✅ 结束日期必须晚于开始日期
1341
+ - ✅ 预约日期必须是未来
1342
+ - ✅ 过期时间验证
1343
+ - ✅ 活动时间范围
1344
+ - ✅ 会员有效期
1345
+
1346
+ **最佳实践**:
1347
+
1348
+ ```javascript
1349
+ // 活动时间范围验证
1350
+ const eventSchema = dsl({
1351
+ startDate: 'string!',
1352
+ dateGreater: new Date().toISOString(), // 必须是未来
1353
+ endDate: 'string!',
1354
+ dateGreater: '${startDate}' // 动态引用(需自行处理)
1355
+ });
1356
+
1357
+ // 会员有效期
1358
+ const membershipSchema = dsl({
1359
+ expireDate: 'string!',
1360
+ dateGreater: new Date().toISOString() // 未过期
1361
+ });
1362
+
1363
+ // 预约系统 - 至少提前1天
1364
+ const bookingSchema = {
1365
+ type: 'object',
1366
+ properties: {
1367
+ bookingDate: {
1368
+ type: 'string',
1369
+ dateGreater: new Date(Date.now() + 86400000).toISOString() // 明天
1370
+ }
1371
+ }
1372
+ };
1373
+ ```
1374
+
1375
+ **动态日期验证**:
1376
+
1377
+ ```javascript
1378
+ // 动态验证 - 结束日期必须晚于开始日期
1379
+ function validateDateRange(data) {
1380
+ // 先验证基础格式
1381
+ const schema = dsl({
1382
+ startDate: 'string!',
1383
+ endDate: 'string!'
1384
+ });
1385
+
1386
+ const result = validate(schema, data);
1387
+ if (!result.valid) return result;
1388
+
1389
+ // 再验证日期范围
1390
+ const rangeSchema = {
1391
+ type: 'object',
1392
+ properties: {
1393
+ endDate: {
1394
+ type: 'string',
1395
+ dateGreater: data.startDate
1396
+ }
1397
+ }
1398
+ };
1399
+
1400
+ return validate(rangeSchema, data);
1401
+ }
1402
+ ```
1403
+
1404
+ ---
1405
+
1406
+ ### 15. dateLess - 日期小于
1407
+
1408
+ **用途**: 验证日期必须小于(早于)指定日期
1409
+
1410
+ **参数**: `string` - 对比日期(ISO 8601 格式)
1411
+
1412
+ **错误消息**:
1413
+ - 中文: "{{#label}}必须早于{{#limit}}"
1414
+ - 英文: "{{#label}} must be before {{#limit}}"
1415
+
1416
+ **使用方法**:
1417
+
1418
+ ```javascript
1419
+ // JSON Schema
1420
+ const schema = {
1421
+ type: 'object',
1422
+ properties: {
1423
+ startDate: {
1424
+ type: 'string',
1425
+ dateLess: '2025-12-31'
1426
+ }
1427
+ }
1428
+ };
1429
+
1430
+ // DSL 语法
1431
+ const schema2 = dsl({
1432
+ startDate: 'string!',
1433
+ dateLess: '2025-12-31'
1434
+ });
1435
+ ```
1436
+
1437
+ **验证示例**:
1438
+
1439
+ ```javascript
1440
+ // ✅ 通过 - 日期在指定日期之前
1441
+ validate(schema, { startDate: '2025-01-01' });
1442
+ validate(schema, { startDate: '2024-12-31' });
1443
+
1444
+ // ❌ 失败 - 日期在指定日期之后或相等
1445
+ validate(schema, { startDate: '2025-12-31' }); // 相等
1446
+ // { valid: false, errors: ['startDate必须早于2025-12-31'], ... }
1447
+
1448
+ validate(schema, { startDate: '2026-01-01' }); // 更晚
1449
+
1450
+ // ❌ 失败 - 无效日期
1451
+ validate(schema, { startDate: 'invalid-date' });
1452
+ ```
1453
+
1454
+ **应用场景**:
1455
+ - ✅ 开始日期必须早于结束日期
1456
+ - ✅ 历史数据验证
1457
+ - ✅ 出生日期(必须是过去)
1458
+ - ✅ 活动报名截止
1459
+ - ✅ 优惠券使用期限
1460
+
1461
+ **最佳实践**:
1462
+
1463
+ ```javascript
1464
+ // 出生日期 - 必须是过去
1465
+ const birthDateSchema = dsl({
1466
+ birthDate: 'string!',
1467
+ dateFormat: 'YYYY-MM-DD',
1468
+ dateLess: new Date().toISOString() // 今天之前
1469
+ });
1470
+
1471
+ // 活动报名 - 截止日期前
1472
+ const registrationSchema = dsl({
1473
+ registrationDate: 'string!',
1474
+ dateLess: '2025-12-31T23:59:59Z' // 截止时间
1475
+ });
1476
+
1477
+ // 历史记录 - 不能是未来
1478
+ const historySchema = dsl({
1479
+ recordDate: 'string!',
1480
+ dateLess: new Date().toISOString()
1481
+ });
1482
+
1483
+ // 促销活动 - 开始日期必须早于结束日期
1484
+ const promotionSchema = {
1485
+ type: 'object',
1486
+ properties: {
1487
+ startDate: {
1488
+ type: 'string',
1489
+ dateLess: '${endDate}' // 动态引用(需自行处理)
1490
+ },
1491
+ endDate: {
1492
+ type: 'string'
1493
+ }
1494
+ }
1495
+ };
1496
+ ```
1497
+
1498
+ **组合使用 dateGreater 和 dateLess**:
1499
+
1500
+ ```javascript
1501
+ // 日期范围验证 - 必须在某个时间段内
1502
+ const dateRangeSchema = dsl({
1503
+ date: 'string!',
1504
+ dateGreater: '2025-01-01', // 必须晚于 2025-01-01
1505
+ dateLess: '2025-12-31' // 必须早于 2025-12-31
1506
+ });
1507
+
1508
+ // 验证
1509
+ validate(dateRangeSchema, { date: '2025-06-15' }); // ✅ 通过
1510
+ validate(dateRangeSchema, { date: '2024-12-31' }); // ❌ 失败(太早)
1511
+ validate(dateRangeSchema, { date: '2026-01-01' }); // ❌ 失败(太晚)
1512
+ ```
1513
+
1514
+ ---
1515
+
1516
+ ## 📝 使用技巧
1517
+
1518
+ ### 组合使用多个验证器
1519
+
1520
+ ```javascript
1521
+ // 用户名 - 3-20位字母数字
1522
+ const usernameSchema = dsl({
1523
+ username: 'string:3-20!',
1524
+ alphanum: true,
1525
+ lowercase: true,
1526
+ trim: true
1527
+ });
1528
+
1529
+ // 产品编码 - 6位大写字母数字
1530
+ const productCodeSchema = dsl({
1531
+ code: 'string!',
1532
+ exactLength: 6,
1533
+ alphanum: true,
1534
+ uppercase: true
1535
+ });
1536
+
1537
+ // 价格 - 正数,2位小数,最大100万
1538
+ const priceSchema = dsl({
1539
+ price: 'number:0.01-1000000!',
1540
+ precision: 2
1541
+ });
1542
+
1543
+ // 严格的配置对象
1544
+ const strictConfigSchema = dsl({
1545
+ host: 'string!',
1546
+ port: 'integer!',
1547
+ port: true,
1548
+ database: 'string!',
1549
+ _requiredAll: true,
1550
+ _strictSchema: true
1551
+ });
1552
+ ```
1553
+
1554
+ ### 错误消息国际化
1555
+
1556
+ ```javascript
1557
+ const { dsl, validate, Locale } = require('schema-dsl');
1558
+
1559
+ // 切换到英文
1560
+ Locale.setLocale('en-US');
1561
+
1562
+ const schema = dsl({
1563
+ code: 'string!',
1564
+ exactLength: 6
1565
+ });
1566
+
1567
+ validate(schema, { code: 'ABC12' });
1568
+ // { valid: false, errors: ['code length must be exactly 6 characters'], ... }
1569
+
1570
+ // 切换回中文
1571
+ Locale.setLocale('zh-CN');
1572
+
1573
+ validate(schema, { code: 'ABC12' });
1574
+ // { valid: false, errors: ['code长度必须是6个字符'], ... }
1575
+ ```
1576
+
1577
+ ---
1578
+
1579
+ ## 🔗 相关文档
1580
+
1581
+ - [完整验证规则参考](./validation-rules-complete.md)
1582
+ - [Pattern 验证器使用指南](./pattern-validators.md)
1583
+ - [自定义验证指南](./custom-validation.md)
1584
+ - [API 参考](./api-reference.md)
1585
+ - [DSL 语法](./dsl-syntax.md)
1586
+
1587
+ ---
1588
+
1589
+ ## 📞 反馈与支持
1590
+
1591
+ 如果您发现文档有误或有改进建议,欢迎:
1592
+ - 提交 [Issue](https://github.com/vextjs/schema-dsl/issues)
1593
+ - 发起 [Pull Request](https://github.com/vextjs/schema-dsl/pulls)
1594
+ - 加入讨论组
1595
+
1596
+ ---
1597
+
1598
+ **文档版本**: v1.0.2
1599
+ **最后更新**: 2025-12-31
1600
+ **维护者**: schema-dsl 开发团队
1601
+