@hestjs/validation 0.1.2
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/dist/decorators/custom.d.ts +221 -0
- package/dist/decorators/custom.d.ts.map +1 -0
- package/dist/decorators/custom.js +283 -0
- package/dist/decorators/custom.js.map +1 -0
- package/dist/decorators/validation.d.ts +120 -0
- package/dist/decorators/validation.d.ts.map +1 -0
- package/dist/decorators/validation.js +179 -0
- package/dist/decorators/validation.js.map +1 -0
- package/dist/dto/examples.d.ts +32 -0
- package/dist/dto/examples.d.ts.map +1 -0
- package/dist/dto/examples.js +127 -0
- package/dist/dto/examples.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/interceptors/validation.interceptor.d.ts +29 -0
- package/dist/interceptors/validation.interceptor.d.ts.map +1 -0
- package/dist/interceptors/validation.interceptor.js +164 -0
- package/dist/interceptors/validation.interceptor.js.map +1 -0
- package/dist/pipes/validation.pipe.d.ts +57 -0
- package/dist/pipes/validation.pipe.d.ts.map +1 -0
- package/dist/pipes/validation.pipe.js +186 -0
- package/dist/pipes/validation.pipe.js.map +1 -0
- package/dist/utils/validation.utils.d.ts +50 -0
- package/dist/utils/validation.utils.d.ts.map +1 -0
- package/dist/utils/validation.utils.js +162 -0
- package/dist/utils/validation.utils.js.map +1 -0
- package/package.json +35 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { Type } from '@sinclair/typebox';
|
|
2
|
+
import 'reflect-metadata';
|
|
3
|
+
/**
|
|
4
|
+
* 验证元数据键
|
|
5
|
+
*/
|
|
6
|
+
export const VALIDATION_METADATA_KEY = Symbol('validation');
|
|
7
|
+
/**
|
|
8
|
+
* 创建属性验证装饰器
|
|
9
|
+
*/
|
|
10
|
+
function createPropertyValidator(schema, options = {}) {
|
|
11
|
+
return function (target, propertyKey) {
|
|
12
|
+
const existingMetadata = Reflect.getMetadata(VALIDATION_METADATA_KEY, target.constructor) || { properties: [] };
|
|
13
|
+
const propertyMetadata = {
|
|
14
|
+
propertyKey,
|
|
15
|
+
schema,
|
|
16
|
+
isOptional: options.optional,
|
|
17
|
+
message: options.message,
|
|
18
|
+
};
|
|
19
|
+
existingMetadata.properties.push(propertyMetadata);
|
|
20
|
+
Reflect.defineMetadata(VALIDATION_METADATA_KEY, existingMetadata, target.constructor);
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 字符串验证装饰器
|
|
25
|
+
*/
|
|
26
|
+
export function IsString(options = {}) {
|
|
27
|
+
let schema = Type.String();
|
|
28
|
+
if (options.minLength !== undefined) {
|
|
29
|
+
schema = Type.String({ minLength: options.minLength });
|
|
30
|
+
}
|
|
31
|
+
if (options.maxLength !== undefined) {
|
|
32
|
+
schema = Type.String({ maxLength: options.maxLength });
|
|
33
|
+
}
|
|
34
|
+
if (options.pattern) {
|
|
35
|
+
schema = Type.String({ pattern: options.pattern });
|
|
36
|
+
}
|
|
37
|
+
if (options.minLength !== undefined && options.maxLength !== undefined) {
|
|
38
|
+
schema = Type.String({ minLength: options.minLength, maxLength: options.maxLength });
|
|
39
|
+
}
|
|
40
|
+
return createPropertyValidator(schema, { message: options.message });
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 数字验证装饰器
|
|
44
|
+
*/
|
|
45
|
+
export function IsNumber(options = {}) {
|
|
46
|
+
let schema = Type.Number();
|
|
47
|
+
if (options.minimum !== undefined) {
|
|
48
|
+
schema = Type.Number({ minimum: options.minimum });
|
|
49
|
+
}
|
|
50
|
+
if (options.maximum !== undefined) {
|
|
51
|
+
schema = Type.Number({ maximum: options.maximum });
|
|
52
|
+
}
|
|
53
|
+
if (options.multipleOf !== undefined) {
|
|
54
|
+
schema = Type.Number({ multipleOf: options.multipleOf });
|
|
55
|
+
}
|
|
56
|
+
if (options.minimum !== undefined && options.maximum !== undefined) {
|
|
57
|
+
schema = Type.Number({ minimum: options.minimum, maximum: options.maximum });
|
|
58
|
+
}
|
|
59
|
+
return createPropertyValidator(schema, { message: options.message });
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* 整数验证装饰器
|
|
63
|
+
*/
|
|
64
|
+
export function IsInteger(options = {}) {
|
|
65
|
+
let schema = Type.Integer();
|
|
66
|
+
if (options.minimum !== undefined && options.maximum !== undefined) {
|
|
67
|
+
schema = Type.Integer({ minimum: options.minimum, maximum: options.maximum });
|
|
68
|
+
}
|
|
69
|
+
else if (options.minimum !== undefined) {
|
|
70
|
+
schema = Type.Integer({ minimum: options.minimum });
|
|
71
|
+
}
|
|
72
|
+
else if (options.maximum !== undefined) {
|
|
73
|
+
schema = Type.Integer({ maximum: options.maximum });
|
|
74
|
+
}
|
|
75
|
+
return createPropertyValidator(schema, { message: options.message });
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 布尔值验证装饰器
|
|
79
|
+
*/
|
|
80
|
+
export function IsBoolean(options = {}) {
|
|
81
|
+
const schema = Type.Boolean();
|
|
82
|
+
return createPropertyValidator(schema, { message: options.message });
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* 邮箱验证装饰器
|
|
86
|
+
*/
|
|
87
|
+
export function IsEmail(options = {}) {
|
|
88
|
+
const schema = Type.String({
|
|
89
|
+
pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'
|
|
90
|
+
});
|
|
91
|
+
return createPropertyValidator(schema, { message: options.message || 'Must be a valid email address' });
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* URL 验证装饰器
|
|
95
|
+
*/
|
|
96
|
+
export function IsUrl(options = {}) {
|
|
97
|
+
const schema = Type.String({
|
|
98
|
+
pattern: '^https?:\\/\\/.+'
|
|
99
|
+
});
|
|
100
|
+
return createPropertyValidator(schema, { message: options.message || 'Must be a valid URL' });
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* 数组验证装饰器
|
|
104
|
+
*/
|
|
105
|
+
export function IsArray(itemSchema, options = {}) {
|
|
106
|
+
let schema = itemSchema ? Type.Array(itemSchema) : Type.Array(Type.Any());
|
|
107
|
+
if (options.minItems !== undefined || options.maxItems !== undefined) {
|
|
108
|
+
const arrayOptions = {};
|
|
109
|
+
if (options.minItems !== undefined)
|
|
110
|
+
arrayOptions.minItems = options.minItems;
|
|
111
|
+
if (options.maxItems !== undefined)
|
|
112
|
+
arrayOptions.maxItems = options.maxItems;
|
|
113
|
+
schema = itemSchema ? Type.Array(itemSchema, arrayOptions) : Type.Array(Type.Any(), arrayOptions);
|
|
114
|
+
}
|
|
115
|
+
return createPropertyValidator(schema, { message: options.message });
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* 枚举验证装饰器
|
|
119
|
+
*/
|
|
120
|
+
export function IsEnum(enumValues, options = {}) {
|
|
121
|
+
const schema = Type.Union(enumValues.map(value => Type.Literal(value)));
|
|
122
|
+
return createPropertyValidator(schema, { message: options.message || `Must be one of: ${enumValues.join(', ')}` });
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 日期验证装饰器
|
|
126
|
+
*/
|
|
127
|
+
export function IsDate(options = {}) {
|
|
128
|
+
const schema = Type.String({ format: 'date-time' });
|
|
129
|
+
return createPropertyValidator(schema, { message: options.message || 'Must be a valid date' });
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* 可选字段装饰器
|
|
133
|
+
*/
|
|
134
|
+
export function IsOptional() {
|
|
135
|
+
return function (target, propertyKey) {
|
|
136
|
+
const existingMetadata = Reflect.getMetadata(VALIDATION_METADATA_KEY, target.constructor) || { properties: [] };
|
|
137
|
+
// 查找对应的属性元数据并标记为可选
|
|
138
|
+
const propertyMetadata = existingMetadata.properties.find(p => p.propertyKey === propertyKey);
|
|
139
|
+
if (propertyMetadata) {
|
|
140
|
+
propertyMetadata.isOptional = true;
|
|
141
|
+
}
|
|
142
|
+
Reflect.defineMetadata(VALIDATION_METADATA_KEY, existingMetadata, target.constructor);
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* 长度验证装饰器
|
|
147
|
+
*/
|
|
148
|
+
export function Length(min, max, options = {}) {
|
|
149
|
+
const schema = max !== undefined
|
|
150
|
+
? Type.String({ minLength: min, maxLength: max })
|
|
151
|
+
: Type.String({ minLength: min });
|
|
152
|
+
const message = options.message || (max !== undefined
|
|
153
|
+
? `Length must be between ${min} and ${max} characters`
|
|
154
|
+
: `Length must be at least ${min} characters`);
|
|
155
|
+
return createPropertyValidator(schema, { message });
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* 最小值验证装饰器
|
|
159
|
+
*/
|
|
160
|
+
export function Min(value, options = {}) {
|
|
161
|
+
const schema = Type.Number({ minimum: value });
|
|
162
|
+
return createPropertyValidator(schema, { message: options.message || `Must be at least ${value}` });
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* 最大值验证装饰器
|
|
166
|
+
*/
|
|
167
|
+
export function Max(value, options = {}) {
|
|
168
|
+
const schema = Type.Number({ maximum: value });
|
|
169
|
+
return createPropertyValidator(schema, { message: options.message || `Must be at most ${value}` });
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* 模式匹配验证装饰器
|
|
173
|
+
*/
|
|
174
|
+
export function Matches(pattern, options = {}) {
|
|
175
|
+
const patternString = pattern instanceof RegExp ? pattern.source : pattern;
|
|
176
|
+
const schema = Type.String({ pattern: patternString });
|
|
177
|
+
return createPropertyValidator(schema, { message: options.message || `Must match pattern: ${patternString}` });
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/decorators/validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 用户创建 DTO 示例
|
|
3
|
+
*/
|
|
4
|
+
export declare class CreateUserDto {
|
|
5
|
+
name: string;
|
|
6
|
+
email: string;
|
|
7
|
+
age: number;
|
|
8
|
+
password: string;
|
|
9
|
+
bio?: string;
|
|
10
|
+
tags?: string[];
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 用户更新 DTO 示例
|
|
14
|
+
*/
|
|
15
|
+
export declare class UpdateUserDto {
|
|
16
|
+
name?: string;
|
|
17
|
+
email?: string;
|
|
18
|
+
age?: number;
|
|
19
|
+
bio?: string;
|
|
20
|
+
tags?: string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 查询参数 DTO 示例
|
|
24
|
+
*/
|
|
25
|
+
export declare class UserQueryDto {
|
|
26
|
+
search?: string;
|
|
27
|
+
page?: number;
|
|
28
|
+
limit?: number;
|
|
29
|
+
sortBy?: string;
|
|
30
|
+
sortOrder?: 'asc' | 'desc';
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=examples.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"examples.d.ts","sourceRoot":"","sources":["../../src/dto/examples.ts"],"names":[],"mappings":"AAYA;;GAEG;AACH,qBAAa,aAAa;IAExB,IAAI,EAAG,MAAM,CAAC;IAGd,KAAK,EAAG,MAAM,CAAC;IAKf,GAAG,EAAG,MAAM,CAAC;IAIb,QAAQ,EAAG,MAAM,CAAC;IAIlB,GAAG,CAAC,EAAE,MAAM,CAAC;IAIb,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,aAAa;IAGxB,IAAI,CAAC,EAAE,MAAM,CAAC;IAId,KAAK,CAAC,EAAE,MAAM,CAAC;IAMf,GAAG,CAAC,EAAE,MAAM,CAAC;IAIb,GAAG,CAAC,EAAE,MAAM,CAAC;IAIb,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,YAAY;IAGvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAKhB,IAAI,CAAC,EAAE,MAAM,CAAC;IAMd,KAAK,CAAC,EAAE,MAAM,CAAC;IAIf,MAAM,CAAC,EAAE,MAAM,CAAC;IAIhB,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;CAC5B"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { Type } from '@sinclair/typebox';
|
|
11
|
+
import { IsString, IsEmail, IsNumber, IsOptional, IsArray, Min, Max, Length } from '../decorators/validation';
|
|
12
|
+
/**
|
|
13
|
+
* 用户创建 DTO 示例
|
|
14
|
+
*/
|
|
15
|
+
export class CreateUserDto {
|
|
16
|
+
name;
|
|
17
|
+
email;
|
|
18
|
+
age;
|
|
19
|
+
password;
|
|
20
|
+
bio;
|
|
21
|
+
tags;
|
|
22
|
+
}
|
|
23
|
+
__decorate([
|
|
24
|
+
IsString({ minLength: 2, maxLength: 50 }),
|
|
25
|
+
__metadata("design:type", String)
|
|
26
|
+
], CreateUserDto.prototype, "name", void 0);
|
|
27
|
+
__decorate([
|
|
28
|
+
IsEmail(),
|
|
29
|
+
__metadata("design:type", String)
|
|
30
|
+
], CreateUserDto.prototype, "email", void 0);
|
|
31
|
+
__decorate([
|
|
32
|
+
IsNumber(),
|
|
33
|
+
Min(0),
|
|
34
|
+
Max(120),
|
|
35
|
+
__metadata("design:type", Number)
|
|
36
|
+
], CreateUserDto.prototype, "age", void 0);
|
|
37
|
+
__decorate([
|
|
38
|
+
IsString(),
|
|
39
|
+
Length(8, 100),
|
|
40
|
+
__metadata("design:type", String)
|
|
41
|
+
], CreateUserDto.prototype, "password", void 0);
|
|
42
|
+
__decorate([
|
|
43
|
+
IsOptional(),
|
|
44
|
+
IsString(),
|
|
45
|
+
__metadata("design:type", String)
|
|
46
|
+
], CreateUserDto.prototype, "bio", void 0);
|
|
47
|
+
__decorate([
|
|
48
|
+
IsOptional(),
|
|
49
|
+
IsArray(Type.String()),
|
|
50
|
+
__metadata("design:type", Array)
|
|
51
|
+
], CreateUserDto.prototype, "tags", void 0);
|
|
52
|
+
/**
|
|
53
|
+
* 用户更新 DTO 示例
|
|
54
|
+
*/
|
|
55
|
+
export class UpdateUserDto {
|
|
56
|
+
name;
|
|
57
|
+
email;
|
|
58
|
+
age;
|
|
59
|
+
bio;
|
|
60
|
+
tags;
|
|
61
|
+
}
|
|
62
|
+
__decorate([
|
|
63
|
+
IsOptional(),
|
|
64
|
+
IsString({ minLength: 2, maxLength: 50 }),
|
|
65
|
+
__metadata("design:type", String)
|
|
66
|
+
], UpdateUserDto.prototype, "name", void 0);
|
|
67
|
+
__decorate([
|
|
68
|
+
IsOptional(),
|
|
69
|
+
IsEmail(),
|
|
70
|
+
__metadata("design:type", String)
|
|
71
|
+
], UpdateUserDto.prototype, "email", void 0);
|
|
72
|
+
__decorate([
|
|
73
|
+
IsOptional(),
|
|
74
|
+
IsNumber(),
|
|
75
|
+
Min(0),
|
|
76
|
+
Max(120),
|
|
77
|
+
__metadata("design:type", Number)
|
|
78
|
+
], UpdateUserDto.prototype, "age", void 0);
|
|
79
|
+
__decorate([
|
|
80
|
+
IsOptional(),
|
|
81
|
+
IsString(),
|
|
82
|
+
__metadata("design:type", String)
|
|
83
|
+
], UpdateUserDto.prototype, "bio", void 0);
|
|
84
|
+
__decorate([
|
|
85
|
+
IsOptional(),
|
|
86
|
+
IsArray(Type.String()),
|
|
87
|
+
__metadata("design:type", Array)
|
|
88
|
+
], UpdateUserDto.prototype, "tags", void 0);
|
|
89
|
+
/**
|
|
90
|
+
* 查询参数 DTO 示例
|
|
91
|
+
*/
|
|
92
|
+
export class UserQueryDto {
|
|
93
|
+
search;
|
|
94
|
+
page;
|
|
95
|
+
limit;
|
|
96
|
+
sortBy;
|
|
97
|
+
sortOrder;
|
|
98
|
+
}
|
|
99
|
+
__decorate([
|
|
100
|
+
IsOptional(),
|
|
101
|
+
IsString(),
|
|
102
|
+
__metadata("design:type", String)
|
|
103
|
+
], UserQueryDto.prototype, "search", void 0);
|
|
104
|
+
__decorate([
|
|
105
|
+
IsOptional(),
|
|
106
|
+
IsNumber(),
|
|
107
|
+
Min(1),
|
|
108
|
+
__metadata("design:type", Number)
|
|
109
|
+
], UserQueryDto.prototype, "page", void 0);
|
|
110
|
+
__decorate([
|
|
111
|
+
IsOptional(),
|
|
112
|
+
IsNumber(),
|
|
113
|
+
Min(1),
|
|
114
|
+
Max(100),
|
|
115
|
+
__metadata("design:type", Number)
|
|
116
|
+
], UserQueryDto.prototype, "limit", void 0);
|
|
117
|
+
__decorate([
|
|
118
|
+
IsOptional(),
|
|
119
|
+
IsString(),
|
|
120
|
+
__metadata("design:type", String)
|
|
121
|
+
], UserQueryDto.prototype, "sortBy", void 0);
|
|
122
|
+
__decorate([
|
|
123
|
+
IsOptional(),
|
|
124
|
+
IsString(),
|
|
125
|
+
__metadata("design:type", String)
|
|
126
|
+
], UserQueryDto.prototype, "sortOrder", void 0);
|
|
127
|
+
//# sourceMappingURL=examples.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"examples.js","sourceRoot":"","sources":["../../src/dto/examples.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,IAAI,EAAgB,MAAM,mBAAmB,CAAC;AACvD,OAAO,EACL,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,UAAU,EACV,OAAO,EACP,GAAG,EACH,GAAG,EACH,MAAM,EACP,MAAM,0BAA0B,CAAC;AAElC;;GAEG;AACH,MAAM,OAAO,aAAa;IAExB,IAAI,CAAU;IAGd,KAAK,CAAU;IAKf,GAAG,CAAU;IAIb,QAAQ,CAAU;IAIlB,GAAG,CAAU;IAIb,IAAI,CAAY;CACjB;AArBC;IADC,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;;2CAC5B;AAGd;IADC,OAAO,EAAE;;4CACK;AAKf;IAHC,QAAQ,EAAE;IACV,GAAG,CAAC,CAAC,CAAC;IACN,GAAG,CAAC,GAAG,CAAC;;0CACI;AAIb;IAFC,QAAQ,EAAE;IACV,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC;;+CACG;AAIlB;IAFC,UAAU,EAAE;IACZ,QAAQ,EAAE;;0CACE;AAIb;IAFC,UAAU,EAAE;IACZ,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;;2CACP;AAGlB;;GAEG;AACH,MAAM,OAAO,aAAa;IAGxB,IAAI,CAAU;IAId,KAAK,CAAU;IAMf,GAAG,CAAU;IAIb,GAAG,CAAU;IAIb,IAAI,CAAY;CACjB;AAnBC;IAFC,UAAU,EAAE;IACZ,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;;2CAC5B;AAId;IAFC,UAAU,EAAE;IACZ,OAAO,EAAE;;4CACK;AAMf;IAJC,UAAU,EAAE;IACZ,QAAQ,EAAE;IACV,GAAG,CAAC,CAAC,CAAC;IACN,GAAG,CAAC,GAAG,CAAC;;0CACI;AAIb;IAFC,UAAU,EAAE;IACZ,QAAQ,EAAE;;0CACE;AAIb;IAFC,UAAU,EAAE;IACZ,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;;2CACP;AAGlB;;GAEG;AACH,MAAM,OAAO,YAAY;IAGvB,MAAM,CAAU;IAKhB,IAAI,CAAU;IAMd,KAAK,CAAU;IAIf,MAAM,CAAU;IAIhB,SAAS,CAAkB;CAC5B;AApBC;IAFC,UAAU,EAAE;IACZ,QAAQ,EAAE;;4CACK;AAKhB;IAHC,UAAU,EAAE;IACZ,QAAQ,EAAE;IACV,GAAG,CAAC,CAAC,CAAC;;0CACO;AAMd;IAJC,UAAU,EAAE;IACZ,QAAQ,EAAE;IACV,GAAG,CAAC,CAAC,CAAC;IACN,GAAG,CAAC,GAAG,CAAC;;2CACM;AAIf;IAFC,UAAU,EAAE;IACZ,QAAQ,EAAE;;4CACK;AAIhB;IAFC,UAAU,EAAE;IACZ,QAAQ,EAAE;;+CACgB"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './decorators/validation';
|
|
2
|
+
export * from './decorators/custom';
|
|
3
|
+
export * from './pipes/validation.pipe';
|
|
4
|
+
export * from './interceptors/validation.interceptor';
|
|
5
|
+
export * from './dto/examples';
|
|
6
|
+
export * from './utils/validation.utils';
|
|
7
|
+
export { Type, type TSchema, type Static } from '@sinclair/typebox';
|
|
8
|
+
export { Value } from '@sinclair/typebox/value';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AAGpC,cAAc,yBAAyB,CAAC;AAGxC,cAAc,uCAAuC,CAAC;AAGtD,cAAc,gBAAgB,CAAC;AAG/B,cAAc,0BAA0B,CAAC;AAGzC,OAAO,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// 装饰器
|
|
2
|
+
export * from './decorators/validation';
|
|
3
|
+
export * from './decorators/custom';
|
|
4
|
+
// 管道
|
|
5
|
+
export * from './pipes/validation.pipe';
|
|
6
|
+
// 拦截器
|
|
7
|
+
export * from './interceptors/validation.interceptor';
|
|
8
|
+
// DTO 示例
|
|
9
|
+
export * from './dto/examples';
|
|
10
|
+
// 工具函数
|
|
11
|
+
export * from './utils/validation.utils';
|
|
12
|
+
// TypeBox 相关导出
|
|
13
|
+
export { Type } from '@sinclair/typebox';
|
|
14
|
+
export { Value } from '@sinclair/typebox/value';
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,MAAM;AACN,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AAEpC,KAAK;AACL,cAAc,yBAAyB,CAAC;AAExC,MAAM;AACN,cAAc,uCAAuC,CAAC;AAEtD,SAAS;AACT,cAAc,gBAAgB,CAAC;AAE/B,OAAO;AACP,cAAc,0BAA0B,CAAC;AAEzC,eAAe;AACf,OAAO,EAAE,IAAI,EAA6B,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { CallHandler, ExecutionContext, Interceptor } from "@hestjs/core";
|
|
2
|
+
/**
|
|
3
|
+
* 参数验证元数据
|
|
4
|
+
*/
|
|
5
|
+
export interface ParameterValidationMetadata {
|
|
6
|
+
index: number;
|
|
7
|
+
dtoClass: new () => any;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Body 验证装饰器
|
|
11
|
+
*/
|
|
12
|
+
export declare function Body<T>(dtoClass: new () => T): (target: any, propertyKey: string | symbol | undefined, parameterIndex: number) => void;
|
|
13
|
+
/**
|
|
14
|
+
* Query 验证装饰器
|
|
15
|
+
*/
|
|
16
|
+
export declare function Query<T>(dtoClass: new () => T): (target: any, propertyKey: string | symbol | undefined, parameterIndex: number) => void;
|
|
17
|
+
/**
|
|
18
|
+
* 验证拦截器
|
|
19
|
+
*/
|
|
20
|
+
export declare class ValidationInterceptor implements Interceptor {
|
|
21
|
+
private readonly validationPipe;
|
|
22
|
+
constructor();
|
|
23
|
+
intercept(context: ExecutionContext, next: CallHandler): Promise<any>;
|
|
24
|
+
/**
|
|
25
|
+
* 获取请求体数据
|
|
26
|
+
*/
|
|
27
|
+
private getRequestBody;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=validation.interceptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.interceptor.d.ts","sourceRoot":"","sources":["../../src/interceptors/validation.interceptor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,gBAAgB,EAEhB,WAAW,EACZ,MAAM,cAAc,CAAC;AAQtB;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,UAAU,GAAG,CAAC;CACzB;AAED;;GAEG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,IAEzC,QAAQ,GAAG,EACX,aAAa,MAAM,GAAG,MAAM,GAAG,SAAS,EACxC,gBAAgB,MAAM,UAwBzB;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,IAE1C,QAAQ,GAAG,EACX,aAAa,MAAM,GAAG,MAAM,GAAG,SAAS,EACxC,gBAAgB,MAAM,UAwBzB;AAED;;GAEG;AACH,qBACa,qBAAsB,YAAW,WAAW;IACvD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;;IAU1C,SAAS,CAAC,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC;IA6E3E;;OAEG;YACW,cAAc;CAkC7B"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { Injectable, } from "@hestjs/core";
|
|
11
|
+
import { ValidationException, ValidationPipe } from "../pipes/validation.pipe";
|
|
12
|
+
/**
|
|
13
|
+
* 参数验证元数据键
|
|
14
|
+
*/
|
|
15
|
+
const PARAMETER_VALIDATION_KEY = Symbol("parameter:validation");
|
|
16
|
+
/**
|
|
17
|
+
* Body 验证装饰器
|
|
18
|
+
*/
|
|
19
|
+
export function Body(dtoClass) {
|
|
20
|
+
return function (target, propertyKey, parameterIndex) {
|
|
21
|
+
const existingMetadata = Reflect.getMetadata(PARAMETER_VALIDATION_KEY, target, propertyKey) || [];
|
|
22
|
+
existingMetadata.push({
|
|
23
|
+
index: parameterIndex,
|
|
24
|
+
dtoClass,
|
|
25
|
+
});
|
|
26
|
+
Reflect.defineMetadata(PARAMETER_VALIDATION_KEY, existingMetadata, target, propertyKey);
|
|
27
|
+
// console.log('🔍 Body装饰器: 已存储验证元数据', {
|
|
28
|
+
// target: target.constructor.name,
|
|
29
|
+
// method: String(propertyKey),
|
|
30
|
+
// parameterIndex,
|
|
31
|
+
// dtoClass: dtoClass.name
|
|
32
|
+
// });
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Query 验证装饰器
|
|
37
|
+
*/
|
|
38
|
+
export function Query(dtoClass) {
|
|
39
|
+
return function (target, propertyKey, parameterIndex) {
|
|
40
|
+
const existingMetadata = Reflect.getMetadata(PARAMETER_VALIDATION_KEY, target, propertyKey) || [];
|
|
41
|
+
existingMetadata.push({
|
|
42
|
+
index: parameterIndex,
|
|
43
|
+
dtoClass,
|
|
44
|
+
});
|
|
45
|
+
Reflect.defineMetadata(PARAMETER_VALIDATION_KEY, existingMetadata, target, propertyKey);
|
|
46
|
+
// console.log('🔍 Query装饰器: 已存储验证元数据', {
|
|
47
|
+
// target: target.constructor.name,
|
|
48
|
+
// method: String(propertyKey),
|
|
49
|
+
// parameterIndex,
|
|
50
|
+
// dtoClass: dtoClass.name
|
|
51
|
+
// });
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 验证拦截器
|
|
56
|
+
*/
|
|
57
|
+
let ValidationInterceptor = class ValidationInterceptor {
|
|
58
|
+
validationPipe;
|
|
59
|
+
constructor() {
|
|
60
|
+
this.validationPipe = new ValidationPipe({
|
|
61
|
+
whitelist: true,
|
|
62
|
+
forbidNonWhitelisted: false,
|
|
63
|
+
transform: true,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async intercept(context, next) {
|
|
67
|
+
const httpContext = context.switchToHttp();
|
|
68
|
+
const request = httpContext.getRequest();
|
|
69
|
+
const handler = context.getHandler();
|
|
70
|
+
const target = context.getClass();
|
|
71
|
+
// console.log('🔍 ValidationInterceptor: 开始验证', handler.name);
|
|
72
|
+
// console.log('🔍 ValidationInterceptor: context 类型:', typeof context);
|
|
73
|
+
// console.log('🔍 ValidationInterceptor: context 键:', Object.keys(context));
|
|
74
|
+
// 尝试获取原始的 Hono Context
|
|
75
|
+
const honoContext = context.context || request;
|
|
76
|
+
// console.log('🔍 ValidationInterceptor: honoContext 类型:', typeof honoContext);
|
|
77
|
+
// 获取参数验证元数据
|
|
78
|
+
const paramValidations = Reflect.getMetadata(PARAMETER_VALIDATION_KEY, target.prototype, handler.name) || [];
|
|
79
|
+
// console.log('🔍 ValidationInterceptor: 找到参数验证数量:', paramValidations.length);
|
|
80
|
+
// console.log('🔍 ValidationInterceptor: 检查目标:', target.name, '方法:', handler.name);
|
|
81
|
+
// console.log('🔍 ValidationInterceptor: 尝试读取元数据键:', PARAMETER_VALIDATION_KEY.toString());
|
|
82
|
+
if (paramValidations.length === 0) {
|
|
83
|
+
// console.log('🔍 ValidationInterceptor: 没有找到验证元数据,跳过验证');
|
|
84
|
+
return next.handle();
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
// 验证请求体和查询参数
|
|
88
|
+
for (const validation of paramValidations) {
|
|
89
|
+
const { dtoClass } = validation;
|
|
90
|
+
// console.log('🔍 ValidationInterceptor: 验证 DTO 类:', dtoClass.name);
|
|
91
|
+
// 获取请求数据 - 优先使用 Hono Context
|
|
92
|
+
const body = await this.getRequestBody(honoContext);
|
|
93
|
+
// console.log('🔍 ValidationInterceptor: 请求体数据:', body);
|
|
94
|
+
if (body && Object.keys(body).length > 0) {
|
|
95
|
+
// 进行验证
|
|
96
|
+
// console.log('🔍 ValidationInterceptor: 开始验证数据');
|
|
97
|
+
const validatedData = await this.validationPipe.validate(dtoClass, body);
|
|
98
|
+
// console.log('🔍 ValidationInterceptor: 验证通过,数据:', validatedData);
|
|
99
|
+
// 将验证后的数据存储到请求中
|
|
100
|
+
honoContext.validatedBody = validatedData;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
// console.log('🔍 ValidationInterceptor: 请求体为空,跳过验证');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return next.handle();
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
// console.log("🔍 ValidationInterceptor: 验证失败:", error);
|
|
110
|
+
if (error instanceof ValidationException) {
|
|
111
|
+
// 抛出 HTTP 异常
|
|
112
|
+
const validationError = new Error("Validation failed");
|
|
113
|
+
validationError.status = 400;
|
|
114
|
+
validationError.details = {
|
|
115
|
+
message: "Validation failed",
|
|
116
|
+
errors: error.getMessages(),
|
|
117
|
+
statusCode: 400,
|
|
118
|
+
};
|
|
119
|
+
throw validationError;
|
|
120
|
+
}
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 获取请求体数据
|
|
126
|
+
*/
|
|
127
|
+
async getRequestBody(request) {
|
|
128
|
+
try {
|
|
129
|
+
// console.log('🔍 getRequestBody: 检查请求对象类型:', typeof request);
|
|
130
|
+
// console.log('🔍 getRequestBody: 请求对象键:', Object.keys(request || {}));
|
|
131
|
+
// 检查是否是 Hono Context
|
|
132
|
+
if (request && request.req) {
|
|
133
|
+
// console.log('🔍 getRequestBody: 检测到 Hono Context,使用 req.json()');
|
|
134
|
+
const body = await request.req.json();
|
|
135
|
+
// console.log('🔍 getRequestBody: 从 Hono Context 获取到的数据:', body);
|
|
136
|
+
return body;
|
|
137
|
+
}
|
|
138
|
+
// 直接尝试调用 json 方法
|
|
139
|
+
if (request && typeof request.json === "function") {
|
|
140
|
+
// console.log('🔍 getRequestBody: 使用 request.json()');
|
|
141
|
+
const body = await request.json();
|
|
142
|
+
// console.log('🔍 getRequestBody: 从 request.json() 获取到的数据:', body);
|
|
143
|
+
return body;
|
|
144
|
+
}
|
|
145
|
+
// 如果已经解析过了,直接返回
|
|
146
|
+
if (request && request.body) {
|
|
147
|
+
// console.log('🔍 getRequestBody: 使用已解析的 body:', request.body);
|
|
148
|
+
return request.body;
|
|
149
|
+
}
|
|
150
|
+
// console.log('🔍 getRequestBody: 无法获取请求体,返回空对象');
|
|
151
|
+
return {};
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
// console.log('🔍 getRequestBody: 获取请求体时出错:', error);
|
|
155
|
+
return {};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
ValidationInterceptor = __decorate([
|
|
160
|
+
Injectable(),
|
|
161
|
+
__metadata("design:paramtypes", [])
|
|
162
|
+
], ValidationInterceptor);
|
|
163
|
+
export { ValidationInterceptor };
|
|
164
|
+
//# sourceMappingURL=validation.interceptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.interceptor.js","sourceRoot":"","sources":["../../src/interceptors/validation.interceptor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type TSchema } from "@sinclair/typebox";
|
|
2
|
+
/**
|
|
3
|
+
* 验证错误
|
|
4
|
+
*/
|
|
5
|
+
export declare class ValidationError extends Error {
|
|
6
|
+
field: string;
|
|
7
|
+
value: any;
|
|
8
|
+
constraint: string;
|
|
9
|
+
constructor(message: string, field: string, value: any, constraint: string);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 验证异常 - 包含多个验证错误
|
|
13
|
+
*/
|
|
14
|
+
export declare class ValidationException extends Error {
|
|
15
|
+
errors: ValidationError[];
|
|
16
|
+
constructor(errors: ValidationError[]);
|
|
17
|
+
getMessages(): string[];
|
|
18
|
+
getFormattedMessage(): string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 验证管道选项
|
|
22
|
+
*/
|
|
23
|
+
export interface ValidationPipeOptions {
|
|
24
|
+
whitelist?: boolean;
|
|
25
|
+
forbidNonWhitelisted?: boolean;
|
|
26
|
+
transform?: boolean;
|
|
27
|
+
disableErrorMessages?: boolean;
|
|
28
|
+
validateCustomDecorators?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 验证管道
|
|
32
|
+
*/
|
|
33
|
+
export declare class ValidationPipe {
|
|
34
|
+
private readonly options;
|
|
35
|
+
constructor(options?: ValidationPipeOptions);
|
|
36
|
+
/**
|
|
37
|
+
* 验证对象
|
|
38
|
+
*/
|
|
39
|
+
validate<T>(target: new () => T, object: any): Promise<T>;
|
|
40
|
+
/**
|
|
41
|
+
* 过滤属性(白名单模式)
|
|
42
|
+
*/
|
|
43
|
+
private filterProperties;
|
|
44
|
+
/**
|
|
45
|
+
* 获取自定义错误消息
|
|
46
|
+
*/
|
|
47
|
+
private getCustomMessage;
|
|
48
|
+
/**
|
|
49
|
+
* 验证单个值
|
|
50
|
+
*/
|
|
51
|
+
validateValue<T>(schema: TSchema, value: any, fieldName?: string): T;
|
|
52
|
+
/**
|
|
53
|
+
* 创建 DTO 验证装饰器
|
|
54
|
+
*/
|
|
55
|
+
static createDtoValidator<T>(dtoClass: new () => T): (target: any, propertyKey: string | symbol, parameterIndex: number) => void;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=validation.pipe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.pipe.d.ts","sourceRoot":"","sources":["../../src/pipes/validation.pipe.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAOvD;;GAEG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IAG/B,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,GAAG;IACV,UAAU,EAAE,MAAM;gBAHzB,OAAO,EAAE,MAAM,EACR,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,GAAG,EACV,UAAU,EAAE,MAAM;CAK5B;AAED;;GAEG;AACH,qBAAa,mBAAoB,SAAQ,KAAK;IACzB,MAAM,EAAE,eAAe,EAAE;gBAAzB,MAAM,EAAE,eAAe,EAAE;IAK5C,WAAW,IAAI,MAAM,EAAE;IAIvB,mBAAmB,IAAI,MAAM;CAK9B;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAED;;GAEG;AACH,qBACa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;gBAEpC,OAAO,GAAE,qBAA0B;IAW/C;;OAEG;IACG,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC;IA8E/D;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA+BxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAUxB;;OAEG;IACH,aAAa,CAAC,CAAC,EACb,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,GAAG,EACV,SAAS,GAAE,MAAgB,GAC1B,CAAC;IA4BJ;;OAEG;IACH,MAAM,CAAC,kBAAkB,CAAC,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,IAE9C,QAAQ,GAAG,EACX,aAAa,MAAM,GAAG,MAAM,EAC5B,gBAAgB,MAAM;CAU3B"}
|