@cleverbrush/schema 0.0.9 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -0
- package/dist/schemaValidator.d.ts +4 -1
- package/dist/schemaValidator.js +10 -0
- package/dist/validators/validateArray.js +11 -0
- package/dist/validators/validateObject.js +14 -0
- package/package.json +2 -2
- package/src/index.ts +19 -0
- package/src/schemaValidator.test.ts +255 -1
- package/src/schemaValidator.ts +23 -4
- package/src/validators/validateArray.ts +13 -0
- package/src/validators/validateObject.ts +24 -0
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,9 @@ export declare type ObjectSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'>
|
|
|
23
23
|
properties?: Partial<{
|
|
24
24
|
[S in keyof T]: Schema<PropType<T, S>>;
|
|
25
25
|
}>;
|
|
26
|
+
preprocessors?: Partial<{
|
|
27
|
+
[S in keyof T | '*']: S extends keyof T ? ((value: unknown) => PropType<T, S> | Promise<PropType<T, S>>) | string : (value: T) => void | Promise<void>;
|
|
28
|
+
}>;
|
|
26
29
|
};
|
|
27
30
|
export declare type AliasSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'> & {
|
|
28
31
|
type: 'alias';
|
|
@@ -53,6 +56,7 @@ export declare type StringSchemaDefinition<TObj> = Omit<SchemaDefintion<TObj>, '
|
|
|
53
56
|
};
|
|
54
57
|
export declare type ArraySchemaDefinition<TObj> = Omit<SchemaDefintion<TObj>, 'type'> & {
|
|
55
58
|
type: 'array';
|
|
59
|
+
preprocessor?: ((value: unknown) => unknown | Promise<unknown>) | string;
|
|
56
60
|
ofType?: Schema<any>;
|
|
57
61
|
minLength?: number;
|
|
58
62
|
maxLength?: number;
|
|
@@ -70,6 +74,8 @@ export interface ISchemasProvider<T = Record<string, never>> {
|
|
|
70
74
|
};
|
|
71
75
|
}
|
|
72
76
|
export interface ISchemaValidator<T = Record<string, never>> {
|
|
77
|
+
get preprocessors(): Map<string, (value: unknown) => unknown | Promise<unknown>>;
|
|
78
|
+
addPreprocessor(name: string, preprocessor: (value: unknown) => unknown | Promise<unknown>): SchemaValidator<T>;
|
|
73
79
|
addSchemaType<K, L extends ObjectSchemaDefinitionParam<M>, M = any>(name: keyof K, schema: L | Array<Schema<any>>): SchemaValidator<T & {
|
|
74
80
|
[key in keyof K]: typeof schema;
|
|
75
81
|
}>;
|
|
@@ -2,6 +2,9 @@ import { ISchemasProvider, Schema, ISchemaActions, ObjectSchemaDefinitionParam,
|
|
|
2
2
|
export default class SchemaValidator<T = Record<string, never>> implements ISchemasProvider<T>, ISchemaValidator<T> {
|
|
3
3
|
private _schemasMap;
|
|
4
4
|
private _schemasCache;
|
|
5
|
+
private _preprocessorsMap;
|
|
6
|
+
get preprocessors(): Map<string, (value: unknown) => unknown>;
|
|
7
|
+
addPreprocessor(name: string, preprocessor: (value: unknown) => unknown | Promise<unknown>): SchemaValidator<T>;
|
|
5
8
|
addSchemaType<K, L extends ObjectSchemaDefinitionParam<M>, M = any>(name: keyof K, schema: L | Array<Schema<any>>): SchemaValidator<T & {
|
|
6
9
|
[key in keyof K]: L;
|
|
7
10
|
}>;
|
|
@@ -10,5 +13,5 @@ export default class SchemaValidator<T = Record<string, never>> implements ISche
|
|
|
10
13
|
};
|
|
11
14
|
private validateDefaultType;
|
|
12
15
|
private checkValidators;
|
|
13
|
-
validate(schema: keyof T | DefaultSchemaType | Schema<
|
|
16
|
+
validate<K>(schema: keyof T | DefaultSchemaType | Schema<K>, obj: any): Promise<ValidationResult>;
|
|
14
17
|
}
|
package/dist/schemaValidator.js
CHANGED
|
@@ -37,6 +37,16 @@ const isDefaultType = (name) => defaultSchemaNames.indexOf(name) !== -1;
|
|
|
37
37
|
class SchemaValidator {
|
|
38
38
|
_schemasMap = new Map();
|
|
39
39
|
_schemasCache = null;
|
|
40
|
+
_preprocessorsMap = new Map();
|
|
41
|
+
get preprocessors() {
|
|
42
|
+
return this._preprocessorsMap;
|
|
43
|
+
}
|
|
44
|
+
addPreprocessor(name, preprocessor) {
|
|
45
|
+
if (this._preprocessorsMap.has(name))
|
|
46
|
+
throw new Error(`Preprocessor '${name}' is already registered`);
|
|
47
|
+
this._preprocessorsMap.set(name, preprocessor);
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
40
50
|
addSchemaType(name, schema) {
|
|
41
51
|
if (typeof name !== 'string' || !name)
|
|
42
52
|
throw new Error('Name is required');
|
|
@@ -14,6 +14,17 @@ const validateArray = async (obj, schema, validator) => {
|
|
|
14
14
|
valid: false,
|
|
15
15
|
errors: ['expected type array']
|
|
16
16
|
};
|
|
17
|
+
if (schema.preprocessor) {
|
|
18
|
+
const preprocessor = typeof schema.preprocessor === 'function'
|
|
19
|
+
? schema.preprocessor
|
|
20
|
+
: validator.preprocessors.get(schema.preprocessor);
|
|
21
|
+
if (typeof preprocessor !== 'function') {
|
|
22
|
+
throw new Error(`unknown preprocessor '${schema.preprocessor}'`);
|
|
23
|
+
}
|
|
24
|
+
for (let i = 0; i < obj.length; i++) {
|
|
25
|
+
obj[i] = await Promise.resolve(preprocessor(obj[i]));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
17
28
|
if (typeof schema.minLength === 'number' && obj.length < schema.minLength) {
|
|
18
29
|
return {
|
|
19
30
|
valid: false,
|
|
@@ -17,6 +17,20 @@ const validateObject = async (obj, schema, validator) => {
|
|
|
17
17
|
]
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
|
+
if (typeof schema.preprocessors === 'object' && schema.preprocessors) {
|
|
21
|
+
await Promise.all(Object.keys(schema.preprocessors).map(async (key) => {
|
|
22
|
+
if (typeof schema.preprocessors[key] === 'function') {
|
|
23
|
+
obj[key] = await Promise.resolve(schema.preprocessors[key](key === '*' ? obj : obj[key]));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
const preprocessor = validator.preprocessors.get(schema.preprocessors[key]);
|
|
27
|
+
if (typeof preprocessor !== 'function') {
|
|
28
|
+
throw new Error(`preprocessor '${schema.preprocessors[key]}' is unknown`);
|
|
29
|
+
}
|
|
30
|
+
obj[key] = await Promise.resolve(preprocessor(obj[key]));
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
20
34
|
if (typeof schema.properties === 'object' && schema.properties) {
|
|
21
35
|
const errors = (await Promise.all(Object.entries(schema.properties).map(async ([name, schema]) => {
|
|
22
36
|
const result = await validator.validate(schema, obj[name]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cleverbrush/schema",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"object schema validator",
|
|
6
6
|
"schema",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"build": "tsc"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@cleverbrush/deep": "0.0.
|
|
22
|
+
"@cleverbrush/deep": "0.0.12"
|
|
23
23
|
},
|
|
24
24
|
"types": "./dist/index.d.ts"
|
|
25
25
|
}
|
package/src/index.ts
CHANGED
|
@@ -39,6 +39,15 @@ export type ObjectSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'> & {
|
|
|
39
39
|
properties?: Partial<{
|
|
40
40
|
[S in keyof T]: Schema<PropType<T, S>>;
|
|
41
41
|
}>;
|
|
42
|
+
preprocessors?: Partial<{
|
|
43
|
+
[S in keyof T | '*']: S extends keyof T
|
|
44
|
+
?
|
|
45
|
+
| ((
|
|
46
|
+
value: unknown
|
|
47
|
+
) => PropType<T, S> | Promise<PropType<T, S>>)
|
|
48
|
+
| string
|
|
49
|
+
: (value: T) => void | Promise<void>;
|
|
50
|
+
}>;
|
|
42
51
|
};
|
|
43
52
|
|
|
44
53
|
export type AliasSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'> & {
|
|
@@ -91,6 +100,7 @@ export type ArraySchemaDefinition<TObj> = Omit<
|
|
|
91
100
|
'type'
|
|
92
101
|
> & {
|
|
93
102
|
type: 'array';
|
|
103
|
+
preprocessor?: ((value: unknown) => unknown | Promise<unknown>) | string;
|
|
94
104
|
ofType?: Schema<any>;
|
|
95
105
|
minLength?: number;
|
|
96
106
|
maxLength?: number;
|
|
@@ -129,6 +139,15 @@ export interface ISchemasProvider<T = Record<string, never>> {
|
|
|
129
139
|
}
|
|
130
140
|
|
|
131
141
|
export interface ISchemaValidator<T = Record<string, never>> {
|
|
142
|
+
get preprocessors(): Map<
|
|
143
|
+
string,
|
|
144
|
+
(value: unknown) => unknown | Promise<unknown>
|
|
145
|
+
>;
|
|
146
|
+
addPreprocessor(
|
|
147
|
+
name: string,
|
|
148
|
+
preprocessor: (value: unknown) => unknown | Promise<unknown>
|
|
149
|
+
): SchemaValidator<T>;
|
|
150
|
+
|
|
132
151
|
addSchemaType<K, L extends ObjectSchemaDefinitionParam<M>, M = any>(
|
|
133
152
|
name: keyof K,
|
|
134
153
|
schema: L | Array<Schema<any>>
|
|
@@ -4,6 +4,7 @@ import { ValidationResult } from '../dist/index.js';
|
|
|
4
4
|
import {
|
|
5
5
|
NumberSchemaDefinition,
|
|
6
6
|
ObjectSchemaDefinitionParam,
|
|
7
|
+
ObjectSchemaDefinition,
|
|
7
8
|
Schema
|
|
8
9
|
} from './index';
|
|
9
10
|
import SchemaValidator from './schemaValidator';
|
|
@@ -829,7 +830,7 @@ test('Validate - object - 1', async () => {
|
|
|
829
830
|
b: 'number'
|
|
830
831
|
},
|
|
831
832
|
validators: [
|
|
832
|
-
(value) => {
|
|
833
|
+
(value: { a: number; b: number }) => {
|
|
833
834
|
if (value.a + value.b === 5) {
|
|
834
835
|
return {
|
|
835
836
|
valid: true
|
|
@@ -1202,3 +1203,256 @@ test('Not required alternative schema alias', async () => {
|
|
|
1202
1203
|
|
|
1203
1204
|
expect(result).toHaveProperty('valid', false);
|
|
1204
1205
|
});
|
|
1206
|
+
|
|
1207
|
+
test('Preprocessors - 1', async () => {
|
|
1208
|
+
const validator = new SchemaValidator().addSchemaType('Date', {
|
|
1209
|
+
validators: [
|
|
1210
|
+
(value) =>
|
|
1211
|
+
value instanceof Date && !Number.isNaN(value)
|
|
1212
|
+
? {
|
|
1213
|
+
valid: true
|
|
1214
|
+
}
|
|
1215
|
+
: {
|
|
1216
|
+
valid: false,
|
|
1217
|
+
errors: ['should be a valid Date object']
|
|
1218
|
+
}
|
|
1219
|
+
]
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1222
|
+
const schema: Schema<{ bornAt: Date }> = {
|
|
1223
|
+
type: 'object',
|
|
1224
|
+
properties: {
|
|
1225
|
+
bornAt: 'Date'
|
|
1226
|
+
},
|
|
1227
|
+
preprocessors: {
|
|
1228
|
+
bornAt: (value: unknown): Date => {
|
|
1229
|
+
const time = Date.parse(value.toString());
|
|
1230
|
+
if (Number.isNaN(time)) return undefined;
|
|
1231
|
+
return new Date(time);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
};
|
|
1235
|
+
|
|
1236
|
+
const result = await validator.validate(schema, {
|
|
1237
|
+
bornAt: new Date().toJSON()
|
|
1238
|
+
});
|
|
1239
|
+
expect(result).toHaveProperty('valid', true);
|
|
1240
|
+
});
|
|
1241
|
+
|
|
1242
|
+
test('Preprocessors - 2', async () => {
|
|
1243
|
+
const validator = new SchemaValidator().addSchemaType('Date', {
|
|
1244
|
+
validators: [
|
|
1245
|
+
(value) =>
|
|
1246
|
+
value instanceof Date && !Number.isNaN(value)
|
|
1247
|
+
? {
|
|
1248
|
+
valid: true
|
|
1249
|
+
}
|
|
1250
|
+
: {
|
|
1251
|
+
valid: false,
|
|
1252
|
+
errors: ['should be a valid Date object']
|
|
1253
|
+
}
|
|
1254
|
+
]
|
|
1255
|
+
});
|
|
1256
|
+
|
|
1257
|
+
let schema: Schema<{ bornAt: Date; diedAt?: Date }> = {
|
|
1258
|
+
type: 'object',
|
|
1259
|
+
properties: {
|
|
1260
|
+
bornAt: 'Date'
|
|
1261
|
+
},
|
|
1262
|
+
preprocessors: {
|
|
1263
|
+
bornAt: 'StringToDate'
|
|
1264
|
+
}
|
|
1265
|
+
};
|
|
1266
|
+
|
|
1267
|
+
validator.addPreprocessor('StringToDate', (value: unknown): Date => {
|
|
1268
|
+
const time = Date.parse(value.toString());
|
|
1269
|
+
if (Number.isNaN(time)) return undefined;
|
|
1270
|
+
return new Date(time);
|
|
1271
|
+
});
|
|
1272
|
+
|
|
1273
|
+
expect(() =>
|
|
1274
|
+
validator.addPreprocessor('StringToDate', (value: unknown): Date => {
|
|
1275
|
+
const time = Date.parse(value.toString());
|
|
1276
|
+
if (Number.isNaN(time)) return undefined;
|
|
1277
|
+
return new Date(time);
|
|
1278
|
+
})
|
|
1279
|
+
).toThrow();
|
|
1280
|
+
|
|
1281
|
+
const result = await validator.validate(schema, {
|
|
1282
|
+
bornAt: new Date().toJSON()
|
|
1283
|
+
});
|
|
1284
|
+
expect(result).toHaveProperty('valid', true);
|
|
1285
|
+
|
|
1286
|
+
schema = {
|
|
1287
|
+
type: 'object',
|
|
1288
|
+
properties: {
|
|
1289
|
+
bornAt: 'Date',
|
|
1290
|
+
diedAt: 'Date'
|
|
1291
|
+
},
|
|
1292
|
+
preprocessors: {
|
|
1293
|
+
bornAt: 'StringToDate',
|
|
1294
|
+
diedAt: 'Unregistered'
|
|
1295
|
+
}
|
|
1296
|
+
};
|
|
1297
|
+
expect(async () => {
|
|
1298
|
+
await validator.validate(schema, {
|
|
1299
|
+
bornAt: new Date().toJSON()
|
|
1300
|
+
});
|
|
1301
|
+
}).rejects.toBeInstanceOf(Error);
|
|
1302
|
+
});
|
|
1303
|
+
|
|
1304
|
+
test('Preprocessors - 3', async () => {
|
|
1305
|
+
const validator = new SchemaValidator().addSchemaType('Date', {
|
|
1306
|
+
validators: [
|
|
1307
|
+
(value) =>
|
|
1308
|
+
value instanceof Date && !Number.isNaN(value)
|
|
1309
|
+
? {
|
|
1310
|
+
valid: true
|
|
1311
|
+
}
|
|
1312
|
+
: {
|
|
1313
|
+
valid: false,
|
|
1314
|
+
errors: ['should be a valid Date object']
|
|
1315
|
+
}
|
|
1316
|
+
]
|
|
1317
|
+
});
|
|
1318
|
+
|
|
1319
|
+
validator.addPreprocessor('StringToDate', (value: unknown): Date => {
|
|
1320
|
+
const time = Date.parse(value.toString());
|
|
1321
|
+
if (Number.isNaN(time)) return undefined;
|
|
1322
|
+
return new Date(time);
|
|
1323
|
+
});
|
|
1324
|
+
|
|
1325
|
+
let obj = [new Date().toJSON()];
|
|
1326
|
+
|
|
1327
|
+
let result = await validator.validate(
|
|
1328
|
+
{
|
|
1329
|
+
preprocessor: 'StringToDate',
|
|
1330
|
+
type: 'array',
|
|
1331
|
+
ofType: 'Date'
|
|
1332
|
+
},
|
|
1333
|
+
obj
|
|
1334
|
+
);
|
|
1335
|
+
expect(result).toHaveProperty('valid', true);
|
|
1336
|
+
|
|
1337
|
+
obj = [new Date().toJSON()];
|
|
1338
|
+
result = await validator.validate(
|
|
1339
|
+
{
|
|
1340
|
+
preprocessor: (value: unknown): Date => {
|
|
1341
|
+
const time = Date.parse(value.toString());
|
|
1342
|
+
if (Number.isNaN(time)) return undefined;
|
|
1343
|
+
return new Date(time);
|
|
1344
|
+
},
|
|
1345
|
+
type: 'array',
|
|
1346
|
+
ofType: 'Date'
|
|
1347
|
+
},
|
|
1348
|
+
obj
|
|
1349
|
+
);
|
|
1350
|
+
expect(result).toHaveProperty('valid', true);
|
|
1351
|
+
|
|
1352
|
+
obj = ['sdfsdf12', new Date().toJSON()];
|
|
1353
|
+
result = await validator.validate(
|
|
1354
|
+
{
|
|
1355
|
+
preprocessor: (value: unknown): Date => {
|
|
1356
|
+
const time = Date.parse(value.toString());
|
|
1357
|
+
if (Number.isNaN(time)) return undefined;
|
|
1358
|
+
return new Date(time);
|
|
1359
|
+
},
|
|
1360
|
+
type: 'array',
|
|
1361
|
+
ofType: 'Date'
|
|
1362
|
+
},
|
|
1363
|
+
obj
|
|
1364
|
+
);
|
|
1365
|
+
expect(result).toHaveProperty('valid', false);
|
|
1366
|
+
});
|
|
1367
|
+
|
|
1368
|
+
test('Preprocessors - 3', async () => {
|
|
1369
|
+
const validator = new SchemaValidator();
|
|
1370
|
+
|
|
1371
|
+
type SomeType = { age: number; marriedAt: number };
|
|
1372
|
+
|
|
1373
|
+
const schema: ObjectSchemaDefinition<SomeType> = {
|
|
1374
|
+
type: 'object',
|
|
1375
|
+
properties: {
|
|
1376
|
+
age: 'number',
|
|
1377
|
+
marriedAt: 'number'
|
|
1378
|
+
},
|
|
1379
|
+
preprocessors: {
|
|
1380
|
+
'*': (value: SomeType): void => {
|
|
1381
|
+
if (value.marriedAt > value.age) {
|
|
1382
|
+
value.marriedAt = value.age;
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
};
|
|
1387
|
+
|
|
1388
|
+
const obj = {
|
|
1389
|
+
age: 50,
|
|
1390
|
+
marriedAt: 80
|
|
1391
|
+
};
|
|
1392
|
+
await validator.validate(schema, obj);
|
|
1393
|
+
expect(obj).toHaveProperty('marriedAt', 50);
|
|
1394
|
+
});
|
|
1395
|
+
|
|
1396
|
+
test('Preprocessors - 4', async () => {
|
|
1397
|
+
const validator = new SchemaValidator().addSchemaType('Date', {
|
|
1398
|
+
validators: [
|
|
1399
|
+
(value) =>
|
|
1400
|
+
value instanceof Date && !Number.isNaN(value)
|
|
1401
|
+
? {
|
|
1402
|
+
valid: true
|
|
1403
|
+
}
|
|
1404
|
+
: {
|
|
1405
|
+
valid: false,
|
|
1406
|
+
errors: ['should be a valid Date object']
|
|
1407
|
+
}
|
|
1408
|
+
]
|
|
1409
|
+
});
|
|
1410
|
+
|
|
1411
|
+
validator.addPreprocessor('StringToDate', (value: unknown): Date => {
|
|
1412
|
+
const time = Date.parse(value.toString());
|
|
1413
|
+
if (Number.isNaN(time)) return undefined;
|
|
1414
|
+
return new Date(time);
|
|
1415
|
+
});
|
|
1416
|
+
|
|
1417
|
+
let obj = [new Date().toJSON()];
|
|
1418
|
+
|
|
1419
|
+
let result = await validator.validate(
|
|
1420
|
+
{
|
|
1421
|
+
preprocessor: 'StringToDate',
|
|
1422
|
+
type: 'array',
|
|
1423
|
+
ofType: 'Date'
|
|
1424
|
+
},
|
|
1425
|
+
obj
|
|
1426
|
+
);
|
|
1427
|
+
expect(result).toHaveProperty('valid', true);
|
|
1428
|
+
|
|
1429
|
+
obj = [new Date().toJSON()];
|
|
1430
|
+
result = await validator.validate(
|
|
1431
|
+
{
|
|
1432
|
+
preprocessor: (value: unknown): Date => {
|
|
1433
|
+
const time = Date.parse(value.toString());
|
|
1434
|
+
if (Number.isNaN(time)) return undefined;
|
|
1435
|
+
return new Date(time);
|
|
1436
|
+
},
|
|
1437
|
+
type: 'array',
|
|
1438
|
+
ofType: 'Date'
|
|
1439
|
+
},
|
|
1440
|
+
obj
|
|
1441
|
+
);
|
|
1442
|
+
expect(result).toHaveProperty('valid', true);
|
|
1443
|
+
|
|
1444
|
+
obj = ['sdfsdf12', new Date().toJSON()];
|
|
1445
|
+
result = await validator.validate(
|
|
1446
|
+
{
|
|
1447
|
+
preprocessor: (value: unknown): Date => {
|
|
1448
|
+
const time = Date.parse(value.toString());
|
|
1449
|
+
if (Number.isNaN(time)) return undefined;
|
|
1450
|
+
return new Date(time);
|
|
1451
|
+
},
|
|
1452
|
+
type: 'array',
|
|
1453
|
+
ofType: 'Date'
|
|
1454
|
+
},
|
|
1455
|
+
obj
|
|
1456
|
+
);
|
|
1457
|
+
expect(result).toHaveProperty('valid', false);
|
|
1458
|
+
});
|
package/src/schemaValidator.ts
CHANGED
|
@@ -12,7 +12,8 @@ import {
|
|
|
12
12
|
ArraySchemaDefinition,
|
|
13
13
|
ISchemaValidator,
|
|
14
14
|
DefaultSchemaType,
|
|
15
|
-
ObjectSchemaDefinition
|
|
15
|
+
ObjectSchemaDefinition,
|
|
16
|
+
SchemaDefintion
|
|
16
17
|
} from './index';
|
|
17
18
|
import { validateNumber } from './validators/validateNumber';
|
|
18
19
|
import { validateString } from './validators/validateString';
|
|
@@ -70,6 +71,24 @@ export default class SchemaValidator<T = Record<string, never>>
|
|
|
70
71
|
{
|
|
71
72
|
private _schemasMap = new Map<string, Schema<any>>();
|
|
72
73
|
private _schemasCache: { [K in keyof T]: ISchemaActions<T, K> } = null;
|
|
74
|
+
private _preprocessorsMap = new Map<
|
|
75
|
+
string,
|
|
76
|
+
(value: unknown) => unknown | Promise<unknown>
|
|
77
|
+
>();
|
|
78
|
+
|
|
79
|
+
public get preprocessors(): Map<string, (value: unknown) => unknown> {
|
|
80
|
+
return this._preprocessorsMap;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public addPreprocessor(
|
|
84
|
+
name: string,
|
|
85
|
+
preprocessor: (value: unknown) => unknown | Promise<unknown>
|
|
86
|
+
): SchemaValidator<T> {
|
|
87
|
+
if (this._preprocessorsMap.has(name))
|
|
88
|
+
throw new Error(`Preprocessor '${name}' is already registered`);
|
|
89
|
+
this._preprocessorsMap.set(name, preprocessor);
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
73
92
|
|
|
74
93
|
public addSchemaType<K, L extends ObjectSchemaDefinitionParam<M>, M = any>(
|
|
75
94
|
name: keyof K,
|
|
@@ -195,8 +214,8 @@ export default class SchemaValidator<T = Record<string, never>>
|
|
|
195
214
|
};
|
|
196
215
|
}
|
|
197
216
|
|
|
198
|
-
public async validate(
|
|
199
|
-
schema: keyof T | DefaultSchemaType | Schema<
|
|
217
|
+
public async validate<K>(
|
|
218
|
+
schema: keyof T | DefaultSchemaType | Schema<K>,
|
|
200
219
|
obj: any
|
|
201
220
|
): Promise<ValidationResult> {
|
|
202
221
|
if (!schema) throw new Error('schemaName is required');
|
|
@@ -275,7 +294,7 @@ export default class SchemaValidator<T = Record<string, never>>
|
|
|
275
294
|
'it is only possible to use a full schema schema definition as alias'
|
|
276
295
|
);
|
|
277
296
|
|
|
278
|
-
const schemaToMerge = { ...schema };
|
|
297
|
+
const schemaToMerge = { ...(schema as any) };
|
|
279
298
|
delete schemaToMerge.type;
|
|
280
299
|
delete schemaToMerge.schemaName;
|
|
281
300
|
const finalSchema: Schema<any> = deepExtend(
|
|
@@ -24,6 +24,19 @@ export const validateArray = async (
|
|
|
24
24
|
errors: ['expected type array']
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
if (schema.preprocessor) {
|
|
28
|
+
const preprocessor =
|
|
29
|
+
typeof schema.preprocessor === 'function'
|
|
30
|
+
? schema.preprocessor
|
|
31
|
+
: validator.preprocessors.get(schema.preprocessor);
|
|
32
|
+
if (typeof preprocessor !== 'function') {
|
|
33
|
+
throw new Error(`unknown preprocessor '${schema.preprocessor}'`);
|
|
34
|
+
}
|
|
35
|
+
for (let i = 0; i < obj.length; i++) {
|
|
36
|
+
obj[i] = await Promise.resolve(preprocessor(obj[i]));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
27
40
|
if (typeof schema.minLength === 'number' && obj.length < schema.minLength) {
|
|
28
41
|
return {
|
|
29
42
|
valid: false,
|
|
@@ -28,6 +28,30 @@ export const validateObject = async (
|
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
if (typeof schema.preprocessors === 'object' && schema.preprocessors) {
|
|
32
|
+
await Promise.all(
|
|
33
|
+
Object.keys(schema.preprocessors).map(async (key: string) => {
|
|
34
|
+
if (typeof schema.preprocessors[key] === 'function') {
|
|
35
|
+
obj[key] = await Promise.resolve(
|
|
36
|
+
(schema.preprocessors[key] as (unknown) => unknown)(
|
|
37
|
+
key === '*' ? obj : obj[key]
|
|
38
|
+
)
|
|
39
|
+
);
|
|
40
|
+
} else {
|
|
41
|
+
const preprocessor = validator.preprocessors.get(
|
|
42
|
+
schema.preprocessors[key] as string
|
|
43
|
+
);
|
|
44
|
+
if (typeof preprocessor !== 'function') {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`preprocessor '${schema.preprocessors[key]}' is unknown`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
obj[key] = await Promise.resolve(preprocessor(obj[key]));
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
31
55
|
if (typeof schema.properties === 'object' && schema.properties) {
|
|
32
56
|
const errors = (
|
|
33
57
|
await Promise.all(
|