koatty_validation 1.3.4 → 1.4.0
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/.rollup.config.js +62 -62
- package/.vscode/launch.json +81 -0
- package/CHANGELOG.md +83 -73
- package/LICENSE +29 -29
- package/README.md +363 -116
- package/coverage.lcov +1607 -0
- package/dist/LICENSE +29 -29
- package/dist/README.md +363 -116
- package/dist/index.d.ts +421 -219
- package/dist/index.js +785 -651
- package/dist/index.mjs +767 -649
- package/dist/package.json +91 -91
- package/examples/README.md +90 -0
- package/examples/basic-usage.ts +239 -0
- package/examples/custom-decorators-example.ts +230 -0
- package/examples/usage-example.ts +284 -0
- package/package.json +91 -91
package/README.md
CHANGED
|
@@ -1,116 +1,363 @@
|
|
|
1
|
-
# koatty_validation
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
1
|
+
# koatty_validation
|
|
2
|
+
|
|
3
|
+
基于 class-validator 扩展的 Koatty 验证工具库,支持中文本地化验证规则、自定义装饰器、性能缓存和错误处理。
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/koatty_validation)
|
|
6
|
+
[](https://github.com/koatty/koatty_validation/actions)
|
|
7
|
+
|
|
8
|
+
## ✨ 特性
|
|
9
|
+
|
|
10
|
+
- 🚀 **高性能**: 内置缓存机制,提升验证性能
|
|
11
|
+
- 🌏 **中文支持**: 内置中文验证规则(姓名、身份证、手机号等)
|
|
12
|
+
- 🔧 **自定义装饰器**: 支持装饰器工厂模式,轻松创建自定义验证器
|
|
13
|
+
- 📊 **性能监控**: 内置性能监控和缓存统计
|
|
14
|
+
- 🎯 **错误处理**: 多语言错误信息支持
|
|
15
|
+
- 📦 **TypeScript**: 完整的 TypeScript 支持
|
|
16
|
+
|
|
17
|
+
## 📦 安装
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install koatty_validation
|
|
21
|
+
# 或
|
|
22
|
+
yarn add koatty_validation
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 🎯 快速开始
|
|
26
|
+
|
|
27
|
+
### 基础用法
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { IsNotEmpty, IsCnName, IsMobile, Valid, Validated } from 'koatty_validation';
|
|
31
|
+
|
|
32
|
+
// 在控制器中使用参数验证
|
|
33
|
+
export class Controller {
|
|
34
|
+
// 参数验证
|
|
35
|
+
Test(@Valid("IsNotEmpty", "不能为空") id: number) {
|
|
36
|
+
// 业务逻辑
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// DTO 验证
|
|
40
|
+
@Validated()
|
|
41
|
+
TestDto(user: UserDTO) {
|
|
42
|
+
// 自动验证 UserDTO
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 定义 DTO 类
|
|
47
|
+
export class UserDTO {
|
|
48
|
+
@IsNotEmpty({ message: "手机号不能为空" })
|
|
49
|
+
@IsMobile({ message: "手机号格式不正确" })
|
|
50
|
+
phoneNum: string;
|
|
51
|
+
|
|
52
|
+
@IsCnName({ message: "姓名必须是有效的中文姓名" })
|
|
53
|
+
userName: string;
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 📋 可用装饰器
|
|
58
|
+
|
|
59
|
+
### 🇨🇳 中文验证装饰器
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
@IsCnName() // 中文姓名
|
|
63
|
+
@IsIdNumber() // 身份证号
|
|
64
|
+
@IsMobile() // 手机号
|
|
65
|
+
@IsZipCode() // 邮政编码
|
|
66
|
+
@IsPlateNumber() // 车牌号
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 🌐 通用验证装饰器
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
@IsNotEmpty() // 非空
|
|
73
|
+
@IsEmail() // 邮箱
|
|
74
|
+
@IsIP() // IP地址
|
|
75
|
+
@IsPhoneNumber() // 国际电话号码
|
|
76
|
+
@IsUrl() // URL
|
|
77
|
+
@IsHash() // 哈希值
|
|
78
|
+
@IsDate() // 日期
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 🔢 数值比较装饰器
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
@Gt(10) // 大于
|
|
85
|
+
@Gte(10) // 大于等于
|
|
86
|
+
@Lt(100) // 小于
|
|
87
|
+
@Lte(100) // 小于等于
|
|
88
|
+
@Equals('value') // 等于
|
|
89
|
+
@NotEquals('x') // 不等于
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 📝 字符串验证装饰器
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
@Contains('test') // 包含字符串
|
|
96
|
+
@IsIn(['a', 'b', 'c']) // 在数组中
|
|
97
|
+
@IsNotIn(['x', 'y', 'z']) // 不在数组中
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 🛠️ 控制装饰器
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
@Valid(rule, options) // 参数验证
|
|
104
|
+
@Validated() // DTO验证
|
|
105
|
+
@Expose() // 暴露属性
|
|
106
|
+
@IsDefined() // 已定义(Expose别名)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 🔧 自定义装饰器
|
|
110
|
+
|
|
111
|
+
### 使用装饰器工厂创建自定义验证器
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { createSimpleDecorator, createParameterizedDecorator } from 'koatty_validation';
|
|
115
|
+
|
|
116
|
+
// 简单装饰器
|
|
117
|
+
export const IsPositiveInteger = createSimpleDecorator(
|
|
118
|
+
'IsPositiveInteger',
|
|
119
|
+
(value: any) => {
|
|
120
|
+
const num = Number(value);
|
|
121
|
+
return Number.isInteger(num) && num > 0;
|
|
122
|
+
},
|
|
123
|
+
'must be a positive integer'
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
// 带参数的装饰器
|
|
127
|
+
export const InRange = createParameterizedDecorator(
|
|
128
|
+
'InRange',
|
|
129
|
+
(value: any, min: number, max: number) => {
|
|
130
|
+
const num = Number(value);
|
|
131
|
+
return num >= min && num <= max;
|
|
132
|
+
},
|
|
133
|
+
'must be between $constraint1 and $constraint2'
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
// 使用自定义装饰器
|
|
137
|
+
class ProductDto {
|
|
138
|
+
@IsPositiveInteger()
|
|
139
|
+
quantity: number;
|
|
140
|
+
|
|
141
|
+
@InRange(0, 100)
|
|
142
|
+
discountPercent: number;
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### 高级自定义装饰器
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
import { createValidationDecorator } from 'koatty_validation';
|
|
150
|
+
|
|
151
|
+
// 复杂验证逻辑
|
|
152
|
+
export function IsStrongPassword(validationOptions?: ValidationOptions) {
|
|
153
|
+
return createValidationDecorator({
|
|
154
|
+
name: 'IsStrongPassword',
|
|
155
|
+
validator: (value: string) => {
|
|
156
|
+
const hasLowercase = /[a-z]/.test(value);
|
|
157
|
+
const hasUppercase = /[A-Z]/.test(value);
|
|
158
|
+
const hasNumbers = /\d/.test(value);
|
|
159
|
+
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(value);
|
|
160
|
+
return value.length >= 8 && hasLowercase && hasUppercase && hasNumbers && hasSpecialChar;
|
|
161
|
+
},
|
|
162
|
+
defaultMessage: 'password must be at least 8 characters with uppercase, lowercase, number and special character',
|
|
163
|
+
requiresValue: false
|
|
164
|
+
})(validationOptions);
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## 🚀 性能优化
|
|
169
|
+
|
|
170
|
+
### 缓存预热
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import { warmupCaches, performanceMonitor } from 'koatty_validation';
|
|
174
|
+
|
|
175
|
+
// 应用启动时预热缓存
|
|
176
|
+
await warmupCaches();
|
|
177
|
+
|
|
178
|
+
// 性能监控
|
|
179
|
+
const timer = performanceMonitor.startTimer('validation');
|
|
180
|
+
// ... 执行验证
|
|
181
|
+
timer(); // 结束计时
|
|
182
|
+
|
|
183
|
+
// 获取性能报告
|
|
184
|
+
const report = performanceMonitor.getReport();
|
|
185
|
+
console.log(report);
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### 缓存统计
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import { getAllCacheStats, clearAllCaches } from 'koatty_validation';
|
|
192
|
+
|
|
193
|
+
// 获取缓存统计
|
|
194
|
+
const stats = getAllCacheStats();
|
|
195
|
+
console.log(stats);
|
|
196
|
+
|
|
197
|
+
// 清理缓存(用于测试或内存管理)
|
|
198
|
+
clearAllCaches();
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## 🌐 错误处理
|
|
202
|
+
|
|
203
|
+
### 多语言支持
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
import { setValidationLanguage, KoattyValidationError } from 'koatty_validation';
|
|
207
|
+
|
|
208
|
+
// 设置中文错误信息
|
|
209
|
+
setValidationLanguage('zh');
|
|
210
|
+
|
|
211
|
+
// 自定义错误处理
|
|
212
|
+
try {
|
|
213
|
+
await validate(userDto);
|
|
214
|
+
} catch (error) {
|
|
215
|
+
if (error instanceof KoattyValidationError) {
|
|
216
|
+
console.log('验证错误:', error.message);
|
|
217
|
+
console.log('错误详情:', error.errors);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### 错误格式化
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
import { errorFormatter } from 'koatty_validation';
|
|
226
|
+
|
|
227
|
+
const errors = await validate(dto);
|
|
228
|
+
if (errors.length > 0) {
|
|
229
|
+
const formatted = errorFormatter(errors, 'zh');
|
|
230
|
+
console.log(formatted);
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## 📖 手动验证
|
|
235
|
+
|
|
236
|
+
### FunctionValidator
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
import { FunctionValidator } from 'koatty_validation';
|
|
240
|
+
|
|
241
|
+
// 手动验证并抛出错误
|
|
242
|
+
try {
|
|
243
|
+
FunctionValidator.IsNotEmpty("", "不能为空");
|
|
244
|
+
FunctionValidator.IsMobile("123", "手机号格式不正确");
|
|
245
|
+
} catch (error) {
|
|
246
|
+
console.log(error.message);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// 带选项的验证
|
|
250
|
+
FunctionValidator.Contains(str, {
|
|
251
|
+
message: "必须包含字母s",
|
|
252
|
+
value: "s"
|
|
253
|
+
});
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### ValidFuncs (纯函数)
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import { ValidFuncs } from 'koatty_validation';
|
|
260
|
+
|
|
261
|
+
// 返回布尔值的验证函数
|
|
262
|
+
if (!ValidFuncs.IsNotEmpty(str)) {
|
|
263
|
+
console.log("字符串为空");
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (!ValidFuncs.IsCnName("张三")) {
|
|
267
|
+
console.log("不是有效的中文姓名");
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (!ValidFuncs.IsMobile("13812345678")) {
|
|
271
|
+
console.log("不是有效的手机号");
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### ClassValidator
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
import { ClassValidator } from 'koatty_validation';
|
|
279
|
+
|
|
280
|
+
class UserSchema {
|
|
281
|
+
@IsDefined()
|
|
282
|
+
id: number;
|
|
283
|
+
|
|
284
|
+
@IsNotEmpty()
|
|
285
|
+
name: string;
|
|
286
|
+
|
|
287
|
+
@IsMobile()
|
|
288
|
+
phone: string;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// 验证对象
|
|
292
|
+
try {
|
|
293
|
+
const result = await ClassValidator.valid(UserSchema, {
|
|
294
|
+
id: 1,
|
|
295
|
+
name: '',
|
|
296
|
+
phone: '123'
|
|
297
|
+
});
|
|
298
|
+
} catch (error) {
|
|
299
|
+
console.log('验证失败:', error.message);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// 转换并验证
|
|
303
|
+
const validatedData = await ClassValidator.valid(UserSchema, rawData, true);
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## 📚 更多示例
|
|
307
|
+
|
|
308
|
+
查看 [examples](./examples/) 目录获取更多使用示例:
|
|
309
|
+
|
|
310
|
+
- [基础用法示例](./examples/basic-usage.ts)
|
|
311
|
+
- [自定义装饰器示例](./examples/custom-decorators-example.ts)
|
|
312
|
+
- [完整使用示例](./examples/usage-example.ts)
|
|
313
|
+
|
|
314
|
+
## 🔍 可用验证函数
|
|
315
|
+
|
|
316
|
+
所有验证函数都同时提供装饰器和函数两种形式:
|
|
317
|
+
|
|
318
|
+
| 函数名 | 描述 | 示例 |
|
|
319
|
+
|--------|------|------|
|
|
320
|
+
| IsCnName | 中文姓名 | `ValidFuncs.IsCnName("张三")` |
|
|
321
|
+
| IsIdNumber | 身份证号 | `ValidFuncs.IsIdNumber("110101199001011234")` |
|
|
322
|
+
| IsMobile | 手机号 | `ValidFuncs.IsMobile("13812345678")` |
|
|
323
|
+
| IsZipCode | 邮政编码 | `ValidFuncs.IsZipCode("100000")` |
|
|
324
|
+
| IsPlateNumber | 车牌号 | `ValidFuncs.IsPlateNumber("京A12345")` |
|
|
325
|
+
| IsEmail | 邮箱 | `ValidFuncs.IsEmail("test@example.com")` |
|
|
326
|
+
| IsIP | IP地址 | `ValidFuncs.IsIP("192.168.1.1")` |
|
|
327
|
+
| IsPhoneNumber | 国际电话 | `ValidFuncs.IsPhoneNumber("+86-138-1234-5678")` |
|
|
328
|
+
| IsUrl | URL | `ValidFuncs.IsUrl("https://example.com")` |
|
|
329
|
+
| IsHash | 哈希值 | `ValidFuncs.IsHash("abc123", "md5")` |
|
|
330
|
+
| IsNotEmpty | 非空 | `ValidFuncs.IsNotEmpty("test")` |
|
|
331
|
+
| Equals | 相等 | `ValidFuncs.Equals("a", "a")` |
|
|
332
|
+
| NotEquals | 不相等 | `ValidFuncs.NotEquals("a", "b")` |
|
|
333
|
+
| Contains | 包含 | `ValidFuncs.Contains("hello", "ell")` |
|
|
334
|
+
| IsIn | 在数组中 | `ValidFuncs.IsIn("a", ["a", "b"])` |
|
|
335
|
+
| IsNotIn | 不在数组中 | `ValidFuncs.IsNotIn("c", ["a", "b"])` |
|
|
336
|
+
| IsDate | 日期 | `ValidFuncs.IsDate(new Date())` |
|
|
337
|
+
| Gt | 大于 | `ValidFuncs.Gt(10, 5)` |
|
|
338
|
+
| Gte | 大于等于 | `ValidFuncs.Gte(10, 10)` |
|
|
339
|
+
| Lt | 小于 | `ValidFuncs.Lt(5, 10)` |
|
|
340
|
+
| Lte | 小于等于 | `ValidFuncs.Lte(10, 10)` |
|
|
341
|
+
|
|
342
|
+
## 📊 测试覆盖率
|
|
343
|
+
|
|
344
|
+
当前测试覆盖率:**76%+**
|
|
345
|
+
|
|
346
|
+
- 语句覆盖率: 76.23%
|
|
347
|
+
- 分支覆盖率: 77.92%
|
|
348
|
+
- 函数覆盖率: 69.62%
|
|
349
|
+
- 行覆盖率: 76.14%
|
|
350
|
+
|
|
351
|
+
## 🤝 贡献
|
|
352
|
+
|
|
353
|
+
欢迎提交 Issue 和 Pull Request!
|
|
354
|
+
|
|
355
|
+
## 📄 许可证
|
|
356
|
+
|
|
357
|
+
[BSD-3-Clause License](LICENSE)
|
|
358
|
+
|
|
359
|
+
## 🔗 相关项目
|
|
360
|
+
|
|
361
|
+
- [koatty](https://github.com/koatty/koatty) - 基于 Koa2 的 Node.js 框架
|
|
362
|
+
- [class-validator](https://github.com/typestack/class-validator) - 基础验证库
|
|
363
|
+
|