@cleverbrush/schema 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +279 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.js +9 -0
- package/dist/schemaValidator.d.ts +14 -0
- package/dist/schemaValidator.js +170 -0
- package/dist/validators/validateArray.d.ts +2 -0
- package/dist/validators/validateArray.js +49 -0
- package/dist/validators/validateNumber.d.ts +2 -0
- package/dist/validators/validateNumber.js +69 -0
- package/dist/validators/validateObject.d.ts +2 -0
- package/dist/validators/validateObject.js +44 -0
- package/dist/validators/validateString.d.ts +2 -0
- package/dist/validators/validateString.js +50 -0
- package/package.json +20 -0
- package/src/index.ts +137 -0
- package/src/schemaValidator.test.ts +887 -0
- package/src/schemaValidator.ts +256 -0
- package/src/validators/validateArray.ts +66 -0
- package/src/validators/validateNumber.ts +87 -0
- package/src/validators/validateObject.ts +65 -0
- package/src/validators/validateString.ts +64 -0
- package/tsconfig.json +16 -0
package/README.md
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# Object Schema Validator
|
|
2
|
+
|
|
3
|
+
This package contains utilities to validate the JavaScript object's schema. There is only one class exported - `SchemaValidator`
|
|
4
|
+
|
|
5
|
+
## Schema Types
|
|
6
|
+
|
|
7
|
+
There are several schema types available:
|
|
8
|
+
|
|
9
|
+
- object
|
|
10
|
+
- string
|
|
11
|
+
- number
|
|
12
|
+
- array
|
|
13
|
+
- function (_TBD_)
|
|
14
|
+
|
|
15
|
+
Schemas could be either described by shortcusts (string value from the list above) or by more detailed specification.
|
|
16
|
+
|
|
17
|
+
## Schema Definitions
|
|
18
|
+
|
|
19
|
+
### Common for all types
|
|
20
|
+
|
|
21
|
+
Any schema defined by object can contain the following fields:
|
|
22
|
+
|
|
23
|
+
- `type` - schema type (see the list above)
|
|
24
|
+
- `isRequired` - defines if `undefined` value is considered valid
|
|
25
|
+
- `isNullable` - defines if `null` value is considered valid
|
|
26
|
+
- `validators` - optional array of custom validation functions (see [Examples](#examples))
|
|
27
|
+
|
|
28
|
+
### Number
|
|
29
|
+
|
|
30
|
+
`number` schema can be defined as follows:
|
|
31
|
+
|
|
32
|
+
import { SchemaValidator } from '@cleverbrush/schema';
|
|
33
|
+
const validator = new SchemaValidator();
|
|
34
|
+
|
|
35
|
+
// validates for integer number between 1 and 100
|
|
36
|
+
let result = await validator.validate(
|
|
37
|
+
{
|
|
38
|
+
type: "number",
|
|
39
|
+
isInteger: true,
|
|
40
|
+
min: 1,
|
|
41
|
+
max: 100,
|
|
42
|
+
},
|
|
43
|
+
10
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
All fields available (apart of common fields for all schemas) are:
|
|
47
|
+
|
|
48
|
+
- `isInteger` - ensures that number is integer
|
|
49
|
+
- `ensureIsFinite` - ensures that nubmer is finite
|
|
50
|
+
- `ensureNotNaN` - ensures that number is not NaN
|
|
51
|
+
- `equals` - checks if a value is equal to provided number
|
|
52
|
+
- `min` - checks if a value is bigger or equal than a provided lower bound
|
|
53
|
+
- `max` - checks if a value is lower or equal than a provided upper bound
|
|
54
|
+
|
|
55
|
+
Also it can be defined either by shortcut:
|
|
56
|
+
|
|
57
|
+
import { SchemaValidator } from '@cleverbrush/schema';
|
|
58
|
+
const validator = new SchemaValidator();
|
|
59
|
+
let result = await validator.validate('number', 10);
|
|
60
|
+
// { valid: true }
|
|
61
|
+
result = await validator.validate('number', 'some string');
|
|
62
|
+
// { valid: false, errors: [ 'expected type number, but saw string' ] }
|
|
63
|
+
|
|
64
|
+
which is equal to:
|
|
65
|
+
|
|
66
|
+
import { SchemaValidator } from '@cleverbrush/schema';
|
|
67
|
+
const validator = new SchemaValidator();
|
|
68
|
+
let result = await validator.validate({
|
|
69
|
+
type: 'number',
|
|
70
|
+
isRequired: true,
|
|
71
|
+
isNullable: false,
|
|
72
|
+
ensureNotNaN: true,
|
|
73
|
+
ensureIsFinite: true
|
|
74
|
+
}, 0 / 0);
|
|
75
|
+
// { valid: false }
|
|
76
|
+
|
|
77
|
+
### String
|
|
78
|
+
|
|
79
|
+
`string` schema can be defined as follows:
|
|
80
|
+
|
|
81
|
+
import { SchemaValidator } from '@cleverbrush/schema';
|
|
82
|
+
const validator = new SchemaValidator();
|
|
83
|
+
|
|
84
|
+
// validates for non empty string no longer than 100 chars
|
|
85
|
+
let result = await validator.validate(
|
|
86
|
+
{
|
|
87
|
+
type: "string",
|
|
88
|
+
minLength: 1,
|
|
89
|
+
maxLength: 100
|
|
90
|
+
},
|
|
91
|
+
"some value here"
|
|
92
|
+
);
|
|
93
|
+
// { valid: true }
|
|
94
|
+
|
|
95
|
+
All fields available (apart of common fields for all schemas) are:
|
|
96
|
+
|
|
97
|
+
- `equals` - checks if value is equal to provided string
|
|
98
|
+
- `minLength` - checks if value is at least `minLength` characters long
|
|
99
|
+
- `maxLength` - checks if value is at most `maxLength` characters long
|
|
100
|
+
|
|
101
|
+
Also it can be defined either by shortcut:
|
|
102
|
+
|
|
103
|
+
import { SchemaValidator } from '@cleverbrush/schema';
|
|
104
|
+
const validator = new SchemaValidator();
|
|
105
|
+
let result = await validator.validate('string', 'something');
|
|
106
|
+
// { valid: true }
|
|
107
|
+
result = await validator.validate('string', 10);
|
|
108
|
+
// { valid: false, errors: [ 'expected type string, but saw number' ] }
|
|
109
|
+
|
|
110
|
+
which is equal to:
|
|
111
|
+
|
|
112
|
+
import { SchemaValidator } from '@cleverbrush/schema';
|
|
113
|
+
const validator = new SchemaValidator();
|
|
114
|
+
let result = await validator.validate({
|
|
115
|
+
type: 'string',
|
|
116
|
+
isNullable: false,
|
|
117
|
+
isRequired: true
|
|
118
|
+
}, 1230);
|
|
119
|
+
// { valid: false }
|
|
120
|
+
|
|
121
|
+
### Array
|
|
122
|
+
|
|
123
|
+
`array` schema can be defined as follows:
|
|
124
|
+
|
|
125
|
+
import { SchemaValidator } from '@cleverbrush/schema';
|
|
126
|
+
const validator = new SchemaValidator();
|
|
127
|
+
|
|
128
|
+
// validates for non empty string no longer than 100 chars
|
|
129
|
+
let result = await validator.validate(
|
|
130
|
+
{
|
|
131
|
+
type: "array",
|
|
132
|
+
minLength: 5,
|
|
133
|
+
maxLength: 10,
|
|
134
|
+
ofType: {
|
|
135
|
+
type: "number",
|
|
136
|
+
min: 1,
|
|
137
|
+
max: 10
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
[5, 6, 7, 8, 9]
|
|
141
|
+
);
|
|
142
|
+
// { valid: true }
|
|
143
|
+
|
|
144
|
+
All fields available (apart of common fields for all schemas) are:
|
|
145
|
+
|
|
146
|
+
- `ofType` - here you can pass the `schema` and all array elements will be checked to match this schema
|
|
147
|
+
- `minLength` - checks if array is at least `minLength` elements long
|
|
148
|
+
- `maxLength` - checks if array is at most `maxLength` elements long
|
|
149
|
+
|
|
150
|
+
Also it can be defined either by shortcut:
|
|
151
|
+
|
|
152
|
+
import { SchemaValidator } from '@cleverbrush/schema';
|
|
153
|
+
const validator = new SchemaValidator();
|
|
154
|
+
let result = await validator.validate('array', []);
|
|
155
|
+
// { valid: true }
|
|
156
|
+
result = await validator.validate('array', 10);
|
|
157
|
+
// { valid: false, errors: [ 'expected array' ] }
|
|
158
|
+
|
|
159
|
+
which is equal to:
|
|
160
|
+
|
|
161
|
+
import { SchemaValidator } from '@cleverbrush/schema';
|
|
162
|
+
const validator = new SchemaValidator();
|
|
163
|
+
let result = await validator.validate({
|
|
164
|
+
type: 'array'
|
|
165
|
+
}, 1230);
|
|
166
|
+
// { valid: false, errors: [ 'expected array' ] }
|
|
167
|
+
|
|
168
|
+
### Object
|
|
169
|
+
|
|
170
|
+
`object` type allows to define a complex object schema. For example:
|
|
171
|
+
|
|
172
|
+
await validator.validate(
|
|
173
|
+
{
|
|
174
|
+
type: "object",
|
|
175
|
+
properties: {
|
|
176
|
+
id: "number",
|
|
177
|
+
name: {
|
|
178
|
+
type: "string",
|
|
179
|
+
minLength: 1,
|
|
180
|
+
maxLength: 100,
|
|
181
|
+
},
|
|
182
|
+
address: {
|
|
183
|
+
type: "object",
|
|
184
|
+
properties: {
|
|
185
|
+
city: "string",
|
|
186
|
+
street: {
|
|
187
|
+
type: "string",
|
|
188
|
+
isRequired: false,
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
id: 10,
|
|
196
|
+
name: "Andrew",
|
|
197
|
+
address: {
|
|
198
|
+
city: "Madrid",
|
|
199
|
+
},
|
|
200
|
+
}
|
|
201
|
+
);
|
|
202
|
+
// {valid: true}
|
|
203
|
+
|
|
204
|
+
All fields available are:
|
|
205
|
+
|
|
206
|
+
- `properties` - the list of properties, every property has corresponding schema definition (see example above).
|
|
207
|
+
|
|
208
|
+
## Alternative schema
|
|
209
|
+
|
|
210
|
+
Everywhere you pass a `schema` object to the library, you may pass an array of `schema` objects which will validate the object to match at least one schema from this list.
|
|
211
|
+
For example, if you want to check that array is consisting either from number or from `{ name: string, value: number }` objects, you can do the following:
|
|
212
|
+
|
|
213
|
+
await validator.validate(
|
|
214
|
+
{
|
|
215
|
+
type: "array",
|
|
216
|
+
ofType: [
|
|
217
|
+
"number",
|
|
218
|
+
{
|
|
219
|
+
type: "object",
|
|
220
|
+
properties: {
|
|
221
|
+
name: "string",
|
|
222
|
+
value: "number",
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
},
|
|
227
|
+
[
|
|
228
|
+
10,
|
|
229
|
+
{ name: "something", value: 1 },
|
|
230
|
+
100,
|
|
231
|
+
{ name: "another string", value: 1 },
|
|
232
|
+
]
|
|
233
|
+
);
|
|
234
|
+
// {valid: true}
|
|
235
|
+
|
|
236
|
+
## Named schemas
|
|
237
|
+
|
|
238
|
+
There is a possibility to register a schema, give it a name and then reuse it:
|
|
239
|
+
|
|
240
|
+
const validator = new SchemaValidator().addSchemaType("Address", {
|
|
241
|
+
properties: {
|
|
242
|
+
id: {
|
|
243
|
+
type: "number",
|
|
244
|
+
min: 1,
|
|
245
|
+
},
|
|
246
|
+
street: "string",
|
|
247
|
+
zip: "number",
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
await validator.validate(
|
|
252
|
+
{
|
|
253
|
+
type: "object",
|
|
254
|
+
properties: {
|
|
255
|
+
name: "string",
|
|
256
|
+
address1: "Address",
|
|
257
|
+
address2: "Address",
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
name: "Andrew",
|
|
262
|
+
address1: {
|
|
263
|
+
id: 1,
|
|
264
|
+
street: "some street",
|
|
265
|
+
zip: 12345,
|
|
266
|
+
},
|
|
267
|
+
address2: {
|
|
268
|
+
id: 2,
|
|
269
|
+
street: "some street 2",
|
|
270
|
+
zip: 3456,
|
|
271
|
+
},
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
|
|
275
|
+
// { valid: true }
|
|
276
|
+
|
|
277
|
+
## Examples {#examples}
|
|
278
|
+
|
|
279
|
+
For Examples see unit tests in the schemaValidator.tests.ts
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import SchemaValidator from './schemaValidator';
|
|
2
|
+
export declare type DefaultSchemaType = 'object' | 'function' | 'number' | 'string' | 'array';
|
|
3
|
+
export declare type PropType<TObj, TProp extends keyof TObj> = TObj[TProp];
|
|
4
|
+
export declare type DefaultPropertyDefinition = {
|
|
5
|
+
isRequired: boolean;
|
|
6
|
+
isNullable: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare type ValidationResultRaw = {
|
|
9
|
+
valid: boolean;
|
|
10
|
+
errors?: Array<string>;
|
|
11
|
+
};
|
|
12
|
+
export declare type ValidationResult = ValidationResultRaw | Promise<ValidationResultRaw>;
|
|
13
|
+
export declare type Validator<TObj> = (value: TObj) => ValidationResult;
|
|
14
|
+
export declare type SchemaDefintion<TObj> = {
|
|
15
|
+
type: DefaultSchemaType;
|
|
16
|
+
isRequired?: boolean;
|
|
17
|
+
isNullable?: boolean;
|
|
18
|
+
validators?: Array<Validator<TObj>>;
|
|
19
|
+
};
|
|
20
|
+
export declare type ObjectSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'> & {
|
|
21
|
+
type: 'object';
|
|
22
|
+
extends?: string;
|
|
23
|
+
properties?: Partial<{
|
|
24
|
+
[S in keyof T]: Schema<PropType<T, S>>;
|
|
25
|
+
}>;
|
|
26
|
+
};
|
|
27
|
+
export declare type ObjectSchemaDefinitionParam<T> = Omit<ObjectSchemaDefinition<T>, 'type'>;
|
|
28
|
+
export declare type ParamsValidators<TFunc extends (...args: any) => any> = {
|
|
29
|
+
[S in keyof Parameters<TFunc>]: SingleSchema<Parameters<TFunc>[S]>;
|
|
30
|
+
};
|
|
31
|
+
export declare type FunctionSchemaDefinition<T extends (...args: any) => any> = Omit<SchemaDefintion<T>, 'type'> & {
|
|
32
|
+
type: 'function';
|
|
33
|
+
params?: ParamsValidators<T>;
|
|
34
|
+
};
|
|
35
|
+
export declare type NumberSchemaDefinition<TObj> = Omit<SchemaDefintion<TObj>, 'type'> & {
|
|
36
|
+
type: 'number';
|
|
37
|
+
min?: number;
|
|
38
|
+
max?: number;
|
|
39
|
+
equals?: number;
|
|
40
|
+
isInteger?: boolean;
|
|
41
|
+
ensureNotNaN?: boolean;
|
|
42
|
+
ensureIsFinite?: boolean;
|
|
43
|
+
};
|
|
44
|
+
export declare type StringSchemaDefinition<TObj> = Omit<SchemaDefintion<TObj>, 'type'> & {
|
|
45
|
+
type: 'string';
|
|
46
|
+
equals?: string;
|
|
47
|
+
minLength?: number;
|
|
48
|
+
maxLength?: number;
|
|
49
|
+
};
|
|
50
|
+
export declare type ArraySchemaDefinition<TObj> = Omit<SchemaDefintion<TObj>, 'type'> & {
|
|
51
|
+
type: 'array';
|
|
52
|
+
ofType?: Schema<any>;
|
|
53
|
+
minLength?: number;
|
|
54
|
+
maxLength?: number;
|
|
55
|
+
};
|
|
56
|
+
export declare type CompositeSchema<TObj> = TObj extends (...args: any) => any ? FunctionSchemaDefinition<TObj> : TObj extends number ? NumberSchemaDefinition<TObj> : TObj extends string ? StringSchemaDefinition<TObj> | 'string' : NumberSchemaDefinition<TObj> | StringSchemaDefinition<TObj> | ArraySchemaDefinition<TObj> | ObjectSchemaDefinition<TObj>;
|
|
57
|
+
export declare type SingleSchema<TObj = Record<string, never>> = number | string | DefaultSchemaType | CompositeSchema<TObj>;
|
|
58
|
+
export declare type Schema<TObj> = SingleSchema<TObj> | Array<SingleSchema<TObj>>;
|
|
59
|
+
export interface ISchemaActions<K, T extends keyof K> {
|
|
60
|
+
validate(value: any): Promise<ValidationResult>;
|
|
61
|
+
schema: PropType<K, T>;
|
|
62
|
+
}
|
|
63
|
+
export interface ISchemasProvider<T = Record<string, never>> {
|
|
64
|
+
schemas: {
|
|
65
|
+
[K in keyof T]: ISchemaActions<T, K>;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export interface ISchemaValidator<T = Record<string, never>> {
|
|
69
|
+
addSchemaType<K, L extends ObjectSchemaDefinitionParam<M>, M = any>(name: keyof K, schema: L): SchemaValidator<T & {
|
|
70
|
+
[key in keyof K]: L;
|
|
71
|
+
}>;
|
|
72
|
+
validate(schema: keyof T | DefaultSchemaType | Schema<any>, obj: any): Promise<ValidationResult>;
|
|
73
|
+
}
|
|
74
|
+
export { SchemaValidator };
|
|
75
|
+
export default SchemaValidator;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SchemaValidator = void 0;
|
|
7
|
+
const schemaValidator_1 = __importDefault(require("./schemaValidator"));
|
|
8
|
+
exports.SchemaValidator = schemaValidator_1.default;
|
|
9
|
+
exports.default = schemaValidator_1.default;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ISchemasProvider, Schema, ISchemaActions, ObjectSchemaDefinitionParam, ValidationResult, ISchemaValidator, DefaultSchemaType } from './index';
|
|
2
|
+
export default class SchemaValidator<T = Record<string, never>> implements ISchemasProvider<T>, ISchemaValidator<T> {
|
|
3
|
+
private _schemasMap;
|
|
4
|
+
private _schemasCache;
|
|
5
|
+
addSchemaType<K, L extends ObjectSchemaDefinitionParam<M>, M = any>(name: keyof K, schema: L): SchemaValidator<T & {
|
|
6
|
+
[key in keyof K]: L;
|
|
7
|
+
}>;
|
|
8
|
+
get schemas(): {
|
|
9
|
+
[K in keyof T]: ISchemaActions<T, K>;
|
|
10
|
+
};
|
|
11
|
+
private validateDefaultType;
|
|
12
|
+
private checkValidators;
|
|
13
|
+
validate(schema: keyof T | DefaultSchemaType | Schema<any>, obj: any): Promise<ValidationResult>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const deep_1 = require("@cleverbrush/deep");
|
|
4
|
+
const validateNumber_1 = require("./validators/validateNumber");
|
|
5
|
+
const validateString_1 = require("./validators/validateString");
|
|
6
|
+
const validateArray_1 = require("./validators/validateArray");
|
|
7
|
+
const validateObject_1 = require("./validators/validateObject");
|
|
8
|
+
const defaultSchemaNames = ['string', 'number', 'date', 'array'];
|
|
9
|
+
const defaultSchemas = {
|
|
10
|
+
number: {
|
|
11
|
+
type: 'number',
|
|
12
|
+
isRequired: true,
|
|
13
|
+
isNullable: false,
|
|
14
|
+
ensureNotNaN: true,
|
|
15
|
+
ensureIsFinite: true
|
|
16
|
+
},
|
|
17
|
+
string: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
isNullable: false,
|
|
20
|
+
isRequired: true
|
|
21
|
+
},
|
|
22
|
+
array: {
|
|
23
|
+
type: 'array'
|
|
24
|
+
},
|
|
25
|
+
object: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
isNullable: false,
|
|
28
|
+
isRequired: true
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const defaultSchemasValidationStrategies = {
|
|
32
|
+
number: (obj, schema, validator) => (0, validateNumber_1.validateNumber)(obj, schema, validator),
|
|
33
|
+
string: (obj, schema, validator) => (0, validateString_1.validateString)(obj, schema, validator),
|
|
34
|
+
array: (obj, schema, validator) => (0, validateArray_1.validateArray)(obj, schema, validator)
|
|
35
|
+
};
|
|
36
|
+
const isDefaultType = (name) => defaultSchemaNames.indexOf(name) !== -1;
|
|
37
|
+
class SchemaValidator {
|
|
38
|
+
_schemasMap = new Map();
|
|
39
|
+
_schemasCache = null;
|
|
40
|
+
addSchemaType(name, schema) {
|
|
41
|
+
if (typeof name !== 'string' || !name)
|
|
42
|
+
throw new Error('Name is required');
|
|
43
|
+
if (typeof schema !== 'object')
|
|
44
|
+
throw new Error('Object is required');
|
|
45
|
+
if (isDefaultType(name.toString()))
|
|
46
|
+
throw new Error(`You can't add a schema named "${name}" because it's a name of a default schema, please consider another name to be used`);
|
|
47
|
+
if (this._schemasMap.has(name.toString())) {
|
|
48
|
+
throw new Error(`Schema "${name}" already exists`);
|
|
49
|
+
}
|
|
50
|
+
this._schemasMap.set(name.toString(), {
|
|
51
|
+
...schema,
|
|
52
|
+
type: 'object'
|
|
53
|
+
});
|
|
54
|
+
this._schemasCache = null;
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
get schemas() {
|
|
58
|
+
if (this._schemasCache)
|
|
59
|
+
return this._schemasCache;
|
|
60
|
+
const res = {};
|
|
61
|
+
for (const key of this._schemasMap.keys()) {
|
|
62
|
+
res[key] = {
|
|
63
|
+
validate: (value) => this.validate(this._schemasMap.get(key), value),
|
|
64
|
+
schema: this._schemasMap.get(key)
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
this._schemasCache = res;
|
|
68
|
+
return this._schemasCache;
|
|
69
|
+
}
|
|
70
|
+
async validateDefaultType(name, value, mergeSchema) {
|
|
71
|
+
const strategy = defaultSchemasValidationStrategies[name];
|
|
72
|
+
let finalSchema = defaultSchemas[name];
|
|
73
|
+
if (strategy) {
|
|
74
|
+
if (typeof mergeSchema === 'object') {
|
|
75
|
+
finalSchema = (0, deep_1.deepExtend)(finalSchema, mergeSchema);
|
|
76
|
+
}
|
|
77
|
+
if (typeof mergeSchema === 'number') {
|
|
78
|
+
finalSchema = {
|
|
79
|
+
...finalSchema,
|
|
80
|
+
equals: mergeSchema
|
|
81
|
+
};
|
|
82
|
+
mergeSchema;
|
|
83
|
+
}
|
|
84
|
+
let preliminaryResult = await strategy(value, finalSchema, this);
|
|
85
|
+
if (!preliminaryResult.valid)
|
|
86
|
+
return preliminaryResult;
|
|
87
|
+
preliminaryResult = await this.checkValidators(finalSchema, value);
|
|
88
|
+
return preliminaryResult;
|
|
89
|
+
}
|
|
90
|
+
throw new Error('not implemented');
|
|
91
|
+
}
|
|
92
|
+
async checkValidators(schema, value) {
|
|
93
|
+
if (Array.isArray(schema.validators)) {
|
|
94
|
+
const validatorsResults = await Promise.allSettled(schema.validators.map((v) => Promise.resolve(v(value))));
|
|
95
|
+
const rejections = validatorsResults
|
|
96
|
+
.filter((f) => f.status === 'rejected')
|
|
97
|
+
.map((f) => f.reason);
|
|
98
|
+
const errors = validatorsResults
|
|
99
|
+
.filter((f) => f.status === 'fulfilled' &&
|
|
100
|
+
typeof f.value !== 'boolean' &&
|
|
101
|
+
f.value.valid === false)
|
|
102
|
+
.map((f) => f.value)
|
|
103
|
+
.map((f) => f.errors);
|
|
104
|
+
if (rejections.length === 0 && errors.length === 0) {
|
|
105
|
+
return {
|
|
106
|
+
valid: true
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
valid: false,
|
|
111
|
+
errors: [...rejections, ...errors]
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
valid: true
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
async validate(schema, obj) {
|
|
119
|
+
if (!schema)
|
|
120
|
+
throw new Error('schemaName is required');
|
|
121
|
+
if (typeof schema === 'string') {
|
|
122
|
+
if (isDefaultType(schema)) {
|
|
123
|
+
return await this.validateDefaultType(schema, obj);
|
|
124
|
+
}
|
|
125
|
+
else if (typeof this.schemas[schema] !== 'undefined') {
|
|
126
|
+
const objSchema = (0, deep_1.deepExtend)(defaultSchemas.object, this.schemas[schema].schema);
|
|
127
|
+
const res = await (0, validateObject_1.validateObject)(obj, objSchema, this);
|
|
128
|
+
if (!res.valid)
|
|
129
|
+
return res;
|
|
130
|
+
return await this.checkValidators(objSchema, obj);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
return await this.validateDefaultType('string', obj, {
|
|
134
|
+
type: 'string',
|
|
135
|
+
equals: schema
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (Array.isArray(schema)) {
|
|
140
|
+
for (let i = 0; i < schema.length; i++) {
|
|
141
|
+
const res = await this.validate(schema[i], obj);
|
|
142
|
+
if (res.valid) {
|
|
143
|
+
return res;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
valid: false,
|
|
148
|
+
errors: ['object does not match any schema']
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
if (typeof schema === 'number') {
|
|
152
|
+
return await this.validateDefaultType('number', obj, schema);
|
|
153
|
+
}
|
|
154
|
+
if (typeof schema === 'object') {
|
|
155
|
+
if (typeof schema.type !== 'string')
|
|
156
|
+
throw new Error('Schema has no type');
|
|
157
|
+
if (isDefaultType(schema.type)) {
|
|
158
|
+
return await this.validateDefaultType(schema.type, obj, schema);
|
|
159
|
+
}
|
|
160
|
+
else if (schema.type === 'object') {
|
|
161
|
+
const preliminaryResult = await (0, validateObject_1.validateObject)(obj, schema, this);
|
|
162
|
+
if (!preliminaryResult.valid)
|
|
163
|
+
return preliminaryResult;
|
|
164
|
+
return await this.checkValidators(schema, obj);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
throw new Error("Coldn't understand the Schema provided");
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
exports.default = SchemaValidator;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateArray = void 0;
|
|
4
|
+
const validateArray = async (obj, schema, validator) => {
|
|
5
|
+
if (typeof obj === 'undefined' &&
|
|
6
|
+
typeof schema === 'object' &&
|
|
7
|
+
schema.isRequired === false) {
|
|
8
|
+
return {
|
|
9
|
+
valid: true
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
if (!Array.isArray(obj))
|
|
13
|
+
return {
|
|
14
|
+
valid: false,
|
|
15
|
+
errors: ['expected type array']
|
|
16
|
+
};
|
|
17
|
+
if (typeof schema.minLength === 'number' && obj.length < schema.minLength) {
|
|
18
|
+
return {
|
|
19
|
+
valid: false,
|
|
20
|
+
errors: [`expected to be at least ${schema.minLength} chars long`]
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (typeof schema.maxLength === 'number' && obj.length > schema.maxLength) {
|
|
24
|
+
return {
|
|
25
|
+
valid: false,
|
|
26
|
+
errors: [`expected to be at most ${schema.maxLength} chars long`]
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (typeof schema.ofType !== 'undefined') {
|
|
30
|
+
const results = await Promise.all(obj.map((i) => validator.validate(schema.ofType, i)));
|
|
31
|
+
const errors = results
|
|
32
|
+
.filter((r) => !r.valid)
|
|
33
|
+
.map((r) => r.errors)
|
|
34
|
+
.flat(Infinity);
|
|
35
|
+
if (errors.length) {
|
|
36
|
+
return {
|
|
37
|
+
valid: false,
|
|
38
|
+
errors
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
valid: true
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
valid: true
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
exports.validateArray = validateArray;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateNumber = void 0;
|
|
4
|
+
const validateNumber = async (obj, schema, validator) => {
|
|
5
|
+
if (typeof obj === 'undefined' &&
|
|
6
|
+
typeof schema === 'object' &&
|
|
7
|
+
schema.isRequired === false) {
|
|
8
|
+
return {
|
|
9
|
+
valid: true
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
if (typeof obj !== 'number')
|
|
13
|
+
return {
|
|
14
|
+
valid: false,
|
|
15
|
+
errors: [`expected type number, but saw ${typeof obj}`]
|
|
16
|
+
};
|
|
17
|
+
if (typeof schema === 'number') {
|
|
18
|
+
return obj === schema
|
|
19
|
+
? { valid: true }
|
|
20
|
+
: {
|
|
21
|
+
valid: false,
|
|
22
|
+
errors: [`should be equal to ${schema}`]
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const num = obj;
|
|
26
|
+
if (schema.ensureNotNaN && Number.isNaN(num)) {
|
|
27
|
+
return {
|
|
28
|
+
valid: false,
|
|
29
|
+
errors: ['is not expected to be NaN']
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (schema.ensureIsFinite &&
|
|
33
|
+
!Number.isFinite(num) &&
|
|
34
|
+
schema.ensureNotNaN &&
|
|
35
|
+
!Number.isNaN(num)) {
|
|
36
|
+
return {
|
|
37
|
+
valid: false,
|
|
38
|
+
errors: ['is expected to be a finite number']
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (typeof schema.equals !== 'undefined' && num !== schema.equals) {
|
|
42
|
+
return {
|
|
43
|
+
valid: false,
|
|
44
|
+
errors: [`expected to be equal to ${schema.equals}`]
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (typeof schema.min !== 'undefined') {
|
|
48
|
+
if (typeof schema.min !== 'number')
|
|
49
|
+
throw new Error('min constraint should be a number');
|
|
50
|
+
if (num < schema.min)
|
|
51
|
+
return {
|
|
52
|
+
valid: false,
|
|
53
|
+
errors: [`expected to be at least ${schema.min}`]
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (typeof schema.max !== 'undefined') {
|
|
57
|
+
if (typeof schema.max !== 'number')
|
|
58
|
+
throw new Error('max constraint should be a number');
|
|
59
|
+
if (num > schema.max)
|
|
60
|
+
return {
|
|
61
|
+
valid: false,
|
|
62
|
+
errors: [`expected to be no more than ${schema.max}`]
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
valid: true
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
exports.validateNumber = validateNumber;
|