schema-dsl 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +135 -33
- package/docs/i18n.md +3 -3
- package/docs/performance-benchmark-report.md +1 -1
- package/docs/typescript-guide.md +2 -2
- package/docs/validate-async.md +1 -1
- package/docs/validation-rules-v1.0.2.md +10 -3
- package/index.d.ts +750 -21
- package/index.js +31 -88
- package/lib/core/Validator.js +12 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -96,6 +96,8 @@ validate(schema, data, { locale: 'en-US' });
|
|
|
96
96
|
**一份定义,多处使用**
|
|
97
97
|
|
|
98
98
|
```javascript
|
|
99
|
+
const { dsl, exporters } = require('schema-dsl');
|
|
100
|
+
|
|
99
101
|
const schema = dsl({
|
|
100
102
|
username: 'string:3-32!',
|
|
101
103
|
email: 'email!',
|
|
@@ -103,13 +105,16 @@ const schema = dsl({
|
|
|
103
105
|
});
|
|
104
106
|
|
|
105
107
|
// 导出 MongoDB Schema
|
|
106
|
-
|
|
108
|
+
const mongoExporter = new exporters.MongoDBExporter();
|
|
109
|
+
const mongoSchema = mongoExporter.export(schema);
|
|
107
110
|
|
|
108
111
|
// 导出 MySQL 建表语句
|
|
109
|
-
|
|
112
|
+
const mysqlExporter = new exporters.MySQLExporter();
|
|
113
|
+
const mysqlDDL = mysqlExporter.export('users', schema);
|
|
110
114
|
|
|
111
115
|
// 导出 PostgreSQL 建表语句
|
|
112
|
-
|
|
116
|
+
const pgExporter = new exporters.PostgreSQLExporter();
|
|
117
|
+
const pgDDL = pgExporter.export('users', schema);
|
|
113
118
|
```
|
|
114
119
|
|
|
115
120
|
**✅ 独家功能**:从验证规则直接生成数据库结构!
|
|
@@ -525,17 +530,82 @@ dsl({
|
|
|
525
530
|
email: 'email!'.label('用户邮箱'),
|
|
526
531
|
|
|
527
532
|
// 字段描述
|
|
528
|
-
bio: 'string:10-500'.description('用户简介,10-500字符')
|
|
533
|
+
bio: 'string:10-500'.description('用户简介,10-500字符')
|
|
534
|
+
})
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### 条件验证 - dsl.match 和 dsl.if
|
|
538
|
+
|
|
539
|
+
**根据其他字段的值动态决定验证规则**
|
|
540
|
+
|
|
541
|
+
```javascript
|
|
542
|
+
const { dsl } = require('schema-dsl');
|
|
543
|
+
|
|
544
|
+
// 1. dsl.match - 根据字段值匹配不同规则(类似 switch-case)
|
|
545
|
+
const contactSchema = dsl({
|
|
546
|
+
contactType: 'email|phone|wechat',
|
|
529
547
|
|
|
530
|
-
//
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
548
|
+
// 根据 contactType 的值决定 contact 字段的验证规则
|
|
549
|
+
contact: dsl.match('contactType', {
|
|
550
|
+
email: 'email!', // contactType='email' 时验证邮箱格式
|
|
551
|
+
phone: 'string:11!', // contactType='phone' 时验证11位手机号
|
|
552
|
+
wechat: 'string:6-20!', // contactType='wechat' 时验证微信号
|
|
553
|
+
_default: 'string' // 默认规则(可选)
|
|
535
554
|
})
|
|
536
|
-
})
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
// ✅ 验证通过
|
|
558
|
+
validate(contactSchema, { contactType: 'email', contact: 'user@example.com' });
|
|
559
|
+
validate(contactSchema, { contactType: 'phone', contact: '13800138000' });
|
|
560
|
+
|
|
561
|
+
// ❌ 验证失败
|
|
562
|
+
validate(contactSchema, { contactType: 'email', contact: 'invalid' });
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
// 2. dsl.if - 简单条件分支(类似 if-else)
|
|
566
|
+
const vipSchema = dsl({
|
|
567
|
+
isVip: 'boolean!',
|
|
568
|
+
|
|
569
|
+
// 如果是 VIP,折扣必须在 10-50 之间;否则在 0-10 之间
|
|
570
|
+
discount: dsl.if('isVip', 'number:10-50!', 'number:0-10')
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// ✅ VIP 用户
|
|
574
|
+
validate(vipSchema, { isVip: true, discount: 30 });
|
|
575
|
+
|
|
576
|
+
// ❌ 非 VIP 用户折扣超过 10
|
|
577
|
+
validate(vipSchema, { isVip: false, discount: 15 });
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
// 3. 实际应用场景:订单验证
|
|
581
|
+
const orderSchema = dsl({
|
|
582
|
+
paymentMethod: 'alipay|wechat|card|cod', // cod = 货到付款
|
|
583
|
+
|
|
584
|
+
// 根据支付方式决定支付信息格式
|
|
585
|
+
paymentInfo: dsl.match('paymentMethod', {
|
|
586
|
+
alipay: 'email!', // 支付宝:邮箱
|
|
587
|
+
wechat: 'string:20-30', // 微信:支付串
|
|
588
|
+
card: 'string:16-19', // 银行卡:卡号
|
|
589
|
+
cod: 'string:0-0', // 货到付款:无需支付信息
|
|
590
|
+
_default: 'string'
|
|
591
|
+
}),
|
|
592
|
+
|
|
593
|
+
// 货到付款需要详细地址
|
|
594
|
+
address: dsl.if('paymentMethod',
|
|
595
|
+
'string:10-200!', // cod = 货到付款时地址必填
|
|
596
|
+
'string:10-200' // 其他支付方式地址可选
|
|
597
|
+
)
|
|
598
|
+
});
|
|
537
599
|
```
|
|
538
600
|
|
|
601
|
+
**💡 使用场景**:
|
|
602
|
+
- ✅ 多种联系方式验证(邮箱/手机/微信)
|
|
603
|
+
- ✅ VIP 和普通用户不同的折扣范围
|
|
604
|
+
- ✅ 不同支付方式的支付信息格式
|
|
605
|
+
- ✅ 根据用户类型决定必填字段
|
|
606
|
+
|
|
607
|
+
**查看完整示例**: [examples/dsl-match-example.js](./examples/dsl-match-example.js)
|
|
608
|
+
|
|
539
609
|
---
|
|
540
610
|
|
|
541
611
|
## 🔧 核心功能
|
|
@@ -653,32 +723,36 @@ const markdown = exporters.MarkdownExporter.export(userSchema, {
|
|
|
653
723
|
### 4. 多语言支持
|
|
654
724
|
|
|
655
725
|
```javascript
|
|
656
|
-
const { dsl,
|
|
726
|
+
const { dsl, validate } = require('schema-dsl');
|
|
727
|
+
const path = require('path');
|
|
728
|
+
|
|
729
|
+
// 方式 1: 从目录加载语言包(推荐)
|
|
730
|
+
dsl.config({
|
|
731
|
+
i18n: path.join(__dirname, 'i18n/dsl') // 直接传字符串路径
|
|
732
|
+
});
|
|
657
733
|
|
|
658
|
-
//
|
|
734
|
+
// 方式 2: 直接传入语言包对象
|
|
659
735
|
dsl.config({
|
|
660
736
|
i18n: {
|
|
661
|
-
|
|
662
|
-
'
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
'
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
'string.min': '{{#label}} must be at least {{#limit}} characters'
|
|
673
|
-
}
|
|
737
|
+
'zh-CN': {
|
|
738
|
+
'label.username': '用户名',
|
|
739
|
+
'label.email': '邮箱地址',
|
|
740
|
+
'required': '{{#label}}不能为空',
|
|
741
|
+
'string.min': '{{#label}}长度不能少于{{#limit}}个字符'
|
|
742
|
+
},
|
|
743
|
+
'en-US': {
|
|
744
|
+
'label.username': 'Username',
|
|
745
|
+
'label.email': 'Email Address',
|
|
746
|
+
'required': '{{#label}} is required',
|
|
747
|
+
'string.min': '{{#label}} must be at least {{#limit}} characters'
|
|
674
748
|
}
|
|
675
749
|
}
|
|
676
750
|
});
|
|
677
751
|
|
|
678
752
|
// 使用 Label Key
|
|
679
753
|
const schema = dsl({
|
|
680
|
-
username: 'string:3-32!'.label('label.username'),
|
|
681
|
-
email: 'email!'.label('label.email')
|
|
754
|
+
username: dsl('string:3-32!').label('label.username'),
|
|
755
|
+
email: dsl('email!').label('label.email')
|
|
682
756
|
});
|
|
683
757
|
|
|
684
758
|
// 验证时指定语言
|
|
@@ -687,16 +761,44 @@ const result1 = validate(schema, data, { locale: 'zh-CN' });
|
|
|
687
761
|
|
|
688
762
|
const result2 = validate(schema, data, { locale: 'en-US' });
|
|
689
763
|
// 错误消息:Username must be at least 3 characters
|
|
764
|
+
```
|
|
690
765
|
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
766
|
+
### 5. 缓存配置 (v1.0.4+)
|
|
767
|
+
|
|
768
|
+
```javascript
|
|
769
|
+
const { dsl, config } = require('schema-dsl');
|
|
770
|
+
|
|
771
|
+
// 配置缓存选项(推荐在使用 DSL 之前调用)
|
|
772
|
+
config({
|
|
773
|
+
cache: {
|
|
774
|
+
maxSize: 1000, // 最大缓存条目数(默认:100)
|
|
775
|
+
ttl: 7200000, // 缓存过期时间(毫秒,默认:3600000,即1小时)
|
|
776
|
+
enabled: true, // 是否启用缓存(默认:true)
|
|
777
|
+
statsEnabled: true // 是否启用统计(默认:true)
|
|
695
778
|
}
|
|
696
779
|
});
|
|
780
|
+
|
|
781
|
+
// 之后创建的 Schema 将使用新的缓存配置
|
|
782
|
+
const schema = dsl({ name: 'string!' });
|
|
783
|
+
|
|
784
|
+
// 也可以在 Validator 创建后动态修改配置(向后兼容)
|
|
785
|
+
const { getDefaultValidator } = require('schema-dsl');
|
|
786
|
+
const validator = getDefaultValidator();
|
|
787
|
+
console.log('当前缓存配置:', validator.cache.options);
|
|
788
|
+
|
|
789
|
+
// 动态修改
|
|
790
|
+
config({
|
|
791
|
+
cache: { maxSize: 5000 } // 只修改某个参数
|
|
792
|
+
});
|
|
697
793
|
```
|
|
698
794
|
|
|
699
|
-
|
|
795
|
+
**缓存说明**:
|
|
796
|
+
- Schema 编译结果会被缓存以提高性能
|
|
797
|
+
- 使用 LRU(最近最少使用)淘汰策略
|
|
798
|
+
- 支持 TTL(生存时间)自动过期
|
|
799
|
+
- 可通过 `validator.cache.getStats()` 查看缓存统计信息
|
|
800
|
+
|
|
801
|
+
### 6. 插件系统
|
|
700
802
|
|
|
701
803
|
```javascript
|
|
702
804
|
const { PluginManager } = require('schema-dsl');
|
|
@@ -748,7 +850,7 @@ const schema = dsl({
|
|
|
748
850
|
});
|
|
749
851
|
```
|
|
750
852
|
|
|
751
|
-
###
|
|
853
|
+
### 7. 错误处理
|
|
752
854
|
|
|
753
855
|
```javascript
|
|
754
856
|
const { validate, ValidationError } = require('schema-dsl');
|
package/docs/i18n.md
CHANGED
|
@@ -19,12 +19,12 @@ schema-dsl 支持完整的多语言功能,允许你自定义字段标签和错
|
|
|
19
19
|
const { dsl, validate } = require('schema-dsl');
|
|
20
20
|
const path = require('path');
|
|
21
21
|
|
|
22
|
-
// 方式 1: 从目录加载(推荐)
|
|
22
|
+
// ✅ 方式 1: 从目录加载(推荐)
|
|
23
23
|
dsl.config({
|
|
24
|
-
i18n: path.join(__dirname, 'i18n/dsl')
|
|
24
|
+
i18n: path.join(__dirname, 'i18n/dsl') // 直接传字符串路径
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
// 方式 2: 直接传入对象
|
|
27
|
+
// ✅ 方式 2: 直接传入对象
|
|
28
28
|
dsl.config({
|
|
29
29
|
i18n: {
|
|
30
30
|
'zh-CN': require('./i18n/dsl/zh-CN'),
|
package/docs/typescript-guide.md
CHANGED
package/docs/validate-async.md
CHANGED
|
@@ -61,10 +61,17 @@ const schema = {
|
|
|
61
61
|
}
|
|
62
62
|
};
|
|
63
63
|
|
|
64
|
-
// 方式2: DSL 语法
|
|
64
|
+
// 方式2: DSL 语法 + 约束(v1.0.3+)
|
|
65
65
|
const schema2 = dsl({
|
|
66
|
-
code: 'string!'
|
|
67
|
-
|
|
66
|
+
code: 'string:6!' // 精确长度 6
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// 方式3: 链式调用 JSON Schema
|
|
70
|
+
const schema3 = dsl({
|
|
71
|
+
code: {
|
|
72
|
+
type: 'string',
|
|
73
|
+
exactLength: 6
|
|
74
|
+
}
|
|
68
75
|
});
|
|
69
76
|
```
|
|
70
77
|
|
package/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Type definitions for schema-dsl v1.0.
|
|
1
|
+
// Type definitions for schema-dsl v1.0.4
|
|
2
2
|
// Project: https://github.com/vextjs/schema-dsl
|
|
3
3
|
// Definitions by: schema-dsl Team
|
|
4
4
|
|
|
@@ -405,6 +405,381 @@ declare module 'schema-dsl' {
|
|
|
405
405
|
* ```
|
|
406
406
|
*/
|
|
407
407
|
phone(country?: 'cn' | 'us' | 'uk' | 'hk' | 'tw' | 'international'): this;
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* 设置格式
|
|
411
|
+
* @param format - 格式名称 (email, url, uuid, date, date-time, time, ipv4, ipv6等)
|
|
412
|
+
* @returns 当前实例(支持链式调用)
|
|
413
|
+
*
|
|
414
|
+
* @example
|
|
415
|
+
* ```typescript
|
|
416
|
+
* builder.format('email');
|
|
417
|
+
* builder.format('uuid');
|
|
418
|
+
* builder.format('date-time');
|
|
419
|
+
* ```
|
|
420
|
+
*/
|
|
421
|
+
format(format: string): this;
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* 手机号别名(phoneNumber是phone的别名)
|
|
425
|
+
* @param country - 国家代码
|
|
426
|
+
* @returns 当前实例(支持链式调用)
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* ```typescript
|
|
430
|
+
* builder.phoneNumber('cn'); // 等同于 phone('cn')
|
|
431
|
+
* ```
|
|
432
|
+
*/
|
|
433
|
+
phoneNumber(country?: 'cn' | 'us' | 'uk' | 'hk' | 'tw' | 'international'): this;
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* 身份证验证
|
|
437
|
+
* @param country - 国家代码(目前仅支持 'cn')
|
|
438
|
+
* @returns 当前实例(支持链式调用)
|
|
439
|
+
*
|
|
440
|
+
* @example
|
|
441
|
+
* ```typescript
|
|
442
|
+
* builder.idCard('cn'); // 中国身份证18位
|
|
443
|
+
* ```
|
|
444
|
+
*/
|
|
445
|
+
idCard(country?: 'cn'): this;
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* URL Slug 验证(只能包含小写字母、数字和连字符)
|
|
449
|
+
* @returns 当前实例(支持链式调用)
|
|
450
|
+
*
|
|
451
|
+
* @example
|
|
452
|
+
* ```typescript
|
|
453
|
+
* builder.slug(); // my-blog-post, hello-world-123
|
|
454
|
+
* ```
|
|
455
|
+
*/
|
|
456
|
+
slug(): this;
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* 信用卡验证
|
|
460
|
+
* @param type - 卡类型
|
|
461
|
+
* @returns 当前实例(支持链式调用)
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* ```typescript
|
|
465
|
+
* builder.creditCard('visa');
|
|
466
|
+
* builder.creditCard('mastercard');
|
|
467
|
+
* builder.creditCard('amex');
|
|
468
|
+
* ```
|
|
469
|
+
*/
|
|
470
|
+
creditCard(type?: 'visa' | 'mastercard' | 'amex' | 'discover' | 'jcb' | 'unionpay'): this;
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* 车牌号验证
|
|
474
|
+
* @param country - 国家代码
|
|
475
|
+
* @returns 当前实例(支持链式调用)
|
|
476
|
+
*
|
|
477
|
+
* @example
|
|
478
|
+
* ```typescript
|
|
479
|
+
* builder.licensePlate('cn'); // 中国车牌号
|
|
480
|
+
* ```
|
|
481
|
+
*/
|
|
482
|
+
licensePlate(country?: 'cn' | 'us' | 'uk'): this;
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* 邮政编码验证
|
|
486
|
+
* @param country - 国家代码
|
|
487
|
+
* @returns 当前实例(支持链式调用)
|
|
488
|
+
*
|
|
489
|
+
* @example
|
|
490
|
+
* ```typescript
|
|
491
|
+
* builder.postalCode('cn'); // 中国邮政编码6位
|
|
492
|
+
* builder.postalCode('us'); // 美国邮政编码
|
|
493
|
+
* ```
|
|
494
|
+
*/
|
|
495
|
+
postalCode(country?: 'cn' | 'us' | 'uk'): this;
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* 护照号码验证
|
|
499
|
+
* @param country - 国家代码
|
|
500
|
+
* @returns 当前实例(支持链式调用)
|
|
501
|
+
*
|
|
502
|
+
* @example
|
|
503
|
+
* ```typescript
|
|
504
|
+
* builder.passport('cn'); // 中国护照号
|
|
505
|
+
* ```
|
|
506
|
+
*/
|
|
507
|
+
passport(country?: 'cn' | 'us' | 'uk'): this;
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* String 最小长度(使用AJV原生minLength)
|
|
511
|
+
* @param n - 最小长度
|
|
512
|
+
* @returns 当前实例(支持链式调用)
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* ```typescript
|
|
516
|
+
* dsl('string!').min(3); // 最少3个字符
|
|
517
|
+
* ```
|
|
518
|
+
*/
|
|
519
|
+
min(n: number): this;
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* String 最大长度(使用AJV原生maxLength)
|
|
523
|
+
* @param n - 最大长度
|
|
524
|
+
* @returns 当前实例(支持链式调用)
|
|
525
|
+
*
|
|
526
|
+
* @example
|
|
527
|
+
* ```typescript
|
|
528
|
+
* dsl('string!').max(32); // 最多32个字符
|
|
529
|
+
* ```
|
|
530
|
+
*/
|
|
531
|
+
max(n: number): this;
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* String 精确长度
|
|
535
|
+
* @param n - 精确长度
|
|
536
|
+
* @returns 当前实例(支持链式调用)
|
|
537
|
+
*
|
|
538
|
+
* @example
|
|
539
|
+
* ```typescript
|
|
540
|
+
* dsl('string!').length(11); // 必须是11个字符
|
|
541
|
+
* ```
|
|
542
|
+
*/
|
|
543
|
+
length(n: number): this;
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* String 只能包含字母和数字
|
|
547
|
+
* @returns 当前实例(支持链式调用)
|
|
548
|
+
*
|
|
549
|
+
* @example
|
|
550
|
+
* ```typescript
|
|
551
|
+
* dsl('string!').alphanum(); // 只能是字母和数字
|
|
552
|
+
* ```
|
|
553
|
+
*/
|
|
554
|
+
alphanum(): this;
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* String 不能包含前后空格
|
|
558
|
+
* @returns 当前实例(支持链式调用)
|
|
559
|
+
*
|
|
560
|
+
* @example
|
|
561
|
+
* ```typescript
|
|
562
|
+
* dsl('string!').trim(); // 不能有前后空格
|
|
563
|
+
* ```
|
|
564
|
+
*/
|
|
565
|
+
trim(): this;
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* String 必须是小写
|
|
569
|
+
* @returns 当前实例(支持链式调用)
|
|
570
|
+
*
|
|
571
|
+
* @example
|
|
572
|
+
* ```typescript
|
|
573
|
+
* dsl('string!').lowercase(); // 必须全小写
|
|
574
|
+
* ```
|
|
575
|
+
*/
|
|
576
|
+
lowercase(): this;
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* String 必须是大写
|
|
580
|
+
* @returns 当前实例(支持链式调用)
|
|
581
|
+
*
|
|
582
|
+
* @example
|
|
583
|
+
* ```typescript
|
|
584
|
+
* dsl('string!').uppercase(); // 必须全大写
|
|
585
|
+
* ```
|
|
586
|
+
*/
|
|
587
|
+
uppercase(): this;
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Number 小数位数限制
|
|
591
|
+
* @param n - 最大小数位数
|
|
592
|
+
* @returns 当前实例(支持链式调用)
|
|
593
|
+
*
|
|
594
|
+
* @example
|
|
595
|
+
* ```typescript
|
|
596
|
+
* dsl('number!').precision(2); // 最多2位小数
|
|
597
|
+
* ```
|
|
598
|
+
*/
|
|
599
|
+
precision(n: number): this;
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* Number 倍数验证(使用AJV原生multipleOf)
|
|
603
|
+
* @param n - 必须是此数的倍数
|
|
604
|
+
* @returns 当前实例(支持链式调用)
|
|
605
|
+
*
|
|
606
|
+
* @example
|
|
607
|
+
* ```typescript
|
|
608
|
+
* dsl('number!').multiple(5); // 必须是5的倍数
|
|
609
|
+
* ```
|
|
610
|
+
*/
|
|
611
|
+
multiple(n: number): this;
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Number 端口号验证(1-65535)
|
|
615
|
+
* @returns 当前实例(支持链式调用)
|
|
616
|
+
*
|
|
617
|
+
* @example
|
|
618
|
+
* ```typescript
|
|
619
|
+
* dsl('integer!').port(); // 必须是有效端口号
|
|
620
|
+
* ```
|
|
621
|
+
*/
|
|
622
|
+
port(): this;
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Object 要求所有属性都必须存在
|
|
626
|
+
* @returns 当前实例(支持链式调用)
|
|
627
|
+
*
|
|
628
|
+
* @example
|
|
629
|
+
* ```typescript
|
|
630
|
+
* dsl({ name: 'string', age: 'number' }).requireAll();
|
|
631
|
+
* ```
|
|
632
|
+
*/
|
|
633
|
+
requireAll(): this;
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Object 严格模式,不允许额外属性
|
|
637
|
+
* @returns 当前实例(支持链式调用)
|
|
638
|
+
*
|
|
639
|
+
* @example
|
|
640
|
+
* ```typescript
|
|
641
|
+
* dsl({ name: 'string!' }).strict();
|
|
642
|
+
* ```
|
|
643
|
+
*/
|
|
644
|
+
strict(): this;
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Array 不允许稀疏数组
|
|
648
|
+
* @returns 当前实例(支持链式调用)
|
|
649
|
+
*
|
|
650
|
+
* @example
|
|
651
|
+
* ```typescript
|
|
652
|
+
* dsl('array<string>').noSparse();
|
|
653
|
+
* ```
|
|
654
|
+
*/
|
|
655
|
+
noSparse(): this;
|
|
656
|
+
|
|
657
|
+
/**
|
|
658
|
+
* Array 必须包含指定元素
|
|
659
|
+
* @param items - 必须包含的元素数组
|
|
660
|
+
* @returns 当前实例(支持链式调用)
|
|
661
|
+
*
|
|
662
|
+
* @example
|
|
663
|
+
* ```typescript
|
|
664
|
+
* dsl('array<string>').includesRequired(['admin', 'user']);
|
|
665
|
+
* ```
|
|
666
|
+
*/
|
|
667
|
+
includesRequired(items: any[]): this;
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Date 自定义日期格式验证
|
|
671
|
+
* @param fmt - 日期格式(YYYY-MM-DD, YYYY/MM/DD, DD-MM-YYYY, DD/MM/YYYY, ISO8601)
|
|
672
|
+
* @returns 当前实例(支持链式调用)
|
|
673
|
+
*
|
|
674
|
+
* @example
|
|
675
|
+
* ```typescript
|
|
676
|
+
* dsl('string!').dateFormat('YYYY-MM-DD');
|
|
677
|
+
* ```
|
|
678
|
+
*/
|
|
679
|
+
dateFormat(fmt: 'YYYY-MM-DD' | 'YYYY/MM/DD' | 'DD-MM-YYYY' | 'DD/MM/YYYY' | 'ISO8601' | string): this;
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* Date 必须晚于指定日期
|
|
683
|
+
* @param date - 比较日期
|
|
684
|
+
* @returns 当前实例(支持链式调用)
|
|
685
|
+
*
|
|
686
|
+
* @example
|
|
687
|
+
* ```typescript
|
|
688
|
+
* dsl('date!').after('2024-01-01');
|
|
689
|
+
* ```
|
|
690
|
+
*/
|
|
691
|
+
after(date: string): this;
|
|
692
|
+
|
|
693
|
+
/**
|
|
694
|
+
* Date 必须早于指定日期
|
|
695
|
+
* @param date - 比较日期
|
|
696
|
+
* @returns 当前实例(支持链式调用)
|
|
697
|
+
*
|
|
698
|
+
* @example
|
|
699
|
+
* ```typescript
|
|
700
|
+
* dsl('date!').before('2025-12-31');
|
|
701
|
+
* ```
|
|
702
|
+
*/
|
|
703
|
+
before(date: string): this;
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Pattern 域名验证
|
|
707
|
+
* @returns 当前实例(支持链式调用)
|
|
708
|
+
*
|
|
709
|
+
* @example
|
|
710
|
+
* ```typescript
|
|
711
|
+
* dsl('string!').domain(); // example.com, sub.example.com
|
|
712
|
+
* ```
|
|
713
|
+
*/
|
|
714
|
+
domain(): this;
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Pattern IP地址验证(IPv4或IPv6)
|
|
718
|
+
* @returns 当前实例(支持链式调用)
|
|
719
|
+
*
|
|
720
|
+
* @example
|
|
721
|
+
* ```typescript
|
|
722
|
+
* dsl('string!').ip(); // 192.168.1.1 或 2001:0db8:85a3::8a2e:0370:7334
|
|
723
|
+
* ```
|
|
724
|
+
*/
|
|
725
|
+
ip(): this;
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Pattern Base64编码验证
|
|
729
|
+
* @returns 当前实例(支持链式调用)
|
|
730
|
+
*
|
|
731
|
+
* @example
|
|
732
|
+
* ```typescript
|
|
733
|
+
* dsl('string!').base64();
|
|
734
|
+
* ```
|
|
735
|
+
*/
|
|
736
|
+
base64(): this;
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* Pattern JWT令牌验证
|
|
740
|
+
* @returns 当前实例(支持链式调用)
|
|
741
|
+
*
|
|
742
|
+
* @example
|
|
743
|
+
* ```typescript
|
|
744
|
+
* dsl('string!').jwt();
|
|
745
|
+
* ```
|
|
746
|
+
*/
|
|
747
|
+
jwt(): this;
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* Pattern JSON字符串验证
|
|
751
|
+
* @returns 当前实例(支持链式调用)
|
|
752
|
+
*
|
|
753
|
+
* @example
|
|
754
|
+
* ```typescript
|
|
755
|
+
* dsl('string!').json();
|
|
756
|
+
* ```
|
|
757
|
+
*/
|
|
758
|
+
json(): this;
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* 日期大于验证
|
|
762
|
+
* @param date - 对比日期
|
|
763
|
+
* @returns 当前实例(支持链式调用)
|
|
764
|
+
*
|
|
765
|
+
* @example
|
|
766
|
+
* ```typescript
|
|
767
|
+
* dsl('string!').dateGreater('2025-01-01');
|
|
768
|
+
* ```
|
|
769
|
+
*/
|
|
770
|
+
dateGreater(date: string): this;
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* 日期小于验证
|
|
774
|
+
* @param date - 对比日期
|
|
775
|
+
* @returns 当前实例(支持链式调用)
|
|
776
|
+
*
|
|
777
|
+
* @example
|
|
778
|
+
* ```typescript
|
|
779
|
+
* dsl('string!').dateLess('2025-12-31');
|
|
780
|
+
* ```
|
|
781
|
+
*/
|
|
782
|
+
dateLess(date: string): this;
|
|
408
783
|
}
|
|
409
784
|
|
|
410
785
|
// ========== String 扩展 ==========
|
|
@@ -506,6 +881,187 @@ declare module 'schema-dsl' {
|
|
|
506
881
|
* @deprecated TypeScript 用户请使用 dsl(string).phone()
|
|
507
882
|
*/
|
|
508
883
|
phone(country?: 'cn' | 'us' | 'uk' | 'hk' | 'tw' | 'international'): DslBuilder;
|
|
884
|
+
|
|
885
|
+
/**
|
|
886
|
+
* 设置格式
|
|
887
|
+
* @deprecated TypeScript 用户请使用 dsl(string).format()
|
|
888
|
+
*/
|
|
889
|
+
format(format: string): DslBuilder;
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* 手机号别名
|
|
893
|
+
* @deprecated TypeScript 用户请使用 dsl(string).phoneNumber()
|
|
894
|
+
*/
|
|
895
|
+
phoneNumber(country?: 'cn' | 'us' | 'uk' | 'hk' | 'tw' | 'international'): DslBuilder;
|
|
896
|
+
|
|
897
|
+
/**
|
|
898
|
+
* 身份证验证
|
|
899
|
+
* @deprecated TypeScript 用户请使用 dsl(string).idCard()
|
|
900
|
+
*/
|
|
901
|
+
idCard(country?: 'cn'): DslBuilder;
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* 信用卡验证
|
|
905
|
+
* @deprecated TypeScript 用户请使用 dsl(string).creditCard()
|
|
906
|
+
*/
|
|
907
|
+
creditCard(type?: 'visa' | 'mastercard' | 'amex' | 'discover' | 'jcb' | 'unionpay'): DslBuilder;
|
|
908
|
+
|
|
909
|
+
/**
|
|
910
|
+
* 车牌号验证
|
|
911
|
+
* @deprecated TypeScript 用户请使用 dsl(string).licensePlate()
|
|
912
|
+
*/
|
|
913
|
+
licensePlate(country?: 'cn' | 'us' | 'uk'): DslBuilder;
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* 邮政编码验证
|
|
917
|
+
* @deprecated TypeScript 用户请使用 dsl(string).postalCode()
|
|
918
|
+
*/
|
|
919
|
+
postalCode(country?: 'cn' | 'us' | 'uk'): DslBuilder;
|
|
920
|
+
|
|
921
|
+
/**
|
|
922
|
+
* 护照号码验证
|
|
923
|
+
* @deprecated TypeScript 用户请使用 dsl(string).passport()
|
|
924
|
+
*/
|
|
925
|
+
passport(country?: 'cn' | 'us' | 'uk'): DslBuilder;
|
|
926
|
+
|
|
927
|
+
/**
|
|
928
|
+
* String 最小长度
|
|
929
|
+
* @deprecated TypeScript 用户请使用 dsl(string).min()
|
|
930
|
+
*/
|
|
931
|
+
min(n: number): DslBuilder;
|
|
932
|
+
|
|
933
|
+
/**
|
|
934
|
+
* String 最大长度
|
|
935
|
+
* @deprecated TypeScript 用户请使用 dsl(string).max()
|
|
936
|
+
*/
|
|
937
|
+
max(n: number): DslBuilder;
|
|
938
|
+
|
|
939
|
+
|
|
940
|
+
/**
|
|
941
|
+
* String 只能包含字母和数字
|
|
942
|
+
* @deprecated TypeScript 用户请使用 dsl(string).alphanum()
|
|
943
|
+
*/
|
|
944
|
+
alphanum(): DslBuilder;
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* String 不能包含前后空格
|
|
948
|
+
* @deprecated TypeScript 用户请使用 dsl(string).trim()
|
|
949
|
+
*/
|
|
950
|
+
trim(): DslBuilder;
|
|
951
|
+
|
|
952
|
+
/**
|
|
953
|
+
* String 必须是小写
|
|
954
|
+
* @deprecated TypeScript 用户请使用 dsl(string).lowercase()
|
|
955
|
+
*/
|
|
956
|
+
lowercase(): DslBuilder;
|
|
957
|
+
|
|
958
|
+
/**
|
|
959
|
+
* String 必须是大写
|
|
960
|
+
* @deprecated TypeScript 用户请使用 dsl(string).uppercase()
|
|
961
|
+
*/
|
|
962
|
+
uppercase(): DslBuilder;
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* Number 小数位数限制
|
|
966
|
+
* @deprecated TypeScript 用户请使用 dsl(string).precision()
|
|
967
|
+
*/
|
|
968
|
+
precision(n: number): DslBuilder;
|
|
969
|
+
|
|
970
|
+
/**
|
|
971
|
+
* Number 倍数验证
|
|
972
|
+
* @deprecated TypeScript 用户请使用 dsl(string).multiple()
|
|
973
|
+
*/
|
|
974
|
+
multiple(n: number): DslBuilder;
|
|
975
|
+
|
|
976
|
+
/**
|
|
977
|
+
* Number 端口号验证
|
|
978
|
+
* @deprecated TypeScript 用户请使用 dsl(string).port()
|
|
979
|
+
*/
|
|
980
|
+
port(): DslBuilder;
|
|
981
|
+
|
|
982
|
+
/**
|
|
983
|
+
* Object 要求所有属性都必须存在
|
|
984
|
+
* @deprecated TypeScript 用户请使用 dsl(obj).requireAll()
|
|
985
|
+
*/
|
|
986
|
+
requireAll(): DslBuilder;
|
|
987
|
+
|
|
988
|
+
/**
|
|
989
|
+
* Object 严格模式
|
|
990
|
+
* @deprecated TypeScript 用户请使用 dsl(obj).strict()
|
|
991
|
+
*/
|
|
992
|
+
strict(): DslBuilder;
|
|
993
|
+
|
|
994
|
+
/**
|
|
995
|
+
* Array 不允许稀疏数组
|
|
996
|
+
* @deprecated TypeScript 用户请使用 dsl(string).noSparse()
|
|
997
|
+
*/
|
|
998
|
+
noSparse(): DslBuilder;
|
|
999
|
+
|
|
1000
|
+
/**
|
|
1001
|
+
* Array 必须包含指定元素
|
|
1002
|
+
* @deprecated TypeScript 用户请使用 dsl(string).includesRequired()
|
|
1003
|
+
*/
|
|
1004
|
+
includesRequired(items: any[]): DslBuilder;
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* Date 自定义日期格式验证
|
|
1008
|
+
* @deprecated TypeScript 用户请使用 dsl(string).dateFormat()
|
|
1009
|
+
*/
|
|
1010
|
+
dateFormat(fmt: string): DslBuilder;
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* Date 必须晚于指定日期
|
|
1014
|
+
* @deprecated TypeScript 用户请使用 dsl(string).after()
|
|
1015
|
+
*/
|
|
1016
|
+
after(date: string): DslBuilder;
|
|
1017
|
+
|
|
1018
|
+
/**
|
|
1019
|
+
* Date 必须早于指定日期
|
|
1020
|
+
* @deprecated TypeScript 用户请使用 dsl(string).before()
|
|
1021
|
+
*/
|
|
1022
|
+
before(date: string): DslBuilder;
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* Pattern 域名验证
|
|
1026
|
+
* @deprecated TypeScript 用户请使用 dsl(string).domain()
|
|
1027
|
+
*/
|
|
1028
|
+
domain(): DslBuilder;
|
|
1029
|
+
|
|
1030
|
+
/**
|
|
1031
|
+
* Pattern IP地址验证
|
|
1032
|
+
* @deprecated TypeScript 用户请使用 dsl(string).ip()
|
|
1033
|
+
*/
|
|
1034
|
+
ip(): DslBuilder;
|
|
1035
|
+
|
|
1036
|
+
/**
|
|
1037
|
+
* Pattern Base64编码验证
|
|
1038
|
+
* @deprecated TypeScript 用户请使用 dsl(string).base64()
|
|
1039
|
+
*/
|
|
1040
|
+
base64(): DslBuilder;
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* Pattern JWT令牌验证
|
|
1044
|
+
* @deprecated TypeScript 用户请使用 dsl(string).jwt()
|
|
1045
|
+
*/
|
|
1046
|
+
jwt(): DslBuilder;
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Pattern JSON字符串验证
|
|
1050
|
+
* @deprecated TypeScript 用户请使用 dsl(string).json()
|
|
1051
|
+
*/
|
|
1052
|
+
json(): DslBuilder;
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* 日期大于验证
|
|
1056
|
+
* @deprecated TypeScript 用户请使用 dsl(string).dateGreater()
|
|
1057
|
+
*/
|
|
1058
|
+
dateGreater(date: string): DslBuilder;
|
|
1059
|
+
|
|
1060
|
+
/**
|
|
1061
|
+
* 日期小于验证
|
|
1062
|
+
* @deprecated TypeScript 用户请使用 dsl(string).dateLess()
|
|
1063
|
+
*/
|
|
1064
|
+
dateLess(date: string): DslBuilder;
|
|
509
1065
|
}
|
|
510
1066
|
}
|
|
511
1067
|
|
|
@@ -764,24 +1320,53 @@ declare module 'schema-dsl' {
|
|
|
764
1320
|
export function match(value: any, cases: Record<string, any>): any;
|
|
765
1321
|
|
|
766
1322
|
/**
|
|
767
|
-
* 条件规则
|
|
1323
|
+
* 条件规则 (if)
|
|
768
1324
|
*
|
|
769
|
-
* @description
|
|
1325
|
+
* @description 根据条件字段的值选择不同的Schema
|
|
1326
|
+
*
|
|
1327
|
+
* JavaScript 中使用: `dsl.if(condition, thenSchema, elseSchema)`
|
|
1328
|
+
* TypeScript 中使用: `dsl['if'](condition, thenSchema, elseSchema)` 或 `dsl._if(...)`
|
|
1329
|
+
*
|
|
1330
|
+
* @param condition - 条件字段名
|
|
1331
|
+
* @param thenSchema - 条件为 true 时的 Schema
|
|
1332
|
+
* @param elseSchema - 条件为 false 时的 Schema(可选)
|
|
770
1333
|
*
|
|
771
1334
|
* @example
|
|
772
1335
|
* ```typescript
|
|
1336
|
+
* // TypeScript 中因为 if 是保留字,需要用字符串索引或 _if
|
|
773
1337
|
* const schema = dsl({
|
|
1338
|
+
* isVip: 'boolean',
|
|
1339
|
+
* discount: dsl['if']('isVip', 'number:10-50!', 'number:0-10')
|
|
1340
|
+
* });
|
|
1341
|
+
*
|
|
1342
|
+
* // 或者使用 _if 别名
|
|
1343
|
+
* const schema2 = dsl({
|
|
774
1344
|
* age: 'number',
|
|
775
|
-
* license: dsl._if(
|
|
776
|
-
*
|
|
777
|
-
*
|
|
778
|
-
*
|
|
779
|
-
*
|
|
1345
|
+
* license: dsl._if('age', 'boolean!', 'boolean')
|
|
1346
|
+
* });
|
|
1347
|
+
* ```
|
|
1348
|
+
*
|
|
1349
|
+
* @example
|
|
1350
|
+
* ```javascript
|
|
1351
|
+
* // JavaScript 中可以直接使用 dsl.if
|
|
1352
|
+
* const schema = dsl({
|
|
1353
|
+
* isVip: 'boolean',
|
|
1354
|
+
* discount: dsl.if('isVip', 'number:10-50!', 'number:0-10')
|
|
780
1355
|
* });
|
|
781
1356
|
* ```
|
|
782
1357
|
*/
|
|
783
1358
|
export const _if: (condition: any, thenSchema: any, elseSchema?: any) => any;
|
|
784
1359
|
|
|
1360
|
+
/**
|
|
1361
|
+
* 条件规则的别名(用于 TypeScript)
|
|
1362
|
+
*
|
|
1363
|
+
* @description 因为 TypeScript 中 `if` 是保留字,提供 `_if` 作为别名
|
|
1364
|
+
*
|
|
1365
|
+
* JavaScript 用户请直接使用 `dsl.if()`
|
|
1366
|
+
* TypeScript 用户可以使用 `dsl['if']()` 或 `dsl._if()`
|
|
1367
|
+
*/
|
|
1368
|
+
export { _if as if };
|
|
1369
|
+
|
|
785
1370
|
/**
|
|
786
1371
|
* 设置默认语言
|
|
787
1372
|
*
|
|
@@ -1992,23 +2577,31 @@ declare module 'schema-dsl' {
|
|
|
1992
2577
|
* // 添加自定义关键字通常通过 Validator 的 addKeyword 方法
|
|
1993
2578
|
* const validator = new Validator();
|
|
1994
2579
|
* const ajv = validator.getAjv();
|
|
1995
|
-
*
|
|
1996
|
-
* // 使用 ajv.addKeyword() 添加自定义关键字
|
|
1997
|
-
* ```
|
|
1998
|
-
*/
|
|
1999
|
-
export const CustomKeywords: any;
|
|
2000
2580
|
|
|
2001
|
-
// ========== dsl.config
|
|
2581
|
+
// ========== dsl.config 选项 ==========
|
|
2002
2582
|
|
|
2003
2583
|
/**
|
|
2004
|
-
* i18n
|
|
2584
|
+
* i18n 配置选项
|
|
2585
|
+
*
|
|
2586
|
+
* @description 支持两种配置方式
|
|
2587
|
+
*
|
|
2588
|
+
* @example
|
|
2589
|
+
* ```typescript
|
|
2590
|
+
* // 方式1: 直接传字符串路径
|
|
2591
|
+
* dsl.config({
|
|
2592
|
+
* i18n: './i18n/dsl'
|
|
2593
|
+
* });
|
|
2594
|
+
*
|
|
2595
|
+
* // 方式2: 传入语言包对象
|
|
2596
|
+
* dsl.config({
|
|
2597
|
+
* i18n: {
|
|
2598
|
+
* 'zh-CN': { required: '必填' },
|
|
2599
|
+
* 'en-US': { required: 'Required' }
|
|
2600
|
+
* }
|
|
2601
|
+
* });
|
|
2602
|
+
* ```
|
|
2005
2603
|
*/
|
|
2006
|
-
export
|
|
2007
|
-
/** 语言包目录路径 */
|
|
2008
|
-
localesPath?: string;
|
|
2009
|
-
/** 直接传入的语言包 */
|
|
2010
|
-
locales?: Record<string, ErrorMessages>;
|
|
2011
|
-
}
|
|
2604
|
+
export type I18nConfig = string | Record<string, ErrorMessages>;
|
|
2012
2605
|
|
|
2013
2606
|
/**
|
|
2014
2607
|
* 缓存配置选项(v2.3.0+)
|
|
@@ -2210,6 +2803,142 @@ declare module 'schema-dsl' {
|
|
|
2210
2803
|
|
|
2211
2804
|
// ========== 默认导出 ==========
|
|
2212
2805
|
|
|
2806
|
+
// ========== 验证器扩展 ==========
|
|
2807
|
+
|
|
2808
|
+
/**
|
|
2809
|
+
* 自定义关键字
|
|
2810
|
+
*
|
|
2811
|
+
* @description 扩展ajv的自定义验证关键字
|
|
2812
|
+
*
|
|
2813
|
+
* @example
|
|
2814
|
+
* ```typescript
|
|
2815
|
+
* import { CustomKeywords, Validator } from 'schema-dsl';
|
|
2816
|
+
*
|
|
2817
|
+
* const validator = new Validator();
|
|
2818
|
+
* const ajv = validator.getAjv();
|
|
2819
|
+
* CustomKeywords.registerAll(ajv);
|
|
2820
|
+
* ```
|
|
2821
|
+
*/
|
|
2822
|
+
export const CustomKeywords: {
|
|
2823
|
+
/**
|
|
2824
|
+
* 注册所有自定义关键字到ajv实例
|
|
2825
|
+
* @param ajv - ajv实例
|
|
2826
|
+
*/
|
|
2827
|
+
registerAll(ajv: any): void;
|
|
2828
|
+
|
|
2829
|
+
/**
|
|
2830
|
+
* 注册元数据关键字
|
|
2831
|
+
* @param ajv - ajv实例
|
|
2832
|
+
*/
|
|
2833
|
+
registerMetadataKeywords(ajv: any): void;
|
|
2834
|
+
|
|
2835
|
+
/**
|
|
2836
|
+
* 注册字符串验证器
|
|
2837
|
+
* @param ajv - ajv实例
|
|
2838
|
+
*/
|
|
2839
|
+
registerStringValidators(ajv: any): void;
|
|
2840
|
+
|
|
2841
|
+
/**
|
|
2842
|
+
* 注册数字验证器
|
|
2843
|
+
* @param ajv - ajv实例
|
|
2844
|
+
*/
|
|
2845
|
+
registerNumberValidators(ajv: any): void;
|
|
2846
|
+
|
|
2847
|
+
/**
|
|
2848
|
+
* 注册对象验证器
|
|
2849
|
+
* @param ajv - ajv实例
|
|
2850
|
+
*/
|
|
2851
|
+
registerObjectValidators(ajv: any): void;
|
|
2852
|
+
|
|
2853
|
+
/**
|
|
2854
|
+
* 注册数组验证器
|
|
2855
|
+
* @param ajv - ajv实例
|
|
2856
|
+
*/
|
|
2857
|
+
registerArrayValidators(ajv: any): void;
|
|
2858
|
+
|
|
2859
|
+
/**
|
|
2860
|
+
* 注册日期验证器
|
|
2861
|
+
* @param ajv - ajv实例
|
|
2862
|
+
*/
|
|
2863
|
+
registerDateValidators(ajv: any): void;
|
|
2864
|
+
};
|
|
2865
|
+
|
|
2866
|
+
// ========== 常量 ==========
|
|
2867
|
+
|
|
2868
|
+
/**
|
|
2869
|
+
* SchemaIO 配置常量
|
|
2870
|
+
*
|
|
2871
|
+
* @description 所有魔法数字和配置项的统一定义
|
|
2872
|
+
*
|
|
2873
|
+
* @example
|
|
2874
|
+
* ```typescript
|
|
2875
|
+
* import { CONSTANTS } from 'schema-dsl';
|
|
2876
|
+
*
|
|
2877
|
+
* console.log(CONSTANTS.VALIDATION.MAX_RECURSION_DEPTH); // 100
|
|
2878
|
+
* console.log(CONSTANTS.CACHE.SCHEMA_CACHE.MAX_SIZE); // 5000
|
|
2879
|
+
* ```
|
|
2880
|
+
*/
|
|
2881
|
+
export const CONSTANTS: {
|
|
2882
|
+
/** 验证配置 */
|
|
2883
|
+
VALIDATION: {
|
|
2884
|
+
/** 递归深度限制 */
|
|
2885
|
+
MAX_RECURSION_DEPTH: number;
|
|
2886
|
+
/** 数组大小限制 */
|
|
2887
|
+
MAX_ARRAY_SIZE: number;
|
|
2888
|
+
/** 字符串长度限制 */
|
|
2889
|
+
MAX_STRING_LENGTH: number;
|
|
2890
|
+
/** 对象属性数量限制 */
|
|
2891
|
+
MAX_OBJECT_KEYS: number;
|
|
2892
|
+
/** 验证超时时间(ms) */
|
|
2893
|
+
DEFAULT_TIMEOUT: number;
|
|
2894
|
+
/** 正则表达式超时(ms) */
|
|
2895
|
+
REGEX_TIMEOUT: number;
|
|
2896
|
+
/** 自定义验证函数超时(ms) */
|
|
2897
|
+
CUSTOM_VALIDATOR_TIMEOUT: number;
|
|
2898
|
+
/** 默认选项 */
|
|
2899
|
+
DEFAULT_OPTIONS: {
|
|
2900
|
+
abortEarly: boolean;
|
|
2901
|
+
stripUnknown: boolean;
|
|
2902
|
+
convert: boolean;
|
|
2903
|
+
presence: string;
|
|
2904
|
+
allowUnknown: boolean;
|
|
2905
|
+
skipFunctions: boolean;
|
|
2906
|
+
};
|
|
2907
|
+
};
|
|
2908
|
+
/** 缓存配置 */
|
|
2909
|
+
CACHE: {
|
|
2910
|
+
/** 缓存开关 */
|
|
2911
|
+
ENABLED: boolean;
|
|
2912
|
+
/** Schema编译缓存 */
|
|
2913
|
+
SCHEMA_CACHE: {
|
|
2914
|
+
/** 最大缓存条目 */
|
|
2915
|
+
MAX_SIZE: number;
|
|
2916
|
+
/** 缓存过期时间(ms) */
|
|
2917
|
+
TTL: number;
|
|
2918
|
+
};
|
|
2919
|
+
};
|
|
2920
|
+
/** 格式配置 */
|
|
2921
|
+
FORMAT: Record<string, any>;
|
|
2922
|
+
/** 类型配置 */
|
|
2923
|
+
TYPES: Record<string, any>;
|
|
2924
|
+
/** 错误配置 */
|
|
2925
|
+
ERRORS: Record<string, any>;
|
|
2926
|
+
};
|
|
2927
|
+
|
|
2928
|
+
/**
|
|
2929
|
+
* 版本信息
|
|
2930
|
+
*
|
|
2931
|
+
* @description 当前schema-dsl版本号
|
|
2932
|
+
*
|
|
2933
|
+
* @example
|
|
2934
|
+
* ```typescript
|
|
2935
|
+
* import { VERSION } from 'schema-dsl';
|
|
2936
|
+
*
|
|
2937
|
+
* console.log(`schema-dsl version: ${VERSION}`); // schema-dsl version: 1.0.4
|
|
2938
|
+
* ```
|
|
2939
|
+
*/
|
|
2940
|
+
export const VERSION: string;
|
|
2941
|
+
|
|
2213
2942
|
/**
|
|
2214
2943
|
* 默认导出(dsl函数)
|
|
2215
2944
|
*
|
package/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* 简洁 + 强大 = 完美平衡
|
|
6
6
|
*
|
|
7
7
|
* @module schema-dsl
|
|
8
|
-
* @version 1.0.
|
|
8
|
+
* @version 1.0.4
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
// ========== 核心层 ==========
|
|
@@ -36,6 +36,7 @@ dsl.if = dsl.DslAdapter.if;
|
|
|
36
36
|
* @param {Object} options - 配置选项
|
|
37
37
|
* @param {Object} options.patterns - 验证规则扩展 (phone, idCard, creditCard)
|
|
38
38
|
* @param {string|Object} options.i18n - 多语言配置(目录路径或语言包对象)
|
|
39
|
+
* @param {Object} options.cache - 缓存配置
|
|
39
40
|
*/
|
|
40
41
|
dsl.config = function (options = {}) {
|
|
41
42
|
const patterns = require('./lib/config/patterns');
|
|
@@ -74,6 +75,29 @@ dsl.config = function (options = {}) {
|
|
|
74
75
|
});
|
|
75
76
|
}
|
|
76
77
|
}
|
|
78
|
+
|
|
79
|
+
// 缓存配置 (v1.0.4+)
|
|
80
|
+
if (options.cache) {
|
|
81
|
+
// 如果 Validator 还未创建,保存配置供后续创建时使用
|
|
82
|
+
if (!_defaultValidator) {
|
|
83
|
+
_validatorOptions.cache = options.cache;
|
|
84
|
+
} else {
|
|
85
|
+
// 如果已创建,动态修改现有实例的配置(向后兼容)
|
|
86
|
+
const cacheOpts = _defaultValidator.cache.options;
|
|
87
|
+
if (options.cache.maxSize !== undefined) {
|
|
88
|
+
cacheOpts.maxSize = options.cache.maxSize;
|
|
89
|
+
}
|
|
90
|
+
if (options.cache.ttl !== undefined) {
|
|
91
|
+
cacheOpts.ttl = options.cache.ttl;
|
|
92
|
+
}
|
|
93
|
+
if (options.cache.enabled !== undefined) {
|
|
94
|
+
cacheOpts.enabled = options.cache.enabled;
|
|
95
|
+
}
|
|
96
|
+
if (options.cache.statsEnabled !== undefined) {
|
|
97
|
+
cacheOpts.statsEnabled = options.cache.statsEnabled;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
77
101
|
};
|
|
78
102
|
|
|
79
103
|
// ========== 导出器层 ==========
|
|
@@ -87,6 +111,7 @@ Object.entries(defaultLocales).forEach(([locale, messages]) => {
|
|
|
87
111
|
|
|
88
112
|
// ========== 单例Validator ==========
|
|
89
113
|
let _defaultValidator = null;
|
|
114
|
+
let _validatorOptions = {}; // 存储 Validator 配置选项
|
|
90
115
|
|
|
91
116
|
/**
|
|
92
117
|
* 获取默认Validator实例(单例)
|
|
@@ -94,7 +119,7 @@ let _defaultValidator = null;
|
|
|
94
119
|
*/
|
|
95
120
|
function getDefaultValidator() {
|
|
96
121
|
if (!_defaultValidator) {
|
|
97
|
-
_defaultValidator = new Validator();
|
|
122
|
+
_defaultValidator = new Validator(_validatorOptions);
|
|
98
123
|
}
|
|
99
124
|
return _defaultValidator;
|
|
100
125
|
}
|
|
@@ -128,91 +153,6 @@ const CONSTANTS = require('./lib/config/constants');
|
|
|
128
153
|
// ========== 自动安装 String 扩展 ==========
|
|
129
154
|
installStringExtensions(dsl);
|
|
130
155
|
|
|
131
|
-
// ========== 全局配置函数 ==========
|
|
132
|
-
/**
|
|
133
|
-
* 全局配置
|
|
134
|
-
* @param {Object} options - 配置选项
|
|
135
|
-
* @param {Object} options.i18n - 多语言配置
|
|
136
|
-
* @param {string} options.i18n.localesPath - 用户语言包目录路径
|
|
137
|
-
* @param {Object} options.i18n.locales - 直接传入的语言包对象
|
|
138
|
-
* @param {Object} options.cache - 缓存配置
|
|
139
|
-
* @param {number} options.cache.maxSize - 缓存最大条目数
|
|
140
|
-
* @param {number} options.cache.ttl - 缓存过期时间(ms)
|
|
141
|
-
*
|
|
142
|
-
* @example
|
|
143
|
-
* dsl.config({
|
|
144
|
-
* i18n: {
|
|
145
|
-
* localesPath: './i18n/labels'
|
|
146
|
-
* },
|
|
147
|
-
* cache: {
|
|
148
|
-
* maxSize: 10000,
|
|
149
|
-
* ttl: 7200000
|
|
150
|
-
* }
|
|
151
|
-
* });
|
|
152
|
-
*/
|
|
153
|
-
dsl.config = function (options = {}) {
|
|
154
|
-
// ========== 用户语言包配置 ==========
|
|
155
|
-
if (options.i18n) {
|
|
156
|
-
const { localesPath, locales } = options.i18n;
|
|
157
|
-
|
|
158
|
-
// 方式 1:从路径加载语言包文件
|
|
159
|
-
if (localesPath) {
|
|
160
|
-
const fs = require('fs');
|
|
161
|
-
const path = require('path');
|
|
162
|
-
|
|
163
|
-
const resolvedPath = path.resolve(localesPath);
|
|
164
|
-
|
|
165
|
-
if (fs.existsSync(resolvedPath)) {
|
|
166
|
-
const files = fs.readdirSync(resolvedPath);
|
|
167
|
-
|
|
168
|
-
files.forEach(file => {
|
|
169
|
-
if (file.endsWith('.js') || file.endsWith('.json')) {
|
|
170
|
-
const locale = path.basename(file, path.extname(file));
|
|
171
|
-
try {
|
|
172
|
-
const messages = require(path.join(resolvedPath, file));
|
|
173
|
-
Locale.addLocale(locale, messages);
|
|
174
|
-
if (process.env.DEBUG) {
|
|
175
|
-
console.log(`[schema-dsl] Loaded user locale: ${locale}`);
|
|
176
|
-
}
|
|
177
|
-
} catch (error) {
|
|
178
|
-
console.warn(`[schema-dsl] Failed to load locale ${locale}:`, error.message);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
} else {
|
|
183
|
-
console.warn(`[schema-dsl] Locales path not found: ${resolvedPath}`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// 方式 2:直接传入语言包对象
|
|
188
|
-
if (locales && typeof locales === 'object') {
|
|
189
|
-
Object.keys(locales).forEach(locale => {
|
|
190
|
-
Locale.addLocale(locale, locales[locale]);
|
|
191
|
-
if (process.env.DEBUG) {
|
|
192
|
-
console.log(`[schema-dsl] Added user locale: ${locale}`);
|
|
193
|
-
}
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// ========== 缓存配置 ==========
|
|
199
|
-
if (options.cache) {
|
|
200
|
-
const { maxSize, ttl } = options.cache;
|
|
201
|
-
|
|
202
|
-
// 更新默认 Validator 的缓存配置
|
|
203
|
-
if (_defaultValidator) {
|
|
204
|
-
if (maxSize !== undefined) {
|
|
205
|
-
_defaultValidator.cache.options.maxSize = maxSize;
|
|
206
|
-
}
|
|
207
|
-
if (ttl !== undefined) {
|
|
208
|
-
_defaultValidator.cache.options.ttl = ttl;
|
|
209
|
-
}
|
|
210
|
-
if (process.env.DEBUG) {
|
|
211
|
-
console.log(`[schema-dsl] Updated cache config: maxSize=${maxSize || 'default'}, ttl=${ttl || 'default'}ms`);
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
156
|
|
|
217
157
|
// ========== 导出 ==========
|
|
218
158
|
|
|
@@ -227,6 +167,9 @@ module.exports = {
|
|
|
227
167
|
dsl,
|
|
228
168
|
DslBuilder,
|
|
229
169
|
|
|
170
|
+
// 配置函数 (v1.0.4+)
|
|
171
|
+
config: dsl.config,
|
|
172
|
+
|
|
230
173
|
// String 扩展控制
|
|
231
174
|
installStringExtensions: () => installStringExtensions(dsl),
|
|
232
175
|
uninstallStringExtensions,
|
|
@@ -272,7 +215,7 @@ module.exports = {
|
|
|
272
215
|
CONSTANTS,
|
|
273
216
|
|
|
274
217
|
// 版本信息
|
|
275
|
-
VERSION: '1.0.
|
|
218
|
+
VERSION: '1.0.4'
|
|
276
219
|
};
|
|
277
220
|
|
|
278
221
|
|
package/lib/core/Validator.js
CHANGED
|
@@ -28,6 +28,9 @@ class Validator {
|
|
|
28
28
|
* @param {boolean} options.useDefaults - 是否使用默认值(默认true)
|
|
29
29
|
* @param {boolean} options.coerceTypes - 是否自动类型转换(默认false)
|
|
30
30
|
* @param {boolean} options.removeAdditional - 是否移除额外属性(默认false)
|
|
31
|
+
* @param {Object} options.cache - 缓存配置选项 (v1.0.4+)
|
|
32
|
+
* @param {number} options.cache.maxSize - 最大缓存条目数(默认100)
|
|
33
|
+
* @param {number} options.cache.ttl - 缓存过期时间(毫秒,默认3600000)
|
|
31
34
|
*/
|
|
32
35
|
constructor(options = {}) {
|
|
33
36
|
// ajv配置
|
|
@@ -49,11 +52,14 @@ class Validator {
|
|
|
49
52
|
// 注册自定义关键字
|
|
50
53
|
CustomKeywords.registerAll(this.ajv);
|
|
51
54
|
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
maxSize: 100,
|
|
55
|
-
ttl: 3600000 // 1小时
|
|
56
|
-
|
|
55
|
+
// 编译缓存(支持自定义配置)
|
|
56
|
+
const cacheOptions = {
|
|
57
|
+
maxSize: options.cache?.maxSize ?? 100,
|
|
58
|
+
ttl: options.cache?.ttl ?? 3600000, // 1小时
|
|
59
|
+
enabled: options.cache?.enabled,
|
|
60
|
+
statsEnabled: options.cache?.statsEnabled
|
|
61
|
+
};
|
|
62
|
+
this.cache = new CacheManager(cacheOptions);
|
|
57
63
|
|
|
58
64
|
// 错误格式化器
|
|
59
65
|
this.errorFormatter = new ErrorFormatter();
|
|
@@ -395,7 +401,7 @@ class Validator {
|
|
|
395
401
|
|
|
396
402
|
// Support calling without new
|
|
397
403
|
const ValidatorProxy = new Proxy(Validator, {
|
|
398
|
-
apply: function(target, thisArg, argumentsList) {
|
|
404
|
+
apply: function (target, thisArg, argumentsList) {
|
|
399
405
|
return new target(...argumentsList);
|
|
400
406
|
}
|
|
401
407
|
});
|