reslib 1.0.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/README.md +298 -0
- package/build/auth/index.d.ts +2034 -0
- package/build/auth/index.js +5 -0
- package/build/auth/types.d.ts +465 -0
- package/build/auth/types.js +1 -0
- package/build/countries/countries.d.ts +1454 -0
- package/build/countries/countries.js +1 -0
- package/build/countries/index.d.ts +159 -0
- package/build/countries/index.js +5 -0
- package/build/countries/types.d.ts +65 -0
- package/build/countries/types.js +1 -0
- package/build/currency/currencies.d.ts +8 -0
- package/build/currency/currencies.js +1 -0
- package/build/currency/index.d.ts +51 -0
- package/build/currency/index.js +5 -0
- package/build/currency/session.d.ts +23 -0
- package/build/currency/session.js +5 -0
- package/build/currency/types.d.ts +1039 -0
- package/build/currency/types.js +1 -0
- package/build/currency/utils.d.ts +25 -0
- package/build/currency/utils.js +1 -0
- package/build/i18n/index.d.ts +640 -0
- package/build/i18n/index.js +5 -0
- package/build/inputFormatter/index.d.ts +396 -0
- package/build/inputFormatter/index.js +5 -0
- package/build/inputFormatter/types.d.ts +544 -0
- package/build/inputFormatter/types.js +1 -0
- package/build/logger/index.d.ts +235 -0
- package/build/logger/index.js +5 -0
- package/build/observable/index.d.ts +329 -0
- package/build/observable/index.js +1 -0
- package/build/platform/index.d.ts +32 -0
- package/build/platform/index.js +1 -0
- package/build/resources/ResourcePaginationHelper.d.ts +537 -0
- package/build/resources/ResourcePaginationHelper.js +2 -0
- package/build/resources/decorators/create.decorator.d.ts +20 -0
- package/build/resources/decorators/create.decorator.js +1 -0
- package/build/resources/decorators/index.d.ts +41 -0
- package/build/resources/decorators/index.js +1 -0
- package/build/resources/fields/index.d.ts +33 -0
- package/build/resources/fields/index.js +1 -0
- package/build/resources/filters.d.ts +62 -0
- package/build/resources/filters.js +1 -0
- package/build/resources/index.d.ts +854 -0
- package/build/resources/index.js +6 -0
- package/build/resources/types/filters.d.ts +508 -0
- package/build/resources/types/filters.js +1 -0
- package/build/resources/types/index.d.ts +4138 -0
- package/build/resources/types/index.js +1 -0
- package/build/session/index.d.ts +1474 -0
- package/build/session/index.js +1 -0
- package/build/translations/auth.en.d.ts +3 -0
- package/build/translations/auth.en.js +1 -0
- package/build/translations/countries.en.d.ts +6 -0
- package/build/translations/countries.en.js +1 -0
- package/build/translations/currencies.en.d.ts +5 -0
- package/build/translations/currencies.en.js +1 -0
- package/build/translations/date.en.d.ts +19 -0
- package/build/translations/date.en.js +1 -0
- package/build/translations/index.d.ts +1583 -0
- package/build/translations/index.js +5 -0
- package/build/translations/resources.en.d.ts +6 -0
- package/build/translations/resources.en.js +1 -0
- package/build/translations/validator.en.d.ts +104 -0
- package/build/translations/validator.en.js +5 -0
- package/build/types/date.d.ts +44 -0
- package/build/types/date.js +1 -0
- package/build/types/dictionary.d.ts +29 -0
- package/build/types/dictionary.js +1 -0
- package/build/types/i18n.d.ts +121 -0
- package/build/types/i18n.js +1 -0
- package/build/types/index.d.ts +145 -0
- package/build/types/index.js +1 -0
- package/build/utils/areEquals.d.ts +19 -0
- package/build/utils/areEquals.js +1 -0
- package/build/utils/date/dateHelper.d.ts +371 -0
- package/build/utils/date/dateHelper.js +5 -0
- package/build/utils/date/index.d.ts +212 -0
- package/build/utils/date/index.js +5 -0
- package/build/utils/date/isDateObj.d.ts +14 -0
- package/build/utils/date/isDateObj.js +1 -0
- package/build/utils/debounce.d.ts +52 -0
- package/build/utils/debounce.js +1 -0
- package/build/utils/defaultArray.d.ts +18 -0
- package/build/utils/defaultArray.js +1 -0
- package/build/utils/defaultBool.d.ts +14 -0
- package/build/utils/defaultBool.js +1 -0
- package/build/utils/defaultStr.d.ts +17 -0
- package/build/utils/defaultStr.js +1 -0
- package/build/utils/defaultVal.d.ts +18 -0
- package/build/utils/defaultVal.js +1 -0
- package/build/utils/dom/index.d.ts +65 -0
- package/build/utils/dom/index.js +1 -0
- package/build/utils/dom/isDOMElement.d.ts +11 -0
- package/build/utils/dom/isDOMElement.js +1 -0
- package/build/utils/file/index.d.ts +26 -0
- package/build/utils/file/index.js +1 -0
- package/build/utils/global.d.ts +53 -0
- package/build/utils/global.js +1 -0
- package/build/utils/image.d.ts +56 -0
- package/build/utils/image.js +1 -0
- package/build/utils/index.d.ts +39 -0
- package/build/utils/index.js +6 -0
- package/build/utils/interpolate.d.ts +105 -0
- package/build/utils/interpolate.js +1 -0
- package/build/utils/isEmail.d.ts +57 -0
- package/build/utils/isEmail.js +1 -0
- package/build/utils/isEmpty.d.ts +18 -0
- package/build/utils/isEmpty.js +1 -0
- package/build/utils/isNonNullString.d.ts +17 -0
- package/build/utils/isNonNullString.js +1 -0
- package/build/utils/isNullable.d.ts +7 -0
- package/build/utils/isNullable.js +1 -0
- package/build/utils/isNumber.d.ts +36 -0
- package/build/utils/isNumber.js +1 -0
- package/build/utils/isPrimitive.d.ts +16 -0
- package/build/utils/isPrimitive.js +1 -0
- package/build/utils/isPromise.d.ts +14 -0
- package/build/utils/isPromise.js +1 -0
- package/build/utils/isRegex.d.ts +15 -0
- package/build/utils/isRegex.js +1 -0
- package/build/utils/isTime.d.ts +18 -0
- package/build/utils/isTime.js +1 -0
- package/build/utils/json.d.ts +224 -0
- package/build/utils/json.js +1 -0
- package/build/utils/numbers.d.ts +148 -0
- package/build/utils/numbers.js +5 -0
- package/build/utils/object.d.ts +567 -0
- package/build/utils/object.js +1 -0
- package/build/utils/sort.d.ts +67 -0
- package/build/utils/sort.js +1 -0
- package/build/utils/string.d.ts +165 -0
- package/build/utils/string.js +1 -0
- package/build/utils/stringify.d.ts +23 -0
- package/build/utils/stringify.js +1 -0
- package/build/utils/uniqid.d.ts +18 -0
- package/build/utils/uniqid.js +1 -0
- package/build/utils/uri/index.d.ts +333 -0
- package/build/utils/uri/index.js +2 -0
- package/build/validator/index.d.ts +4 -0
- package/build/validator/index.js +6 -0
- package/build/validator/rules/array.d.ts +848 -0
- package/build/validator/rules/array.js +5 -0
- package/build/validator/rules/boolean.d.ts +87 -0
- package/build/validator/rules/boolean.js +5 -0
- package/build/validator/rules/date.d.ts +551 -0
- package/build/validator/rules/date.js +5 -0
- package/build/validator/rules/default.d.ts +367 -0
- package/build/validator/rules/default.js +5 -0
- package/build/validator/rules/enum.d.ts +155 -0
- package/build/validator/rules/enum.js +5 -0
- package/build/validator/rules/file.d.ts +356 -0
- package/build/validator/rules/file.js +5 -0
- package/build/validator/rules/format.d.ts +2825 -0
- package/build/validator/rules/format.js +6 -0
- package/build/validator/rules/index.d.ts +16 -0
- package/build/validator/rules/index.js +6 -0
- package/build/validator/rules/multiRules.d.ts +475 -0
- package/build/validator/rules/multiRules.js +5 -0
- package/build/validator/rules/numeric.d.ts +1135 -0
- package/build/validator/rules/numeric.js +5 -0
- package/build/validator/rules/string.d.ts +504 -0
- package/build/validator/rules/string.js +5 -0
- package/build/validator/rules/target.d.ts +137 -0
- package/build/validator/rules/target.js +5 -0
- package/build/validator/rules/utils.d.ts +1 -0
- package/build/validator/rules/utils.js +1 -0
- package/build/validator/rulesMarkers.d.ts +11 -0
- package/build/validator/rulesMarkers.js +1 -0
- package/build/validator/types.d.ts +2906 -0
- package/build/validator/types.js +1 -0
- package/build/validator/validator.d.ts +3692 -0
- package/build/validator/validator.js +5 -0
- package/lib/cjs/auth.js +1 -0
- package/lib/cjs/countries.js +1 -0
- package/lib/cjs/currency.js +1 -0
- package/lib/cjs/i18n.js +1 -0
- package/lib/cjs/inputFormatter.js +1 -0
- package/lib/cjs/logger.js +1 -0
- package/lib/cjs/observable.js +1 -0
- package/lib/cjs/platform.js +1 -0
- package/lib/cjs/resources.js +1 -0
- package/lib/cjs/session.js +1 -0
- package/lib/cjs/types.js +1 -0
- package/lib/cjs/utils.js +1 -0
- package/lib/cjs/validator.js +1 -0
- package/lib/esm/auth.mjs +1 -0
- package/lib/esm/countries.mjs +1 -0
- package/lib/esm/currency.mjs +1 -0
- package/lib/esm/i18n.mjs +1 -0
- package/lib/esm/inputFormatter.mjs +1 -0
- package/lib/esm/logger.mjs +1 -0
- package/lib/esm/observable.mjs +1 -0
- package/lib/esm/platform.mjs +1 -0
- package/lib/esm/resources.mjs +1 -0
- package/lib/esm/session.mjs +1 -0
- package/lib/esm/types.mjs +1 -0
- package/lib/esm/utils.mjs +1 -0
- package/lib/esm/validator.mjs +1 -0
- package/package.json +244 -0
|
@@ -0,0 +1,2906 @@
|
|
|
1
|
+
import { I18n } from '../i18n';
|
|
2
|
+
import { InputFormatterResult } from '../inputFormatter/types';
|
|
3
|
+
import { ClassConstructor, Dictionary } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* ## Validator Sync Result
|
|
6
|
+
*
|
|
7
|
+
* Represents the synchronous result returned by a validation rule function.
|
|
8
|
+
*
|
|
9
|
+
* - `true` means the validation rule passed successfully.
|
|
10
|
+
* - `string` means the validation rule failed and the string is the error
|
|
11
|
+
* message to display to the user.
|
|
12
|
+
*
|
|
13
|
+
* This narrow type is intentionally small to make it easy to return a
|
|
14
|
+
* meaningful result from fast, CPU-only rule functions. If a rule needs to
|
|
15
|
+
* perform asynchronous work, it should return a {@link ValidatorAsyncResult}
|
|
16
|
+
* (i.e. a `Promise<ValidatorSyncResult>`).
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* // Success
|
|
21
|
+
* return true;
|
|
22
|
+
*
|
|
23
|
+
* // Failure with message
|
|
24
|
+
* return 'Must be at least 3 characters.';
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
export type ValidatorSyncResult = true | string;
|
|
30
|
+
/**
|
|
31
|
+
* ## Validator Async Result
|
|
32
|
+
*
|
|
33
|
+
* A convenience alias for the asynchronous validator result. Asynchronous
|
|
34
|
+
* rules return a Promise that resolves to a {@link ValidatorSyncResult}.
|
|
35
|
+
*
|
|
36
|
+
* Use this type when declaring asynchronous rule implementations so that
|
|
37
|
+
* type-checking and tooling can correctly surface the expected resolved
|
|
38
|
+
* result values (`true` or error `string`).
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* // Asynchronous rule example
|
|
43
|
+
* async function rule(opts) {
|
|
44
|
+
* const ok = await someAsyncCheck(opts.value);
|
|
45
|
+
* return ok ? true : 'Async check failed';
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @public
|
|
50
|
+
*/
|
|
51
|
+
export type ValidatorAsyncResult = Promise<ValidatorSyncResult>;
|
|
52
|
+
/**
|
|
53
|
+
* ## Validator Result
|
|
54
|
+
*
|
|
55
|
+
* Union type that describes the full set of possible return values from a
|
|
56
|
+
* validator rule function (`ValidatorRuleFunction`). The union includes both
|
|
57
|
+
* synchronous and asynchronous outcomes so rule implementations can be either
|
|
58
|
+
* sync or async without requiring the caller to have special handling logic.
|
|
59
|
+
*
|
|
60
|
+
* When consuming a `ValidatorResult` you should `await` it, or treat it as a
|
|
61
|
+
* possible `Promise`, which resolves to a `ValidatorSyncResult`.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* // Generic rule consumer (supports both sync and async rules)
|
|
66
|
+
* const r = await myRule({ value: 'x' });
|
|
67
|
+
* if (r === true) {
|
|
68
|
+
* // success
|
|
69
|
+
* } else {
|
|
70
|
+
* // r is the failure message
|
|
71
|
+
* console.error(r);
|
|
72
|
+
* }
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* @see {@link ValidatorSyncResult}
|
|
76
|
+
* @see {@link ValidatorAsyncResult}
|
|
77
|
+
* @public
|
|
78
|
+
*/
|
|
79
|
+
export type ValidatorResult = ValidatorSyncResult | ValidatorAsyncResult;
|
|
80
|
+
/**
|
|
81
|
+
* ## Validation Rule Type
|
|
82
|
+
*
|
|
83
|
+
* The core union type representing all possible ways to specify a validation rule in the validator system.
|
|
84
|
+
* This type provides maximum flexibility by supporting multiple rule specification formats while maintaining
|
|
85
|
+
* type safety and runtime validation capabilities.
|
|
86
|
+
*
|
|
87
|
+
* ### Purpose
|
|
88
|
+
* Defines the complete set of valid rule specifications that can be used in validation operations.
|
|
89
|
+
* Supports four different rule formats to accommodate various use cases and developer preferences.
|
|
90
|
+
*
|
|
91
|
+
* ### Union Members
|
|
92
|
+
*
|
|
93
|
+
* #### 1. Function Rules (`ValidatorRuleFunction`)
|
|
94
|
+
* Custom validation logic defined as functions. Most flexible but requires implementation.
|
|
95
|
+
* ```typescript
|
|
96
|
+
* ({ value, context }) => value.length > 5
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* #### 2. Named Rules (`ValidatorRuleName`)
|
|
100
|
+
* Simple string references to built-in validation rules. Most concise format.
|
|
101
|
+
* ```typescript
|
|
102
|
+
* "Required" | "Email" | "MinLength" | etc.
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* #### 3. Parameterized Rules (Template Literal)
|
|
106
|
+
* Built-in rules with parameters specified in string format. Readable and concise.
|
|
107
|
+
* ```typescript
|
|
108
|
+
* {MinLength:[5]}, {MaxLength:[100]} or {NumberBetween:[0,100]}
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
111
|
+
* #### 4. Object Rules (`ValidatorRuleObject`)
|
|
112
|
+
* Structured object format with type-safe parameters. Most type-safe format.
|
|
113
|
+
* ```typescript
|
|
114
|
+
* { MinLength: [5] } | { Email: [] } | { NumberBetween: [0, 100] }
|
|
115
|
+
* ```
|
|
116
|
+
*
|
|
117
|
+
* ### Type Parameters
|
|
118
|
+
* - **TParams**: Array type for rule parameters (default: `Array<any>`)
|
|
119
|
+
* - **Context**: Type of optional validation context (default: `unknown`)
|
|
120
|
+
*
|
|
121
|
+
* ### Usage Examples
|
|
122
|
+
*
|
|
123
|
+
* #### Mixed Rule Array
|
|
124
|
+
* ```typescript
|
|
125
|
+
* const rules: ValidatorRules = [
|
|
126
|
+
* "Required", // Named rule
|
|
127
|
+
* "MinLength[3]", // Parameterized rule
|
|
128
|
+
* { MaxLength: [50] }, // Object rule
|
|
129
|
+
* ({ value }) => value !== "", // Function rule
|
|
130
|
+
* ];
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* #### Type-Safe Rule Creation
|
|
134
|
+
* ```typescript
|
|
135
|
+
* // All these are valid ValidatorRule instances
|
|
136
|
+
* const rule1: ValidatorRule = "Email";
|
|
137
|
+
* const rule3: ValidatorRule = { Required: [] };
|
|
138
|
+
* const rule4: ValidatorRule = ({ value }) => typeof value === 'string';
|
|
139
|
+
* ```
|
|
140
|
+
*
|
|
141
|
+
* #### In Validation Operations
|
|
142
|
+
* ```typescript
|
|
143
|
+
* // Single rule validation
|
|
144
|
+
* const result = await Validator.validate({
|
|
145
|
+
* value: "test@example.com",
|
|
146
|
+
* rules: "Email", // ValidatorRule
|
|
147
|
+
* });
|
|
148
|
+
*
|
|
149
|
+
* // Multiple rules validation
|
|
150
|
+
* const multiResult = await Validator.validate({
|
|
151
|
+
* value: "hello",
|
|
152
|
+
* rules: ["Required", "MinLength[3]", { MaxLength: [10] }], // ValidatorRule[]
|
|
153
|
+
* });
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
* ### Rule Resolution Process
|
|
157
|
+
* When a rule is processed, the system:
|
|
158
|
+
* 1. **Identifies the format** based on the union member
|
|
159
|
+
* 2. **Resolves to a function** using {@link Validator.getRule}
|
|
160
|
+
* 3. **Applies parameters** if specified
|
|
161
|
+
* 4. **Executes validation** with value and context
|
|
162
|
+
*
|
|
163
|
+
* ### Type Safety Benefits
|
|
164
|
+
* - **Compile-time validation** of rule names and parameters
|
|
165
|
+
* - **IDE autocomplete** for built-in rules
|
|
166
|
+
* - **Refactoring safety** - rule signature changes are caught
|
|
167
|
+
* - **Runtime safety** - invalid rules are rejected during parsing
|
|
168
|
+
*
|
|
169
|
+
* ### Performance Considerations
|
|
170
|
+
* - **Function rules**: Fastest (direct execution)
|
|
171
|
+
* - **Named rules**: Fast (lookup table)
|
|
172
|
+
* - **Parameterized rules**: Medium (parsing required)
|
|
173
|
+
* - **Object rules**: Medium (type mapping required)
|
|
174
|
+
*
|
|
175
|
+
* ### Best Practices
|
|
176
|
+
*
|
|
177
|
+
* #### Choose Rule Format Wisely
|
|
178
|
+
* ```typescript
|
|
179
|
+
* // ✅ Use named rules for simple cases
|
|
180
|
+
* const simpleRules = ["Required", "Email"];
|
|
181
|
+
*
|
|
182
|
+
* // ✅ Use parameterized rules for single parameters
|
|
183
|
+
* const lengthRules = [{ MinLength: [5] }, { MaxLength: [100] }];
|
|
184
|
+
*
|
|
185
|
+
* // ✅ Use object rules for complex parameters or type safety
|
|
186
|
+
* const complexRules = [{ NumberBetween: [0, 100] }];
|
|
187
|
+
*
|
|
188
|
+
* // ✅ Use function rules for custom logic
|
|
189
|
+
* const customRules = [({ value }) => value % 2 === 0];
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* #### Combine Rule Types
|
|
193
|
+
* ```typescript
|
|
194
|
+
* const comprehensiveRules: ValidatorRules = [
|
|
195
|
+
* "Required", // Built-in
|
|
196
|
+
* "MinLength[3]", // Parameterized
|
|
197
|
+
* { Email: [] }, // Object (type-safe)
|
|
198
|
+
* ({ value, context }) => { // Custom function
|
|
199
|
+
* return context?.allowSpecialChars || !/[!@#$%]/.test(value);
|
|
200
|
+
* },
|
|
201
|
+
* ];
|
|
202
|
+
* ```
|
|
203
|
+
*
|
|
204
|
+
* ### Error Handling
|
|
205
|
+
* Invalid rules are caught during validation:
|
|
206
|
+
* ```typescript
|
|
207
|
+
* // These will throw validation errors:
|
|
208
|
+
* const invalid1 = "UnknownRule"; // Rule doesn't exist
|
|
209
|
+
* const invalid2 = "MinLength[abc]"; // Invalid parameter type
|
|
210
|
+
* const invalid3 = { UnknownRule: [] }; // Unknown rule name
|
|
211
|
+
* ```
|
|
212
|
+
*
|
|
213
|
+
* ### Relationship to Validation System
|
|
214
|
+
* This type is the foundation of the validation system and is used by:
|
|
215
|
+
* - All validation decorators and rule builders
|
|
216
|
+
*
|
|
217
|
+
* @template TParams - Array type for rule parameters, defaults to any array
|
|
218
|
+
* @template Context - Type of optional validation context, defaults to unknown
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```typescript
|
|
222
|
+
* // Define flexible validation rules
|
|
223
|
+
* type UserRules = ValidatorRule[];
|
|
224
|
+
*
|
|
225
|
+
* const userValidationRules: UserRules = [
|
|
226
|
+
* "Required",
|
|
227
|
+
* "MinLength[2]",
|
|
228
|
+
* { MaxLength: [50] },
|
|
229
|
+
* ({ value }) => !/\s/.test(value), // No spaces
|
|
230
|
+
* ];
|
|
231
|
+
*
|
|
232
|
+
* // Use in validation
|
|
233
|
+
* const result = await Validator.validate({
|
|
234
|
+
* value: "john_doe",
|
|
235
|
+
* rules: userValidationRules,
|
|
236
|
+
* });
|
|
237
|
+
* ```
|
|
238
|
+
*
|
|
239
|
+
*
|
|
240
|
+
* @see {@link ValidatorRuleFunction} - Function-based rules
|
|
241
|
+
* @see {@link ValidatorRuleName} - Built-in rule names
|
|
242
|
+
* @see {@link ValidatorRuleObject} - Object-based rules
|
|
243
|
+
* @see {@link ValidatorRuleParamTypes} - Built-in rule definitions
|
|
244
|
+
* @see {@link Validator} - Main validation class
|
|
245
|
+
* @public
|
|
246
|
+
*/
|
|
247
|
+
export type ValidatorRule<TParams extends ValidatorRuleParams = ValidatorRuleParams, Context = unknown> = ValidatorRuleFunction<TParams, Context> | ValidatorOptionalOrEmptyRuleNames | ValidatorRuleObject;
|
|
248
|
+
/**
|
|
249
|
+
* @typedef {ValidatorOptionalOrEmptyRuleNames}
|
|
250
|
+
* Union of rule names whose **runtime parameter list** is either
|
|
251
|
+
* - completely empty (`[]`), or
|
|
252
|
+
* - contains only optional elements (e.g. `[countryCode?: string]`).
|
|
253
|
+
*
|
|
254
|
+
* These are the rules that can be invoked without supplying arguments
|
|
255
|
+
* or whose arguments are truly optional at the call-site.
|
|
256
|
+
*
|
|
257
|
+
* ┌-------------------------------------------------------------------------┐
|
|
258
|
+
* │ EXAMPLES │
|
|
259
|
+
* │ ---------- │
|
|
260
|
+
* │ ✔ "Email" // Array<[]> │
|
|
261
|
+
* │ ✔ "PhoneNumber" // Array<[countryCode?: string]> │
|
|
262
|
+
* │ ✘ "Length" // Array<[number, number?]> │
|
|
263
|
+
* │ ✘ "NumberLT" // Array<[number]> │
|
|
264
|
+
* └-------------------------------------------------------------------------┘
|
|
265
|
+
*
|
|
266
|
+
* The type is built in two steps:
|
|
267
|
+
* 1. `ExtractOptionalOrEmptyKeys` keeps the keys whose tuple is empty or
|
|
268
|
+
* fully optional (see helper below).
|
|
269
|
+
* 2. `& keyof ValidatorRuleParamTypes` is a sanity filter that guarantees we
|
|
270
|
+
* never leak alien keys should the utility mis-behave.
|
|
271
|
+
*/
|
|
272
|
+
export type ValidatorOptionalOrEmptyRuleNames = ExtractOptionalOrEmptyKeys<ValidatorRuleParamTypes>;
|
|
273
|
+
/**
|
|
274
|
+
* ## Tuple Allows Empty Type
|
|
275
|
+
*
|
|
276
|
+
* A conditional type that determines if a tuple type allows empty invocation (no arguments).
|
|
277
|
+
* This type is fundamental to the validator's parameter system, enabling type-safe determination
|
|
278
|
+
* of which validation rules can be called without supplying arguments.
|
|
279
|
+
*
|
|
280
|
+
* ### Purpose
|
|
281
|
+
* Provides compile-time type safety for determining whether validation rule parameter tuples
|
|
282
|
+
* support empty invocation. This is crucial for distinguishing between rules that require
|
|
283
|
+
* parameters (like `MinLength[5]`) and rules that can be called without them (like `Required`).
|
|
284
|
+
*
|
|
285
|
+
* ### Type Logic
|
|
286
|
+
* The type uses conditional type checking to evaluate tuple structures:
|
|
287
|
+
* - **Empty tuples `[]`**: Always allow empty invocation (returns `true`)
|
|
288
|
+
* - **Non-empty tuples**: Check if empty array is assignable using `[] extends T`
|
|
289
|
+
* - If assignable: All parameters are optional (returns `true`)
|
|
290
|
+
* - If not assignable: At least one parameter is required (returns `false`)
|
|
291
|
+
*
|
|
292
|
+
* ### Examples
|
|
293
|
+
*
|
|
294
|
+
* #### Empty Parameter Rules (returns `true`)
|
|
295
|
+
* ```typescript
|
|
296
|
+
* // Rules with no parameters - can be called without arguments
|
|
297
|
+
* type EmailParams = []; // true
|
|
298
|
+
* type RequiredParams = []; // true
|
|
299
|
+
* type PhoneParams = [countryCode?: string]; // true (optional param)
|
|
300
|
+
* type NullableParams = []; // true
|
|
301
|
+
* ```
|
|
302
|
+
*
|
|
303
|
+
* #### Required Parameter Rules (returns `false`)
|
|
304
|
+
* ```typescript
|
|
305
|
+
* // Rules with required parameters - must be called with arguments
|
|
306
|
+
* type MinLengthParams = [number]; // false
|
|
307
|
+
* type MaxLengthParams = [number]; // false
|
|
308
|
+
* type LengthParams = [number, number?]; // false (first param required)
|
|
309
|
+
* type NumberBetweenParams = [number, number]; // false
|
|
310
|
+
* ```
|
|
311
|
+
*
|
|
312
|
+
* ### Usage in Validation System
|
|
313
|
+
* This type is used internally by the validator to:
|
|
314
|
+
* - **Generate rule unions**: Create {@link ValidatorOptionalOrEmptyRuleNames}
|
|
315
|
+
* - **Type parameter extraction**: Determine which rules can be called without args
|
|
316
|
+
* - **Rule registry filtering**: Separate parameterless from parameterized rules
|
|
317
|
+
*
|
|
318
|
+
* ### Advanced Type-Level Operations
|
|
319
|
+
* ```typescript
|
|
320
|
+
* // Extract rules that can be called without parameters
|
|
321
|
+
* type ParameterlessRules = {
|
|
322
|
+
* [K in keyof ValidatorRuleParamTypes]: ValidatorTupleAllowsEmpty<
|
|
323
|
+
* ValidatorRuleParamTypes[K]
|
|
324
|
+
* > extends true ? K : never;
|
|
325
|
+
* }[keyof ValidatorRuleParamTypes];
|
|
326
|
+
*
|
|
327
|
+
* // Extract rules that require parameters
|
|
328
|
+
* type ParameterizedRules = {
|
|
329
|
+
* [K in keyof ValidatorRuleParamTypes]: ValidatorTupleAllowsEmpty<
|
|
330
|
+
* ValidatorRuleParamTypes[K]
|
|
331
|
+
* > extends false ? K : never;
|
|
332
|
+
* }[keyof ValidatorRuleParamTypes];
|
|
333
|
+
* ```
|
|
334
|
+
*
|
|
335
|
+
* ### Relationship to Validation System
|
|
336
|
+
* - **Used by**: {@link ExtractOptionalOrEmptyKeys} to filter rule parameter types
|
|
337
|
+
* - **Enables**: {@link ValidatorOptionalOrEmptyRuleNames} union type creation
|
|
338
|
+
* - **Supports**: Type-safe rule invocation without parameters
|
|
339
|
+
* - **Foundation**: Core type for parameter validation logic
|
|
340
|
+
*
|
|
341
|
+
* ### Type Safety Benefits
|
|
342
|
+
* - **Compile-time validation**: Prevents calling parameterized rules without args
|
|
343
|
+
* - **IDE support**: Better autocomplete for parameterless rules
|
|
344
|
+
* - **Refactoring safety**: Changes to rule parameters are caught by TypeScript
|
|
345
|
+
* - **Runtime safety**: Ensures proper parameter handling in rule implementations
|
|
346
|
+
*
|
|
347
|
+
* ### Implementation Details
|
|
348
|
+
* The type uses advanced TypeScript conditional types and assignability checks:
|
|
349
|
+
* - `T extends []`: Direct check for empty tuple literals
|
|
350
|
+
* - `[] extends T`: Covariant assignability check for optional parameters
|
|
351
|
+
* - This correctly handles both mutable and readonly array types
|
|
352
|
+
*
|
|
353
|
+
* ### Best Practices
|
|
354
|
+
*
|
|
355
|
+
* #### When Adding New Rules
|
|
356
|
+
* ```typescript
|
|
357
|
+
* // ✅ Parameterless rules (can be called as "RuleName")
|
|
358
|
+
* Required: []; // No parameters needed
|
|
359
|
+
* Email: []; // No parameters needed
|
|
360
|
+
* PhoneNumber: [countryCode?: string]; // Optional parameter
|
|
361
|
+
*
|
|
362
|
+
* // ❌ Parameterized rules (must be called as "RuleName[param]")
|
|
363
|
+
* MinLength: [number]; // Required parameter
|
|
364
|
+
* MaxLength: [number]; // Required parameter
|
|
365
|
+
* Length: [number, number?]; // First parameter required
|
|
366
|
+
* ```
|
|
367
|
+
*
|
|
368
|
+
* #### Type-Level Programming
|
|
369
|
+
* ```typescript
|
|
370
|
+
* // Create union of parameterless rule names
|
|
371
|
+
* type ParameterlessRuleNames = {
|
|
372
|
+
* [K in keyof ValidatorRuleParamTypes]: ValidatorTupleAllowsEmpty<
|
|
373
|
+
* ValidatorRuleParamTypes[K]
|
|
374
|
+
* > extends true ? K : never;
|
|
375
|
+
* }[keyof ValidatorRuleParamTypes];
|
|
376
|
+
* // Result: "Required" | "Email" | "PhoneNumber" | "Empty" | "Nullable" | "Optional"
|
|
377
|
+
* ```
|
|
378
|
+
*
|
|
379
|
+
* @template T - The tuple type to check (must extend Array<any>)
|
|
380
|
+
*
|
|
381
|
+
* @public
|
|
382
|
+
*
|
|
383
|
+
* @see {@link ValidatorOptionalOrEmptyRuleNames} - Union type created using this
|
|
384
|
+
* @see {@link ExtractOptionalOrEmptyKeys} - Helper type that uses this
|
|
385
|
+
* @see {@link ValidatorRuleParamTypes} - Rule parameter definitions checked by this
|
|
386
|
+
* @see {@link ValidatorRuleName} - Rule names validated by this type
|
|
387
|
+
*/
|
|
388
|
+
export type ValidatorTupleAllowsEmpty<T extends Array<unknown>> = T extends [] ? true : [] extends T ? true : false;
|
|
389
|
+
/**
|
|
390
|
+
* Extracts keys whose rule parameter tuple is empty or fully optional.
|
|
391
|
+
* This correctly captures cases like `[countryCode?: CountryCode]`.
|
|
392
|
+
*/
|
|
393
|
+
type ExtractOptionalOrEmptyKeys<T> = {
|
|
394
|
+
[K in keyof T]: T[K] extends Array<unknown> ? ValidatorTupleAllowsEmpty<T[K]> extends true ? K : never : never;
|
|
395
|
+
}[keyof T];
|
|
396
|
+
/**
|
|
397
|
+
* ## Validation Rule Object Type
|
|
398
|
+
*
|
|
399
|
+
* Represents a structured object format for specifying validation rules with their parameters.
|
|
400
|
+
* This type creates a mapped type that ensures type safety when defining rules as objects
|
|
401
|
+
* rather than strings or functions.
|
|
402
|
+
*
|
|
403
|
+
* ### Purpose
|
|
404
|
+
* Provides a strongly-typed way to specify validation rules with parameters using object notation.
|
|
405
|
+
* This is particularly useful when you need to ensure type safety for rule parameters at compile time.
|
|
406
|
+
*
|
|
407
|
+
* ### Type Structure
|
|
408
|
+
* This is a mapped type that creates an object where:
|
|
409
|
+
* - **Key**: Must be a valid `ValidatorRuleName` (e.g., "MinLength", "Email", etc.)
|
|
410
|
+
* - **Value**: Must match the parameter type defined in `ValidatorRuleParamTypes` for that rule
|
|
411
|
+
*
|
|
412
|
+
* ### Generated Structure
|
|
413
|
+
* For each rule in `ValidatorRuleParamTypes`, this type generates an object like:
|
|
414
|
+
* ```typescript
|
|
415
|
+
* {
|
|
416
|
+
* MinLength: [number]; // Requires array with one number
|
|
417
|
+
* Email: []; // Requires empty array
|
|
418
|
+
* NumberBetween: [number, number]; // Requires array with two numbers
|
|
419
|
+
* }
|
|
420
|
+
* ```
|
|
421
|
+
*
|
|
422
|
+
* ### Usage Examples
|
|
423
|
+
*
|
|
424
|
+
* #### Basic Rule Objects
|
|
425
|
+
* ```typescript
|
|
426
|
+
* // Valid rule objects
|
|
427
|
+
* const minLengthRule: ValidatorRuleObject = {
|
|
428
|
+
* MinLength: [5] // Must be array with one number
|
|
429
|
+
* };
|
|
430
|
+
*
|
|
431
|
+
* const emailRule: ValidatorRuleObject = {
|
|
432
|
+
* Email: [] // Must be empty array
|
|
433
|
+
* };
|
|
434
|
+
*
|
|
435
|
+
* const betweenRule: ValidatorRuleObject = {
|
|
436
|
+
* NumberBetween: [0, 100] // Must be array with two numbers
|
|
437
|
+
* };
|
|
438
|
+
* ```
|
|
439
|
+
*
|
|
440
|
+
* #### In Validation Rules Array
|
|
441
|
+
* ```typescript
|
|
442
|
+
* const rules: ValidatorRules = [
|
|
443
|
+
* "Required", // String rule
|
|
444
|
+
* { MinLength: [5] }, // Object rule (this type)
|
|
445
|
+
* ({ value }) => value > 0, // Function rule
|
|
446
|
+
* ];
|
|
447
|
+
* ```
|
|
448
|
+
*
|
|
449
|
+
* #### Type Safety Benefits
|
|
450
|
+
* ```typescript
|
|
451
|
+
* // TypeScript will catch these errors:
|
|
452
|
+
* const invalid1: ValidatorRuleObject = {
|
|
453
|
+
* MinLength: 5 // ❌ Error: Must be array, not number
|
|
454
|
+
* };
|
|
455
|
+
*
|
|
456
|
+
* const invalid2: ValidatorRuleObject = {
|
|
457
|
+
* MinLength: [5, 10] // ❌ Error: MinLength only takes one parameter
|
|
458
|
+
* };
|
|
459
|
+
*
|
|
460
|
+
* const invalid3: ValidatorRuleObject = {
|
|
461
|
+
* UnknownRule: [] // ❌ Error: UnknownRule not in ValidatorRuleName
|
|
462
|
+
* };
|
|
463
|
+
* ```
|
|
464
|
+
*
|
|
465
|
+
* ### Relationship to Other Rule Types
|
|
466
|
+
* This type is one of four union members in {@link ValidatorRule}:
|
|
467
|
+
* - `ValidatorRuleFunction` - Custom validation functions
|
|
468
|
+
* - `ValidatorRuleName` - Simple rule names (strings)
|
|
469
|
+
* - `` `${ValidatorRuleName}[${string}]` `` - Parameterized rule strings
|
|
470
|
+
* - `ValidatorRuleObject` - Structured rule objects (this type)
|
|
471
|
+
*
|
|
472
|
+
* ### When to Use
|
|
473
|
+
* Use this type when you need:
|
|
474
|
+
* - **Type Safety**: Compile-time validation of rule parameters
|
|
475
|
+
* - **IDE Support**: Better autocomplete and error detection
|
|
476
|
+
* - **Complex Parameters**: Rules with multiple typed parameters
|
|
477
|
+
* - **Refactoring Safety**: Changes to rule signatures are caught by TypeScript
|
|
478
|
+
*
|
|
479
|
+
* ### Comparison with String Rules
|
|
480
|
+
* | Aspect | Object Rules | String Rules |
|
|
481
|
+
* |--------|-------------|--------------|
|
|
482
|
+
* | Type Safety | ✅ Full compile-time checking | ⚠️ Runtime parameter validation |
|
|
483
|
+
* | Autocomplete | ✅ Parameter types shown | ❌ No parameter hints |
|
|
484
|
+
* | Refactoring | ✅ Breaking changes caught | ❌ May break silently |
|
|
485
|
+
* | Readability | ✅ Self-documenting | ⚠️ Requires knowledge of syntax |
|
|
486
|
+
* | Flexibility | ✅ Strongly typed | ✅ Dynamic |
|
|
487
|
+
*
|
|
488
|
+
* @template Context - Type of the optional validation context
|
|
489
|
+
*
|
|
490
|
+
* @example
|
|
491
|
+
* ```typescript
|
|
492
|
+
* // Define rules with full type safety
|
|
493
|
+
* const userRules: ValidatorRules = [
|
|
494
|
+
* { Required: [] },
|
|
495
|
+
* { Email: [] },
|
|
496
|
+
* { MinLength: [3] },
|
|
497
|
+
* { MaxLength: [50] },
|
|
498
|
+
* ];
|
|
499
|
+
*
|
|
500
|
+
* // TypeScript ensures parameter types match
|
|
501
|
+
* const result = await Validator.validate({
|
|
502
|
+
* value: "test@example.com",
|
|
503
|
+
* rules: userRules,
|
|
504
|
+
* });
|
|
505
|
+
* ```
|
|
506
|
+
*
|
|
507
|
+
*
|
|
508
|
+
* @see {@link ValidatorRule} - Union type that includes this
|
|
509
|
+
* @see {@link ValidatorRuleName} - Valid rule names
|
|
510
|
+
* @see {@link ValidatorRuleParamTypes} - Parameter type definitions
|
|
511
|
+
* @see {@link ValidatorRuleFunction} - Function-based rules
|
|
512
|
+
* @public
|
|
513
|
+
*/
|
|
514
|
+
export type ValidatorRuleObject = Partial<{
|
|
515
|
+
[K in ValidatorRuleName]: ValidatorRuleParamTypes[K];
|
|
516
|
+
}>;
|
|
517
|
+
/**
|
|
518
|
+
* Represents an array of validation rules to be applied to a value.
|
|
519
|
+
*
|
|
520
|
+
* This type defines a collection of validation rules that will be executed
|
|
521
|
+
* in sequence against a single value. Each rule in the array can be specified
|
|
522
|
+
* in various formats and will be processed by the validator.
|
|
523
|
+
*
|
|
524
|
+
* @template Context - The type of the optional validation context
|
|
525
|
+
*
|
|
526
|
+
* @example
|
|
527
|
+
* ```typescript
|
|
528
|
+
* // Using rule names
|
|
529
|
+
* const rules1: ValidatorRules = ["Required", "Email"];
|
|
530
|
+
*
|
|
531
|
+
* // Using parameterized rules
|
|
532
|
+
* const rules2: ValidatorRules = ["Required", { MinLength: [5] }, { MaxLength: [100] }];
|
|
533
|
+
*
|
|
534
|
+
* // Using validation functions
|
|
535
|
+
* const rules3: ValidatorRules = [
|
|
536
|
+
* "Required",
|
|
537
|
+
* ({ value }) => value.length >= 5 || "Too short"
|
|
538
|
+
* ];
|
|
539
|
+
*
|
|
540
|
+
* // Using rule objects
|
|
541
|
+
* const rules4: ValidatorRules = [
|
|
542
|
+
* { ruleName: "Required" },
|
|
543
|
+
* { ruleName: "MinLength", params: [8] }
|
|
544
|
+
* ];
|
|
545
|
+
* ```
|
|
546
|
+
*
|
|
547
|
+
* @public
|
|
548
|
+
*
|
|
549
|
+
* @see {@link ValidatorRule} - Individual rule type
|
|
550
|
+
* @see {@link ValidatorValidateOptions} - Options interface that uses this type
|
|
551
|
+
* @see {@link Validator.validate} - Validation method that accepts these rules
|
|
552
|
+
*/
|
|
553
|
+
export type ValidatorRules<Context = unknown> = Array<ValidatorRule<Array<unknown>, Context>>;
|
|
554
|
+
/**
|
|
555
|
+
* @typedef ValidatorSanitizedRule
|
|
556
|
+
* Represents a sanitized validation rule.
|
|
557
|
+
*
|
|
558
|
+
* This type can either be a validation rule function or an object that contains
|
|
559
|
+
* detailed information about a validation rule, including its name, parameters,
|
|
560
|
+
* and the function that implements the validation logic.
|
|
561
|
+
*
|
|
562
|
+
* @example
|
|
563
|
+
* // Example of a validation rule function
|
|
564
|
+
* const minLengthRule: ValidatorSanitizedRule = ({ value }) => {
|
|
565
|
+
* return value.length >= 5 || "Minimum length is 5 characters.";
|
|
566
|
+
* };
|
|
567
|
+
*
|
|
568
|
+
* // Example of a sanitized rule object
|
|
569
|
+
* const sanitizedRule: ValidatorSanitizedRule = {
|
|
570
|
+
* ruleName: "minLength",
|
|
571
|
+
* params: [5],
|
|
572
|
+
* ruleFunction: minLengthRule,
|
|
573
|
+
* };
|
|
574
|
+
*/
|
|
575
|
+
export type ValidatorSanitizedRule<TParams extends ValidatorRuleParams = ValidatorRuleParams, Context = unknown> = ValidatorRuleFunction<TParams, Context> | ValidatorSanitizedRuleObject<TParams>;
|
|
576
|
+
/**
|
|
577
|
+
* ## Sanitized Rule Object
|
|
578
|
+
*
|
|
579
|
+
* Represents a structured object containing parsed and sanitized validation rule information.
|
|
580
|
+
* This interface defines the shape of objects that contain all the necessary details
|
|
581
|
+
* for executing a validation rule after it has been processed from its raw form.
|
|
582
|
+
*
|
|
583
|
+
* ### Purpose
|
|
584
|
+
* After validation rules are parsed from objects like `{ MinLength: [5] }` or `{ ruleName: "Required" }`, they are converted into this standardized object format
|
|
585
|
+
* `{ ruleName: "Required" }`, they are converted into this standardized object format
|
|
586
|
+
* that contains all the information needed to execute the validation.
|
|
587
|
+
*
|
|
588
|
+
* ### Properties Overview
|
|
589
|
+
* - **ruleName**: The parsed rule identifier (e.g., "MinLength")
|
|
590
|
+
* - **params**: Array of parameters extracted from the rule (e.g., `[5]`)
|
|
591
|
+
* - **ruleFunction**: The actual validation function to execute
|
|
592
|
+
* - **rawRuleName**: The original unparsed rule string (e.g., {MinLength:[5]})
|
|
593
|
+
*
|
|
594
|
+
* ### Usage in Validation Pipeline
|
|
595
|
+
* ```typescript
|
|
596
|
+
* // Raw rule input
|
|
597
|
+
* const rawRule = "MinLength[8]";
|
|
598
|
+
*
|
|
599
|
+
* // After parsing/sanitization
|
|
600
|
+
* const sanitizedRule: ValidatorSanitizedRuleObject = {
|
|
601
|
+
* ruleName: "MinLength",
|
|
602
|
+
* params: [8],
|
|
603
|
+
* ruleFunction: minLengthFunction,
|
|
604
|
+
* rawRuleName: "MinLength[8]"
|
|
605
|
+
* };
|
|
606
|
+
*
|
|
607
|
+
* // During validation
|
|
608
|
+
* const result = await sanitizedRule.ruleFunction({
|
|
609
|
+
* value: "password123",
|
|
610
|
+
* ruleParams: sanitizedRule.params,
|
|
611
|
+
* // ... other options
|
|
612
|
+
* });
|
|
613
|
+
* ```
|
|
614
|
+
*
|
|
615
|
+
* ### Relationship to ValidatorSanitizedRule
|
|
616
|
+
* This interface is one of the union members of {@link ValidatorSanitizedRule}.
|
|
617
|
+
* The union allows rules to be represented as either:
|
|
618
|
+
* - A direct function (`ValidatorRuleFunction`)
|
|
619
|
+
* - A structured object (`ValidatorSanitizedRuleObject`)
|
|
620
|
+
*
|
|
621
|
+
* @template TParams - The type of parameters that the rule accepts (default: Array<any>)
|
|
622
|
+
* @template Context - The type of the optional validation context
|
|
623
|
+
*
|
|
624
|
+
* @public
|
|
625
|
+
*
|
|
626
|
+
* @see {@link ValidatorSanitizedRule} - Union type that includes this interface
|
|
627
|
+
* @see {@link ValidatorRuleFunction} - The validation function type
|
|
628
|
+
* @see {@link ValidatorRuleName} - Rule name type
|
|
629
|
+
*/
|
|
630
|
+
export interface ValidatorSanitizedRuleObject<TParams extends ValidatorRuleParams = ValidatorRuleParams, Context = unknown> {
|
|
631
|
+
/**
|
|
632
|
+
* The parsed name of the validation rule
|
|
633
|
+
*
|
|
634
|
+
* This is the rule identifier extracted from the original rule specification.
|
|
635
|
+
* For example, if the raw rule was {MinLength:[5]}, this would be "MinLength".
|
|
636
|
+
* Must be a valid rule name from {@link ValidatorRuleName}.
|
|
637
|
+
*
|
|
638
|
+
* @type {ValidatorRuleName}
|
|
639
|
+
* @example "MinLength"
|
|
640
|
+
* @example "Required"
|
|
641
|
+
* @example "Email"
|
|
642
|
+
*
|
|
643
|
+
* @see {@link ValidatorRuleName}
|
|
644
|
+
*/
|
|
645
|
+
ruleName: ValidatorRuleName;
|
|
646
|
+
/**
|
|
647
|
+
* The parameters extracted from the rule specification
|
|
648
|
+
*
|
|
649
|
+
* Array of values that were parsed from the rule's parameter brackets.
|
|
650
|
+
* For example, "MinLength[5,10]" would result in `[5, 10]`.
|
|
651
|
+
* Empty array for rules that don't take parameters.
|
|
652
|
+
*
|
|
653
|
+
* @type {TParams}
|
|
654
|
+
* @example [] // For "Required" rule
|
|
655
|
+
* @example [5] // For {MinLength:[5]} rule
|
|
656
|
+
* @example [0, 100] // For {NumberBetween:[0,100]} rule
|
|
657
|
+
*/
|
|
658
|
+
params: TParams;
|
|
659
|
+
/**
|
|
660
|
+
* The validation function that implements the rule logic
|
|
661
|
+
*
|
|
662
|
+
* The actual executable function that performs the validation.
|
|
663
|
+
* This function receives validation options and returns a result
|
|
664
|
+
* indicating whether the validation passed or failed.
|
|
665
|
+
*
|
|
666
|
+
* @type {ValidatorRuleFunction<TParams>}
|
|
667
|
+
* @see {@link ValidatorRuleFunction}
|
|
668
|
+
*/
|
|
669
|
+
ruleFunction: ValidatorRuleFunction<TParams, Context>;
|
|
670
|
+
/**
|
|
671
|
+
* The original unparsed rule specification
|
|
672
|
+
*
|
|
673
|
+
* The raw rule string as it was originally provided, before parsing.
|
|
674
|
+
* This is useful for error reporting and debugging, as it shows
|
|
675
|
+
* exactly what the user specified.
|
|
676
|
+
*
|
|
677
|
+
* @type {ValidatorRuleName | string}
|
|
678
|
+
* @example {MinLength:[5]}
|
|
679
|
+
* @example "Required"
|
|
680
|
+
* @example "Email"
|
|
681
|
+
*/
|
|
682
|
+
rawRuleName: ValidatorRuleName | string;
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* @typedef ValidatorSanitizedRules
|
|
686
|
+
* Represents an array of sanitized validation rules.
|
|
687
|
+
*
|
|
688
|
+
* This type is a collection of sanitized rules, allowing for multiple
|
|
689
|
+
* validation rules to be applied in a structured manner.
|
|
690
|
+
*
|
|
691
|
+
* @template Context The type of the optional validation context.
|
|
692
|
+
*
|
|
693
|
+
* @example
|
|
694
|
+
* const sanitizedRules: ValidatorSanitizedRules = [
|
|
695
|
+
* {
|
|
696
|
+
* ruleName: "required",
|
|
697
|
+
* params: [],
|
|
698
|
+
* ruleFunction: ({ value }) => !!value || "This field is required.",
|
|
699
|
+
* },
|
|
700
|
+
* {
|
|
701
|
+
* ruleName: "minLength",
|
|
702
|
+
* params: [5],
|
|
703
|
+
* ruleFunction: ({ value }) => value.length >= 5 || "Minimum length is 5 characters.",
|
|
704
|
+
* },
|
|
705
|
+
* ];
|
|
706
|
+
*/
|
|
707
|
+
export type ValidatorSanitizedRules<Context = unknown> = ValidatorSanitizedRule<Array<unknown>, Context>[];
|
|
708
|
+
/**
|
|
709
|
+
* ## Validator Validate Rule Function Type
|
|
710
|
+
*
|
|
711
|
+
* Represents a validation rule function that is used within the validation system.
|
|
712
|
+
* This function takes a set of options and performs validation on a given value,
|
|
713
|
+
* returning the result of the validation process.
|
|
714
|
+
*
|
|
715
|
+
* @template TParams The type of the parameters that the rule function accepts.
|
|
716
|
+
*
|
|
717
|
+
* ### Structure:
|
|
718
|
+
* - The function accepts a single parameter:
|
|
719
|
+
* - `options` (ValidatorValidateOptions): An object containing the necessary parameters for validation.
|
|
720
|
+
*
|
|
721
|
+
* ### Parameters:
|
|
722
|
+
* - **options**: An object of type `ValidatorValidateOptions` which includes:
|
|
723
|
+
* - `rules`: A collection of validation rules to apply. This can be a single rule or an array of rules.
|
|
724
|
+
* - `rule`: An optional specific validation rule to apply, overriding the rules defined in the `rules` property.
|
|
725
|
+
* - `value`: The actual value that needs to be validated against the specified rules.
|
|
726
|
+
* - `ruleParams`: Optional parameters that may be required for specific validation rules.
|
|
727
|
+
*
|
|
728
|
+
* ### Return Value:
|
|
729
|
+
* - The function returns a {@link ValidatorResult}, which is either:
|
|
730
|
+
* - a `ValidatorSyncResult` (synchronous rule result) — `true` for success, or a `string` containing the error message on failure
|
|
731
|
+
* - or a `Promise<ValidatorSyncResult>` (asynchronous rule result)
|
|
732
|
+
*
|
|
733
|
+
* ### Example Usage:
|
|
734
|
+
* ```typescript
|
|
735
|
+
* function validateEmail({ value }) {
|
|
736
|
+
* const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
737
|
+
* if (!emailPattern.test(value)) {
|
|
738
|
+
* return "Invalid email format."; // Invalid validation
|
|
739
|
+
* }
|
|
740
|
+
* return true; // Valid validation
|
|
741
|
+
* }
|
|
742
|
+
*
|
|
743
|
+
* // Example of using the validation function
|
|
744
|
+
* const result = validateEmail({ value: "test@example.com" });
|
|
745
|
+
* if (typeof result === "string") {
|
|
746
|
+
* console.error(result); // Output: "Invalid email format." if validation fails
|
|
747
|
+
* } else {
|
|
748
|
+
* console.log("Validation passed."); // Output: "Validation passed." if validation succeeds
|
|
749
|
+
* }
|
|
750
|
+
* ```
|
|
751
|
+
*
|
|
752
|
+
* ### Notes:
|
|
753
|
+
* - This type is essential for defining custom validation logic in forms, allowing developers to create reusable and flexible validation rules.
|
|
754
|
+
* - The function can be synchronous or asynchronous, depending on the validation logic implemented.
|
|
755
|
+
*/
|
|
756
|
+
export type ValidatorRuleFunction<TParams extends ValidatorRuleParams = ValidatorRuleParams, Context = unknown> = (options: ValidatorValidateOptions<TParams, Context>) => ValidatorResult;
|
|
757
|
+
/**
|
|
758
|
+
* ## Validation Rule Parameters Type
|
|
759
|
+
*
|
|
760
|
+
* A conditional type that defines the parameter structure for validation rules.
|
|
761
|
+
* This type handles both mutable and readonly array parameters, providing flexibility
|
|
762
|
+
* for validation rules that accept different parameter formats.
|
|
763
|
+
*
|
|
764
|
+
* ### Type Behavior
|
|
765
|
+
* - **Empty Arrays**: When `TParams` is an empty array `[]`, resolves to `[]`
|
|
766
|
+
* - **Non-Empty Arrays**: Resolves to either the original `TParams` or its readonly variant `Readonly<TParams>`
|
|
767
|
+
* - **Readonly Support**: Accepts both `Array<any>` and `ReadonlyArray<any>` as input types
|
|
768
|
+
*
|
|
769
|
+
* ### Purpose
|
|
770
|
+
* This type enables validation rules to accept parameters in multiple formats:
|
|
771
|
+
* - Regular arrays: `[minLength: number]` for `MinLength[5]`
|
|
772
|
+
* - Readonly arrays: `readonly [minLength: number]` for const assertions
|
|
773
|
+
* - Empty parameters: `[]` for rules like `Required` that take no parameters
|
|
774
|
+
*
|
|
775
|
+
* ### Generic Parameters
|
|
776
|
+
* - **TParams**: The parameter array type (must extend `Array<any>` or `ReadonlyArray<any>`)
|
|
777
|
+
* - **Context**: Optional context type (defaults to `unknown`)
|
|
778
|
+
*
|
|
779
|
+
* ### Usage in Rule Definitions
|
|
780
|
+
* ```typescript
|
|
781
|
+
* // Rule that takes a single number parameter
|
|
782
|
+
* MinLength: ValidatorRuleParams<[minLength: number]>;
|
|
783
|
+
*
|
|
784
|
+
* // Rule that takes min and max number parameters
|
|
785
|
+
* Length: ValidatorRuleParams<[lengthOrMin: number, maxLength?: number]>;
|
|
786
|
+
*
|
|
787
|
+
* // Rule that takes no parameters
|
|
788
|
+
* Required: ValidatorRuleParams<[]>;
|
|
789
|
+
*
|
|
790
|
+
* // Rule that accepts readonly arrays (e.g., const assertions)
|
|
791
|
+
* IsEnum: ValidatorRuleParams<ReadonlyArray<string>>;
|
|
792
|
+
* ```
|
|
793
|
+
*
|
|
794
|
+
* ### Type Resolution Examples
|
|
795
|
+
* ```typescript
|
|
796
|
+
* // Empty array resolves to empty array
|
|
797
|
+
* type RequiredParams = ValidatorRuleParams<[]>; // []
|
|
798
|
+
*
|
|
799
|
+
* // Single parameter array
|
|
800
|
+
* type MinLengthParams = ValidatorRuleParams<[number]>; // [number] | readonly [number]
|
|
801
|
+
*
|
|
802
|
+
* // Multiple parameters
|
|
803
|
+
* type BetweenParams = ValidatorRuleParams<[number, number]>; // [number, number] | readonly [number, number]
|
|
804
|
+
* ```
|
|
805
|
+
*
|
|
806
|
+
* ### Relationship to Validation System
|
|
807
|
+
* - Used by {@link ValidatorRuleParamTypes} to define parameter types for each rule
|
|
808
|
+
* - Compatible with {@link ValidatorRuleFunction} parameter signatures
|
|
809
|
+
* - Supports both mutable and immutable parameter arrays for flexibility
|
|
810
|
+
*
|
|
811
|
+
* @template TParams - The parameter array type (extends Array<unknown> | ReadonlyArray<unknown>)
|
|
812
|
+
* @template Context - Optional context type for validation (defaults to unknown)
|
|
813
|
+
*
|
|
814
|
+
* @public
|
|
815
|
+
*
|
|
816
|
+
* @see {@link ValidatorRuleParamTypes} - Uses this type for rule parameter definitions
|
|
817
|
+
* @see {@link ValidatorRuleFunction} - Validation function that receives these parameters
|
|
818
|
+
* @see {@link ValidatorRule} - Complete rule definition including this parameter type
|
|
819
|
+
*/
|
|
820
|
+
export type ValidatorRuleParams<TParams extends Array<unknown> | ReadonlyArray<unknown> = Array<unknown>, Context = unknown> = TParams extends [] ? [] : TParams;
|
|
821
|
+
/**
|
|
822
|
+
* ## Nested Rule Function Options
|
|
823
|
+
*
|
|
824
|
+
* Configuration interface for validating nested objects or complex data structures
|
|
825
|
+
* within the validation system. This interface is specifically designed for rule functions
|
|
826
|
+
* that need to validate target objects (classes with decorators) rather than simple values.
|
|
827
|
+
*
|
|
828
|
+
* ### Purpose
|
|
829
|
+
* Provides a specialized options interface for validation rule functions that operate on
|
|
830
|
+
* nested or complex data structures. Unlike {@link ValidatorValidateOptions} which handles
|
|
831
|
+
* single values, this interface is tailored for scenarios where validation rules need to
|
|
832
|
+
* work with entire class instances or nested object hierarchies.
|
|
833
|
+
*
|
|
834
|
+
* ### Key Differences from ValidatorValidateOptions
|
|
835
|
+
* - **Extends from ValidatorValidateTargetOptions**: Inherits target-specific properties
|
|
836
|
+
* - **Omits "data" property**: Uses its own `data` property instead
|
|
837
|
+
* - **Optional value property**: Accepts target data instead of single values
|
|
838
|
+
* - **Flexible data property**: Allows any record structure for nested validation
|
|
839
|
+
*
|
|
840
|
+
* ### Inheritance Structure
|
|
841
|
+
* ```
|
|
842
|
+
* ValidatorNestedRuleFunctionOptions
|
|
843
|
+
* ↳ extends Omit<ValidatorValidateTargetOptions<Target, Context, [target: Target]>, "data">
|
|
844
|
+
* ↳ extends Omit<ValidatorValidateOptions<TParams, Context>, "data" | "rule" | "value">
|
|
845
|
+
* ↳ extends Omit<Partial<InputFormatterResult>, "value">
|
|
846
|
+
* ↳ extends BaseData<Context>
|
|
847
|
+
* ```
|
|
848
|
+
*
|
|
849
|
+
* ### Generic Parameters
|
|
850
|
+
* - **Target**: The class constructor type being validated (extends `ClassConstructor`)
|
|
851
|
+
* - **Context**: Optional context type for validation (defaults to `unknown`)
|
|
852
|
+
*
|
|
853
|
+
* ### Properties Overview
|
|
854
|
+
*
|
|
855
|
+
* #### Inherited Properties
|
|
856
|
+
* - **rules**: Array of validation rules to apply
|
|
857
|
+
* - **ruleParams**: Parameters for the current rule
|
|
858
|
+
* - **ruleName**: Name of the validation rule
|
|
859
|
+
* - **rawRuleName**: Original unparsed rule name
|
|
860
|
+
* - **message**: Custom error message
|
|
861
|
+
* - **fieldName**: Form field identifier
|
|
862
|
+
* - **propertyName**: Object property name
|
|
863
|
+
* - **translatedPropertyName**: Localized property name
|
|
864
|
+
* - **i18n**: Internationalization instance
|
|
865
|
+
* - **sanitizedRules**: Preprocessed rules
|
|
866
|
+
* - **startTime**: Performance tracking timestamp
|
|
867
|
+
* - **errorMessageBuilder**: Custom error message builder
|
|
868
|
+
* - **parentData**: Parent context for nested validations
|
|
869
|
+
*
|
|
870
|
+
* #### Own Properties
|
|
871
|
+
* - **value**: Optional target data to validate
|
|
872
|
+
* - **data**: Flexible data object for nested validation context
|
|
873
|
+
*
|
|
874
|
+
* ### Usage in Nested Validation
|
|
875
|
+
* ```typescript
|
|
876
|
+
* class UserProfile {
|
|
877
|
+
* @IsRequired()
|
|
878
|
+
* @IsEmail()
|
|
879
|
+
* email: string;
|
|
880
|
+
*
|
|
881
|
+
* @IsRequired()
|
|
882
|
+
* @ValidateNested
|
|
883
|
+
* address: Address;
|
|
884
|
+
* }
|
|
885
|
+
*
|
|
886
|
+
* // Custom nested validation rule
|
|
887
|
+
* async function validateNestedProfile(options: ValidatorNestedRuleFunctionOptions<UserProfile, ValidationContext>) {
|
|
888
|
+
* const { value, data, context } = options;
|
|
889
|
+
*
|
|
890
|
+
* // Validate the nested profile
|
|
891
|
+
* if (value && typeof value === 'object') {
|
|
892
|
+
* // Perform nested validation logic
|
|
893
|
+
* const result = await Validator.validateTarget(UserProfile, value);
|
|
894
|
+
* return result.success || "Profile validation failed";
|
|
895
|
+
* }
|
|
896
|
+
*
|
|
897
|
+
* return true;
|
|
898
|
+
* }
|
|
899
|
+
* ```
|
|
900
|
+
*
|
|
901
|
+
* ### Relationship to Validation System
|
|
902
|
+
* - **Used by**: {@link Validator.validateNestedRule} method
|
|
903
|
+
* - **Complements**: {@link ValidatorValidateTargetOptions} for target validation
|
|
904
|
+
* - **Extends**: {@link ValidatorValidateOptions} with target-specific modifications
|
|
905
|
+
* - **Supports**: Complex nested object validation scenarios
|
|
906
|
+
*
|
|
907
|
+
* ### Common Use Cases
|
|
908
|
+
*
|
|
909
|
+
* #### 1. Nested Object Validation
|
|
910
|
+
* ```typescript
|
|
911
|
+
* const options: ValidatorNestedRuleFunctionOptions<User, Context> = {
|
|
912
|
+
* value: userInstance, // Full user object
|
|
913
|
+
* data: { parentForm: form }, // Additional context
|
|
914
|
+
* propertyName: "user", // Property being validated
|
|
915
|
+
* context: validationContext, // Typed context
|
|
916
|
+
* };
|
|
917
|
+
* ```
|
|
918
|
+
*
|
|
919
|
+
* #### 2. Array of Objects Validation
|
|
920
|
+
* ```typescript
|
|
921
|
+
* const options: ValidatorNestedRuleFunctionOptions<Item[], Context> = {
|
|
922
|
+
* value: itemsArray, // Array of items
|
|
923
|
+
* data: { index: 0 }, // Current index context
|
|
924
|
+
* propertyName: "items", // Array property name
|
|
925
|
+
* };
|
|
926
|
+
* ```
|
|
927
|
+
*
|
|
928
|
+
* #### 3. Conditional Nested Validation
|
|
929
|
+
* ```typescript
|
|
930
|
+
* const options: ValidatorNestedRuleFunctionOptions<Address, Context> = {
|
|
931
|
+
* value: addressData, // Address object (if present)
|
|
932
|
+
* data: { required: true }, // Validation requirements
|
|
933
|
+
* propertyName: "shippingAddress",
|
|
934
|
+
* context: { userType: "premium" },
|
|
935
|
+
* };
|
|
936
|
+
* ```
|
|
937
|
+
*
|
|
938
|
+
* ### Type Safety Benefits
|
|
939
|
+
* - **Compile-time validation** of target types
|
|
940
|
+
* - **Type-safe property access** on nested objects
|
|
941
|
+
* - **Context propagation** through validation hierarchy
|
|
942
|
+
* - **Flexible data structures** for complex validation scenarios
|
|
943
|
+
*
|
|
944
|
+
* ### Performance Considerations
|
|
945
|
+
* - **Target validation overhead**: More expensive than single-value validation
|
|
946
|
+
* - **Parallel processing**: Multiple nested validations can run concurrently
|
|
947
|
+
* - **Memory usage**: Larger data structures require more memory
|
|
948
|
+
* - **Serialization**: Complex objects may need special handling
|
|
949
|
+
*
|
|
950
|
+
* @template Target - The class constructor type being validated (must extend ClassConstructor)
|
|
951
|
+
* @template Context - Optional context type for validation (defaults to unknown)
|
|
952
|
+
*
|
|
953
|
+
* @public
|
|
954
|
+
*
|
|
955
|
+
* @see {@link ValidatorValidateTargetOptions} - Base target validation options
|
|
956
|
+
* @see {@link ValidatorValidateOptions} - Single-value validation options
|
|
957
|
+
* @see {@link Validator.validateNestedRule} - Method that uses this interface
|
|
958
|
+
* @see {@link ValidatorValidateTargetData} - Target data type
|
|
959
|
+
* @see {@link ClassConstructor} - Class constructor constraint
|
|
960
|
+
*/
|
|
961
|
+
export interface ValidatorNestedRuleFunctionOptions<Target extends ClassConstructor = ClassConstructor, Context = unknown> extends Omit<ValidatorValidateTargetOptions<Target, Context, [target: Target]>, 'data'> {
|
|
962
|
+
value?: ValidatorValidateTargetData<Target>;
|
|
963
|
+
data?: Dictionary;
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* @interface ValidatorRuleName
|
|
967
|
+
* Represents the name of a validation rule as defined in the `ValidatorRuleParamTypes`.
|
|
968
|
+
*
|
|
969
|
+
* The `ValidatorRuleName` type is a union of string literal types that correspond to the keys
|
|
970
|
+
* of the `ValidatorRuleParamTypes` interface. This allows for type-safe access to the names of
|
|
971
|
+
* validation rules, ensuring that only valid rule names can be used in contexts where a rule name
|
|
972
|
+
* is required.
|
|
973
|
+
*
|
|
974
|
+
* ### Structure:
|
|
975
|
+
* - The type is derived from the keys of the `ValidatorRuleParamTypes`, meaning it will include
|
|
976
|
+
* all the rule names defined in that map.
|
|
977
|
+
*
|
|
978
|
+
* ### Example:
|
|
979
|
+
*
|
|
980
|
+
* ```typescript
|
|
981
|
+
* const ruleName: ValidatorRuleName = "required"; // Valid
|
|
982
|
+
* const anotherRuleName: ValidatorRuleName = "minLength"; // Valid
|
|
983
|
+
*
|
|
984
|
+
* // Usage in a function that accepts a rule name
|
|
985
|
+
* function getValidationRule(ruleName: ValidatorRuleName) {
|
|
986
|
+
* return validationRules[ruleName];
|
|
987
|
+
* }
|
|
988
|
+
*
|
|
989
|
+
* const rule = getValidationRule("maxLength"); // Valid usage
|
|
990
|
+
* // const invalidRule = getValidationRule("unknownRule"); // TypeScript will throw an error
|
|
991
|
+
* ```
|
|
992
|
+
*
|
|
993
|
+
* This type enhances type safety in your code by ensuring that only valid validation rule names
|
|
994
|
+
* can be used, reducing the risk of runtime errors due to typos or invalid rule names.
|
|
995
|
+
*/
|
|
996
|
+
export type ValidatorRuleName = keyof ValidatorRuleParamTypes & string;
|
|
997
|
+
/**
|
|
998
|
+
* ## Validation Rules Parameter Map
|
|
999
|
+
*
|
|
1000
|
+
* Central type definition mapping validation rule names to their parameter signatures.
|
|
1001
|
+
* This interface serves as the authoritative source for all built-in validation rules,
|
|
1002
|
+
* defining the exact parameter types each rule accepts.
|
|
1003
|
+
*
|
|
1004
|
+
* ### Purpose
|
|
1005
|
+
* Provides compile-time type safety for validation rule parameters across the entire
|
|
1006
|
+
* validation system. Each property represents a built-in validation rule and its
|
|
1007
|
+
* expected parameter structure. This is a static interface with no generics.
|
|
1008
|
+
*
|
|
1009
|
+
* ### Type Structure
|
|
1010
|
+
* - **Key**: Rule name (string literal from {@link ValidatorRuleName})
|
|
1011
|
+
* - **Value**: Parameter array type (extends {@link ValidatorRuleParams})
|
|
1012
|
+
*
|
|
1013
|
+
* ### Parameter Type Patterns
|
|
1014
|
+
* - **Empty Arrays `[]`**: Rules that take no parameters (e.g., "Required", "Email")
|
|
1015
|
+
* - **Single Parameters `[Type]`**: Rules with one required parameter (e.g., "MinLength[number]")
|
|
1016
|
+
* - **Optional Parameters `[Type?]`**: Rules with optional parameters (e.g., "PhoneNumber[string?]")
|
|
1017
|
+
* - **Multiple Parameters `[Type1, Type2]`**: Rules with multiple required parameters
|
|
1018
|
+
* - **Complex Parameters**: Rules with mixed required/optional parameters
|
|
1019
|
+
*
|
|
1020
|
+
* ### Usage in Type System
|
|
1021
|
+
* This interface is used throughout the validator to:
|
|
1022
|
+
* - Type-check rule parameters at compile time
|
|
1023
|
+
* - Generate {@link ValidatorRuleName} union type
|
|
1024
|
+
* - Create {@link ValidatorRuleFunctionsMap} registry type
|
|
1025
|
+
* - Validate rule definitions in rule implementation files
|
|
1026
|
+
*
|
|
1027
|
+
* ### Rule Categories
|
|
1028
|
+
*
|
|
1029
|
+
* #### Presence Validation
|
|
1030
|
+
* - **Required**: Ensures value is present and not empty
|
|
1031
|
+
* - **Nullable**: Allows null/undefined values (skips validation)
|
|
1032
|
+
* - **Optional**: Allows undefined values (skips validation)
|
|
1033
|
+
* - **Empty**: Allows empty strings (validation skipped if "")
|
|
1034
|
+
*
|
|
1035
|
+
* #### Type Validation
|
|
1036
|
+
* - **String**: Validates value is a string
|
|
1037
|
+
* - **Number**: Validates value is a number
|
|
1038
|
+
* - **NonNullString**: Validates value is a non-null string
|
|
1039
|
+
*
|
|
1040
|
+
* #### String Validation
|
|
1041
|
+
* - **MinLength**: Minimum character length requirement
|
|
1042
|
+
* - **MaxLength**: Maximum character length limit
|
|
1043
|
+
* - **Length**: Exact length or length range (min and optional max)
|
|
1044
|
+
* - **FileName**: Valid file name format
|
|
1045
|
+
*
|
|
1046
|
+
* #### Numeric Validation
|
|
1047
|
+
* - **NumberGT**: Value must be greater than specified number
|
|
1048
|
+
* - **NumberGTE**: Value must be >= specified number
|
|
1049
|
+
* - **NumberLT**: Value must be less than specified number
|
|
1050
|
+
* - **NumberLTE**: Value must be <= specified number
|
|
1051
|
+
* - **NumberEQ**: Value must equal specified number
|
|
1052
|
+
* - **NumberNE**: Value must differ from specified number
|
|
1053
|
+
*
|
|
1054
|
+
* #### Format Validation
|
|
1055
|
+
* - **Email**: Valid email address format
|
|
1056
|
+
* - **Url**: Valid URL format
|
|
1057
|
+
* - **PhoneNumber**: Valid phone number (with optional country code)
|
|
1058
|
+
* - **EmailOrPhoneNumber**: Valid email or phone number
|
|
1059
|
+
*
|
|
1060
|
+
* ### Parameter Examples
|
|
1061
|
+
* ```typescript
|
|
1062
|
+
* // Rules with no parameters
|
|
1063
|
+
* Required: ValidatorRuleParams<[]>; // "Required"
|
|
1064
|
+
* Email: ValidatorRuleParams<[]>; // "Email"
|
|
1065
|
+
*
|
|
1066
|
+
* // Rules with single parameters
|
|
1067
|
+
* MinLength: ValidatorRuleParams<[number]>; // {MinLength:[5]}
|
|
1068
|
+
* NumberEQ: ValidatorRuleParams<[number]>; // "NumberEQ[42]"
|
|
1069
|
+
*
|
|
1070
|
+
* // Rules with optional parameters
|
|
1071
|
+
* PhoneNumber: ValidatorRuleParams<[CountryCode?]>; // "PhoneNumber" or "PhoneNumber[US]"
|
|
1072
|
+
*
|
|
1073
|
+
* // Rules with multiple parameters
|
|
1074
|
+
* Length: ValidatorRuleParams<[number, number?]>; // "Length[5]" or "Length[5,10]"
|
|
1075
|
+
* ```
|
|
1076
|
+
*
|
|
1077
|
+
* ### Extending the Rules Map
|
|
1078
|
+
* When adding new validation rules:
|
|
1079
|
+
* 1. Add the rule name and parameter type to this interface
|
|
1080
|
+
* 2. Implement the rule function in the appropriate rule file
|
|
1081
|
+
* 3. Register the rule in the validator's rule registry
|
|
1082
|
+
* 4. Update rule name unions and type definitions as needed
|
|
1083
|
+
*
|
|
1084
|
+
* ### Relationship to Validation System
|
|
1085
|
+
* - **Foundation**: Base type for all rule definitions
|
|
1086
|
+
* - **Type Safety**: Ensures parameter type checking
|
|
1087
|
+
* - **Rule Discovery**: Used to generate valid rule names
|
|
1088
|
+
* - **Function Signatures**: Defines parameter types for rule functions
|
|
1089
|
+
* - **Runtime Validation**: Parameters validated against these types
|
|
1090
|
+
*
|
|
1091
|
+
* @public
|
|
1092
|
+
* @template Context - Type of the optional validation context
|
|
1093
|
+
* @see {@link ValidatorRuleName} - Union type derived from this interface's keys
|
|
1094
|
+
* @see {@link ValidatorRuleFunctionsMap} - Registry type using this interface
|
|
1095
|
+
* @see {@link ValidatorRuleParams} - Base parameter type for all rules
|
|
1096
|
+
* @see {@link Validator} - Main validator class that uses these rules
|
|
1097
|
+
*/
|
|
1098
|
+
export interface ValidatorRuleParamTypes<Context = unknown> {
|
|
1099
|
+
}
|
|
1100
|
+
export interface ValidatorValidateOptions<TParams extends ValidatorRuleParams = ValidatorRuleParams, Context = unknown> extends Omit<Partial<InputFormatterResult>, 'value'>, BaseData<Context> {
|
|
1101
|
+
/**
|
|
1102
|
+
* The list of validation rules to apply
|
|
1103
|
+
*
|
|
1104
|
+
* Array of rules that will be executed in sequence against the value.
|
|
1105
|
+
* Each rule can have its own parameters and configuration.
|
|
1106
|
+
*
|
|
1107
|
+
* @type {ValidatorRule[]}
|
|
1108
|
+
* @optional
|
|
1109
|
+
*
|
|
1110
|
+
* @example
|
|
1111
|
+
* ```typescript
|
|
1112
|
+
* const options: ValidatorValidateOptions = {
|
|
1113
|
+
* value: "example@test.com",
|
|
1114
|
+
* rules: [
|
|
1115
|
+
* { ruleName: "Required" },
|
|
1116
|
+
* { ruleName: "Email" },
|
|
1117
|
+
* { ruleName: "MaxLength", params: [100] }
|
|
1118
|
+
* ]
|
|
1119
|
+
* };
|
|
1120
|
+
* ```
|
|
1121
|
+
*
|
|
1122
|
+
* @see {@link ValidatorRule}
|
|
1123
|
+
*/
|
|
1124
|
+
rules?: ValidatorRules<Context>;
|
|
1125
|
+
/**
|
|
1126
|
+
* Internal: Sanitized rules after preprocessing
|
|
1127
|
+
*
|
|
1128
|
+
* This property is used internally by the validator after rules have been
|
|
1129
|
+
* parsed and sanitized. Users typically do not need to set this manually.
|
|
1130
|
+
*
|
|
1131
|
+
* @type {ValidatorSanitizedRules<Context>}
|
|
1132
|
+
* @internal
|
|
1133
|
+
* @optional
|
|
1134
|
+
*/
|
|
1135
|
+
sanitizedRules?: ValidatorSanitizedRules<Context>;
|
|
1136
|
+
/**
|
|
1137
|
+
* The current/primary validation rule being applied
|
|
1138
|
+
*
|
|
1139
|
+
* Specifies the specific rule to apply. Can be used to override or specify
|
|
1140
|
+
* a particular rule from the `rules` array, or to apply a single rule directly.
|
|
1141
|
+
*
|
|
1142
|
+
* @type {ValidatorRule<TParams, Context>}
|
|
1143
|
+
* @optional
|
|
1144
|
+
*
|
|
1145
|
+
* @example
|
|
1146
|
+
* ```typescript
|
|
1147
|
+
* const options: ValidatorValidateOptions = {
|
|
1148
|
+
* value: "test",
|
|
1149
|
+
* rule: { ruleName: "Required" },
|
|
1150
|
+
* propertyName: "username"
|
|
1151
|
+
* };
|
|
1152
|
+
* ```
|
|
1153
|
+
*
|
|
1154
|
+
* @see {@link ValidatorRule}
|
|
1155
|
+
*/
|
|
1156
|
+
rule?: ValidatorRule<TParams, Context>;
|
|
1157
|
+
/**
|
|
1158
|
+
* Parameters passed to the validation rule
|
|
1159
|
+
*
|
|
1160
|
+
* Contains the parameters required by the current rule. For example, for a
|
|
1161
|
+
* MinLength rule, this would be `[5]` to require minimum 5 characters.
|
|
1162
|
+
* These are typically extracted from raw rule names like {MinLength:[5]}.
|
|
1163
|
+
*
|
|
1164
|
+
* @type {TParams}
|
|
1165
|
+
* @optional
|
|
1166
|
+
*
|
|
1167
|
+
* @example
|
|
1168
|
+
* ```typescript
|
|
1169
|
+
* // For MinLength rule
|
|
1170
|
+
* const options: ValidatorValidateOptions = {
|
|
1171
|
+
* value: "password123",
|
|
1172
|
+
* rule: { ruleName: "MinLength" },
|
|
1173
|
+
* ruleParams: [8], // Minimum 8 characters
|
|
1174
|
+
* propertyName: "password"
|
|
1175
|
+
* };
|
|
1176
|
+
*
|
|
1177
|
+
* // For NumberBetween rule
|
|
1178
|
+
* const options2: ValidatorValidateOptions = {
|
|
1179
|
+
* value: 50,
|
|
1180
|
+
* rule: { ruleName: "NumberBetween" },
|
|
1181
|
+
* ruleParams: [0, 100], // Between 0 and 100
|
|
1182
|
+
* propertyName: "percentage"
|
|
1183
|
+
* };
|
|
1184
|
+
* ```
|
|
1185
|
+
*/
|
|
1186
|
+
ruleParams: TParams;
|
|
1187
|
+
/**
|
|
1188
|
+
* The name of the validation rule
|
|
1189
|
+
*
|
|
1190
|
+
* Identifies which validation rule is being applied. Examples include:
|
|
1191
|
+
* "Required", "Email", "MinLength", "MaxLength", "Regex", "Custom", etc.
|
|
1192
|
+
*
|
|
1193
|
+
* @type {ValidatorRuleName}
|
|
1194
|
+
* @optional
|
|
1195
|
+
*
|
|
1196
|
+
* @example
|
|
1197
|
+
* ```typescript
|
|
1198
|
+
* const options: ValidatorValidateOptions = {
|
|
1199
|
+
* value: "user@example.com",
|
|
1200
|
+
* ruleName: "Email",
|
|
1201
|
+
* propertyName: "email"
|
|
1202
|
+
* };
|
|
1203
|
+
* ```
|
|
1204
|
+
*
|
|
1205
|
+
* @see {@link ValidatorRuleName}
|
|
1206
|
+
*/
|
|
1207
|
+
ruleName?: ValidatorRuleName;
|
|
1208
|
+
/**
|
|
1209
|
+
* The raw rule name as originally specified (before parsing)
|
|
1210
|
+
*
|
|
1211
|
+
* The unparsed rule name including any parameters in brackets.
|
|
1212
|
+
* For example, {MinLength:[5]} or {NumberGT:[0]} before the name
|
|
1213
|
+
* and parameters are extracted into `ruleName` and `ruleParams`.
|
|
1214
|
+
*
|
|
1215
|
+
* @type {string}
|
|
1216
|
+
* @optional
|
|
1217
|
+
*
|
|
1218
|
+
* @example
|
|
1219
|
+
* ```typescript
|
|
1220
|
+
* const options: ValidatorValidateOptions = {
|
|
1221
|
+
* value: "test",
|
|
1222
|
+
* rawRuleName: { MinLength: [5] }, // Raw form
|
|
1223
|
+
* ruleName: "MinLength", // Parsed name
|
|
1224
|
+
* ruleParams: [5], // Parsed params
|
|
1225
|
+
* propertyName: "username"
|
|
1226
|
+
* };
|
|
1227
|
+
* ```
|
|
1228
|
+
*/
|
|
1229
|
+
rawRuleName?: ValidatorRuleName | string;
|
|
1230
|
+
/**
|
|
1231
|
+
* Custom error message for validation failure
|
|
1232
|
+
*
|
|
1233
|
+
* Allows specifying a custom error message to display when validation fails.
|
|
1234
|
+
* If provided, this message will be used instead of the default rule-generated message.
|
|
1235
|
+
* Supports i18n translations and dynamic content.
|
|
1236
|
+
*
|
|
1237
|
+
* @type {string}
|
|
1238
|
+
* @optional
|
|
1239
|
+
*
|
|
1240
|
+
* @example
|
|
1241
|
+
* ```typescript
|
|
1242
|
+
* const options: ValidatorValidateOptions = {
|
|
1243
|
+
* value: "invalid-email",
|
|
1244
|
+
* rules: ["Email"],
|
|
1245
|
+
* message: "Please enter a valid email address (e.g., user@example.com)",
|
|
1246
|
+
* propertyName: "email"
|
|
1247
|
+
* };
|
|
1248
|
+
*
|
|
1249
|
+
* // Custom message for specific context
|
|
1250
|
+
* const options2: ValidatorValidateOptions = {
|
|
1251
|
+
* value: "short",
|
|
1252
|
+
* rule: { ruleName: "MinLength" },
|
|
1253
|
+
* ruleParams: [8],
|
|
1254
|
+
* message: "Your password must be at least 8 characters for security",
|
|
1255
|
+
* propertyName: "password"
|
|
1256
|
+
* };
|
|
1257
|
+
* ```
|
|
1258
|
+
*/
|
|
1259
|
+
message?: string;
|
|
1260
|
+
/**
|
|
1261
|
+
* The form field name/identifier
|
|
1262
|
+
*
|
|
1263
|
+
* Identifies the field in a form or data structure. Typically used for
|
|
1264
|
+
* form attributes like `name="field_name"` or `id="field_id"`.
|
|
1265
|
+
* Used to map errors back to UI elements or log error context.
|
|
1266
|
+
*
|
|
1267
|
+
* @type {string}
|
|
1268
|
+
* @optional
|
|
1269
|
+
*
|
|
1270
|
+
* @example
|
|
1271
|
+
* ```typescript
|
|
1272
|
+
* const options: ValidatorValidateOptions = {
|
|
1273
|
+
* value: "invalid@",
|
|
1274
|
+
* rules: ["Email"],
|
|
1275
|
+
* fieldName: "email_input", // HTML form field ID
|
|
1276
|
+
* propertyName: "email", // JS object property name
|
|
1277
|
+
* message: "Invalid email format"
|
|
1278
|
+
* };
|
|
1279
|
+
* ```
|
|
1280
|
+
*/
|
|
1281
|
+
fieldName?: string;
|
|
1282
|
+
/**
|
|
1283
|
+
* The label of the field being validated
|
|
1284
|
+
*
|
|
1285
|
+
* Identifies the label of the field being validated.
|
|
1286
|
+
* This is typically the actual label of your data class.
|
|
1287
|
+
* Used for error reporting and mapping validation errors back to properties.
|
|
1288
|
+
* This is used to display the field label in the error message.
|
|
1289
|
+
* If translatedPropertyName is provided, it will have the same value otherwise it will be the fieldName.
|
|
1290
|
+
*
|
|
1291
|
+
* @type {string}
|
|
1292
|
+
* @optional
|
|
1293
|
+
*/
|
|
1294
|
+
fieldLabel?: string;
|
|
1295
|
+
/**
|
|
1296
|
+
* The object property name being validated
|
|
1297
|
+
*
|
|
1298
|
+
* Identifies the property on the object/class being validated.
|
|
1299
|
+
* This is typically the actual property name on your data class.
|
|
1300
|
+
* Used for error reporting and mapping validation errors back to properties.
|
|
1301
|
+
*
|
|
1302
|
+
* @type {string}
|
|
1303
|
+
* @optional
|
|
1304
|
+
*
|
|
1305
|
+
* @example
|
|
1306
|
+
* ```typescript
|
|
1307
|
+
* class UserData {
|
|
1308
|
+
* email: string;
|
|
1309
|
+
* password: string;
|
|
1310
|
+
* }
|
|
1311
|
+
*
|
|
1312
|
+
* const options: ValidatorValidateOptions = {
|
|
1313
|
+
* value: "invalid-email",
|
|
1314
|
+
* rules: ["Email"],
|
|
1315
|
+
* propertyName: "email", // Maps to UserData.email
|
|
1316
|
+
* fieldName: "email_field", // HTML field identifier
|
|
1317
|
+
* message: "Invalid email"
|
|
1318
|
+
* };
|
|
1319
|
+
* ```
|
|
1320
|
+
*/
|
|
1321
|
+
propertyName?: string;
|
|
1322
|
+
/**
|
|
1323
|
+
* The translated/localized property name
|
|
1324
|
+
*
|
|
1325
|
+
* A user-friendly or localized version of the property name for display in
|
|
1326
|
+
* error messages. For example, if `propertyName` is "user_birth_date",
|
|
1327
|
+
* `translatedPropertyName` might be "Date of Birth" in English or
|
|
1328
|
+
* "Date de Naissance" in French.
|
|
1329
|
+
*
|
|
1330
|
+
* This property is typically populated by the validator's translation system.
|
|
1331
|
+
*
|
|
1332
|
+
* @type {string}
|
|
1333
|
+
* @optional
|
|
1334
|
+
*
|
|
1335
|
+
* @example
|
|
1336
|
+
* ```typescript
|
|
1337
|
+
* // Before translation
|
|
1338
|
+
* const options: ValidatorValidateOptions = {
|
|
1339
|
+
* value: "invalid",
|
|
1340
|
+
* rules: ["Required"],
|
|
1341
|
+
* propertyName: "user_phone_number"
|
|
1342
|
+
* };
|
|
1343
|
+
*
|
|
1344
|
+
* // After translation (populated by validator)
|
|
1345
|
+
* // options.translatedPropertyName = "Phone Number"
|
|
1346
|
+
* // options.message = "[Phone Number]: Must not be empty"
|
|
1347
|
+
* ```
|
|
1348
|
+
*/
|
|
1349
|
+
translatedPropertyName?: string;
|
|
1350
|
+
/**
|
|
1351
|
+
* Internationalization instance for translations
|
|
1352
|
+
*
|
|
1353
|
+
* Provides access to the i18n system for translating messages and property names.
|
|
1354
|
+
*/
|
|
1355
|
+
i18n: I18n;
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* ## OneOf Rule Validation Options
|
|
1359
|
+
*
|
|
1360
|
+
* Configuration interface for validating a value against an array of alternative validation rules
|
|
1361
|
+
* where at least one rule must pass. This interface extends {@link ValidatorValidateOptions}
|
|
1362
|
+
* with specialized properties for OneOf rule validation.
|
|
1363
|
+
*
|
|
1364
|
+
* ### Purpose
|
|
1365
|
+
* Used specifically by {@link Validator.validateOneOfRule} to handle the "OneOf" validation logic,
|
|
1366
|
+
* which allows validation to succeed if any one of the provided sub-rules passes validation.
|
|
1367
|
+
*
|
|
1368
|
+
* ### Key Differences from Base Options
|
|
1369
|
+
* - **ruleParams**: Overrides base to require an array of rule functions (not mixed rule types)
|
|
1370
|
+
* - **rules**: Excluded via `Omit` since OneOf uses `ruleParams` instead
|
|
1371
|
+
* - **startTime**: Optional timestamp for performance tracking
|
|
1372
|
+
*
|
|
1373
|
+
* ### Rule Parameter Structure
|
|
1374
|
+
* The `ruleParams` property contains an array of validation rule functions that will be
|
|
1375
|
+
* executed in parallel. Each function should follow the {@link ValidatorRuleFunction} signature.
|
|
1376
|
+
*
|
|
1377
|
+
* ### Usage Context
|
|
1378
|
+
* This interface is primarily used internally by the validator when processing "OneOf" rules,
|
|
1379
|
+
* but can also be used directly when calling {@link Validator.validateOneOfRule}.
|
|
1380
|
+
*
|
|
1381
|
+
* ### Examples
|
|
1382
|
+
*
|
|
1383
|
+
* #### Basic OneOf Validation Setup
|
|
1384
|
+
* ```typescript
|
|
1385
|
+
* const options: ValidatorValidateMultiRuleOptions = {
|
|
1386
|
+
* value: "user@example.com",
|
|
1387
|
+
* ruleParams: [
|
|
1388
|
+
* ({ value }) => value.includes("@") || "Must contain @",
|
|
1389
|
+
* ({ value }) => value.endsWith(".com") || "Must end with .com",
|
|
1390
|
+
* ({ value }) => value.length > 10 || "Must be longer than 10 chars"
|
|
1391
|
+
* ],
|
|
1392
|
+
* fieldName: "contact",
|
|
1393
|
+
* propertyName: "contact",
|
|
1394
|
+
* translatedPropertyName: "Contact Information",
|
|
1395
|
+
* startTime: Date.now()
|
|
1396
|
+
* };
|
|
1397
|
+
*
|
|
1398
|
+
* const result = await Validator.validateOneOfRule(options);
|
|
1399
|
+
* ```
|
|
1400
|
+
*
|
|
1401
|
+
* #### With Context and Additional Options
|
|
1402
|
+
* ```typescript
|
|
1403
|
+
* interface ValidationContext {
|
|
1404
|
+
* userId: number;
|
|
1405
|
+
* allowedDomains: string[];
|
|
1406
|
+
* }
|
|
1407
|
+
*
|
|
1408
|
+
* const options: ValidatorValidateMultiRuleOptions<ValidationContext> = {
|
|
1409
|
+
* value: "admin@company.com",
|
|
1410
|
+
* ruleParams: [
|
|
1411
|
+
* // Email validation
|
|
1412
|
+
* ({ value }) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) || "Invalid email",
|
|
1413
|
+
*
|
|
1414
|
+
* // Phone validation
|
|
1415
|
+
* ({ value }) => /^\+?[\d\s\-\(\)]+$/.test(value) || "Invalid phone",
|
|
1416
|
+
*
|
|
1417
|
+
* // Context-aware validation
|
|
1418
|
+
* ({ value, context }) => {
|
|
1419
|
+
* if (!context) return "Context required";
|
|
1420
|
+
* const domain = value.split("@")[1];
|
|
1421
|
+
* return context.allowedDomains.includes(domain) || "Domain not allowed";
|
|
1422
|
+
* }
|
|
1423
|
+
* ],
|
|
1424
|
+
* context: {
|
|
1425
|
+
* userId: 123,
|
|
1426
|
+
* allowedDomains: ["company.com", "partner.org"]
|
|
1427
|
+
* },
|
|
1428
|
+
* data: { formId: "registration" },
|
|
1429
|
+
* fieldName: "contact_input",
|
|
1430
|
+
* propertyName: "contact",
|
|
1431
|
+
* i18n: defaultI18n,
|
|
1432
|
+
* startTime: Date.now()
|
|
1433
|
+
* };
|
|
1434
|
+
* ```
|
|
1435
|
+
*
|
|
1436
|
+
* ### Performance Considerations
|
|
1437
|
+
* - All rules in `ruleParams` are executed in parallel using `Promise.all`
|
|
1438
|
+
* - Validation stops immediately when the first rule succeeds (early exit optimization)
|
|
1439
|
+
* - The `startTime` property enables duration tracking for performance monitoring
|
|
1440
|
+
*
|
|
1441
|
+
* ### Error Handling
|
|
1442
|
+
* When all rules fail, error messages are aggregated with semicolons ("; ") as separators.
|
|
1443
|
+
* Each failed rule's error message is collected and joined for comprehensive error reporting.
|
|
1444
|
+
*
|
|
1445
|
+
* @template Context - Type of the optional validation context object
|
|
1446
|
+
*
|
|
1447
|
+
* @public
|
|
1448
|
+
* @see {@link Validator.validateOneOfRule} - Method that uses this interface
|
|
1449
|
+
* @see {@link ValidatorValidateOptions} - Base options interface being extended
|
|
1450
|
+
* @see {@link ValidatorRuleFunction} - Type of functions in ruleParams array
|
|
1451
|
+
* @see {@link ValidatorValidateResult} - Result type returned by validation
|
|
1452
|
+
*/
|
|
1453
|
+
export interface ValidatorValidateMultiRuleOptions<Context = unknown, RulesFunctions extends ValidatorDefaultMultiRule<Context> = ValidatorDefaultMultiRule<Context>> extends ValidatorValidateOptions<RulesFunctions, Context> {
|
|
1454
|
+
startTime?: number;
|
|
1455
|
+
}
|
|
1456
|
+
/**
|
|
1457
|
+
* ## Default Multi-Rule Type
|
|
1458
|
+
*
|
|
1459
|
+
* A generic type alias representing an array of validation rules with configurable parameter types.
|
|
1460
|
+
* This type serves as the default constraint for multi-rule validation functions that accept
|
|
1461
|
+
* arrays of rules with varying parameter signatures.
|
|
1462
|
+
*
|
|
1463
|
+
* ### Purpose
|
|
1464
|
+
* Provides a flexible type for representing collections of validation rules where each rule
|
|
1465
|
+
* can have different parameter types. Used as a constraint for {@link ValidatorMultiRuleFunction}
|
|
1466
|
+
* and {@link ValidatorValidateMultiRuleOptions} to ensure type safety in multi-rule scenarios.
|
|
1467
|
+
*
|
|
1468
|
+
* ### Type Parameters
|
|
1469
|
+
* - **Context**: Optional context type for validation (defaults to `unknown`)
|
|
1470
|
+
* - **ParamsTypes**: Parameter types for the rules (defaults to `any` for maximum flexibility)
|
|
1471
|
+
*
|
|
1472
|
+
* ### Usage in Multi-Rule Validation
|
|
1473
|
+
* This type is used internally by the validator for operations that process multiple rules
|
|
1474
|
+
* simultaneously, such as "OneOf" and "AllOf" validation patterns.
|
|
1475
|
+
*
|
|
1476
|
+
* ### Example
|
|
1477
|
+
* ```typescript
|
|
1478
|
+
* // Array of rules with different parameter types
|
|
1479
|
+
* const rules: ValidatorDefaultMultiRule = [
|
|
1480
|
+
* { ruleName: "Required" }, // No params
|
|
1481
|
+
* { ruleName: "MinLength", params: [5] }, // Number param
|
|
1482
|
+
* { ruleName: "Email" }, // No params
|
|
1483
|
+
* ];
|
|
1484
|
+
* ```
|
|
1485
|
+
*
|
|
1486
|
+
* ### Relationship to Validation System
|
|
1487
|
+
* - **Used by**: {@link ValidatorValidateMultiRuleOptions} as constraint
|
|
1488
|
+
* - **Constrains**: {@link ValidatorMultiRuleFunction} parameter types
|
|
1489
|
+
* - **Enables**: Type-safe multi-rule validation operations
|
|
1490
|
+
*
|
|
1491
|
+
* @template Context - Type of the optional validation context
|
|
1492
|
+
* @template ParamsTypes - Type of rule parameters (defaults to any for flexibility)
|
|
1493
|
+
*
|
|
1494
|
+
* @public
|
|
1495
|
+
*
|
|
1496
|
+
* @see {@link ValidatorValidateMultiRuleOptions} - Uses this as constraint
|
|
1497
|
+
* @see {@link ValidatorMultiRuleFunction} - Function type that accepts this
|
|
1498
|
+
* @see {@link ValidatorRule} - Individual rule type
|
|
1499
|
+
*/
|
|
1500
|
+
export type ValidatorDefaultMultiRule<Context = unknown, ParamsTypes extends ValidatorRuleParams = ValidatorRuleParams> = Array<ValidatorRule<ParamsTypes, Context>>;
|
|
1501
|
+
/**
|
|
1502
|
+
* ## Multi-Rule Validation Function Type
|
|
1503
|
+
*
|
|
1504
|
+
* A specialized validation function type for operations that process multiple validation rules
|
|
1505
|
+
* simultaneously. This type is used for complex validation patterns like "OneOf" and "AllOf"
|
|
1506
|
+
* where multiple rules need to be evaluated together.
|
|
1507
|
+
*
|
|
1508
|
+
* ### Purpose
|
|
1509
|
+
* Defines the signature for validation functions that accept arrays of rules as parameters,
|
|
1510
|
+
* enabling advanced validation logic that depends on multiple rule outcomes. Used by
|
|
1511
|
+
* {@link Validator.validateOneOfRule} and {@link Validator.validateAllOfRule} methods.
|
|
1512
|
+
*
|
|
1513
|
+
* ### Type Parameters
|
|
1514
|
+
* - **Context**: Optional context type for validation (defaults to `unknown`)
|
|
1515
|
+
* - **RulesFunctions**: Array type of rules accepted as parameters (constrained by {@link ValidatorDefaultMultiRule})
|
|
1516
|
+
*
|
|
1517
|
+
* ### Function Signature
|
|
1518
|
+
* ```typescript
|
|
1519
|
+
* (options: ValidatorValidateOptions<RulesFunctions, Context>) => ValidatorResult
|
|
1520
|
+
* ```
|
|
1521
|
+
*
|
|
1522
|
+
* ### Usage in Validation System
|
|
1523
|
+
* This type enables the creation of higher-order validation rules that combine multiple
|
|
1524
|
+
* simpler rules with logical operators (AND, OR, etc.).
|
|
1525
|
+
*
|
|
1526
|
+
* ### Example
|
|
1527
|
+
* ```typescript
|
|
1528
|
+
* // OneOf validation function
|
|
1529
|
+
* const validateOneOf: ValidatorMultiRuleFunction = async (options) => {
|
|
1530
|
+
* const { ruleParams, value } = options;
|
|
1531
|
+
*
|
|
1532
|
+
* // ruleParams is an array of validation functions
|
|
1533
|
+
* for (const ruleFunc of ruleParams) {
|
|
1534
|
+
* const result = await ruleFunc({ ...options, rule: undefined });
|
|
1535
|
+
* if (result === true) return true; // At least one rule passed
|
|
1536
|
+
* }
|
|
1537
|
+
*
|
|
1538
|
+
* return "None of the rules passed validation";
|
|
1539
|
+
* };
|
|
1540
|
+
* ```
|
|
1541
|
+
*
|
|
1542
|
+
* ### Relationship to Validation System
|
|
1543
|
+
* - **Used by**: Multi-rule validation methods in {@link Validator}
|
|
1544
|
+
* - **Constrained by**: {@link ValidatorDefaultMultiRule} for parameter types
|
|
1545
|
+
* - **Returns**: Standard {@link ValidatorResult} for consistency
|
|
1546
|
+
* - **Enables**: Complex validation logic with multiple rules
|
|
1547
|
+
*
|
|
1548
|
+
* @template Context - Type of the optional validation context
|
|
1549
|
+
* @template RulesFunctions - Type of the rules array parameter
|
|
1550
|
+
*
|
|
1551
|
+
* @public
|
|
1552
|
+
*
|
|
1553
|
+
* @see {@link ValidatorDefaultMultiRule} - Constrains the RulesFunctions parameter
|
|
1554
|
+
* @see {@link Validator.validateOneOfRule} - Uses this function type
|
|
1555
|
+
* @see {@link Validator.validateAllOfRule} - Uses this function type
|
|
1556
|
+
* @see {@link ValidatorResult} - Return type
|
|
1557
|
+
*/
|
|
1558
|
+
export type ValidatorMultiRuleFunction<Context = unknown, RulesFunctions extends Array<ValidatorRule<Array<unknown>, Context>> = Array<ValidatorRule<Array<unknown>, Context>>> = ValidatorRuleFunction<RulesFunctions, Context>;
|
|
1559
|
+
/**
|
|
1560
|
+
* ## Target Validation Data Type
|
|
1561
|
+
*
|
|
1562
|
+
* A mapped type representing the data structure expected for class-based validation using
|
|
1563
|
+
* {@link Validator.validateTarget}. This type creates a partial record mapping class properties
|
|
1564
|
+
* to their values, enabling type-safe validation of entire class instances.
|
|
1565
|
+
*
|
|
1566
|
+
* ### Purpose
|
|
1567
|
+
* Provides compile-time type safety for data passed to {@link Validator.validateTarget} method.
|
|
1568
|
+
* Ensures that the data object matches the structure of the target class constructor, allowing
|
|
1569
|
+
* validation decorators to be applied to class properties with full type checking.
|
|
1570
|
+
*
|
|
1571
|
+
* ### Type Construction
|
|
1572
|
+
* ```typescript
|
|
1573
|
+
* Partial<Record<keyof InstanceType<Target>, any>>
|
|
1574
|
+
* ```
|
|
1575
|
+
* - **Target**: Class constructor type (must extend `ClassConstructor`)
|
|
1576
|
+
* - **InstanceType<Target>**: Properties of the class instance
|
|
1577
|
+
* - **Partial**: All properties are optional (validation fills in defaults)
|
|
1578
|
+
* - **Record<..., any>**: Values can be any type (validation will check)
|
|
1579
|
+
*
|
|
1580
|
+
* ### Usage in Target Validation
|
|
1581
|
+
* ```typescript
|
|
1582
|
+
* class UserForm {
|
|
1583
|
+
* @IsRequired()
|
|
1584
|
+
* @IsEmail()
|
|
1585
|
+
* email: string;
|
|
1586
|
+
*
|
|
1587
|
+
* @IsRequired()
|
|
1588
|
+
* @MinLength(3)
|
|
1589
|
+
* name: string;
|
|
1590
|
+
*
|
|
1591
|
+
* @IsOptional()
|
|
1592
|
+
* age?: number;
|
|
1593
|
+
* }
|
|
1594
|
+
*
|
|
1595
|
+
* // Type-safe data object
|
|
1596
|
+
* const data: ValidatorValidateTargetData<UserForm> = {
|
|
1597
|
+
* email: "user@example.com", // ✓ Matches UserForm.email
|
|
1598
|
+
* name: "John", // ✓ Matches UserForm.name
|
|
1599
|
+
* age: 25, // ✓ Matches UserForm.age
|
|
1600
|
+
* };
|
|
1601
|
+
*
|
|
1602
|
+
* const result = await Validator.validateTarget(UserForm, data);
|
|
1603
|
+
* ```
|
|
1604
|
+
*
|
|
1605
|
+
* ### Key Features
|
|
1606
|
+
* - **Partial Mapping**: Not all class properties need to be provided
|
|
1607
|
+
* - **Type Safety**: Property names and types are checked at compile time
|
|
1608
|
+
* - **Decorator Integration**: Works with validation decorators on class properties
|
|
1609
|
+
* - **Flexible Values**: Accepts any value type (validation rules determine validity)
|
|
1610
|
+
*
|
|
1611
|
+
* ### Comparison with Single-Value Validation
|
|
1612
|
+
* | Aspect | Target Data | Single Value |
|
|
1613
|
+
* |--------|-------------|--------------|
|
|
1614
|
+
* | Structure | Object with multiple properties | Single value |
|
|
1615
|
+
* | Validation | Multiple fields simultaneously | One value at a time |
|
|
1616
|
+
* | Type Safety | Class property mapping | Any value type |
|
|
1617
|
+
* | Use Case | Form validation | Field validation |
|
|
1618
|
+
*
|
|
1619
|
+
* ### Runtime Behavior
|
|
1620
|
+
* - **Missing Properties**: Validation decorators determine if properties are required
|
|
1621
|
+
* - **Extra Properties**: Ignored (only decorated properties are validated)
|
|
1622
|
+
* - **Type Coercion**: Values are validated according to decorator rules, not TypeScript types
|
|
1623
|
+
*
|
|
1624
|
+
* ### Relationship to Validation System
|
|
1625
|
+
* - **Used by**: {@link Validator.validateTarget} as input data type
|
|
1626
|
+
* - **Mapped from**: Class constructor type via `InstanceType<Target>`
|
|
1627
|
+
* - **Validated by**: Decorator-based rules on class properties
|
|
1628
|
+
* - **Returns**: {@link ValidatorValidateTargetResult} with validated instance
|
|
1629
|
+
*
|
|
1630
|
+
* @template Target - The class constructor type being validated
|
|
1631
|
+
*
|
|
1632
|
+
* @public
|
|
1633
|
+
*
|
|
1634
|
+
* @see {@link Validator.validateTarget} - Method that accepts this data type
|
|
1635
|
+
* @see {@link ValidatorValidateTargetOptions} - Options type that includes this
|
|
1636
|
+
* @see {@link ValidatorValidateTargetResult} - Result type returned after validation
|
|
1637
|
+
* @see {@link ClassConstructor} - Base constructor type constraint
|
|
1638
|
+
*/
|
|
1639
|
+
export type ValidatorValidateTargetData<Target extends ClassConstructor = ClassConstructor> = Partial<Record<keyof InstanceType<Target>, any>>;
|
|
1640
|
+
/**
|
|
1641
|
+
* ## Target Validation Options
|
|
1642
|
+
*
|
|
1643
|
+
* Configuration interface for validating entire class instances with decorated properties.
|
|
1644
|
+
* This interface extends {@link ValidatorValidateOptions} with target-specific properties
|
|
1645
|
+
* for complex object validation scenarios.
|
|
1646
|
+
*
|
|
1647
|
+
* ### Purpose
|
|
1648
|
+
* Provides a specialized options interface for validating class instances where multiple
|
|
1649
|
+
* properties have validation decorators. Unlike single-value validation, this interface
|
|
1650
|
+
* handles validation of entire objects with potentially many fields and nested structures.
|
|
1651
|
+
*
|
|
1652
|
+
* ### Key Differences from ValidatorValidateOptions
|
|
1653
|
+
* - **data property**: Required and typed as target data (not optional generic data)
|
|
1654
|
+
* - **Omits "rule" and "value"**: Uses target-specific data structure instead
|
|
1655
|
+
* - **parentData**: Supports nested validation context
|
|
1656
|
+
* - **errorMessageBuilder**: Customizable error message formatting for target validation
|
|
1657
|
+
* - **startTime**: Performance tracking for multi-field validation
|
|
1658
|
+
*
|
|
1659
|
+
* ### Inheritance Structure
|
|
1660
|
+
* ```
|
|
1661
|
+
* ValidatorValidateTargetOptions
|
|
1662
|
+
* ↳ extends Omit<ValidatorValidateOptions<ParamsTypes, Context>, "data" | "rule" | "value">
|
|
1663
|
+
* ↳ extends Omit<Partial<InputFormatterResult>, "value">
|
|
1664
|
+
* ↳ extends BaseData<Context> (but overrides data property)
|
|
1665
|
+
* ```
|
|
1666
|
+
*
|
|
1667
|
+
* ### Generic Parameters
|
|
1668
|
+
* - **Target**: The class constructor type being validated (extends `ClassConstructor`)
|
|
1669
|
+
* - **Context**: Optional context type for validation (defaults to `unknown`)
|
|
1670
|
+
* - **ParamsTypes**: Parameter types for validation rules (defaults to `ValidatorRuleParams`)
|
|
1671
|
+
*
|
|
1672
|
+
* ### Properties Overview
|
|
1673
|
+
*
|
|
1674
|
+
* #### Inherited Properties (from ValidatorValidateOptions)
|
|
1675
|
+
* - **rules**: Array of validation rules to apply to the target
|
|
1676
|
+
* - **ruleParams**: Parameters for the current rule
|
|
1677
|
+
* - **ruleName**: Name of the validation rule
|
|
1678
|
+
* - **rawRuleName**: Original unparsed rule name
|
|
1679
|
+
* - **message**: Custom error message
|
|
1680
|
+
* - **fieldName**: Form field identifier
|
|
1681
|
+
* - **propertyName**: Object property name
|
|
1682
|
+
* - **translatedPropertyName**: Localized property name
|
|
1683
|
+
* - **i18n**: Internationalization instance
|
|
1684
|
+
* - **sanitizedRules**: Preprocessed rules
|
|
1685
|
+
*
|
|
1686
|
+
* #### Target-Specific Properties
|
|
1687
|
+
* - **data**: Required target data to validate (typed as `ValidatorValidateTargetData<Target>`)
|
|
1688
|
+
* - **parentData**: Parent context for nested validations
|
|
1689
|
+
* - **startTime**: Performance tracking timestamp
|
|
1690
|
+
* - **errorMessageBuilder**: Custom error message builder function
|
|
1691
|
+
*
|
|
1692
|
+
* ### Usage in Target Validation
|
|
1693
|
+
* ```typescript
|
|
1694
|
+
* class UserProfile {
|
|
1695
|
+
* @IsRequired()
|
|
1696
|
+
* @IsEmail()
|
|
1697
|
+
* email: string;
|
|
1698
|
+
*
|
|
1699
|
+
* @IsRequired()
|
|
1700
|
+
* @MinLength(2)
|
|
1701
|
+
* name: string;
|
|
1702
|
+
*
|
|
1703
|
+
* @ValidateNested
|
|
1704
|
+
* address: Address;
|
|
1705
|
+
* }
|
|
1706
|
+
*
|
|
1707
|
+
* // Basic target validation
|
|
1708
|
+
* const options: ValidatorValidateTargetOptions<UserProfile> = {
|
|
1709
|
+
* data: {
|
|
1710
|
+
* email: "user@example.com",
|
|
1711
|
+
* name: "John",
|
|
1712
|
+
* address: { street: "123 Main St", city: "Anytown" }
|
|
1713
|
+
* },
|
|
1714
|
+
* propertyName: "userProfile",
|
|
1715
|
+
* context: validationContext,
|
|
1716
|
+
* i18n: defaultI18n,
|
|
1717
|
+
* };
|
|
1718
|
+
*
|
|
1719
|
+
* const result = await Validator.validateTarget(UserProfile, options.data);
|
|
1720
|
+
* ```
|
|
1721
|
+
*
|
|
1722
|
+
* ### Error Message Builder
|
|
1723
|
+
* The `errorMessageBuilder` allows customization of error message formatting:
|
|
1724
|
+
* ```typescript
|
|
1725
|
+
* const customErrorBuilder = (
|
|
1726
|
+
* translatedPropertyName: string,
|
|
1727
|
+
* error: string,
|
|
1728
|
+
* options: ValidatorValidationError & {
|
|
1729
|
+
* propertyName: string;
|
|
1730
|
+
* translatedPropertyName: string;
|
|
1731
|
+
* i18n: I18n;
|
|
1732
|
+
* separators: { multiple: string; single: string };
|
|
1733
|
+
* data: Partial<Record<keyof Target, any>>;
|
|
1734
|
+
* }
|
|
1735
|
+
* ) => {
|
|
1736
|
+
* return `[${translatedPropertyName}]: ${error}`;
|
|
1737
|
+
* };
|
|
1738
|
+
*
|
|
1739
|
+
* const options: ValidatorValidateTargetOptions<UserProfile> = {
|
|
1740
|
+
* data: userData,
|
|
1741
|
+
* errorMessageBuilder: customErrorBuilder,
|
|
1742
|
+
* };
|
|
1743
|
+
* ```
|
|
1744
|
+
*
|
|
1745
|
+
* ### Nested Validation Context
|
|
1746
|
+
* The `parentData` property enables context sharing in nested validations:
|
|
1747
|
+
* ```typescript
|
|
1748
|
+
* // Parent validation
|
|
1749
|
+
* const parentOptions: ValidatorValidateTargetOptions<Company> = {
|
|
1750
|
+
* data: {
|
|
1751
|
+
* name: "ACME Corp",
|
|
1752
|
+
* employees: [employeeData1, employeeData2]
|
|
1753
|
+
* },
|
|
1754
|
+
* parentData: undefined, // Root level
|
|
1755
|
+
* };
|
|
1756
|
+
*
|
|
1757
|
+
* // Nested validation (for each employee)
|
|
1758
|
+
* const nestedOptions: ValidatorValidateTargetOptions<Employee> = {
|
|
1759
|
+
* data: employeeData,
|
|
1760
|
+
* parentData: { companyName: "ACME Corp" }, // Context from parent
|
|
1761
|
+
* propertyName: "employee",
|
|
1762
|
+
* };
|
|
1763
|
+
* ```
|
|
1764
|
+
*
|
|
1765
|
+
* ### Performance Tracking
|
|
1766
|
+
* The `startTime` property enables duration measurement:
|
|
1767
|
+
* ```typescript
|
|
1768
|
+
* const startTime = Date.now();
|
|
1769
|
+
* const options: ValidatorValidateTargetOptions<UserForm> = {
|
|
1770
|
+
* data: formData,
|
|
1771
|
+
* startTime, // Track when validation began
|
|
1772
|
+
* };
|
|
1773
|
+
*
|
|
1774
|
+
* const result = await Validator.validateTarget(UserForm, formData, options);
|
|
1775
|
+
* if (result.success) {
|
|
1776
|
+
* console.log(`Validation took ${result.duration}ms`);
|
|
1777
|
+
* }
|
|
1778
|
+
* ```
|
|
1779
|
+
*
|
|
1780
|
+
* ### Type Safety Benefits
|
|
1781
|
+
* - **Compile-time validation** of target class types
|
|
1782
|
+
* - **Property type checking** for data objects
|
|
1783
|
+
* - **Context propagation** through validation hierarchy
|
|
1784
|
+
* - **Error message customization** with proper typing
|
|
1785
|
+
*
|
|
1786
|
+
* ### Common Use Cases
|
|
1787
|
+
*
|
|
1788
|
+
* #### 1. Form Validation
|
|
1789
|
+
* ```typescript
|
|
1790
|
+
* const formOptions: ValidatorValidateTargetOptions<RegistrationForm> = {
|
|
1791
|
+
* data: {
|
|
1792
|
+
* email: submittedEmail,
|
|
1793
|
+
* password: submittedPassword,
|
|
1794
|
+
* confirmPassword: submittedConfirm,
|
|
1795
|
+
* },
|
|
1796
|
+
* fieldName: "registration_form",
|
|
1797
|
+
* context: { userType: "new" },
|
|
1798
|
+
* };
|
|
1799
|
+
* ```
|
|
1800
|
+
*
|
|
1801
|
+
* #### 2. API Request Validation
|
|
1802
|
+
* ```typescript
|
|
1803
|
+
* const apiOptions: ValidatorValidateTargetOptions<CreateUserRequest> = {
|
|
1804
|
+
* data: requestBody,
|
|
1805
|
+
* propertyName: "request",
|
|
1806
|
+
* context: { requestId: req.id, userAgent: req.headers['user-agent'] },
|
|
1807
|
+
* };
|
|
1808
|
+
* ```
|
|
1809
|
+
*
|
|
1810
|
+
* #### 3. Nested Object Validation
|
|
1811
|
+
* ```typescript
|
|
1812
|
+
* const nestedOptions: ValidatorValidateTargetOptions<OrderItem> = {
|
|
1813
|
+
* data: itemData,
|
|
1814
|
+
* parentData: { orderId: "12345", customerId: "67890" },
|
|
1815
|
+
* propertyName: "item",
|
|
1816
|
+
* errorMessageBuilder: customFormatter,
|
|
1817
|
+
* };
|
|
1818
|
+
* ```
|
|
1819
|
+
*
|
|
1820
|
+
* ### Relationship to Validation System
|
|
1821
|
+
* - **Used by**: {@link Validator.validateTarget} method
|
|
1822
|
+
* - **Extends**: {@link ValidatorValidateOptions} with target-specific modifications
|
|
1823
|
+
* - **Supports**: Multi-field validation with error aggregation
|
|
1824
|
+
* - **Integrates with**: Decorator-based validation system
|
|
1825
|
+
*
|
|
1826
|
+
* @template Target - The class constructor type being validated (must extend ClassConstructor)
|
|
1827
|
+
* @template Context - Optional context type for validation (defaults to unknown)
|
|
1828
|
+
* @template ParamsTypes - Parameter types for validation rules (defaults to ValidatorRuleParams)
|
|
1829
|
+
*
|
|
1830
|
+
* @public
|
|
1831
|
+
*
|
|
1832
|
+
* @see {@link ValidatorValidateOptions} - Base options interface being extended
|
|
1833
|
+
* @see {@link ValidatorValidateTargetData} - Target data type
|
|
1834
|
+
* @see {@link Validator.validateTarget} - Method that uses this interface
|
|
1835
|
+
* @see {@link ClassConstructor} - Class constructor constraint
|
|
1836
|
+
* @see {@link ValidatorValidationError} - Error type for errorMessageBuilder
|
|
1837
|
+
*/
|
|
1838
|
+
export interface ValidatorValidateTargetOptions<Target extends ClassConstructor = ClassConstructor, Context = unknown, ParamsTypes extends ValidatorRuleParams = ValidatorRuleParams> extends Omit<ValidatorValidateOptions<ParamsTypes, Context>, 'data' | 'rule' | 'value'> {
|
|
1839
|
+
data: ValidatorValidateTargetData<Target>;
|
|
1840
|
+
/**
|
|
1841
|
+
* The parent data/context for nested validations
|
|
1842
|
+
*
|
|
1843
|
+
* When validating nested objects, this property holds the parent
|
|
1844
|
+
*/
|
|
1845
|
+
parentData?: Dictionary;
|
|
1846
|
+
startTime?: number;
|
|
1847
|
+
errorMessageBuilder?: (translatedPropertyName: string, error: string, builderOptions: ValidatorValidationError & {
|
|
1848
|
+
propertyName: keyof InstanceType<Target> | string;
|
|
1849
|
+
translatedPropertyName: string;
|
|
1850
|
+
i18n: I18n;
|
|
1851
|
+
separators: {
|
|
1852
|
+
multiple: string;
|
|
1853
|
+
single: string;
|
|
1854
|
+
};
|
|
1855
|
+
data: Partial<Record<keyof InstanceType<Target>, any>>;
|
|
1856
|
+
}) => string;
|
|
1857
|
+
}
|
|
1858
|
+
/**
|
|
1859
|
+
* ## Multi-Rule Names Union
|
|
1860
|
+
*
|
|
1861
|
+
* A union type defining the names of validation rules that operate on multiple sub-rules.
|
|
1862
|
+
* These rules combine the results of several validation rules using logical operations.
|
|
1863
|
+
*
|
|
1864
|
+
* ### Purpose
|
|
1865
|
+
* Defines the specific rule names that support multi-rule validation patterns.
|
|
1866
|
+
* These rules allow combining multiple validation conditions with logical operators
|
|
1867
|
+
* like "one of" or "all of", enabling complex validation scenarios.
|
|
1868
|
+
*
|
|
1869
|
+
* ### Supported Multi-Rules
|
|
1870
|
+
* - **'OneOf'**: Passes if at least one of the sub-rules passes (logical OR)
|
|
1871
|
+
* - **'AllOf'**: Passes only if all sub-rules pass (logical AND)
|
|
1872
|
+
*
|
|
1873
|
+
* ### Type Structure
|
|
1874
|
+
* Simple string literal union with two possible values:
|
|
1875
|
+
* ```typescript
|
|
1876
|
+
* 'OneOf' | 'AllOf'
|
|
1877
|
+
* ```
|
|
1878
|
+
*
|
|
1879
|
+
* ### Usage in Validation
|
|
1880
|
+
* Multi-rule names are used in {@link ValidatorMultiRuleFunction} to specify
|
|
1881
|
+
* which logical operation to apply to a collection of validation rules.
|
|
1882
|
+
*
|
|
1883
|
+
* ```typescript
|
|
1884
|
+
* // Example: Email must be valid OR be empty (optional email field)
|
|
1885
|
+
* const rule: ValidatorMultiRuleFunction = (rules, context) => {
|
|
1886
|
+
* return rules.OneOf([
|
|
1887
|
+
* rules.Email([], context),
|
|
1888
|
+
* rules.IsEmpty([], context)
|
|
1889
|
+
* ]);
|
|
1890
|
+
* };
|
|
1891
|
+
* ```
|
|
1892
|
+
*
|
|
1893
|
+
* ### Relationship to Validation System
|
|
1894
|
+
* - **Used by**: {@link ValidatorMultiRuleFunction} as operation selector
|
|
1895
|
+
* - **Implemented in**: Rule registry as special multi-rule handlers
|
|
1896
|
+
* - **Combines with**: Regular validation rules via logical operations
|
|
1897
|
+
* - **Returns**: Single validation result from multiple rule evaluations
|
|
1898
|
+
*
|
|
1899
|
+
* ### Key Characteristics
|
|
1900
|
+
* - **Logical Operations**: Supports OR ('OneOf') and AND ('AllOf') combinations
|
|
1901
|
+
* - **Rule Composition**: Enables building complex validation logic from simple rules
|
|
1902
|
+
* - **Type Safety**: Compile-time guarantees for valid multi-rule names
|
|
1903
|
+
* - **Extensible**: New logical operations can be added by extending this union
|
|
1904
|
+
*
|
|
1905
|
+
* ### Comparison with Single Rules
|
|
1906
|
+
* | Aspect | Single Rule | Multi-Rule |
|
|
1907
|
+
* |--------|-------------|------------|
|
|
1908
|
+
* | Operation | One condition | Multiple conditions |
|
|
1909
|
+
* | Logic | Direct validation | Logical combination |
|
|
1910
|
+
* | Use Case | Basic validation | Complex conditional validation |
|
|
1911
|
+
* | Example | "IsEmail" | "OneOf(IsEmail, IsEmpty())" |
|
|
1912
|
+
*
|
|
1913
|
+
* ### Runtime Behavior
|
|
1914
|
+
* - **OneOf**: Returns success if any sub-rule passes, failure if all fail
|
|
1915
|
+
* - **AllOf**: Returns success only if all sub-rules pass, failure if any fails
|
|
1916
|
+
* - **Short-circuiting**: May stop evaluation early based on logical operation
|
|
1917
|
+
* - **Error Aggregation**: Collects errors from all evaluated rules
|
|
1918
|
+
*
|
|
1919
|
+
* @public
|
|
1920
|
+
*
|
|
1921
|
+
* @see {@link ValidatorMultiRuleFunction} - Function type that uses these names
|
|
1922
|
+
* @see {@link ValidatorDefaultMultiRule} - Default multi-rule configuration
|
|
1923
|
+
* @see {@link ValidatorRuleName} - General rule names (includes these)
|
|
1924
|
+
*/
|
|
1925
|
+
export type ValidatorMultiRuleNames = 'OneOf' | 'AllOf';
|
|
1926
|
+
/**
|
|
1927
|
+
* ## Validation Result Types (Either Pattern)
|
|
1928
|
+
*
|
|
1929
|
+
* Uses the Either<L, R> pattern where Left represents failure and Right represents success.
|
|
1930
|
+
* This provides strong type safety and prevents accessing wrong properties based on the result state.
|
|
1931
|
+
*/
|
|
1932
|
+
/**
|
|
1933
|
+
* ## Validation Error Details
|
|
1934
|
+
*
|
|
1935
|
+
* Comprehensive error information structure for validation failures.
|
|
1936
|
+
* This interface defines the complete error object that is returned when validation rules fail,
|
|
1937
|
+
* providing detailed context about what went wrong and where.
|
|
1938
|
+
*
|
|
1939
|
+
* ### Purpose
|
|
1940
|
+
* Serves as the standardized error format across the entire validation system.
|
|
1941
|
+
* Contains all necessary information for error reporting, debugging, and user feedback.
|
|
1942
|
+
* Used by both single-value and target validation failure results.
|
|
1943
|
+
*
|
|
1944
|
+
* ### Key Properties
|
|
1945
|
+
* - **status**: Always "error" for type discrimination
|
|
1946
|
+
* - **name**: Error class name ("ValidatorValidationError")
|
|
1947
|
+
* - **message**: Human-readable error message (translated if available)
|
|
1948
|
+
* - **ruleName**: The specific validation rule that failed
|
|
1949
|
+
* - **value**: The actual value that failed validation
|
|
1950
|
+
* - **propertyName**: Object property name (for target validation)
|
|
1951
|
+
* - **fieldName**: Form field identifier
|
|
1952
|
+
*
|
|
1953
|
+
* ### Usage in Validation Results
|
|
1954
|
+
* This interface is used in failure results:
|
|
1955
|
+
* - {@link ValidatorValidateFailure.error} - Single value validation failures
|
|
1956
|
+
* - {@link ValidatorValidateTargetFailure.errors} - Array of errors in target validation
|
|
1957
|
+
*
|
|
1958
|
+
* ### Error Message Structure
|
|
1959
|
+
* Error messages follow a consistent format:
|
|
1960
|
+
* ```
|
|
1961
|
+
* "[PropertyName]: Error message from rule"
|
|
1962
|
+
* ```
|
|
1963
|
+
* For example: `"[Email]: Must be valid email format"`
|
|
1964
|
+
*
|
|
1965
|
+
* ### Internationalization Support
|
|
1966
|
+
* - **translatedPropertyName**: Localized property name for user-facing messages
|
|
1967
|
+
* - **message**: Can be translated based on i18n configuration
|
|
1968
|
+
* - **timestamp**: When the error occurred (for logging/debugging)
|
|
1969
|
+
*
|
|
1970
|
+
* ### Metadata and Extensibility
|
|
1971
|
+
* - **code**: Programmatic error code for conditional handling
|
|
1972
|
+
* - **severity**: Error level ("error", "warning", "info")
|
|
1973
|
+
* - **metadata**: Additional error context as key-value pairs
|
|
1974
|
+
*
|
|
1975
|
+
* ### Example Error Object
|
|
1976
|
+
* ```typescript
|
|
1977
|
+
* const error: ValidatorValidationError = {
|
|
1978
|
+
* status: "error",
|
|
1979
|
+
* name: "ValidatorValidationError",
|
|
1980
|
+
* message: "[Email]: Must be valid email format",
|
|
1981
|
+
* ruleName: "Email",
|
|
1982
|
+
* ruleParams: [],
|
|
1983
|
+
* rawRuleName: "Email",
|
|
1984
|
+
* propertyName: "email",
|
|
1985
|
+
* fieldName: "email_input",
|
|
1986
|
+
* translatedPropertyName: "Email Address",
|
|
1987
|
+
* value: "invalid-email",
|
|
1988
|
+
* code: "INVALID_EMAIL",
|
|
1989
|
+
* severity: "error",
|
|
1990
|
+
* timestamp: new Date(),
|
|
1991
|
+
* metadata: {
|
|
1992
|
+
* suggestion: "Please use format: user@example.com",
|
|
1993
|
+
* domain: "example.com"
|
|
1994
|
+
* }
|
|
1995
|
+
* };
|
|
1996
|
+
* ```
|
|
1997
|
+
*
|
|
1998
|
+
* ### Relationship to Validation System
|
|
1999
|
+
* - **Created by**: Validation rule functions when they return failure strings
|
|
2000
|
+
* - **Processed by**: {@link Validator.validate} and {@link Validator.validateTarget}
|
|
2001
|
+
* - **Used in**: Error aggregation and reporting throughout the system
|
|
2002
|
+
* - **Compatible with**: Standard error handling patterns and logging systems
|
|
2003
|
+
*
|
|
2004
|
+
* ### Best Practices
|
|
2005
|
+
*
|
|
2006
|
+
* #### Error Message Guidelines
|
|
2007
|
+
* ```typescript
|
|
2008
|
+
* // ✅ Good: Specific, actionable messages
|
|
2009
|
+
* message: "[Password]: Must contain at least one uppercase letter"
|
|
2010
|
+
*
|
|
2011
|
+
* // ❌ Avoid: Generic or unhelpful messages
|
|
2012
|
+
* message: "Invalid input"
|
|
2013
|
+
* ```
|
|
2014
|
+
*
|
|
2015
|
+
* #### Using Error Codes
|
|
2016
|
+
* ```typescript
|
|
2017
|
+
* // Enable programmatic error handling
|
|
2018
|
+
* if (error.code === "EMAIL_INVALID_FORMAT") {
|
|
2019
|
+
* highlightEmailField();
|
|
2020
|
+
* showEmailFormatHint();
|
|
2021
|
+
* }
|
|
2022
|
+
* ```
|
|
2023
|
+
*
|
|
2024
|
+
* #### Metadata for Rich Errors
|
|
2025
|
+
* ```typescript
|
|
2026
|
+
* // Provide additional context
|
|
2027
|
+
* error.metadata = {
|
|
2028
|
+
* minLength: 8,
|
|
2029
|
+
* actualLength: 5,
|
|
2030
|
+
* missingChars: ["uppercase", "number"]
|
|
2031
|
+
* };
|
|
2032
|
+
* ```
|
|
2033
|
+
*
|
|
2034
|
+
* @public
|
|
2035
|
+
*
|
|
2036
|
+
* @see {@link ValidatorValidateFailure} - Single validation failure result
|
|
2037
|
+
* @see {@link ValidatorValidateTargetFailure} - Target validation failure result
|
|
2038
|
+
* @see {@link Validator.validate} - Method that creates these errors
|
|
2039
|
+
* @see {@link Validator.validateTarget} - Method that creates these errors
|
|
2040
|
+
*/
|
|
2041
|
+
export interface ValidatorValidationError {
|
|
2042
|
+
/** Always 'error' for failures */
|
|
2043
|
+
status: 'error';
|
|
2044
|
+
name: 'ValidatorValidationError';
|
|
2045
|
+
/** The property name that failed validation (required) */
|
|
2046
|
+
fieldName?: string;
|
|
2047
|
+
/** Alias for fieldName (required) */
|
|
2048
|
+
propertyName?: string;
|
|
2049
|
+
/** The validation error message (required) */
|
|
2050
|
+
message: string;
|
|
2051
|
+
/** Localized field name for user-facing messages */
|
|
2052
|
+
translatedPropertyName?: string;
|
|
2053
|
+
/** The specific rule that failed */
|
|
2054
|
+
ruleName?: ValidatorRuleName;
|
|
2055
|
+
/** Parameters passed to the failing rule */
|
|
2056
|
+
ruleParams: any[];
|
|
2057
|
+
/** The value that failed validation */
|
|
2058
|
+
value: any;
|
|
2059
|
+
/** Raw rule name with parameters (e.g., "minLength[5]") */
|
|
2060
|
+
rawRuleName?: ValidatorRuleName | string;
|
|
2061
|
+
/** Error code for programmatic handling */
|
|
2062
|
+
code?: string;
|
|
2063
|
+
/** Error severity level */
|
|
2064
|
+
severity?: 'error' | 'warning' | 'info';
|
|
2065
|
+
/** When the validation failed */
|
|
2066
|
+
timestamp?: Date;
|
|
2067
|
+
/** Additional error metadata */
|
|
2068
|
+
metadata?: Dictionary;
|
|
2069
|
+
}
|
|
2070
|
+
/**
|
|
2071
|
+
* ## Single Value Validation Success Result
|
|
2072
|
+
*
|
|
2073
|
+
* Represents a successful validation result for a single value.
|
|
2074
|
+
* This type is used as the success branch of the {@link ValidatorValidateResult} discriminated union.
|
|
2075
|
+
*
|
|
2076
|
+
* ### Type Guard
|
|
2077
|
+
* Can be narrowed using {@link Validator.isSuccess}:
|
|
2078
|
+
* ```typescript
|
|
2079
|
+
* if (Validator.isSuccess(result)) {
|
|
2080
|
+
* // TypeScript knows: result satisfies ValidatorValidateSuccess
|
|
2081
|
+
* // Can safely access result.value, result.validatedAt, result.duration
|
|
2082
|
+
* }
|
|
2083
|
+
* ```
|
|
2084
|
+
*
|
|
2085
|
+
* ### Properties
|
|
2086
|
+
* - **success**: Literal `true` for type discrimination
|
|
2087
|
+
* - **value**: The original value that passed validation
|
|
2088
|
+
* - **validatedAt**: ISO timestamp indicating when validation completed
|
|
2089
|
+
* - **duration**: Duration in milliseconds from validation start to completion
|
|
2090
|
+
* - **error**: Explicitly `undefined` for success (aids type narrowing)
|
|
2091
|
+
* - **failedAt**: Explicitly `undefined` for success (aids type narrowing)
|
|
2092
|
+
* - **data**: Optional context data (inherited from BaseData)
|
|
2093
|
+
* - **context**: Optional validation context (inherited from BaseData)
|
|
2094
|
+
*
|
|
2095
|
+
* ### Example
|
|
2096
|
+
* ```typescript
|
|
2097
|
+
* const result = await Validator.validate({
|
|
2098
|
+
* value: "user@example.com",
|
|
2099
|
+
* rules: ["Required", "Email"],
|
|
2100
|
+
* });
|
|
2101
|
+
*
|
|
2102
|
+
* if (result.success) {
|
|
2103
|
+
* // result is ValidatorValidateSuccess
|
|
2104
|
+
* console.log("Validated:", result.value);
|
|
2105
|
+
* console.log("Took:", result.duration, "ms");
|
|
2106
|
+
* console.log("Completed at:", result.validatedAt.toISOString());
|
|
2107
|
+
* }
|
|
2108
|
+
* ```
|
|
2109
|
+
*
|
|
2110
|
+
* @template Context - Type of the optional validation context
|
|
2111
|
+
*
|
|
2112
|
+
* @public
|
|
2113
|
+
*
|
|
2114
|
+
* @see {@link ValidatorValidateResult}
|
|
2115
|
+
* @see {@link ValidatorValidateFailure}
|
|
2116
|
+
* @see {@link Validator.validate}
|
|
2117
|
+
* @see {@link Validator.isSuccess}
|
|
2118
|
+
*/
|
|
2119
|
+
export interface ValidatorValidateSuccess<Context = unknown> extends BaseData<Context> {
|
|
2120
|
+
/** Discriminant for type narrowing - always `true` for success */
|
|
2121
|
+
success: true;
|
|
2122
|
+
/**
|
|
2123
|
+
* ISO timestamp indicating when validation completed successfully
|
|
2124
|
+
* @example "2024-11-08T10:30:45.123Z"
|
|
2125
|
+
*/
|
|
2126
|
+
validatedAt?: Date;
|
|
2127
|
+
/**
|
|
2128
|
+
* Duration of validation in milliseconds (from start to completion)
|
|
2129
|
+
* @example 15 (milliseconds)
|
|
2130
|
+
*/
|
|
2131
|
+
duration?: number;
|
|
2132
|
+
/** Always undefined for success results (type narrowing aid) */
|
|
2133
|
+
error?: undefined;
|
|
2134
|
+
/** Always undefined for success results (type narrowing aid) */
|
|
2135
|
+
failedAt?: undefined;
|
|
2136
|
+
}
|
|
2137
|
+
/**
|
|
2138
|
+
* ## Base Data Structure
|
|
2139
|
+
*
|
|
2140
|
+
* Shared data structure for both validation success and failure results.
|
|
2141
|
+
* Contains the core properties that exist in all validation outcomes.
|
|
2142
|
+
*
|
|
2143
|
+
* ### Purpose
|
|
2144
|
+
* Provides a common interface for passing data through the validation pipeline
|
|
2145
|
+
* and in the result objects. Used by both {@link ValidatorValidateSuccess}
|
|
2146
|
+
* and {@link ValidatorValidateFailure}.
|
|
2147
|
+
*
|
|
2148
|
+
* ### Properties
|
|
2149
|
+
* - **value**: The actual value being validated (required)
|
|
2150
|
+
* - **data**: Optional contextual data available to validation rules
|
|
2151
|
+
* - **context**: Optional typed context object for advanced validations
|
|
2152
|
+
*
|
|
2153
|
+
* ### Usage in Validation Results
|
|
2154
|
+
* ```typescript
|
|
2155
|
+
* // In ValidatorValidateSuccess
|
|
2156
|
+
* const successResult: ValidatorValidateSuccess = {
|
|
2157
|
+
* success: true,
|
|
2158
|
+
* value: "user@example.com", // Original validated value
|
|
2159
|
+
* data: { userId: 123 }, // Additional context
|
|
2160
|
+
* context: { ... }, // Typed context object
|
|
2161
|
+
* validatedAt: new Date(),
|
|
2162
|
+
* duration: 5,
|
|
2163
|
+
* };
|
|
2164
|
+
*
|
|
2165
|
+
* // In ValidatorValidateFailure
|
|
2166
|
+
* const failureResult: ValidatorValidateFailure = {
|
|
2167
|
+
* success: false,
|
|
2168
|
+
* value: "invalid-email", // Value that failed
|
|
2169
|
+
* data: { userId: 123 }, // Available during failure too
|
|
2170
|
+
* context: { ... }, // Context from validation request
|
|
2171
|
+
* error: { ... },
|
|
2172
|
+
* failedAt: new Date(),
|
|
2173
|
+
* duration: 2,
|
|
2174
|
+
* };
|
|
2175
|
+
* ```
|
|
2176
|
+
*
|
|
2177
|
+
* @template Context - Type parameter for optional typed context object
|
|
2178
|
+
*
|
|
2179
|
+
* @public
|
|
2180
|
+
*
|
|
2181
|
+
* @see {@link ValidatorValidateOptions} - Options passed to validation
|
|
2182
|
+
* @see {@link ValidatorValidateSuccess} - Success result type
|
|
2183
|
+
* @see {@link ValidatorValidateFailure} - Failure result type
|
|
2184
|
+
*/
|
|
2185
|
+
interface BaseData<Context = unknown> {
|
|
2186
|
+
/**
|
|
2187
|
+
* The value to use for performing the validation.
|
|
2188
|
+
* This is the actual data that will be validated against the specified rules.
|
|
2189
|
+
*
|
|
2190
|
+
* @type {any}
|
|
2191
|
+
*
|
|
2192
|
+
* @example
|
|
2193
|
+
* ```typescript
|
|
2194
|
+
* const result = await Validator.validate({
|
|
2195
|
+
* value: "user@example.com", // This is the value being validated
|
|
2196
|
+
* rules: ["Required", "Email"],
|
|
2197
|
+
* });
|
|
2198
|
+
* ```
|
|
2199
|
+
*
|
|
2200
|
+
* @remarks
|
|
2201
|
+
* - This is the core data being validated
|
|
2202
|
+
* - Type can be any JavaScript value: string, number, object, array, etc.
|
|
2203
|
+
* - Available in both success and failure results
|
|
2204
|
+
*/
|
|
2205
|
+
value: any;
|
|
2206
|
+
/**
|
|
2207
|
+
* Optional data object providing contextual information for validation rules.
|
|
2208
|
+
*
|
|
2209
|
+
* This property is used to provide additional context for the validation rule.
|
|
2210
|
+
* It can be used to pass any additional data that might be needed for validation,
|
|
2211
|
+
* such as form data, related field values, or other contextual information.
|
|
2212
|
+
*
|
|
2213
|
+
* @type {Dictionary | undefined}
|
|
2214
|
+
*
|
|
2215
|
+
* @example
|
|
2216
|
+
* ```typescript
|
|
2217
|
+
* const result = await Validator.validate({
|
|
2218
|
+
* value: "test@example.com",
|
|
2219
|
+
* rules: ["Required", "Email"],
|
|
2220
|
+
* data: {
|
|
2221
|
+
* userId: 123,
|
|
2222
|
+
* formId: "user_form",
|
|
2223
|
+
* },
|
|
2224
|
+
* });
|
|
2225
|
+
* ```
|
|
2226
|
+
*
|
|
2227
|
+
* @remarks
|
|
2228
|
+
* - Optional property (not required)
|
|
2229
|
+
* - Passed to validation rule functions via options.data
|
|
2230
|
+
* - Useful for multi-field validation scenarios
|
|
2231
|
+
* - Commonly used for form data context in validateTarget
|
|
2232
|
+
*/
|
|
2233
|
+
data?: Dictionary;
|
|
2234
|
+
/**
|
|
2235
|
+
* Optional typed context object for validation.
|
|
2236
|
+
*
|
|
2237
|
+
* Provides a typed context that can be passed to validation rules for
|
|
2238
|
+
* advanced validation scenarios requiring external data or permissions.
|
|
2239
|
+
*
|
|
2240
|
+
* @template Context - Type of the context object
|
|
2241
|
+
*
|
|
2242
|
+
* @example
|
|
2243
|
+
* ```typescript
|
|
2244
|
+
* interface UserContext {
|
|
2245
|
+
* userId: number;
|
|
2246
|
+
* permissions: string[];
|
|
2247
|
+
* isAdmin: boolean;
|
|
2248
|
+
* }
|
|
2249
|
+
*
|
|
2250
|
+
* const result = await Validator.validate<UserContext>({
|
|
2251
|
+
* value: "admin_action",
|
|
2252
|
+
* rules: ["Required"],
|
|
2253
|
+
* context: {
|
|
2254
|
+
* userId: 123,
|
|
2255
|
+
* permissions: ["read", "write", "admin"],
|
|
2256
|
+
* isAdmin: true,
|
|
2257
|
+
* },
|
|
2258
|
+
* });
|
|
2259
|
+
* ```
|
|
2260
|
+
*
|
|
2261
|
+
* @remarks
|
|
2262
|
+
* - Optional property (not required)
|
|
2263
|
+
* - Type is defined by the Context generic parameter
|
|
2264
|
+
* - Passed to all validation rule functions
|
|
2265
|
+
* - Enables context-aware validation rules
|
|
2266
|
+
* - Commonly used for permission-based or user-specific validations
|
|
2267
|
+
*/
|
|
2268
|
+
context?: Context;
|
|
2269
|
+
}
|
|
2270
|
+
/**
|
|
2271
|
+
* ## Single Value Validation Failure Result
|
|
2272
|
+
*
|
|
2273
|
+
* Represents a failed validation result for a single value.
|
|
2274
|
+
* This type is used as the failure branch of the {@link ValidatorValidateResult} discriminated union.
|
|
2275
|
+
*
|
|
2276
|
+
* ### Type Guard
|
|
2277
|
+
* Can be narrowed using {@link Validator.isFailure}:
|
|
2278
|
+
* ```typescript
|
|
2279
|
+
* if (Validator.isFailure(result)) {
|
|
2280
|
+
* // TypeScript knows: result satisfies ValidatorValidateFailure
|
|
2281
|
+
* // Can safely access result.error, result.failedAt, result.duration
|
|
2282
|
+
* }
|
|
2283
|
+
* ```
|
|
2284
|
+
*
|
|
2285
|
+
* ### Properties
|
|
2286
|
+
* - **success**: Literal `false` for type discrimination
|
|
2287
|
+
* - **error**: Validation error details (name, message, rule info)
|
|
2288
|
+
* - **failedAt**: ISO timestamp indicating when validation failed
|
|
2289
|
+
* - **duration**: Duration in milliseconds until failure
|
|
2290
|
+
* - **validatedAt**: Explicitly `undefined` for failure (aids type narrowing)
|
|
2291
|
+
* - **value**: The original value that failed validation
|
|
2292
|
+
* - **data**: Optional context data (inherited from BaseData)
|
|
2293
|
+
* - **context**: Optional validation context (inherited from BaseData)
|
|
2294
|
+
*
|
|
2295
|
+
* ### Error Object Structure
|
|
2296
|
+
* The `error` property contains:
|
|
2297
|
+
* ```typescript
|
|
2298
|
+
* {
|
|
2299
|
+
* name: "ValidatorValidationError",
|
|
2300
|
+
* message: "Error message (translated if available)",
|
|
2301
|
+
* ruleName: "Email", // Name of failing rule
|
|
2302
|
+
* ruleParams: [], // Parameters passed to rule
|
|
2303
|
+
* rawRuleName: "Email", // Original rule specification
|
|
2304
|
+
* fieldName: "email_field", // Optional field identifier
|
|
2305
|
+
* propertyName: "email", // Optional property name
|
|
2306
|
+
* translatedPropertyName?: "Email Address", // Translated name
|
|
2307
|
+
* value: "invalid@", // Value that failed
|
|
2308
|
+
* }
|
|
2309
|
+
* ```
|
|
2310
|
+
*
|
|
2311
|
+
* ### Example
|
|
2312
|
+
* ```typescript
|
|
2313
|
+
* const result = await Validator.validate({
|
|
2314
|
+
* value: "not-an-email",
|
|
2315
|
+
* rules: ["Required", "Email"],
|
|
2316
|
+
* });
|
|
2317
|
+
*
|
|
2318
|
+
* if (!result.success) {
|
|
2319
|
+
* // result is ValidatorValidateFailure
|
|
2320
|
+
* console.error("Validation failed:");
|
|
2321
|
+
* console.error(" Value:", result.value);
|
|
2322
|
+
* console.error(" Error:", result.error.message);
|
|
2323
|
+
* console.error(" Rule:", result.error.ruleName);
|
|
2324
|
+
* console.error(" Failed at:", result.failedAt.toISOString());
|
|
2325
|
+
* console.error(" Duration:", result.duration, "ms");
|
|
2326
|
+
* }
|
|
2327
|
+
* ```
|
|
2328
|
+
*
|
|
2329
|
+
* @template Context - Type of the optional validation context
|
|
2330
|
+
*
|
|
2331
|
+
* @public
|
|
2332
|
+
*
|
|
2333
|
+
* @see {@link ValidatorValidateResult}
|
|
2334
|
+
* @see {@link ValidatorValidateSuccess}
|
|
2335
|
+
* @see {@link ValidatorValidationError}
|
|
2336
|
+
* @see {@link Validator.validate}
|
|
2337
|
+
* @see {@link Validator.isFailure}
|
|
2338
|
+
*/
|
|
2339
|
+
export interface ValidatorValidateFailure<Context = unknown> extends BaseData<Context> {
|
|
2340
|
+
/** Discriminant for type narrowing - always `false` for failure */
|
|
2341
|
+
success: false;
|
|
2342
|
+
/**
|
|
2343
|
+
* The validation error details
|
|
2344
|
+
*
|
|
2345
|
+
* Contains complete information about what validation rule failed
|
|
2346
|
+
* and why, including the rule name, parameters, and error message.
|
|
2347
|
+
*
|
|
2348
|
+
* @type {ValidatorValidationError}
|
|
2349
|
+
* @see {@link ValidatorValidationError}
|
|
2350
|
+
*/
|
|
2351
|
+
error: ValidatorValidationError;
|
|
2352
|
+
/**
|
|
2353
|
+
* ISO timestamp indicating when validation failed
|
|
2354
|
+
* @example "2024-11-08T10:30:45.118Z"
|
|
2355
|
+
*/
|
|
2356
|
+
failedAt?: Date;
|
|
2357
|
+
/**
|
|
2358
|
+
* Duration of validation before failure in milliseconds
|
|
2359
|
+
* @example 2 (milliseconds - failed quickly on first rule)
|
|
2360
|
+
*/
|
|
2361
|
+
duration?: number;
|
|
2362
|
+
/** Always undefined for failure results (type narrowing aid) */
|
|
2363
|
+
validatedAt?: undefined;
|
|
2364
|
+
}
|
|
2365
|
+
/**
|
|
2366
|
+
* ## Validation Result Type (Discriminated Union)
|
|
2367
|
+
*
|
|
2368
|
+
* Represents the result of a single-value validation operation.
|
|
2369
|
+
* This is a discriminated union that can be narrowed to either success or failure.
|
|
2370
|
+
*
|
|
2371
|
+
* ### Type Narrowing Strategies
|
|
2372
|
+
*
|
|
2373
|
+
* #### Approach 1: Check the `success` property
|
|
2374
|
+
* ```typescript
|
|
2375
|
+
* const result = await Validator.validate({ value: "...", rules: [...] });
|
|
2376
|
+
*
|
|
2377
|
+
* if (result.success) {
|
|
2378
|
+
* // TypeScript knows: ValidatorValidateSuccess
|
|
2379
|
+
* console.log(result.value); // ✓ Available
|
|
2380
|
+
* console.log(result.validatedAt); // ✓ Available
|
|
2381
|
+
* console.log(result.error); // ✗ Type error (undefined for success)
|
|
2382
|
+
* } else {
|
|
2383
|
+
* // TypeScript knows: ValidatorValidateFailure
|
|
2384
|
+
* console.log(result.value); // ✓ Available
|
|
2385
|
+
* console.log(result.error); // ✓ Available
|
|
2386
|
+
* console.log(result.validatedAt); // ✗ Type error (undefined for failure)
|
|
2387
|
+
* }
|
|
2388
|
+
* ```
|
|
2389
|
+
*
|
|
2390
|
+
* #### Approach 2: Use type guard functions
|
|
2391
|
+
* ```typescript
|
|
2392
|
+
* const result = await Validator.validate({ value: "...", rules: [...] });
|
|
2393
|
+
*
|
|
2394
|
+
* if (Validator.isSuccess(result)) {
|
|
2395
|
+
* // result is ValidatorValidateSuccess<Context>
|
|
2396
|
+
* console.log(result.value);
|
|
2397
|
+
* console.log(result.validatedAt);
|
|
2398
|
+
* } else if (Validator.isFailure(result)) {
|
|
2399
|
+
* // result is ValidatorValidateFailure<Context>
|
|
2400
|
+
* console.log(result.error.message);
|
|
2401
|
+
* console.log(result.error.ruleName);
|
|
2402
|
+
* }
|
|
2403
|
+
* ```
|
|
2404
|
+
*
|
|
2405
|
+
* #### Approach 3: Use switch on discriminant
|
|
2406
|
+
* ```typescript
|
|
2407
|
+
* const result = await Validator.validate({ value: "...", rules: [...] });
|
|
2408
|
+
*
|
|
2409
|
+
* switch (result.success) {
|
|
2410
|
+
* case true:
|
|
2411
|
+
* console.log("Validated:", result.value);
|
|
2412
|
+
* break;
|
|
2413
|
+
* case false:
|
|
2414
|
+
* console.error("Failed:", result.error.message);
|
|
2415
|
+
* break;
|
|
2416
|
+
* }
|
|
2417
|
+
* ```
|
|
2418
|
+
*
|
|
2419
|
+
* ### Union Members
|
|
2420
|
+
* - {@link ValidatorValidateSuccess} - When validation passes (success: true)
|
|
2421
|
+
* - {@link ValidatorValidateFailure} - When validation fails (success: false)
|
|
2422
|
+
*
|
|
2423
|
+
* @template Context - Type of the optional validation context
|
|
2424
|
+
*
|
|
2425
|
+
* @example
|
|
2426
|
+
* ```typescript
|
|
2427
|
+
* interface MyContext {
|
|
2428
|
+
* userId: number;
|
|
2429
|
+
* }
|
|
2430
|
+
*
|
|
2431
|
+
* const result: ValidatorValidateResult<MyContext> = await Validator.validate({
|
|
2432
|
+
* value: "test@example.com",
|
|
2433
|
+
* rules: ["Required", "Email"],
|
|
2434
|
+
* context: { userId: 123 },
|
|
2435
|
+
* });
|
|
2436
|
+
* ```
|
|
2437
|
+
*
|
|
2438
|
+
* @public
|
|
2439
|
+
*
|
|
2440
|
+
* @see {@link ValidatorValidateSuccess} - Success variant
|
|
2441
|
+
* @see {@link ValidatorValidateFailure} - Failure variant
|
|
2442
|
+
* @see {@link Validator.validate} - Main validation method
|
|
2443
|
+
* @see {@link Validator.isSuccess} - Type guard for success
|
|
2444
|
+
* @see {@link Validator.isFailure} - Type guard for failure
|
|
2445
|
+
*/
|
|
2446
|
+
export type ValidatorValidateResult<Context = unknown> = ValidatorValidateSuccess<Context> | ValidatorValidateFailure<Context>;
|
|
2447
|
+
/**
|
|
2448
|
+
* ## Validate Target Result Types
|
|
2449
|
+
*
|
|
2450
|
+
* Types for class-based validation using decorators.
|
|
2451
|
+
* Supports accumulation of multiple field errors across all decorated properties.
|
|
2452
|
+
*
|
|
2453
|
+
* ### Key Differences from Single-Value Validation
|
|
2454
|
+
* - **Multiple Errors**: Collects errors from all fields that fail validation
|
|
2455
|
+
* - **Parallel Validation**: All fields are validated concurrently
|
|
2456
|
+
* - **Error Aggregation**: Returns array of errors with field-level details
|
|
2457
|
+
* - **Class-Based**: Works with decorated class properties rather than single values
|
|
2458
|
+
* - **FieldMeta Mapping**: Maps validated data back to class structure with proper typing
|
|
2459
|
+
*/
|
|
2460
|
+
/**
|
|
2461
|
+
* ## Class Validation Failure Result
|
|
2462
|
+
*
|
|
2463
|
+
* Represents a failed multi-field validation result when using {@link Validator.validateTarget}.
|
|
2464
|
+
* Unlike single-value validation, this accumulates errors from all fields that fail.
|
|
2465
|
+
*
|
|
2466
|
+
* ### Type Guard
|
|
2467
|
+
* Can be narrowed by checking the `success` property:
|
|
2468
|
+
* ```typescript
|
|
2469
|
+
* const result = await Validator.validateTarget(UserForm, data);
|
|
2470
|
+
*
|
|
2471
|
+
* if (!result.success) {
|
|
2472
|
+
* // result is ValidatorValidateTargetFailure
|
|
2473
|
+
* console.log(result.errors); // Array of field errors
|
|
2474
|
+
* console.log(result.failureCount); // Number of failed fields
|
|
2475
|
+
* console.log(result.message); // Summary message
|
|
2476
|
+
* }
|
|
2477
|
+
* ```
|
|
2478
|
+
*
|
|
2479
|
+
* ### Properties
|
|
2480
|
+
* - **success**: Literal `false` for type discrimination
|
|
2481
|
+
* - **errors**: Array of ValidatorValidationError, one per failed field
|
|
2482
|
+
* - **failureCount**: Number of fields that failed validation
|
|
2483
|
+
* - **message**: Summary message (e.g., "Validation failed for 3 fields")
|
|
2484
|
+
* - **status**: Always "error" for consistency
|
|
2485
|
+
* - **failedAt**: ISO timestamp of when validation failed
|
|
2486
|
+
* - **duration**: Milliseconds elapsed during validation
|
|
2487
|
+
* - **data**: Always `undefined` for target failures
|
|
2488
|
+
* - **value**: Always `undefined` for target (use `errors` instead)
|
|
2489
|
+
* - **context**: Optional validation context provided
|
|
2490
|
+
*
|
|
2491
|
+
* ### Error Array Structure
|
|
2492
|
+
* Each error in the `errors` array contains:
|
|
2493
|
+
* ```typescript
|
|
2494
|
+
* {
|
|
2495
|
+
* name: "ValidatorValidationError",
|
|
2496
|
+
* status: "error",
|
|
2497
|
+
* fieldName: "email_field", // Form field identifier
|
|
2498
|
+
* propertyName: "email", // Class property name
|
|
2499
|
+
* message: "[Email]: Must be valid email", // Formatted error message
|
|
2500
|
+
* ruleName: "Email", // Name of failing rule
|
|
2501
|
+
* ruleParams: [], // Rule parameters
|
|
2502
|
+
* value: "invalid@", // Value that failed
|
|
2503
|
+
* }
|
|
2504
|
+
* ```
|
|
2505
|
+
*
|
|
2506
|
+
* ### Example
|
|
2507
|
+
* ```typescript
|
|
2508
|
+
* class UserForm {
|
|
2509
|
+
* @IsRequired()
|
|
2510
|
+
* @IsEmail()
|
|
2511
|
+
* email: string;
|
|
2512
|
+
*
|
|
2513
|
+
* @IsRequired()
|
|
2514
|
+
* @MinLength(3)
|
|
2515
|
+
* name: string;
|
|
2516
|
+
* }
|
|
2517
|
+
*
|
|
2518
|
+
* const result = await Validator.validateTarget(UserForm, {
|
|
2519
|
+
* email: "invalid-email",
|
|
2520
|
+
* name: "ab", // Too short
|
|
2521
|
+
* });
|
|
2522
|
+
*
|
|
2523
|
+
* if (!result.success) {
|
|
2524
|
+
* // result.failureCount === 2
|
|
2525
|
+
* // result.errors.length === 2
|
|
2526
|
+
* result.errors.forEach(error => {
|
|
2527
|
+
* console.error(`${error.propertyName}: ${error.message}`);
|
|
2528
|
+
* });
|
|
2529
|
+
* }
|
|
2530
|
+
* ```
|
|
2531
|
+
* @template Context - Type of the optional validation context
|
|
2532
|
+
*
|
|
2533
|
+
* @public
|
|
2534
|
+
*
|
|
2535
|
+
* @see {@link ValidatorValidateTargetResult}
|
|
2536
|
+
* @see {@link ValidatorValidationError}
|
|
2537
|
+
* @see {@link Validator.validateTarget}
|
|
2538
|
+
*/
|
|
2539
|
+
export interface ValidatorValidateTargetFailure<Context = unknown> extends Omit<BaseData<Context>, 'value' | 'data'> {
|
|
2540
|
+
/** Discriminant for type narrowing - always `false` for failures */
|
|
2541
|
+
success: false;
|
|
2542
|
+
/**
|
|
2543
|
+
* Summary message describing the failure
|
|
2544
|
+
*
|
|
2545
|
+
* Typically formatted as "Validation failed for N fields" where N is the number of failures.
|
|
2546
|
+
* Can be customized via i18n translations.
|
|
2547
|
+
*
|
|
2548
|
+
* @type {string}
|
|
2549
|
+
* @example "Validation failed for 3 fields"
|
|
2550
|
+
*/
|
|
2551
|
+
message: string;
|
|
2552
|
+
/**
|
|
2553
|
+
* Array of validation errors for each field that failed
|
|
2554
|
+
*
|
|
2555
|
+
* Contains one error object per field that failed validation.
|
|
2556
|
+
* Each error includes the field name, error message, rule name, and value.
|
|
2557
|
+
*
|
|
2558
|
+
* @type {ValidatorValidationError[]}
|
|
2559
|
+
* @see {@link ValidatorValidationError}
|
|
2560
|
+
*/
|
|
2561
|
+
errors: ValidatorValidationError[];
|
|
2562
|
+
/**
|
|
2563
|
+
* Number of fields that failed validation
|
|
2564
|
+
*
|
|
2565
|
+
* Equal to errors.length. Provided for convenience.
|
|
2566
|
+
*
|
|
2567
|
+
* @type {number}
|
|
2568
|
+
* @example 3
|
|
2569
|
+
*/
|
|
2570
|
+
failureCount: number;
|
|
2571
|
+
/**
|
|
2572
|
+
* Status indicator for this result
|
|
2573
|
+
*
|
|
2574
|
+
* Always "error" for failures. Provided for consistency with HTTP and API conventions.
|
|
2575
|
+
*
|
|
2576
|
+
* @type {"error"}
|
|
2577
|
+
*/
|
|
2578
|
+
status: 'error';
|
|
2579
|
+
/**
|
|
2580
|
+
* ISO timestamp of when validation failed
|
|
2581
|
+
*
|
|
2582
|
+
* Indicates the exact time validation completed with failures.
|
|
2583
|
+
*
|
|
2584
|
+
* @type {Date | undefined}
|
|
2585
|
+
* @example new Date("2024-11-08T10:30:45.523Z")
|
|
2586
|
+
*/
|
|
2587
|
+
failedAt?: Date;
|
|
2588
|
+
/**
|
|
2589
|
+
* Duration of validation in milliseconds
|
|
2590
|
+
*
|
|
2591
|
+
* Measures time from validation start until failures were detected.
|
|
2592
|
+
* Note: All fields are validated in parallel, so this is not the sum of individual field times.
|
|
2593
|
+
*
|
|
2594
|
+
* @type {number | undefined}
|
|
2595
|
+
* @example 45 (milliseconds)
|
|
2596
|
+
*/
|
|
2597
|
+
duration?: number;
|
|
2598
|
+
/** Validation context (if provided) */
|
|
2599
|
+
context?: Context;
|
|
2600
|
+
/** Always `undefined` for target failures (type narrowing aid) */
|
|
2601
|
+
validatedAt?: undefined;
|
|
2602
|
+
data: Dictionary;
|
|
2603
|
+
}
|
|
2604
|
+
/**
|
|
2605
|
+
* ## Class Validation Success Result
|
|
2606
|
+
*
|
|
2607
|
+
* Represents a successful multi-field validation result when using {@link Validator.validateTarget}.
|
|
2608
|
+
* All decorated fields passed their respective validation rules.
|
|
2609
|
+
*
|
|
2610
|
+
* ### Type Guard
|
|
2611
|
+
* Can be narrowed by checking the `success` property:
|
|
2612
|
+
* ```typescript
|
|
2613
|
+
* const result = await Validator.validateTarget(UserForm, data);
|
|
2614
|
+
*
|
|
2615
|
+
* if (result.success) {
|
|
2616
|
+
* // result is ValidatorValidateTargetSuccess
|
|
2617
|
+
* console.log(result.data); // Validated instance of T
|
|
2618
|
+
* console.log(result.validatedAt); // Timestamp of validation
|
|
2619
|
+
* }
|
|
2620
|
+
* ```
|
|
2621
|
+
*
|
|
2622
|
+
* ### Properties vs Single-Value Success
|
|
2623
|
+
* Unlike {@link ValidatorValidateSuccess}, target success uses:
|
|
2624
|
+
* - **data**: The validated class instance (not `value`)
|
|
2625
|
+
* - **value**: Always `undefined` (type narrowing aid)
|
|
2626
|
+
* - **errors**: Always `undefined` (type narrowing aid)
|
|
2627
|
+
*
|
|
2628
|
+
* ### Data Property
|
|
2629
|
+
* The `data` property contains the fully validated class instance with type `T`.
|
|
2630
|
+
* This is the instance you pass after decoration is complete.
|
|
2631
|
+
*
|
|
2632
|
+
* ```typescript
|
|
2633
|
+
* class UserForm {
|
|
2634
|
+
* @IsRequired()
|
|
2635
|
+
* @IsEmail()
|
|
2636
|
+
* email: string;
|
|
2637
|
+
*
|
|
2638
|
+
* @IsRequired()
|
|
2639
|
+
* @MinLength(3)
|
|
2640
|
+
* name: string;
|
|
2641
|
+
* }
|
|
2642
|
+
*
|
|
2643
|
+
* const result = await Validator.validateTarget(UserForm, {
|
|
2644
|
+
* email: "user@example.com",
|
|
2645
|
+
* name: "John",
|
|
2646
|
+
* });
|
|
2647
|
+
*
|
|
2648
|
+
* if (result.success) {
|
|
2649
|
+
* // result.data is UserForm instance
|
|
2650
|
+
* console.log(result.data.email); // "user@example.com"
|
|
2651
|
+
* console.log(result.data.name); // "John"
|
|
2652
|
+
*
|
|
2653
|
+
* // Timing information
|
|
2654
|
+
* console.log(result.validatedAt); // ISO timestamp
|
|
2655
|
+
* console.log(result.duration); // Milliseconds (approximately)
|
|
2656
|
+
* }
|
|
2657
|
+
* ```
|
|
2658
|
+
*
|
|
2659
|
+
* ### Comparison with Single-Value Success
|
|
2660
|
+
* | Aspect | Single-Value | Target |
|
|
2661
|
+
* |--------|-------------|--------|
|
|
2662
|
+
* | Property | `value` | `data` |
|
|
2663
|
+
* | Validates | One value | Multiple fields |
|
|
2664
|
+
* | Returns | Original value | Class instance |
|
|
2665
|
+
* | Error accumulation | Not applicable | Multiple errors collected |
|
|
2666
|
+
* | Use case | Single field | Entire form/object |
|
|
2667
|
+
*
|
|
2668
|
+
* ### Practical Usage
|
|
2669
|
+
* ```typescript
|
|
2670
|
+
* const form = new UserForm();
|
|
2671
|
+
* form.email = "user@example.com";
|
|
2672
|
+
* form.name = "John";
|
|
2673
|
+
*
|
|
2674
|
+
* const result = await Validator.validateTarget(UserForm, form);
|
|
2675
|
+
*
|
|
2676
|
+
* if (result.success) {
|
|
2677
|
+
* // Safe to use result.data
|
|
2678
|
+
* await saveUser(result.data);
|
|
2679
|
+
* console.log(`Validation took ${result.duration}ms`);
|
|
2680
|
+
* }
|
|
2681
|
+
* ```
|
|
2682
|
+
*
|
|
2683
|
+
* @template Context - Type of the optional validation context
|
|
2684
|
+
*
|
|
2685
|
+
* @public
|
|
2686
|
+
*
|
|
2687
|
+
* @see {@link ValidatorValidateTargetResult}
|
|
2688
|
+
* @see {@link ValidatorValidateSuccess} - Single-value equivalent
|
|
2689
|
+
* @see {@link Validator.validateTarget}
|
|
2690
|
+
*/
|
|
2691
|
+
export interface ValidatorValidateTargetSuccess<Context = unknown> extends Omit<BaseData<Context>, 'data'> {
|
|
2692
|
+
/** Discriminant for type narrowing - always `true` for success */
|
|
2693
|
+
success: true;
|
|
2694
|
+
message?: undefined;
|
|
2695
|
+
/**
|
|
2696
|
+
* Status indicator for this result
|
|
2697
|
+
*
|
|
2698
|
+
* Always "success" for successful validations. Provided for consistency with HTTP
|
|
2699
|
+
* and API conventions.
|
|
2700
|
+
*
|
|
2701
|
+
* @type {"success"}
|
|
2702
|
+
*/
|
|
2703
|
+
status: 'success';
|
|
2704
|
+
/**
|
|
2705
|
+
* ISO timestamp of when validation succeeded
|
|
2706
|
+
*
|
|
2707
|
+
* Indicates the exact time validation completed successfully.
|
|
2708
|
+
*
|
|
2709
|
+
* @type {Date | undefined}
|
|
2710
|
+
* @example new Date("2024-11-08T10:30:45.123Z")
|
|
2711
|
+
*/
|
|
2712
|
+
validatedAt?: Date;
|
|
2713
|
+
/**
|
|
2714
|
+
* Duration of validation in milliseconds
|
|
2715
|
+
*
|
|
2716
|
+
* Measures time from validation start until all fields completed validation.
|
|
2717
|
+
* Note: All fields are validated in parallel, so this is not the sum of individual field times.
|
|
2718
|
+
*
|
|
2719
|
+
* @type {number | undefined}
|
|
2720
|
+
* @example 23 (milliseconds)
|
|
2721
|
+
*/
|
|
2722
|
+
duration?: number;
|
|
2723
|
+
data: Dictionary;
|
|
2724
|
+
}
|
|
2725
|
+
/**
|
|
2726
|
+
* ## Class Validation Result Type (Discriminated Union)
|
|
2727
|
+
*
|
|
2728
|
+
* Discriminated union type representing the result of a {@link Validator.validateTarget} operation.
|
|
2729
|
+
* Can be either {@link ValidatorValidateTargetSuccess} or {@link ValidatorValidateTargetFailure}.
|
|
2730
|
+
*
|
|
2731
|
+
* ### Type Narrowing Strategies
|
|
2732
|
+
*
|
|
2733
|
+
* **Strategy 1: Check `success` property**
|
|
2734
|
+
* ```typescript
|
|
2735
|
+
* const result = await Validator.validateTarget(UserForm, data);
|
|
2736
|
+
*
|
|
2737
|
+
* if (result.success) {
|
|
2738
|
+
* // result is ValidatorValidateTargetSuccess<T>
|
|
2739
|
+
* console.log(result.data); // Class instance with all fields valid
|
|
2740
|
+
* console.log(result.validatedAt); // Validation timestamp
|
|
2741
|
+
* } else {
|
|
2742
|
+
* // result is ValidatorValidateTargetFailure
|
|
2743
|
+
* console.log(result.errors); // Array of field-level errors
|
|
2744
|
+
* console.log(result.failureCount); // Number of failed fields
|
|
2745
|
+
* }
|
|
2746
|
+
* ```
|
|
2747
|
+
*
|
|
2748
|
+
* **Strategy 2: Use switch statement**
|
|
2749
|
+
* ```typescript
|
|
2750
|
+
* switch (result.status) {
|
|
2751
|
+
* case "success":
|
|
2752
|
+
* // result is ValidatorValidateTargetSuccess
|
|
2753
|
+
* await saveToDatabase(result.data);
|
|
2754
|
+
* break;
|
|
2755
|
+
* case "error":
|
|
2756
|
+
* // result is ValidatorValidateTargetFailure
|
|
2757
|
+
* logErrors(result.errors);
|
|
2758
|
+
* break;
|
|
2759
|
+
* }
|
|
2760
|
+
* ```
|
|
2761
|
+
*
|
|
2762
|
+
* **Strategy 3: Use type guard helper**
|
|
2763
|
+
* ```typescript
|
|
2764
|
+
* if (Validator.isSuccess(result)) {
|
|
2765
|
+
* // result is ValidatorValidateTargetSuccess
|
|
2766
|
+
* return result.data;
|
|
2767
|
+
* }
|
|
2768
|
+
* // result is ValidatorValidateTargetFailure
|
|
2769
|
+
* throw new Error(result.message);
|
|
2770
|
+
* ```
|
|
2771
|
+
*
|
|
2772
|
+
* ### Comparison with Single-Value Result
|
|
2773
|
+
* | Aspect | Single-Value | Target |
|
|
2774
|
+
* |--------|-------------|--------|
|
|
2775
|
+
* | Success Property | `value` | `data` |
|
|
2776
|
+
* | On Failure | Single error | Array of errors |
|
|
2777
|
+
* | Type Param | One generic | Two generics (T, Context) |
|
|
2778
|
+
* | Use Case | Single field validation | Multiple field validation |
|
|
2779
|
+
*
|
|
2780
|
+
* ### Real-World Example
|
|
2781
|
+
* ```typescript
|
|
2782
|
+
* class RegistrationForm {
|
|
2783
|
+
* @IsRequired()
|
|
2784
|
+
* @IsEmail()
|
|
2785
|
+
* email: string;
|
|
2786
|
+
*
|
|
2787
|
+
* @IsRequired()
|
|
2788
|
+
* @MinLength(8)
|
|
2789
|
+
* password: string;
|
|
2790
|
+
*
|
|
2791
|
+
* @IsRequired()
|
|
2792
|
+
* @Equals([{{ value: "password" }}])
|
|
2793
|
+
* confirmPassword: string;
|
|
2794
|
+
* }
|
|
2795
|
+
*
|
|
2796
|
+
* const result = await Validator.validateTarget(RegistrationForm, {
|
|
2797
|
+
* email: "user@example.com",
|
|
2798
|
+
* password: "SecurePass123",
|
|
2799
|
+
* confirmPassword: "SecurePass123",
|
|
2800
|
+
* });
|
|
2801
|
+
*
|
|
2802
|
+
* if (result.success) {
|
|
2803
|
+
* // All validations passed
|
|
2804
|
+
* console.log("Ready to register:", result.data);
|
|
2805
|
+
* } else {
|
|
2806
|
+
* // Display field-level errors to user
|
|
2807
|
+
* result.errors.forEach(error => {
|
|
2808
|
+
* console.error(`[${error.propertyName}]: ${error.message}`);
|
|
2809
|
+
* });
|
|
2810
|
+
* }
|
|
2811
|
+
* ```
|
|
2812
|
+
*
|
|
2813
|
+
* ### Union Members
|
|
2814
|
+
* - {@link ValidatorValidateTargetSuccess} - When all fields pass (success: true)
|
|
2815
|
+
* - {@link ValidatorValidateTargetFailure} - When one or more fields fail (success: false)
|
|
2816
|
+
*
|
|
2817
|
+
* @template Context - Type of the optional validation context
|
|
2818
|
+
*
|
|
2819
|
+
* @public
|
|
2820
|
+
*
|
|
2821
|
+
* @see {@link ValidatorValidateTargetSuccess} - Success variant
|
|
2822
|
+
* @see {@link ValidatorValidateTargetFailure} - Failure variant
|
|
2823
|
+
* @see {@link Validator.validateTarget} - Main target validation method
|
|
2824
|
+
* @see {@link Validator.isSuccess} - Type guard for success
|
|
2825
|
+
* @see {@link Validator.isFailure} - Type guard for failure
|
|
2826
|
+
* @see {@link ValidatorValidateResult} - Single-value equivalent
|
|
2827
|
+
*/
|
|
2828
|
+
export type ValidatorValidateTargetResult<Context = unknown> = ValidatorValidateTargetSuccess<Context> | ValidatorValidateTargetFailure<Context>;
|
|
2829
|
+
/**
|
|
2830
|
+
* ## Validator Rule Functions Map
|
|
2831
|
+
*
|
|
2832
|
+
* A type-safe mapped type that creates a lookup table of validation rule names to their corresponding validation functions.
|
|
2833
|
+
* This mapped type provides compile-time guarantees that only valid rule names can be used as keys
|
|
2834
|
+
* to access their associated validation functions, preventing runtime errors from invalid rule lookups.
|
|
2835
|
+
*
|
|
2836
|
+
* ### Purpose
|
|
2837
|
+
* Serves as the central type definition for the validation rule function lookup table in the validator system.
|
|
2838
|
+
* Enables type-safe retrieval and execution of validation functions by their string names,
|
|
2839
|
+
* ensuring that each validation rule has a properly typed function with correct parameters and context.
|
|
2840
|
+
*
|
|
2841
|
+
* ### Type Structure
|
|
2842
|
+
* - **Key**: `ValidatorRuleName` - Valid rule names from {@link ValidatorRuleParamTypes}
|
|
2843
|
+
* - **Value**: `ValidatorRuleFunction<Params, Context>` - Corresponding validation function with proper typing
|
|
2844
|
+
* - **Mapped Type**: `[K in ValidatorRuleName]` ensures every rule name maps to its function
|
|
2845
|
+
*
|
|
2846
|
+
* ### Type Safety Benefits
|
|
2847
|
+
* - **Compile-time Validation**: Only valid rule names can be used as keys
|
|
2848
|
+
* - **Parameter Type Safety**: Each rule function has correctly typed parameters based on the rule
|
|
2849
|
+
* - **Context Propagation**: Context types are properly maintained throughout the validation pipeline
|
|
2850
|
+
* - **Function Signature Consistency**: Ensures all rule functions follow the same signature pattern
|
|
2851
|
+
*
|
|
2852
|
+
* ### Usage in Validator Class
|
|
2853
|
+
* This type is primarily used internally by the {@link Validator} class:
|
|
2854
|
+
* - {@link Validator.getRules} returns an instance of this mapped type
|
|
2855
|
+
* - {@link Validator.validateTarget} uses it to retrieve rule functions by name
|
|
2856
|
+
* - Rule execution methods access functions through this type-safe lookup table
|
|
2857
|
+
*
|
|
2858
|
+
* ### Example Structure
|
|
2859
|
+
* ```typescript
|
|
2860
|
+
* const rules: ValidatorRuleFunctionsMap = {
|
|
2861
|
+
* Required: (params, context) => {
|
|
2862
|
+
* // validation logic here
|
|
2863
|
+
* },
|
|
2864
|
+
* Email: (params, context) => {
|
|
2865
|
+
* // email validation logic
|
|
2866
|
+
* },
|
|
2867
|
+
* MinLength: ([minLen], context) => {
|
|
2868
|
+
* // length validation logic
|
|
2869
|
+
* },
|
|
2870
|
+
* // ... all other built-in rules
|
|
2871
|
+
* };
|
|
2872
|
+
* ```
|
|
2873
|
+
*
|
|
2874
|
+
* ### Relationship to Other Types
|
|
2875
|
+
* - **Source of Keys**: Keys come from {@link ValidatorRuleName} (derived from {@link ValidatorRuleParamTypes})
|
|
2876
|
+
* - **Function Signatures**: Values are {@link ValidatorRuleFunction} instances with proper generic parameters
|
|
2877
|
+
* - **Parameter Types**: Parameters typed via {@link ValidatorRuleParamTypes} lookups for each specific rule
|
|
2878
|
+
* - **Context**: Context type propagated from generic parameter throughout the validation system
|
|
2879
|
+
*
|
|
2880
|
+
* ### Runtime Usage
|
|
2881
|
+
* ```typescript
|
|
2882
|
+
* // Type-safe rule retrieval
|
|
2883
|
+
* const rules = Validator.getRules();
|
|
2884
|
+
* const emailRule = rules.Email; // ✓ Type-safe access
|
|
2885
|
+
* const unknownRule = rules.Unknown; // ✗ TypeScript error
|
|
2886
|
+
*
|
|
2887
|
+
* // Parameter type safety
|
|
2888
|
+
* const minLengthRule = rules.MinLength; // Function<[number], Context>
|
|
2889
|
+
* minLengthRule([5], context); // ✓ Correct parameter types
|
|
2890
|
+
* minLengthRule("5", context); // ✗ Type error
|
|
2891
|
+
* ```
|
|
2892
|
+
*
|
|
2893
|
+
* @template Context - Type of the optional validation context object
|
|
2894
|
+
*
|
|
2895
|
+
* @public
|
|
2896
|
+
*
|
|
2897
|
+
* @see {@link ValidatorRuleName} - Valid rule names (keys of this map)
|
|
2898
|
+
* @see {@link ValidatorRuleParamTypes} - Rule parameter definitions
|
|
2899
|
+
* @see {@link ValidatorRuleFunction} - Validation function signature
|
|
2900
|
+
* @see {@link Validator.getRules} - Method that returns this map
|
|
2901
|
+
* @see {@link Validator.validateTarget} - Method that uses this map
|
|
2902
|
+
*/
|
|
2903
|
+
export type ValidatorRuleFunctionsMap<Context = unknown> = {
|
|
2904
|
+
[K in ValidatorRuleName]: ValidatorRuleFunction<ValidatorRuleParamTypes<Context>[K], Context>;
|
|
2905
|
+
};
|
|
2906
|
+
export {};
|