@decaf-ts/decorator-validation 1.7.1 → 1.7.3
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 +312 -20
- package/dist/decorator-validation.cjs +245 -94
- package/dist/decorator-validation.esm.cjs +245 -95
- package/lib/constants/validation.cjs +6 -8
- package/lib/constants/validation.d.ts +4 -6
- package/lib/esm/constants/validation.d.ts +4 -6
- package/lib/esm/constants/validation.js +6 -8
- package/lib/esm/index.d.ts +8 -1
- package/lib/esm/index.js +9 -2
- package/lib/esm/model/Model.d.ts +164 -40
- package/lib/esm/model/Model.js +165 -41
- package/lib/esm/model/construction.d.ts +4 -2
- package/lib/esm/model/construction.js +4 -2
- package/lib/esm/model/decorators.d.ts +25 -1
- package/lib/esm/model/decorators.js +26 -2
- package/lib/esm/model/types.d.ts +48 -31
- package/lib/esm/model/types.js +1 -1
- package/lib/esm/utils/decorators.d.ts +7 -12
- package/lib/esm/utils/decorators.js +8 -13
- package/lib/esm/validation/Validators/EmailValidator.js +2 -1
- package/lib/esm/validation/Validators/PasswordValidator.js +3 -2
- package/lib/esm/validation/Validators/URLValidator.js +2 -1
- package/lib/esm/validation/Validators/decorators.d.ts +1 -1
- package/lib/esm/validation/Validators/decorators.js +2 -2
- package/lib/esm/validation/Validators/utils.d.ts +4 -0
- package/lib/esm/validation/Validators/utils.js +5 -1
- package/lib/esm/validation/decorators.d.ts +20 -26
- package/lib/esm/validation/decorators.js +21 -27
- package/lib/index.cjs +9 -2
- package/lib/index.d.ts +8 -1
- package/lib/model/Model.cjs +165 -41
- package/lib/model/Model.d.ts +164 -40
- package/lib/model/construction.cjs +4 -2
- package/lib/model/construction.d.ts +4 -2
- package/lib/model/decorators.cjs +26 -2
- package/lib/model/decorators.d.ts +25 -1
- package/lib/model/types.cjs +1 -1
- package/lib/model/types.d.ts +48 -31
- package/lib/utils/decorators.cjs +8 -13
- package/lib/utils/decorators.d.ts +7 -12
- package/lib/validation/Validators/EmailValidator.cjs +2 -1
- package/lib/validation/Validators/PasswordValidator.cjs +2 -1
- package/lib/validation/Validators/URLValidator.cjs +2 -1
- package/lib/validation/Validators/decorators.cjs +2 -2
- package/lib/validation/Validators/decorators.d.ts +1 -1
- package/lib/validation/Validators/utils.cjs +5 -1
- package/lib/validation/Validators/utils.d.ts +4 -0
- package/lib/validation/decorators.cjs +21 -27
- package/lib/validation/decorators.d.ts +20 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|

|
|
2
2
|
## Simple Decorator based Model Validation Engine
|
|
3
3
|
|
|
4
|
+
A comprehensive TypeScript library that provides a powerful model validation framework using decorators. It enables type-safe, declarative validation for your TypeScript models with features for serialization, comparison, and hashing. The library offers a rich set of validation decorators for various data types and constraints, making it easy to define and enforce validation rules on your model properties.
|
|
5
|
+
|
|
6
|
+
|
|
4
7
|

|
|
5
8
|

|
|
6
9
|

|
|
@@ -15,12 +18,6 @@
|
|
|
15
18
|

|
|
16
19
|

|
|
17
20
|
|
|
18
|
-

|
|
19
|
-

|
|
20
|
-

|
|
21
|
-

|
|
22
|
-
|
|
23
|
-
|
|
24
21
|

|
|
25
22
|

|
|
26
23
|

|
|
@@ -32,21 +29,42 @@ Documentation available [here](https://decaf-ts.github.io/decorator-validation/)
|
|
|
32
29
|
|
|
33
30
|
### Description
|
|
34
31
|
|
|
35
|
-
|
|
32
|
+
The decorator-validation library is a comprehensive TypeScript implementation of a decorator-based validation system. It provides a robust framework for defining, validating, and managing model objects in TypeScript applications.
|
|
33
|
+
|
|
34
|
+
Meant to be easily extended, customized, and integrated with browser input validation mechanisms, this library offers a declarative approach to validation through TypeScript decorators.
|
|
35
|
+
|
|
36
|
+
#### Core Components
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
##### Model System
|
|
39
|
+
The library is built around the abstract `Model` class, which serves as the foundation for all model objects. The Model system provides:
|
|
40
|
+
|
|
41
|
+
- A registry mechanism for storing and retrieving model constructors
|
|
42
|
+
- Serialization and deserialization capabilities
|
|
43
|
+
- Hashing functionality for model objects
|
|
44
|
+
- Equality comparison between model objects
|
|
45
|
+
- Support for nested model instantiation and validation
|
|
46
|
+
|
|
47
|
+
##### Validation Framework
|
|
48
|
+
The validation framework offers a rich set of decorators for validating model properties:
|
|
49
|
+
|
|
50
|
+
- **Basic Validation**: `required()`, `min()`, `max()`, `step()`, `minlength()`, `maxlength()`, `pattern()`
|
|
51
|
+
- **Type-Specific Validation**: `email()`, `url()`, `type()`, `date()`, `password()`, `list()`, `set()`
|
|
52
|
+
- **Comparison Validation**: `eq()`, `diff()`, `lt()`, `lte()`, `gt()`, `gte()` for comparing properties
|
|
53
|
+
|
|
54
|
+
##### Key Features
|
|
55
|
+
- **Decorator-based validation API** with recursive validation for nested models
|
|
56
|
+
- **Customizable Model building factories** enabling nested instantiation
|
|
57
|
+
- **Model serialization/deserialization** with configurable serializers
|
|
58
|
+
- **Model Hashing** with configurable algorithms
|
|
59
|
+
- **Model Equality** comparison with support for excluding properties
|
|
60
|
+
- **Easily extended custom validation** through the decorator system
|
|
61
|
+
- **Java-like date handling** (format and serialization)
|
|
62
|
+
- **Configurable error messages** for all validation rules
|
|
63
|
+
- **Comparative validation** between attributes, supporting various comparison operators
|
|
64
|
+
- **Type safety** through TypeScript's static typing system
|
|
65
|
+
|
|
66
|
+
The library is designed with extensibility in mind, allowing developers to create custom validators and decorators to meet specific application requirements. It integrates seamlessly with TypeScript's type system to provide compile-time type checking alongside runtime validation.
|
|
38
67
|
|
|
39
|
-
Standalone module, defines the base Model class:
|
|
40
|
-
- decorator based validation api with recursive validation;
|
|
41
|
-
- Customizable Model building factories enabling nested instantiation;
|
|
42
|
-
- Model serialization/deserialization;
|
|
43
|
-
- Model Hashing;
|
|
44
|
-
- Model Equality;
|
|
45
|
-
- Easily extended custom validation;
|
|
46
|
-
- Java like date handling (format and serialization);
|
|
47
|
-
- Configurable error messages;
|
|
48
|
-
- TODO: comparative validation (between attributes, hierarchical, dates);
|
|
49
|
-
- TODO: Model Deep Cloning;
|
|
50
68
|
|
|
51
69
|
### How to Use
|
|
52
70
|
|
|
@@ -55,7 +73,281 @@ Standalone module, defines the base Model class:
|
|
|
55
73
|
|
|
56
74
|
### Examples
|
|
57
75
|
|
|
58
|
-
|
|
76
|
+
#### Creating a Model Class
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { Model, model, required, email, minlength, maxlength, min, hashedBy, serializedBy } from 'decorator-validation';
|
|
80
|
+
|
|
81
|
+
@model()
|
|
82
|
+
@hashedBy('sha256')
|
|
83
|
+
@serializedBy('json')
|
|
84
|
+
class User extends Model {
|
|
85
|
+
@required()
|
|
86
|
+
@minlength(3)
|
|
87
|
+
@maxlength(50)
|
|
88
|
+
username!: string;
|
|
89
|
+
|
|
90
|
+
@required()
|
|
91
|
+
@email()
|
|
92
|
+
email!: string;
|
|
93
|
+
|
|
94
|
+
@required()
|
|
95
|
+
@min(18, "User must be at least 18 years old")
|
|
96
|
+
age!: number;
|
|
97
|
+
|
|
98
|
+
constructor(data?: any) {
|
|
99
|
+
super(data);
|
|
100
|
+
Model.fromModel(this, data);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### Basic Validation
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// Create a user with invalid data
|
|
109
|
+
const invalidUser = new User({
|
|
110
|
+
username: "jo", // too short
|
|
111
|
+
email: "not-an-email",
|
|
112
|
+
age: 16 // below minimum
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// Check for validation errors
|
|
116
|
+
const errors = invalidUser.hasErrors();
|
|
117
|
+
console.log(errors);
|
|
118
|
+
// Output will contain validation errors for username, email, and age
|
|
119
|
+
|
|
120
|
+
// Create a valid user
|
|
121
|
+
const validUser = new User({
|
|
122
|
+
username: "john_doe",
|
|
123
|
+
email: "john@example.com",
|
|
124
|
+
age: 25
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Check for validation errors
|
|
128
|
+
const validErrors = validUser.hasErrors();
|
|
129
|
+
console.log(validErrors); // undefined - no errors
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
#### Using Different Validation Decorators
|
|
133
|
+
|
|
134
|
+
##### Numeric Validation
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
class Product {
|
|
138
|
+
@required()
|
|
139
|
+
name!: string;
|
|
140
|
+
|
|
141
|
+
@required()
|
|
142
|
+
@min(0, "Price cannot be negative")
|
|
143
|
+
@max(10000, "Price cannot exceed 10,000")
|
|
144
|
+
@step(0.01, "Price must have at most 2 decimal places")
|
|
145
|
+
price!: number;
|
|
146
|
+
|
|
147
|
+
constructor(data?: any) {
|
|
148
|
+
Model.fromModel(this, data);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
##### String Validation
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
class Article {
|
|
157
|
+
@required()
|
|
158
|
+
@minlength(5)
|
|
159
|
+
@maxlength(100)
|
|
160
|
+
title!: string;
|
|
161
|
+
|
|
162
|
+
@required()
|
|
163
|
+
@minlength(50)
|
|
164
|
+
@maxlength(5000)
|
|
165
|
+
content!: string;
|
|
166
|
+
|
|
167
|
+
@pattern(/^[a-z0-9-]+$/, "Slug must contain only lowercase letters, numbers, and hyphens")
|
|
168
|
+
slug!: string;
|
|
169
|
+
|
|
170
|
+
constructor(data?: any) {
|
|
171
|
+
Model.fromModel(this, data);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
##### Special Types Validation
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
class Contact {
|
|
180
|
+
@required()
|
|
181
|
+
name!: string;
|
|
182
|
+
|
|
183
|
+
@required()
|
|
184
|
+
@email()
|
|
185
|
+
email!: string;
|
|
186
|
+
|
|
187
|
+
@url()
|
|
188
|
+
website?: string;
|
|
189
|
+
|
|
190
|
+
@date("yyyy-MM-dd")
|
|
191
|
+
birthdate?: Date;
|
|
192
|
+
|
|
193
|
+
@password()
|
|
194
|
+
password!: string;
|
|
195
|
+
|
|
196
|
+
constructor(data?: any) {
|
|
197
|
+
Model.fromModel(this, data);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
##### Comparison Validation
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
class DateRange {
|
|
206
|
+
@required()
|
|
207
|
+
@date("yyyy-MM-dd")
|
|
208
|
+
startDate!: Date;
|
|
209
|
+
|
|
210
|
+
@required()
|
|
211
|
+
@date("yyyy-MM-dd")
|
|
212
|
+
@gt("startDate", "End date must be after start date")
|
|
213
|
+
endDate!: Date;
|
|
214
|
+
|
|
215
|
+
constructor(data?: any) {
|
|
216
|
+
Model.fromModel(this, data);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
class PriceRange {
|
|
221
|
+
@required()
|
|
222
|
+
@min(0)
|
|
223
|
+
minPrice!: number;
|
|
224
|
+
|
|
225
|
+
@required()
|
|
226
|
+
@min(0)
|
|
227
|
+
@gte("minPrice", "Maximum price must be greater than or equal to minimum price")
|
|
228
|
+
maxPrice!: number;
|
|
229
|
+
|
|
230
|
+
constructor(data?: any) {
|
|
231
|
+
Model.fromModel(this, data);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
##### Collection Validation
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
class Tag {
|
|
240
|
+
@required()
|
|
241
|
+
name!: string;
|
|
242
|
+
|
|
243
|
+
constructor(data?: any) {
|
|
244
|
+
Model.fromModel(this, data);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
class BlogPost {
|
|
249
|
+
@required()
|
|
250
|
+
title!: string;
|
|
251
|
+
|
|
252
|
+
@required()
|
|
253
|
+
content!: string;
|
|
254
|
+
|
|
255
|
+
@list(Tag)
|
|
256
|
+
tags!: Tag[];
|
|
257
|
+
|
|
258
|
+
@set(Tag)
|
|
259
|
+
uniqueTags!: Set<Tag>;
|
|
260
|
+
|
|
261
|
+
constructor(data?: any) {
|
|
262
|
+
Model.fromModel(this, data);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
#### Model Registry and Building
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
// Register models
|
|
271
|
+
Model.register(User);
|
|
272
|
+
Model.register(BlogPost);
|
|
273
|
+
Model.register(Tag);
|
|
274
|
+
|
|
275
|
+
// Build a model from plain object
|
|
276
|
+
const userData = {
|
|
277
|
+
username: "jane_doe",
|
|
278
|
+
email: "jane@example.com",
|
|
279
|
+
age: 28
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const user = Model.build(userData, "User");
|
|
283
|
+
|
|
284
|
+
// Bulk register models
|
|
285
|
+
bulkModelRegister(User, BlogPost, Tag);
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
#### Serialization and Deserialization
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
// Create a user
|
|
292
|
+
const user = new User({
|
|
293
|
+
username: "john_doe",
|
|
294
|
+
email: "john@example.com",
|
|
295
|
+
age: 25
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
// Serialize to string
|
|
299
|
+
const serialized = user.serialize();
|
|
300
|
+
console.log(serialized);
|
|
301
|
+
// Output: JSON string representation of the user
|
|
302
|
+
|
|
303
|
+
// Deserialize from string
|
|
304
|
+
const deserialized = Model.deserialize(serialized);
|
|
305
|
+
console.log(deserialized);
|
|
306
|
+
// Output: User object with the same properties
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
#### Comparing Models
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
const user1 = new User({
|
|
313
|
+
username: "john_doe",
|
|
314
|
+
email: "john@example.com",
|
|
315
|
+
age: 25
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
const user2 = new User({
|
|
319
|
+
username: "john_doe",
|
|
320
|
+
email: "john@example.com",
|
|
321
|
+
age: 25
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
const user3 = new User({
|
|
325
|
+
username: "jane_doe",
|
|
326
|
+
email: "jane@example.com",
|
|
327
|
+
age: 28
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
console.log(user1.equals(user2)); // true - same properties
|
|
331
|
+
console.log(user1.equals(user3)); // false - different properties
|
|
332
|
+
|
|
333
|
+
// Compare ignoring specific properties
|
|
334
|
+
console.log(user1.equals(user3, "username", "email")); // true - only comparing age
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
#### Hashing Models
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
const user = new User({
|
|
341
|
+
username: "john_doe",
|
|
342
|
+
email: "john@example.com",
|
|
343
|
+
age: 25
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// Get hash of the model
|
|
347
|
+
const hash = user.hash();
|
|
348
|
+
console.log(hash);
|
|
349
|
+
// Output: Hash string based on the configured algorithm (sha256)
|
|
350
|
+
```
|
|
59
351
|
|
|
60
352
|
|
|
61
353
|
### Related
|