validno 0.3.0 → 0.3.1
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 +517 -1
- package/dist/Schema.js +2 -1
- package/dist/constants/details.js +1 -0
- package/dist/dev.js +9 -56
- package/dist/engine/methods/validateRules.js +19 -4
- package/dist/engine/methods/validateType.js +14 -13
- package/dist/utils/errors.js +5 -5
- package/dist/utils/helpers.js +2 -4
- package/dist/utils/validations.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1 +1,517 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Validno
|
|
2
|
+
|
|
3
|
+
A lightweight and flexible TypeScript validation library for Node.js applications.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i validno
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import Schema from 'validno';
|
|
15
|
+
|
|
16
|
+
// Define your schema
|
|
17
|
+
const userSchema = new Schema({
|
|
18
|
+
name: {
|
|
19
|
+
type: String,
|
|
20
|
+
required: true,
|
|
21
|
+
rules: {
|
|
22
|
+
lengthMin: 2,
|
|
23
|
+
lengthMax: 50
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
email: {
|
|
27
|
+
type: String,
|
|
28
|
+
required: true,
|
|
29
|
+
rules: {
|
|
30
|
+
isEmail: true
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
age: {
|
|
34
|
+
type: Number,
|
|
35
|
+
required: false,
|
|
36
|
+
rules: {
|
|
37
|
+
min: 18,
|
|
38
|
+
max: 120
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Validate data
|
|
44
|
+
const userData = {
|
|
45
|
+
name: "Barney Stinson",
|
|
46
|
+
email: "barney@himym.com",
|
|
47
|
+
age: 35
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const result = userSchema.validate(userData);
|
|
51
|
+
|
|
52
|
+
if (result.ok) {
|
|
53
|
+
console.log('Validation passed!');
|
|
54
|
+
} else {
|
|
55
|
+
console.log('Errors:', result.errors);
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Features
|
|
60
|
+
|
|
61
|
+
- **Type Validation**: Support for built-in types (String, Number, Boolean, Array, Object, Date, RegExp) and custom types
|
|
62
|
+
- **Flexible Rules**: Comprehensive set of validation rules for strings, numbers, arrays, and custom logic
|
|
63
|
+
- **Nested Objects**: Full support for nested object validation
|
|
64
|
+
- **Custom Messages**: Define custom error messages for validation failures
|
|
65
|
+
- **Partial Validation**: Validate only specific keys when needed
|
|
66
|
+
- **TypeScript Support**: Written in TypeScript with full type definitions
|
|
67
|
+
|
|
68
|
+
## Schema Definition
|
|
69
|
+
|
|
70
|
+
### Basic Schema Structure
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
const schema = new Schema({
|
|
74
|
+
fieldName: {
|
|
75
|
+
type: String, // Required: field type
|
|
76
|
+
required: true, // Optional: whether field is required (default: true)
|
|
77
|
+
rules: {}, // Optional: validation rules
|
|
78
|
+
title: "Field Name", // Optional: human-readable field name (only used in custom messages for now)
|
|
79
|
+
customMessage: (details) => "Custom error" // Optional: custom error function
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Supported Types
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
const schema = new Schema({
|
|
88
|
+
stringField: { type: String },
|
|
89
|
+
numberField: { type: Number },
|
|
90
|
+
booleanField: { type: Boolean },
|
|
91
|
+
arrayField: { type: Array },
|
|
92
|
+
objectField: { type: Object },
|
|
93
|
+
dateField: { type: Date },
|
|
94
|
+
regexField: { type: RegExp },
|
|
95
|
+
nullField: { type: null },
|
|
96
|
+
|
|
97
|
+
// Union types (multiple allowed types)
|
|
98
|
+
mixedField: { type: [String, Number] },
|
|
99
|
+
|
|
100
|
+
// Custom classes
|
|
101
|
+
customField: { type: MyCustomClass },
|
|
102
|
+
|
|
103
|
+
// Any type
|
|
104
|
+
anyField: { type: 'any' }
|
|
105
|
+
});
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Array Type Validation
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
const schema = new Schema({
|
|
112
|
+
// Array of any items
|
|
113
|
+
items: { type: Array },
|
|
114
|
+
|
|
115
|
+
// Array where each item must be a specific type
|
|
116
|
+
numbers: {
|
|
117
|
+
type: Array,
|
|
118
|
+
eachType: Number,
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Validation Rules
|
|
124
|
+
|
|
125
|
+
### String Rules
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
const schema = new Schema({
|
|
129
|
+
text: {
|
|
130
|
+
type: String,
|
|
131
|
+
rules: {
|
|
132
|
+
// Length validations
|
|
133
|
+
length: 10, // Exact length
|
|
134
|
+
lengthMin: 5, // Minimum length
|
|
135
|
+
lengthMax: 100, // Maximum length
|
|
136
|
+
lengthMinMax: [5, 100], // Length range
|
|
137
|
+
lengthNot: 0, // Not this length
|
|
138
|
+
|
|
139
|
+
// Format validations
|
|
140
|
+
isEmail: true, // Valid email format
|
|
141
|
+
regex: /^[A-Z]+$/, // Custom regex pattern
|
|
142
|
+
|
|
143
|
+
// Value comparisons
|
|
144
|
+
is: "exact value", // Must equal this value
|
|
145
|
+
isNot: "forbidden" // Must not equal this value
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Number Rules
|
|
152
|
+
|
|
153
|
+
```javascript
|
|
154
|
+
const schema = new Schema({
|
|
155
|
+
count: {
|
|
156
|
+
type: Number,
|
|
157
|
+
rules: {
|
|
158
|
+
min: 0, // Minimum value (>=)
|
|
159
|
+
max: 100, // Maximum value (<=)
|
|
160
|
+
minMax: [0, 100], // Value range
|
|
161
|
+
is: 42, // Must equal this value
|
|
162
|
+
isNot: 0 // Must not equal this value
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Array Rules
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
const schema = new Schema({
|
|
172
|
+
items: {
|
|
173
|
+
type: Array,
|
|
174
|
+
rules: {
|
|
175
|
+
length: 5, // Exact length
|
|
176
|
+
lengthMin: 1, // Minimum length
|
|
177
|
+
lengthMax: 10, // Maximum length
|
|
178
|
+
lengthMinMax: [1, 10], // Length range
|
|
179
|
+
enum: ['a', 'b', 'c'] // All items must be from this list
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Custom Rules
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
const schema = new Schema({
|
|
189
|
+
password: {
|
|
190
|
+
type: String,
|
|
191
|
+
rules: {
|
|
192
|
+
custom: (value, { schema, input }) => {
|
|
193
|
+
// Custom validation logic
|
|
194
|
+
const hasUpperCase = /[A-Z]/.test(value);
|
|
195
|
+
const hasLowerCase = /[a-z]/.test(value);
|
|
196
|
+
const hasNumbers = /\d/.test(value);
|
|
197
|
+
|
|
198
|
+
const isPassed = hasUpperCase && hasLowerCase && hasNumbers
|
|
199
|
+
|
|
200
|
+
// Return true or false value...
|
|
201
|
+
return isPassed
|
|
202
|
+
|
|
203
|
+
// ...or provide details for the validation
|
|
204
|
+
return {
|
|
205
|
+
result: isPassed,
|
|
206
|
+
details: isPassed ? '' : "Password must contain an uppercase letter, a lowercase letter, and a number"
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Enum Validation
|
|
215
|
+
|
|
216
|
+
```javascript
|
|
217
|
+
const schema = new Schema({
|
|
218
|
+
status: {
|
|
219
|
+
type: String,
|
|
220
|
+
rules: {
|
|
221
|
+
enum: ['active', 'inactive', 'pending']
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Nested Objects
|
|
228
|
+
|
|
229
|
+
```javascript
|
|
230
|
+
const schema = new Schema({
|
|
231
|
+
user: {
|
|
232
|
+
name: {
|
|
233
|
+
type: String,
|
|
234
|
+
required: true
|
|
235
|
+
},
|
|
236
|
+
address: {
|
|
237
|
+
street: {
|
|
238
|
+
type: String,
|
|
239
|
+
required: true
|
|
240
|
+
},
|
|
241
|
+
city: {
|
|
242
|
+
type: String,
|
|
243
|
+
required: true
|
|
244
|
+
},
|
|
245
|
+
zipCode: {
|
|
246
|
+
type: String,
|
|
247
|
+
required: false,
|
|
248
|
+
rules: {
|
|
249
|
+
regex: /^\d{5}$/
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const data = {
|
|
257
|
+
user: {
|
|
258
|
+
name: "Barney Stinson",
|
|
259
|
+
address: {
|
|
260
|
+
street: "123 Main St",
|
|
261
|
+
city: "New York",
|
|
262
|
+
zipCode: "10001"
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const result = schema.validate(data);
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Custom Error Messages
|
|
271
|
+
|
|
272
|
+
### Field-Level Custom Messages
|
|
273
|
+
|
|
274
|
+
```javascript
|
|
275
|
+
const schema = new Schema({
|
|
276
|
+
email: {
|
|
277
|
+
type: String,
|
|
278
|
+
required: true,
|
|
279
|
+
rules: {
|
|
280
|
+
isEmail: true
|
|
281
|
+
},
|
|
282
|
+
customMessage: ({ keyword, value, key }) => {
|
|
283
|
+
if (keyword === 'isEmail') {
|
|
284
|
+
return `Please enter a valid email address for ${key}`;
|
|
285
|
+
}
|
|
286
|
+
return `Invalid value for ${key}`;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Custom Message Parameters
|
|
293
|
+
|
|
294
|
+
The `customMessage` function receives an object with:
|
|
295
|
+
- `keyword`: The validation rule that failed
|
|
296
|
+
- `value`: The actual value being validated
|
|
297
|
+
- `key`: The field name
|
|
298
|
+
- `title`: The field title (if specified)
|
|
299
|
+
- `reqs`: The field requirements object
|
|
300
|
+
- `schema`: The full schema object
|
|
301
|
+
- `rules`: The rules object for this field
|
|
302
|
+
|
|
303
|
+
## Partial Validation
|
|
304
|
+
|
|
305
|
+
Validate only specific fields:
|
|
306
|
+
|
|
307
|
+
```javascript
|
|
308
|
+
const schema = new Schema({
|
|
309
|
+
name: { type: String },
|
|
310
|
+
email: { type: String },
|
|
311
|
+
phone: { type: String }
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
const data = { name: "Barney", email: "barney@himym.com" };
|
|
315
|
+
|
|
316
|
+
// Validate only the name field
|
|
317
|
+
const nameResult = schema.validate(data, 'name');
|
|
318
|
+
|
|
319
|
+
// Validate only name and email fields
|
|
320
|
+
const partialResult = schema.validate(data, ['name', 'email']);
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Validation Result
|
|
324
|
+
|
|
325
|
+
The `validate` method returns a result object with:
|
|
326
|
+
|
|
327
|
+
```javascript
|
|
328
|
+
{
|
|
329
|
+
ok: boolean, // Overall validation success
|
|
330
|
+
passed: string[], // Array of field names that passed
|
|
331
|
+
failed: string[], // Array of field names that failed
|
|
332
|
+
missed: string[], // Array of required fields that were missing
|
|
333
|
+
errors: string[], // Array of all error messages
|
|
334
|
+
byKeys: { // Validation status by field name
|
|
335
|
+
fieldName: boolean
|
|
336
|
+
},
|
|
337
|
+
errorsByKeys: { // Error messages by field name
|
|
338
|
+
fieldName: string[]
|
|
339
|
+
},
|
|
340
|
+
joinErrors: (separator?) => string // Method to join all errors
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Using the Result
|
|
345
|
+
|
|
346
|
+
```javascript
|
|
347
|
+
const result = schema.validate(data);
|
|
348
|
+
|
|
349
|
+
if (result.ok) {
|
|
350
|
+
console.log('All validations passed!');
|
|
351
|
+
} else {
|
|
352
|
+
console.log('Failed fields:', result.failed);
|
|
353
|
+
console.log('Missing fields:', result.missed);
|
|
354
|
+
console.log('All errors:', result.joinErrors(', '));
|
|
355
|
+
|
|
356
|
+
// Check specific field
|
|
357
|
+
if (!result.byKeys.email) {
|
|
358
|
+
console.log('Email errors:', result.errorsByKeys.email);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## Built-in Validation Utilities
|
|
364
|
+
|
|
365
|
+
Validno exports validation utilities that you can use independently:
|
|
366
|
+
|
|
367
|
+
```javascript
|
|
368
|
+
import { validations } from 'validno';
|
|
369
|
+
|
|
370
|
+
// Type checks
|
|
371
|
+
validations.isString(value);
|
|
372
|
+
validations.isNumber(value);
|
|
373
|
+
validations.isArray(value);
|
|
374
|
+
validations.isObject(value);
|
|
375
|
+
validations.isDate(value);
|
|
376
|
+
validations.isBoolean(value);
|
|
377
|
+
|
|
378
|
+
// String format validation
|
|
379
|
+
validations.isEmail(email);
|
|
380
|
+
validations.isDateYYYYMMDD(dateString);
|
|
381
|
+
validations.isHex(colorCode);
|
|
382
|
+
|
|
383
|
+
// Length validation
|
|
384
|
+
validations.lengthIs(value, 5);
|
|
385
|
+
validations.lengthMin(value, 2);
|
|
386
|
+
validations.lengthMax(value, 10);
|
|
387
|
+
|
|
388
|
+
// Number comparisons
|
|
389
|
+
validations.isNumberGte(value, 10);
|
|
390
|
+
validations.isNumberLt(value, 100);
|
|
391
|
+
|
|
392
|
+
// Date comparisons
|
|
393
|
+
validations.isDateLte(date1, date2);
|
|
394
|
+
validations.isDateGt(date1, date2);
|
|
395
|
+
|
|
396
|
+
// Deep equality
|
|
397
|
+
validations.is(obj1, obj2);
|
|
398
|
+
validations.not(value1, value2);
|
|
399
|
+
|
|
400
|
+
// Regular expressions
|
|
401
|
+
validations.regexTested(string, /pattern/);
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
## Advanced Examples
|
|
405
|
+
|
|
406
|
+
### Complex Nested Validation
|
|
407
|
+
|
|
408
|
+
```javascript
|
|
409
|
+
const orderSchema = new Schema({
|
|
410
|
+
orderId: {
|
|
411
|
+
type: String,
|
|
412
|
+
required: true,
|
|
413
|
+
rules: {
|
|
414
|
+
regex: /^ORD-\d{6}$/
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
customer: {
|
|
418
|
+
id: {
|
|
419
|
+
type: Number,
|
|
420
|
+
required: true,
|
|
421
|
+
rules: {
|
|
422
|
+
min: 1
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
profile: {
|
|
426
|
+
firstName: {
|
|
427
|
+
type: String,
|
|
428
|
+
required: true,
|
|
429
|
+
rules: {
|
|
430
|
+
lengthMin: 2,
|
|
431
|
+
lengthMax: 50
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
lastName: {
|
|
435
|
+
type: String,
|
|
436
|
+
required: true,
|
|
437
|
+
rules: {
|
|
438
|
+
lengthMin: 2,
|
|
439
|
+
lengthMax: 50
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
email: {
|
|
443
|
+
type: String,
|
|
444
|
+
required: true,
|
|
445
|
+
rules: {
|
|
446
|
+
isEmail: true
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
},
|
|
451
|
+
items: {
|
|
452
|
+
type: Array,
|
|
453
|
+
eachType: Object,
|
|
454
|
+
required: true,
|
|
455
|
+
rules: {
|
|
456
|
+
lengthMin: 1
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
totalAmount: {
|
|
460
|
+
type: Number,
|
|
461
|
+
required: true,
|
|
462
|
+
rules: {
|
|
463
|
+
min: 0.01
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
status: {
|
|
467
|
+
type: String,
|
|
468
|
+
required: true,
|
|
469
|
+
rules: {
|
|
470
|
+
enum: ['pending', 'processing', 'shipped', 'delivered', 'cancelled']
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
## TypeScript Support
|
|
477
|
+
|
|
478
|
+
Validno is written in TypeScript and provides full type definitions:
|
|
479
|
+
|
|
480
|
+
```typescript
|
|
481
|
+
import Schema from 'validno';
|
|
482
|
+
import { SchemaDefinition, FieldSchema } from 'validno';
|
|
483
|
+
|
|
484
|
+
interface User {
|
|
485
|
+
name: string;
|
|
486
|
+
email: string;
|
|
487
|
+
age?: number;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
const userSchema = new Schema({
|
|
491
|
+
name: {
|
|
492
|
+
type: String,
|
|
493
|
+
required: true
|
|
494
|
+
} as FieldSchema,
|
|
495
|
+
email: {
|
|
496
|
+
type: String,
|
|
497
|
+
required: true,
|
|
498
|
+
rules: {
|
|
499
|
+
isEmail: true
|
|
500
|
+
}
|
|
501
|
+
} as FieldSchema,
|
|
502
|
+
age: {
|
|
503
|
+
type: Number,
|
|
504
|
+
required: false
|
|
505
|
+
} as FieldSchema
|
|
506
|
+
} as SchemaDefinition);
|
|
507
|
+
|
|
508
|
+
const newUser = {
|
|
509
|
+
name: "Barney",
|
|
510
|
+
email: "barney@himym.com",
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// Use generic type...
|
|
514
|
+
const result = userSchema.validate<User>(newUser, ['name', 'email'])
|
|
515
|
+
|
|
516
|
+
// ...or use automatic type inference based on the object
|
|
517
|
+
const result = userSchema.validate(newUser, ['name', 'email'])
|
package/dist/Schema.js
CHANGED
|
@@ -10,6 +10,7 @@ export class Schema {
|
|
|
10
10
|
}
|
|
11
11
|
validate(inputData, validationKeys) {
|
|
12
12
|
const engine = new ValidateEngine(this.definition);
|
|
13
|
-
|
|
13
|
+
const result = engine.validate(inputData, validationKeys);
|
|
14
|
+
return result;
|
|
14
15
|
}
|
|
15
16
|
}
|
package/dist/dev.js
CHANGED
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import Schema from './index.js';
|
|
2
|
-
const
|
|
2
|
+
const userSchema = new Schema({
|
|
3
3
|
name: {
|
|
4
4
|
type: String,
|
|
5
5
|
required: true
|
|
6
6
|
},
|
|
7
|
-
lastVisit: {
|
|
8
|
-
type: Date,
|
|
9
|
-
required: true,
|
|
10
|
-
},
|
|
11
|
-
age: {
|
|
12
|
-
type: Number,
|
|
13
|
-
required: true,
|
|
14
|
-
},
|
|
15
7
|
email: {
|
|
16
8
|
type: String,
|
|
17
9
|
required: true,
|
|
@@ -19,52 +11,13 @@ const schema = new Schema({
|
|
|
19
11
|
isEmail: true
|
|
20
12
|
}
|
|
21
13
|
},
|
|
22
|
-
|
|
23
|
-
type:
|
|
24
|
-
required:
|
|
25
|
-
}
|
|
26
|
-
friends: {
|
|
27
|
-
type: Array,
|
|
28
|
-
required: true,
|
|
29
|
-
eachType: String,
|
|
30
|
-
},
|
|
31
|
-
broRegex: {
|
|
32
|
-
type: RegExp,
|
|
33
|
-
required: true,
|
|
34
|
-
},
|
|
35
|
-
socials: {
|
|
36
|
-
x: {
|
|
37
|
-
type: String,
|
|
38
|
-
required: false
|
|
39
|
-
},
|
|
40
|
-
instagram: {
|
|
41
|
-
type: String,
|
|
42
|
-
required: false
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
nullableField: {
|
|
46
|
-
type: null,
|
|
47
|
-
required: false,
|
|
48
|
-
},
|
|
14
|
+
age: {
|
|
15
|
+
type: Number,
|
|
16
|
+
required: false
|
|
17
|
+
}
|
|
49
18
|
});
|
|
50
|
-
const
|
|
51
|
-
name:
|
|
52
|
-
|
|
53
|
-
lastVisit: new Date('2025-05-05'),
|
|
54
|
-
email: 'legggen@dary.com',
|
|
55
|
-
isAwesome: true,
|
|
56
|
-
friends: [
|
|
57
|
-
'Ted Mosby',
|
|
58
|
-
'Marshall Eriksen',
|
|
59
|
-
'Lily Aldrin',
|
|
60
|
-
'Robin Scherbatsky'
|
|
61
|
-
],
|
|
62
|
-
socials: {
|
|
63
|
-
x: '@barney_stinson',
|
|
64
|
-
insstagram: '@barney_stinson'
|
|
65
|
-
},
|
|
66
|
-
broRegex: /bro/i,
|
|
67
|
-
deletedAt: null,
|
|
19
|
+
const newUser = {
|
|
20
|
+
name: "Barney",
|
|
21
|
+
email: "barney@himym.com",
|
|
68
22
|
};
|
|
69
|
-
const
|
|
70
|
-
console.log(validation);
|
|
23
|
+
const result = userSchema.validate(newUser, 'age');
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import _validations from "../../utils/validations.js";
|
|
2
|
+
import { ValidationDetails } from "../../constants/details.js";
|
|
2
3
|
export const rulesParams = {
|
|
3
4
|
lengthMin: {
|
|
4
5
|
allowedTypes: [String]
|
|
@@ -13,7 +14,21 @@ const ensureRuleHasCorrectType = (value, allowedTypes) => {
|
|
|
13
14
|
};
|
|
14
15
|
const rulesFunctions = {
|
|
15
16
|
custom: (key, val, func, extra) => {
|
|
16
|
-
|
|
17
|
+
const customResult = func(val, extra);
|
|
18
|
+
if (typeof customResult === 'object' && 'result' in customResult) {
|
|
19
|
+
return {
|
|
20
|
+
result: customResult.result,
|
|
21
|
+
details: customResult.details || ValidationDetails.CustomRuleFailed,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (typeof customResult === 'boolean') {
|
|
25
|
+
return {
|
|
26
|
+
result: customResult,
|
|
27
|
+
details: customResult ? "" : ValidationDetails.CustomRuleFailed
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
throw new Error(`Custom rule function must return an object with 'result' and 'details' properties or a boolean value. Received: ${typeof customResult}`);
|
|
31
|
+
return;
|
|
17
32
|
},
|
|
18
33
|
isEmail: (key, val) => {
|
|
19
34
|
return {
|
|
@@ -110,7 +125,7 @@ const rulesFunctions = {
|
|
|
110
125
|
return output;
|
|
111
126
|
}
|
|
112
127
|
};
|
|
113
|
-
function
|
|
128
|
+
function checkRules(key, value, requirements, inputObj) {
|
|
114
129
|
const result = {
|
|
115
130
|
ok: true,
|
|
116
131
|
details: []
|
|
@@ -133,7 +148,7 @@ function unnamed(key, value, requirements, inputObj) {
|
|
|
133
148
|
}
|
|
134
149
|
const func = rulesFunctions[ruleName];
|
|
135
150
|
const args = rules[ruleName];
|
|
136
|
-
|
|
151
|
+
let result = func(key, value, args, { schema: this.schema, input: inputObj });
|
|
137
152
|
if (requirements.customMessage && typeof requirements.customMessage === 'function') {
|
|
138
153
|
result.details = requirements.customMessage({
|
|
139
154
|
keyword: ruleName,
|
|
@@ -158,7 +173,7 @@ function unnamed(key, value, requirements, inputObj) {
|
|
|
158
173
|
;
|
|
159
174
|
function validateRules(input) {
|
|
160
175
|
const { results, nestedKey, value, reqs, data, rulesChecked } = input;
|
|
161
|
-
const ruleCheck =
|
|
176
|
+
const ruleCheck = checkRules.call(this, nestedKey, value, reqs, data);
|
|
162
177
|
if (!ruleCheck.ok) {
|
|
163
178
|
rulesChecked.push(false);
|
|
164
179
|
ruleCheck.details.forEach((el) => {
|
|
@@ -20,33 +20,34 @@ const validateUnionType = (key, value, requirements, keyName = key) => {
|
|
|
20
20
|
};
|
|
21
21
|
const handleTypeValidation = (key, value, requirements, keyName = key) => {
|
|
22
22
|
var _a;
|
|
23
|
+
const reqs = Object.assign({ required: true }, requirements);
|
|
23
24
|
const isNotNull = value !== null;
|
|
24
|
-
const keyTitle = 'title' in
|
|
25
|
-
const hasCustomMessage =
|
|
26
|
-
if (value === undefined &&
|
|
25
|
+
const keyTitle = 'title' in reqs && reqs.title !== undefined ? reqs.title : keyName;
|
|
26
|
+
const hasCustomMessage = reqs.customMessage && typeof reqs.customMessage === 'function';
|
|
27
|
+
if (value === undefined && reqs.required) {
|
|
27
28
|
return [_validateType.getResult(keyName, false, _errors.getMissingError(keyName))];
|
|
28
29
|
}
|
|
29
|
-
if (Array.isArray(
|
|
30
|
-
return [validateUnionType(key, value,
|
|
30
|
+
if (Array.isArray(reqs.type)) {
|
|
31
|
+
return [validateUnionType(key, value, reqs)];
|
|
31
32
|
}
|
|
32
|
-
if (value === undefined &&
|
|
33
|
+
if (value === undefined && reqs.required === false) {
|
|
33
34
|
return [_validateType.getResult(keyName, true)];
|
|
34
35
|
}
|
|
35
36
|
const customErrDetails = hasCustomMessage ?
|
|
36
|
-
|
|
37
|
+
reqs.customMessage({
|
|
37
38
|
keyword: ValidationIds.Type,
|
|
38
39
|
value: value,
|
|
39
40
|
key: keyName,
|
|
40
41
|
title: keyTitle,
|
|
41
|
-
reqs:
|
|
42
|
-
schema:
|
|
42
|
+
reqs: reqs,
|
|
43
|
+
schema: {}
|
|
43
44
|
}) :
|
|
44
45
|
null;
|
|
45
|
-
const baseErrDetails = _errors.getErrorDetails(keyName,
|
|
46
|
+
const baseErrDetails = _errors.getErrorDetails(keyName, reqs.type, value);
|
|
46
47
|
const getDetails = (isOK, errorText) => isOK ?
|
|
47
48
|
ValidationDetails.OK :
|
|
48
49
|
errorText || customErrDetails || baseErrDetails;
|
|
49
|
-
const typeBySchema =
|
|
50
|
+
const typeBySchema = reqs.type;
|
|
50
51
|
const result = [];
|
|
51
52
|
switch (typeBySchema) {
|
|
52
53
|
case 'any': {
|
|
@@ -82,9 +83,9 @@ const handleTypeValidation = (key, value, requirements, keyName = key) => {
|
|
|
82
83
|
break;
|
|
83
84
|
}
|
|
84
85
|
let isEachChecked = { passed: true, details: "" };
|
|
85
|
-
if ('eachType' in
|
|
86
|
+
if ('eachType' in reqs) {
|
|
86
87
|
for (const el of value) {
|
|
87
|
-
const result = handleTypeValidation(`each of ${key}`, el, { type:
|
|
88
|
+
const result = handleTypeValidation(`each of ${key}`, el, { type: reqs.eachType, required: true });
|
|
88
89
|
if (!result[0].passed) {
|
|
89
90
|
isEachChecked.passed = false;
|
|
90
91
|
isEachChecked.details = result[0].details || '';
|
package/dist/utils/errors.js
CHANGED
|
@@ -5,17 +5,17 @@ class ErrorUtility {
|
|
|
5
5
|
getErrorDetails(key, expectedType, receivedValue) {
|
|
6
6
|
const receivedType = this.getTypeString(receivedValue);
|
|
7
7
|
const expectedOutput = this.getExpectedTypeString(expectedType);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
if (expectedOutput === receivedType) {
|
|
9
|
+
return '';
|
|
10
|
+
}
|
|
11
11
|
return `Check the type of '${key}': expected ${expectedOutput}, received ${receivedType}`;
|
|
12
12
|
}
|
|
13
13
|
joinErrors(errorsArr, separator = '; ') {
|
|
14
|
-
|
|
14
|
+
var _a;
|
|
15
15
|
return ((_a = errorsArr === null || errorsArr === void 0 ? void 0 : errorsArr.filter(error => error === null || error === void 0 ? void 0 : error.trim())) === null || _a === void 0 ? void 0 : _a.join(separator)) || '';
|
|
16
16
|
}
|
|
17
17
|
getTypeString(value) {
|
|
18
|
-
|
|
18
|
+
var _a;
|
|
19
19
|
if (value === undefined)
|
|
20
20
|
return 'undefined';
|
|
21
21
|
if (value === null)
|
package/dist/utils/helpers.js
CHANGED
|
@@ -27,10 +27,8 @@ class HelperUtility {
|
|
|
27
27
|
}
|
|
28
28
|
hasMissing(input) {
|
|
29
29
|
const { reqs, data, key } = input;
|
|
30
|
-
const isRequired =
|
|
31
|
-
const missingData = (data === undefined ||
|
|
32
|
-
!(key in data) ||
|
|
33
|
-
data[key] === undefined);
|
|
30
|
+
const isRequired = reqs.required === undefined || reqs.required === true;
|
|
31
|
+
const missingData = (data === undefined || !(key in data) || data[key] === undefined);
|
|
34
32
|
return isRequired && missingData;
|
|
35
33
|
}
|
|
36
34
|
compareArrs(v1, v2) {
|
|
@@ -10,7 +10,7 @@ class ValidationUtility {
|
|
|
10
10
|
return Array.isArray(value);
|
|
11
11
|
}
|
|
12
12
|
isObject(value) {
|
|
13
|
-
|
|
13
|
+
var _a;
|
|
14
14
|
return value !== null &&
|
|
15
15
|
typeof value === 'object' &&
|
|
16
16
|
((_a = value === null || value === void 0 ? void 0 : value.constructor) === null || _a === void 0 ? void 0 : _a.name) === 'Object' &&
|