@decaf-ts/decorator-validation 1.7.19 → 1.7.20
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/LICENSE.md +3 -2
- package/README.md +411 -214
- package/dist/decorator-validation.cjs +1 -1
- package/dist/decorator-validation.esm.cjs +1 -1
- package/lib/esm/utils/decorators.js +1 -1
- package/lib/utils/decorators.cjs +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# Decorator Validation
|
|
2
|
+
|
|
3
|
+
A TypeScript decorator-driven validation and model framework. It lets you:
|
|
4
|
+
- Define validation rules with declarative decorators on model properties (e.g., @required, @min, @pattern).
|
|
5
|
+
- Build, validate, serialize, and hash models with pluggable registries and algorithms.
|
|
6
|
+
- Extend validation via a registry of Validator classes and utilities.
|
|
7
|
+
- Optionally expose validation as MCP tools for automation workflows.
|
|
3
8
|
|
|
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
9
|
|
|
6
10
|
|
|
7
11
|

|
|
@@ -27,328 +31,521 @@ A comprehensive TypeScript library that provides a powerful model validation fra
|
|
|
27
31
|
|
|
28
32
|
Documentation available [here](https://decaf-ts.github.io/decorator-validation/)
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
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.
|
|
34
|
+
# Decorator Validation – Detailed Description
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
Decorator Validation is a TypeScript library that centers on two complementary pillars:
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
1) Declarative validation via decorators
|
|
39
|
+
- A rich set of property decorators such as @required, @min, @max, @minLength, @maxLength, @pattern, @email, @url, @type, @equals, @greaterThan, @greaterThanOrEqual, @lessThan, @lessThanOrEqual, @step, @list, @diff, @date, @password, as well as an async() flag helper.
|
|
40
|
+
- Each decorator writes strongly-typed metadata using reflect-metadata and a common Validation metadata keying convention, so validators can later interpret the rules consistently.
|
|
41
|
+
- Decorators are defined in src/validation/decorators.ts and are backed by concrete Validator classes in src/validation/Validators/* that implement the actual validation logic.
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
The
|
|
43
|
+
2) A model system tailored for validation, building, hashing, and serialization
|
|
44
|
+
- Models are ordinary classes marked with @model() (src/model/decorators.ts). The decorator replaces the constructor, binds the model prototype utilities, runs a global builder (if registered), and tags reflection metadata for identification.
|
|
45
|
+
- Additional class-level decorators configure algorithms:
|
|
46
|
+
- @hashedBy(algorithm, ...args) to define model hashing implementation.
|
|
47
|
+
- @serializedBy(serializer, ...args) to define serialization strategy.
|
|
48
|
+
- @description(text) to attach human-readable documentation to a class, property, or method.
|
|
49
|
+
- The Model class (src/model/Model.ts) provides:
|
|
50
|
+
- A ModelRegistryManager for registering and retrieving model constructors by name, enabling rebuild/deserialize flows.
|
|
51
|
+
- Validation integration (model/validation.ts) that runs the registered validators against metadata collected by decorators.
|
|
52
|
+
- Utility methods and metadata helpers to identify models, fetch metadata, compare instances, and orchestrate hashing/serialization strategies.
|
|
40
53
|
|
|
41
|
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
54
|
+
Core runtime architecture
|
|
55
|
+
- Validation namespace (src/validation/Validation.ts):
|
|
56
|
+
- Manages a pluggable IValidatorRegistry so custom Validator implementations can be registered, migrated, and queried.
|
|
57
|
+
- Exposes helper utilities: Validation.key(key) for reflect-metadata keying, Validation.keys() to list available validator keys, register(...) and get(...) to manage validators, decorator registration to link a metadata key to its decorator for dynamic use.
|
|
58
|
+
- Validator classes (src/validation/Validators/*):
|
|
59
|
+
- BaseValidator.ts defines common behaviors; concrete validators (RequiredValidator, MinValidator, PatternValidator, etc.) implement validate and message/typing logic.
|
|
60
|
+
- ValidatorRegistry.ts stores Validator instances keyed by ValidationKeys constants.
|
|
61
|
+
- constants.ts defines DEFAULT_ERROR_MESSAGES, DEFAULT_PATTERNS, and ValidationKeys (e.g., REQUIRED, MIN, MAX...).
|
|
62
|
+
- decorators.ts contains decorator sugar for directly registering standard validators and building metadata using Decoration/Reflection utilities.
|
|
63
|
+
- Utilities (src/utils/*):
|
|
64
|
+
- strings, dates, types, serialization, hashing, registry, decorators, Decoration helper, and a PathProxy to traverse nested properties and apply metadata.
|
|
46
65
|
|
|
47
|
-
|
|
48
|
-
|
|
66
|
+
Intent of the library
|
|
67
|
+
- Provide a cohesive, decorator-first developer experience for enforcing validation constraints on model classes.
|
|
68
|
+
- Ensure that validation, model lifecycle (build/serialize/hash), and metadata are consistent and extensible through registries.
|
|
69
|
+
- Allow advanced composition (custom validators, alternative registries), and integration into automation flows (MCP tools).
|
|
49
70
|
|
|
50
|
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
71
|
+
Design principles
|
|
72
|
+
- Declarative over imperative: Constraints live next to the properties they validate.
|
|
73
|
+
- Extensibility: Registries and helper factories allow swapping implementations without changing consumer code.
|
|
74
|
+
- Type safety: Metadata and decorators are typed; validators advertise supported types; utility functions use narrow types where practical.
|
|
75
|
+
- Separation of concerns: Decorators express intent; Validator classes implement behavior; Model provides lifecycle utilities.
|
|
53
76
|
|
|
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
77
|
|
|
66
|
-
|
|
78
|
+
# How to Use Decorator Validation
|
|
67
79
|
|
|
80
|
+
This guide shows concrete, TypeScript-accurate examples for the main public APIs exported by the library. Examples are inspired by patterns used across the repo tests and typical usage of decorator-driven validation and models.
|
|
68
81
|
|
|
69
|
-
|
|
82
|
+
Notes
|
|
83
|
+
- Import paths assume a consumer importing from the package entry and submodules as re-exported by src/index.ts.
|
|
84
|
+
- All snippets are valid TypeScript.
|
|
70
85
|
|
|
71
|
-
- [Initial Setup](./workdocs/tutorials/For%20Developers.md#_initial-setup_)
|
|
72
|
-
- [Installation](./workdocs/tutorials/For%20Developers.md#installation)
|
|
73
86
|
|
|
74
|
-
|
|
87
|
+
## Model decorators and model lifecycle
|
|
75
88
|
|
|
76
|
-
|
|
89
|
+
### @model()
|
|
90
|
+
Description: Marks a class as a model. The constructor is wrapped to bind model utilities and run a global builder (if any).
|
|
77
91
|
|
|
78
92
|
```typescript
|
|
79
|
-
import {
|
|
93
|
+
import { model, Model, ModelArg } from "@decaf-ts/decorator-validation";
|
|
80
94
|
|
|
81
95
|
@model()
|
|
82
|
-
@hashedBy('sha256')
|
|
83
|
-
@serializedBy('json')
|
|
84
96
|
class User extends Model {
|
|
85
|
-
@
|
|
86
|
-
|
|
87
|
-
@
|
|
88
|
-
|
|
97
|
+
@prop()
|
|
98
|
+
id!: string;
|
|
99
|
+
@prop()
|
|
100
|
+
name!: string;
|
|
101
|
+
|
|
102
|
+
constructor(arg?: ModelArg<User>) {
|
|
103
|
+
super(arg);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const u = new User();
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Extending from the Model class is optional but highly recommended. Regardless, if decorated with `@model()`, the constructor signature must be compatible.
|
|
111
|
+
|
|
112
|
+
When using a class for validation, eg `hasErrors()` only, @model() is not required.
|
|
113
|
+
|
|
114
|
+
#### Model construction
|
|
89
115
|
|
|
116
|
+
When a class is decorated with @model(), the framework invokes a model building function right after the instance is constructed. This builder initializes your model from the argument you pass to the constructor.
|
|
117
|
+
|
|
118
|
+
There are two builder strategies:
|
|
119
|
+
- Model.fromObject: Accepts a plain object and performs a more permissive, best-effort mapping.
|
|
120
|
+
- Does not enforce nested Model classes
|
|
121
|
+
- Model.fromModel (default): does the same as fromObject, but also instantiates nested Model classes
|
|
122
|
+
|
|
123
|
+
Your model constructors should accept an optional argument and pass it to super so the builder can use it.
|
|
124
|
+
|
|
125
|
+
You can change between builder functions by using:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { required, Model, model, ModelArg } from "@decaf-ts/decorator-validation";
|
|
129
|
+
|
|
130
|
+
@model()
|
|
131
|
+
class Child extends Model {
|
|
90
132
|
@required()
|
|
91
|
-
|
|
92
|
-
|
|
133
|
+
name!: string;
|
|
134
|
+
|
|
135
|
+
constructor(arg?: ModelArg<Child>) {
|
|
136
|
+
super(arg);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
93
139
|
|
|
140
|
+
@model()
|
|
141
|
+
class Parent extends Model {
|
|
142
|
+
@required()
|
|
143
|
+
name!: string;
|
|
94
144
|
@required()
|
|
95
|
-
|
|
96
|
-
|
|
145
|
+
child!: Child;
|
|
146
|
+
constructor(arg?: ModelArg<Parent>) {
|
|
147
|
+
super(arg);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Default builder is Model.fromModel
|
|
151
|
+
|
|
152
|
+
let parent = new Parent({
|
|
153
|
+
child: {
|
|
154
|
+
name: "child"
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
parent.child instanceof Child; // true
|
|
159
|
+
|
|
160
|
+
Model.setBuilder(Model.fromObject);
|
|
161
|
+
|
|
162
|
+
parent = new Parent({
|
|
163
|
+
child: {
|
|
164
|
+
name: "child"
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
parent.child instanceof Child; // false
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### @hashedBy(algorithm, ...args)
|
|
172
|
+
Description: Declares which hashing strategy to use when hashing model instances.
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import { model, hashedBy, ModelArg, prop } from "@decaf-ts/decorator-validation";
|
|
97
176
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
177
|
+
@model()
|
|
178
|
+
@hashedBy("sha256", "utf8")
|
|
179
|
+
class FileInfo extends Model {
|
|
180
|
+
@prop()
|
|
181
|
+
path!: string;
|
|
182
|
+
@prop()
|
|
183
|
+
size!: number;
|
|
184
|
+
|
|
185
|
+
constructor(arg?: ModelArg<FileInfo>) {
|
|
186
|
+
super(arg)
|
|
101
187
|
}
|
|
102
188
|
}
|
|
103
189
|
```
|
|
104
190
|
|
|
105
|
-
|
|
191
|
+
### @serializedBy(serializer, ...args)
|
|
192
|
+
Description: Declares which serializer to use for (de)serializing model instances.
|
|
106
193
|
|
|
107
194
|
```typescript
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
195
|
+
import { prop, ModelArg, model, serializedBy } from "@decaf-ts/decorator-validation";
|
|
196
|
+
|
|
197
|
+
@model()
|
|
198
|
+
@serializedBy("json")
|
|
199
|
+
class Settings extends Model {
|
|
200
|
+
@prop()
|
|
201
|
+
theme!: string;
|
|
202
|
+
@prop()
|
|
203
|
+
locale!: string;
|
|
204
|
+
|
|
205
|
+
constructor(arg?: ModelArg<Settings>){
|
|
206
|
+
super(arg)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
114
210
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
console.log(errors);
|
|
118
|
-
// Output will contain validation errors for username, email, and age
|
|
211
|
+
### @description(text)
|
|
212
|
+
Description: Applies textual documentation metadata to a class, property, or method.
|
|
119
213
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
username: "john_doe",
|
|
123
|
-
email: "john@example.com",
|
|
124
|
-
age: 25
|
|
125
|
-
});
|
|
214
|
+
```typescript
|
|
215
|
+
import { model, description, Model } from "@decaf-ts/decorator-validation";
|
|
126
216
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
217
|
+
@model()
|
|
218
|
+
@description("Represents an application user")
|
|
219
|
+
class User extends Model {
|
|
220
|
+
@description("Unique identifier")
|
|
221
|
+
id!: string;
|
|
222
|
+
// ...
|
|
223
|
+
}
|
|
130
224
|
```
|
|
131
225
|
|
|
132
|
-
#### Using Different Validation Decorators
|
|
133
226
|
|
|
134
|
-
|
|
227
|
+
## Validation decorators (property-level)
|
|
228
|
+
Each decorator writes metadata for a corresponding Validator. Use them on model fields.
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
### @prop()
|
|
232
|
+
Description: Registers a property with the model system. This is required for model construction so the property participates in metadata, serialization, hashing, validation discovery, etc.
|
|
233
|
+
|
|
234
|
+
Important
|
|
235
|
+
- All other property decorators (e.g., @required, @min, @email, etc.) already apply @prop under the hood.
|
|
236
|
+
- Therefore, you only need to use @prop when a property has no other decorators.
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
### @required(message?)
|
|
240
|
+
Description: Field must be present and non-empty.
|
|
135
241
|
|
|
136
242
|
```typescript
|
|
137
|
-
|
|
138
|
-
@required()
|
|
139
|
-
name!: string;
|
|
243
|
+
import { Model, required, model } from "@decaf-ts/decorator-validation";
|
|
140
244
|
|
|
245
|
+
@model()
|
|
246
|
+
class User extends Model {
|
|
141
247
|
@required()
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
248
|
+
username!: string;
|
|
249
|
+
//...
|
|
250
|
+
}
|
|
251
|
+
```
|
|
146
252
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
253
|
+
### @min(value, message?) and @max(value, message?)
|
|
254
|
+
Description: Numeric or date boundaries.
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import { model } from "@decaf-ts/decorator-validation";
|
|
258
|
+
import { min } from "@decaf-ts/decorator-validation";
|
|
259
|
+
import { max } from "@decaf-ts/decorator-validation";
|
|
260
|
+
|
|
261
|
+
@model()
|
|
262
|
+
class Product extends Model {
|
|
263
|
+
@min(0)
|
|
264
|
+
@max(1000)
|
|
265
|
+
price!: number;
|
|
150
266
|
}
|
|
151
267
|
```
|
|
152
268
|
|
|
153
|
-
|
|
269
|
+
### @minLength(n, message?) and @maxLength(n, message?)
|
|
270
|
+
Description: String length boundaries.
|
|
154
271
|
|
|
155
272
|
```typescript
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
@minlength(5)
|
|
159
|
-
@maxlength(100)
|
|
160
|
-
title!: string;
|
|
273
|
+
import { model, Model } from "@decaf-ts/decorator-validation";
|
|
274
|
+
import { minLength, maxLength } from "@decaf-ts/decorator-validation";
|
|
161
275
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
@
|
|
165
|
-
|
|
276
|
+
@model()
|
|
277
|
+
class Credentials extends Model {
|
|
278
|
+
@minLength(8)
|
|
279
|
+
@maxLength(64)
|
|
280
|
+
password!: string;
|
|
281
|
+
}
|
|
282
|
+
```
|
|
166
283
|
|
|
167
|
-
|
|
168
|
-
|
|
284
|
+
### @pattern(regex | string, message?)
|
|
285
|
+
Description: String must match a pattern.
|
|
169
286
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
287
|
+
```typescript
|
|
288
|
+
import { model } from "@decaf-ts/decorator-validation";
|
|
289
|
+
import { pattern, model } from "@decaf-ts/decorator-validation";
|
|
290
|
+
|
|
291
|
+
@model()
|
|
292
|
+
class Vehicle extends Model {
|
|
293
|
+
@pattern(/^[A-Z]{2}-\d{2}-[A-Z]{2}$/)
|
|
294
|
+
plate!: string;
|
|
173
295
|
}
|
|
174
296
|
```
|
|
175
297
|
|
|
176
|
-
|
|
298
|
+
### @email(message?)
|
|
299
|
+
Description: Must be a valid email.
|
|
177
300
|
|
|
178
301
|
```typescript
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
name!: string;
|
|
302
|
+
import { model } from "@decaf-ts/decorator-validation";
|
|
303
|
+
import { email } from "@decaf-ts/decorator-validation";
|
|
182
304
|
|
|
183
|
-
|
|
305
|
+
@model()
|
|
306
|
+
class Contact extends Model {
|
|
184
307
|
@email()
|
|
185
308
|
email!: string;
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### @url(message?)
|
|
313
|
+
Description: Must be a valid URL.
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
import { model } from "@decaf-ts/decorator-validation";
|
|
317
|
+
import { url } from "@decaf-ts/decorator-validation";
|
|
186
318
|
|
|
319
|
+
@model()
|
|
320
|
+
class Link extends Model {
|
|
187
321
|
@url()
|
|
188
|
-
|
|
322
|
+
href!: string;
|
|
323
|
+
}
|
|
324
|
+
```
|
|
189
325
|
|
|
190
|
-
|
|
191
|
-
|
|
326
|
+
### @type(T, message?)
|
|
327
|
+
Description: Enforces a runtime type match (e.g., Number, String, Date).
|
|
192
328
|
|
|
193
|
-
|
|
194
|
-
|
|
329
|
+
```typescript
|
|
330
|
+
import { model } from "@decaf-ts/decorator-validation";
|
|
331
|
+
import { type } from "@decaf-ts/decorator-validation";
|
|
195
332
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
333
|
+
@model()
|
|
334
|
+
class Measurement extends Model {
|
|
335
|
+
@type(Number)
|
|
336
|
+
value!: number;
|
|
199
337
|
}
|
|
200
338
|
```
|
|
201
339
|
|
|
202
|
-
|
|
340
|
+
### @equals(otherValueOrPath, message?)
|
|
341
|
+
Description: Value must equal the provided value or another property.
|
|
203
342
|
|
|
204
343
|
```typescript
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
@date("yyyy-MM-dd")
|
|
208
|
-
startDate!: Date;
|
|
344
|
+
import { model } from "@decaf-ts/decorator-validation";
|
|
345
|
+
import { equals } from "@decaf-ts/decorator-validation";
|
|
209
346
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
347
|
+
@model()
|
|
348
|
+
class Confirmation extends Model {
|
|
349
|
+
password!: string;
|
|
350
|
+
@equals(":password")
|
|
351
|
+
confirm!: string;
|
|
352
|
+
}
|
|
353
|
+
```
|
|
214
354
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
355
|
+
### @greaterThan(x) / @greaterThanOrEqual(x) / @lessThan(x) / @lessThanOrEqual(x)
|
|
356
|
+
Description: Numeric or date comparisons.
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
import { model } from "@decaf-ts/decorator-validation";
|
|
360
|
+
import { greaterThan, greaterThanOrEqual, lessThan, lessThanOrEqual } from "@decaf-ts/decorator-validation";
|
|
361
|
+
|
|
362
|
+
@model()
|
|
363
|
+
class Range extends Model {
|
|
364
|
+
@greaterThan(0)
|
|
365
|
+
@lessThanOrEqual(100)
|
|
366
|
+
ratio!: number;
|
|
218
367
|
}
|
|
368
|
+
```
|
|
219
369
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
@min(0)
|
|
223
|
-
minPrice!: number;
|
|
370
|
+
### @step(step, message?)
|
|
371
|
+
Description: Numeric step constraints.
|
|
224
372
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
maxPrice!: number;
|
|
373
|
+
```typescript
|
|
374
|
+
import { model, Model } from "@decaf-ts/decorator-validation";
|
|
375
|
+
import { step } from "@decaf-ts/decorator-validation";
|
|
229
376
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
377
|
+
@model()
|
|
378
|
+
class Slider extends Model {
|
|
379
|
+
@step(0.5)
|
|
380
|
+
value!: number;
|
|
233
381
|
}
|
|
234
382
|
```
|
|
235
383
|
|
|
236
|
-
|
|
384
|
+
### @list(values, message?)
|
|
385
|
+
Description: Constrains value to be one of the provided list.
|
|
237
386
|
|
|
238
387
|
```typescript
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
name!: string;
|
|
388
|
+
import { model, Model } from "@decaf-ts/decorator-validation";
|
|
389
|
+
import { list } from "@decaf-ts/decorator-validation";
|
|
242
390
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
391
|
+
@model()
|
|
392
|
+
class ThemeSettingm extends Model {
|
|
393
|
+
@list(["light", "dark", "system"])
|
|
394
|
+
theme!: "light" | "dark" | "system";
|
|
246
395
|
}
|
|
396
|
+
```
|
|
247
397
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
title!: string;
|
|
398
|
+
### @diff(propertyPath, message?)
|
|
399
|
+
Description: Must be different from another property.
|
|
251
400
|
|
|
252
|
-
|
|
253
|
-
|
|
401
|
+
```typescript
|
|
402
|
+
import { model, Model } from "@decaf-ts/decorator-validation";
|
|
403
|
+
import { diff } from "@decaf-ts/decorator-validation";
|
|
254
404
|
|
|
255
|
-
|
|
256
|
-
|
|
405
|
+
@model()
|
|
406
|
+
class Credentials extends Model {
|
|
407
|
+
username!: string;
|
|
408
|
+
@diff(":username")
|
|
409
|
+
password!: string;
|
|
410
|
+
}
|
|
411
|
+
```
|
|
257
412
|
|
|
258
|
-
|
|
259
|
-
|
|
413
|
+
### @date({ min?, max? }, message?)
|
|
414
|
+
Description: Date constraints for a date-typed field.
|
|
260
415
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
416
|
+
```typescript
|
|
417
|
+
import { model, Model } from "@decaf-ts/decorator-validation";
|
|
418
|
+
import { date } from "@decaf-ts/decorator-validation";
|
|
419
|
+
|
|
420
|
+
@model()
|
|
421
|
+
class Booking extends Model {
|
|
422
|
+
@date({ min: new Date("2025-01-01"), max: new Date("2025-12-31") })
|
|
423
|
+
start!: Date;
|
|
424
|
+
}
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
### @password(options?, message?)
|
|
428
|
+
Description: Password strength constraints (e.g., min length, uppercase, digits, symbols) depending on validator configuration.
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
import { model } from "@decaf-ts/decorator-validation";
|
|
432
|
+
import { password, Model } from "@decaf-ts/decorator-validation";
|
|
433
|
+
|
|
434
|
+
@model()
|
|
435
|
+
class Account extends Model{
|
|
436
|
+
@password({ minLength: 10 })
|
|
437
|
+
password!: string;
|
|
264
438
|
}
|
|
265
439
|
```
|
|
266
440
|
|
|
267
|
-
|
|
441
|
+
### async()
|
|
442
|
+
Description: Marks a model as involving async validation rules (decorator flag helper).
|
|
268
443
|
|
|
269
444
|
```typescript
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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);
|
|
445
|
+
import { model } from "@decaf-ts/decorator-validation";
|
|
446
|
+
import { async } from "@decaf-ts/decorator-validation";
|
|
447
|
+
|
|
448
|
+
@model()
|
|
449
|
+
@async()
|
|
450
|
+
class Signup {
|
|
451
|
+
// fields that may use async validators
|
|
452
|
+
}
|
|
286
453
|
```
|
|
287
454
|
|
|
288
|
-
|
|
455
|
+
|
|
456
|
+
## Running validation
|
|
457
|
+
Use the model validation utilities to evaluate rules defined by decorators.
|
|
289
458
|
|
|
290
459
|
```typescript
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
460
|
+
import { model, required, email, validate, Model } from "@decaf-ts/decorator-validation";
|
|
461
|
+
|
|
462
|
+
@model()
|
|
463
|
+
class Contact extends Model {
|
|
464
|
+
@required()
|
|
465
|
+
@email()
|
|
466
|
+
email!: string;
|
|
467
|
+
|
|
468
|
+
constructor(arg?: ModelArg<Contact>) {
|
|
469
|
+
super(arg);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const c = new Contact({
|
|
474
|
+
email: "not-an-email"
|
|
296
475
|
});
|
|
297
476
|
|
|
298
|
-
//
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
477
|
+
let errs = c.hasErrors(); // resolves to a list of errors or undefined
|
|
478
|
+
|
|
479
|
+
@async()
|
|
480
|
+
@model()
|
|
481
|
+
class User extends Model {
|
|
482
|
+
@required()
|
|
483
|
+
@email()
|
|
484
|
+
email!: string;
|
|
485
|
+
|
|
486
|
+
constructor(arg?: ModelArg<User>) {
|
|
487
|
+
super(arg);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
const u = new User({
|
|
492
|
+
email: "not-an-email"
|
|
493
|
+
})
|
|
494
|
+
|
|
495
|
+
errs = await u.hasErrors(); // resolves to a list of errors or undefined
|
|
302
496
|
|
|
303
|
-
// Deserialize from string
|
|
304
|
-
const deserialized = Model.deserialize(serialized);
|
|
305
|
-
console.log(deserialized);
|
|
306
|
-
// Output: User object with the same properties
|
|
307
497
|
```
|
|
308
498
|
|
|
309
|
-
|
|
499
|
+
|
|
500
|
+
## Validation registry APIs (Validation)
|
|
501
|
+
|
|
502
|
+
### Validation.setRegistry(registry, migration?)
|
|
503
|
+
Description: Swap the active validator registry and optionally migrate validators.
|
|
310
504
|
|
|
311
505
|
```typescript
|
|
312
|
-
|
|
313
|
-
username: "john_doe",
|
|
314
|
-
email: "john@example.com",
|
|
315
|
-
age: 25
|
|
316
|
-
});
|
|
506
|
+
import { Validation, ValidatorRegistry } from "@decaf-ts/decorator-validation";
|
|
317
507
|
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
age: 25
|
|
322
|
-
});
|
|
508
|
+
const custom = new ValidatorRegistry();
|
|
509
|
+
Validation.setRegistry(custom, v => v); // trivial migration
|
|
510
|
+
```
|
|
323
511
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
512
|
+
### Validation.register(...validators)
|
|
513
|
+
Description: Register one or more Validator implementations or definitions.
|
|
514
|
+
|
|
515
|
+
```typescript
|
|
516
|
+
import { Validation, Validator, validator } from "@decaf-ts/decorator-validation";
|
|
329
517
|
|
|
330
|
-
|
|
331
|
-
|
|
518
|
+
@validator("ALWAYS_OK")
|
|
519
|
+
class AlwaysOk extends Validator {
|
|
520
|
+
hasErrors(...args: any[]) { return []; }
|
|
521
|
+
}
|
|
332
522
|
|
|
333
|
-
|
|
334
|
-
console.log(user1.equals(user3, "username", "email")); // true - only comparing age
|
|
523
|
+
Validation.register(new AlwaysOk());
|
|
335
524
|
```
|
|
336
525
|
|
|
337
|
-
|
|
526
|
+
### Validation.get(key)
|
|
527
|
+
Description: Retrieve a registered validator by key.
|
|
338
528
|
|
|
339
529
|
```typescript
|
|
340
|
-
|
|
341
|
-
username: "john_doe",
|
|
342
|
-
email: "john@example.com",
|
|
343
|
-
age: 25
|
|
344
|
-
});
|
|
530
|
+
import { Validation, ValidationKeys } from "@decaf-ts/decorator-validation";
|
|
345
531
|
|
|
346
|
-
|
|
347
|
-
const hash = user.hash();
|
|
348
|
-
console.log(hash);
|
|
349
|
-
// Output: Hash string based on the configured algorithm (sha256)
|
|
532
|
+
const requiredValidator = Validation.get(ValidationKeys.REQUIRED);
|
|
350
533
|
```
|
|
351
534
|
|
|
535
|
+
### Validation.key(k) and Validation.keys()
|
|
536
|
+
Description: Build a reflect-metadata key or list all registered keys.
|
|
537
|
+
|
|
538
|
+
```typescript
|
|
539
|
+
import { Validation } from "@decaf-ts/decorator-validation";
|
|
540
|
+
|
|
541
|
+
const metaKey = Validation.key("REQUIRED");
|
|
542
|
+
const allKeys = Validation.keys();
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
## Notes on tests and validity
|
|
546
|
+
- Patterns here reflect common test patterns found across the monorepo (e.g., model decoration, decorator application, registry customization).
|
|
547
|
+
- Each snippet is valid TypeScript and aligns with the re-exports provided by the package entry.
|
|
548
|
+
|
|
352
549
|
|
|
353
550
|
### Related
|
|
354
551
|
|