@cleverbrush/schema 0.0.13 → 0.0.16
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 +22 -13
- package/dist/schemaValidator.d.ts +7 -8
- package/dist/schemaValidator.js +32 -12
- package/dist/validators/validateBoolean.d.ts +2 -0
- package/dist/validators/validateBoolean.js +33 -0
- package/dist/validators/validateObject.d.ts +1 -1
- package/package.json +2 -2
- package/src/index.ts +47 -12
- package/src/schemaValidator.test.ts +242 -45
- package/src/schemaValidator.ts +83 -38
- package/src/validators/validateBoolean.ts +45 -0
- package/src/validators/validateObject.ts +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { Merge } from '@cleverbrush/deep';
|
|
1
2
|
import SchemaValidator from './schemaValidator';
|
|
2
|
-
export declare type DefaultSchemaType = 'object' | 'function' | 'number' | 'string' | 'array' | 'alias';
|
|
3
|
+
export declare type DefaultSchemaType = 'object' | 'boolean' | 'function' | 'number' | 'string' | 'array' | 'alias';
|
|
3
4
|
export declare type PropType<TObj, TProp extends keyof TObj> = TObj[TProp];
|
|
4
5
|
export declare type DefaultPropertyDefinition = {
|
|
5
6
|
isRequired: boolean;
|
|
@@ -24,7 +25,7 @@ export declare type ObjectSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'>
|
|
|
24
25
|
[S in keyof T]: Schema<PropType<T, S>>;
|
|
25
26
|
}>;
|
|
26
27
|
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
|
+
[S in keyof T | '*']: S extends keyof T ? ((value: unknown) => undefined | PropType<T, S> | Promise<PropType<T, S>>) | string : (value: T) => void | Promise<void>;
|
|
28
29
|
}>;
|
|
29
30
|
};
|
|
30
31
|
export declare type AliasSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'> & {
|
|
@@ -39,6 +40,10 @@ export declare type FunctionSchemaDefinition<T extends (...args: any) => any> =
|
|
|
39
40
|
type: 'function';
|
|
40
41
|
params?: ParamsValidators<T>;
|
|
41
42
|
};
|
|
43
|
+
export declare type BooleanSchemaDefinition<TObj> = Omit<SchemaDefintion<TObj>, 'type'> & {
|
|
44
|
+
type: 'boolean';
|
|
45
|
+
equals?: boolean;
|
|
46
|
+
};
|
|
42
47
|
export declare type NumberSchemaDefinition<TObj> = Omit<SchemaDefintion<TObj>, 'type'> & {
|
|
43
48
|
type: 'number';
|
|
44
49
|
min?: number;
|
|
@@ -61,25 +66,29 @@ export declare type ArraySchemaDefinition<TObj> = Omit<SchemaDefintion<TObj>, 't
|
|
|
61
66
|
minLength?: number;
|
|
62
67
|
maxLength?: number;
|
|
63
68
|
};
|
|
64
|
-
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> | AliasSchemaDefinition<TObj>;
|
|
69
|
+
export declare type CompositeSchema<TObj> = TObj extends (...args: any) => any ? FunctionSchemaDefinition<TObj> : TObj extends number ? NumberSchemaDefinition<TObj> : TObj extends string ? StringSchemaDefinition<TObj> | 'string' : BooleanSchemaDefinition<TObj> | NumberSchemaDefinition<TObj> | StringSchemaDefinition<TObj> | ArraySchemaDefinition<TObj> | ObjectSchemaDefinition<TObj> | AliasSchemaDefinition<TObj>;
|
|
65
70
|
export declare type SingleSchema<TObj = Record<string, never>> = number | string | DefaultSchemaType | CompositeSchema<TObj>;
|
|
66
71
|
export declare type Schema<TObj> = SingleSchema<TObj> | Array<SingleSchema<TObj>>;
|
|
67
|
-
export
|
|
72
|
+
export declare type Cons<H, T extends unknown[] = []> = T['length'] extends 0 ? [H] : ((h: H, ...t: T) => void) extends (...r: infer R) => void ? R : never;
|
|
73
|
+
export interface ISchemaActions<S> {
|
|
68
74
|
validate(value: any): Promise<ValidationResult>;
|
|
69
|
-
schema:
|
|
75
|
+
schema: S;
|
|
70
76
|
}
|
|
71
|
-
export interface ISchemasProvider<T
|
|
72
|
-
schemas:
|
|
73
|
-
[K in keyof T]: ISchemaActions<T, K>;
|
|
74
|
-
};
|
|
77
|
+
export interface ISchemasProvider<T extends unknown[]> {
|
|
78
|
+
schemas: Merge<T>;
|
|
75
79
|
}
|
|
76
|
-
export interface ISchemaValidator<T = Record<string, never
|
|
80
|
+
export interface ISchemaValidator<T extends Record<string, never> = Record<string, never>, SchemaTypesStructures extends unknown[] = []> {
|
|
77
81
|
get preprocessors(): Map<string, (value: unknown) => unknown | Promise<unknown>>;
|
|
78
|
-
addPreprocessor(name: string, preprocessor: (value: unknown) => unknown | Promise<unknown>): SchemaValidator<T>;
|
|
79
|
-
addSchemaType<K, L extends ObjectSchemaDefinitionParam<M
|
|
82
|
+
addPreprocessor(name: string, preprocessor: (value: unknown) => unknown | Promise<unknown>): SchemaValidator<T, SchemaTypesStructures>;
|
|
83
|
+
addSchemaType<K, L extends ObjectSchemaDefinitionParam<M> | Array<Schema<any>>, M = any>(name: keyof K, schema: L): SchemaValidator<T & {
|
|
80
84
|
[key in keyof K]: typeof schema;
|
|
81
|
-
}
|
|
85
|
+
}, Cons<Unfold<keyof K, ISchemaActions<L>>, SchemaTypesStructures>>;
|
|
82
86
|
validate(schema: keyof T | DefaultSchemaType | Schema<any>, obj: any): Promise<ValidationResult>;
|
|
83
87
|
}
|
|
88
|
+
export declare type Unfold<T, K> = T extends string ? T extends `${infer F}.${infer L}` ? {
|
|
89
|
+
[k in F]: Unfold<L, K>;
|
|
90
|
+
} : {
|
|
91
|
+
[k in T]: K;
|
|
92
|
+
} : never;
|
|
84
93
|
export { SchemaValidator };
|
|
85
94
|
export default SchemaValidator;
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { Merge } from '@cleverbrush/deep';
|
|
2
|
+
import { ISchemasProvider, Schema, ISchemaActions, ObjectSchemaDefinitionParam, ValidationResult, ISchemaValidator, DefaultSchemaType, Cons, Unfold } from './index';
|
|
3
|
+
export default class SchemaValidator<T extends Record<string, never> = Record<string, never>, SchemaTypesStructures extends unknown[] = []> implements ISchemasProvider<SchemaTypesStructures>, ISchemaValidator<T, SchemaTypesStructures> {
|
|
3
4
|
private _schemasMap;
|
|
4
5
|
private _schemasCache;
|
|
5
6
|
private _preprocessorsMap;
|
|
6
7
|
get preprocessors(): Map<string, (value: unknown) => unknown>;
|
|
7
|
-
addPreprocessor(name: string, preprocessor: (value: unknown) => unknown | Promise<unknown>): SchemaValidator<T>;
|
|
8
|
-
addSchemaType<K, L extends ObjectSchemaDefinitionParam<M
|
|
8
|
+
addPreprocessor(name: string, preprocessor: (value: unknown) => unknown | Promise<unknown>): SchemaValidator<T, SchemaTypesStructures>;
|
|
9
|
+
addSchemaType<K, L extends ObjectSchemaDefinitionParam<M> | Array<Schema<any>>, M = any>(name: keyof K, schema: L): SchemaValidator<T & {
|
|
9
10
|
[key in keyof K]: L;
|
|
10
|
-
}
|
|
11
|
-
get schemas():
|
|
12
|
-
[K in keyof T]: ISchemaActions<T, K>;
|
|
13
|
-
};
|
|
11
|
+
}, Cons<Unfold<keyof K, ISchemaActions<L>>, SchemaTypesStructures>>;
|
|
12
|
+
get schemas(): Merge<SchemaTypesStructures>;
|
|
14
13
|
private validateDefaultType;
|
|
15
14
|
private checkValidators;
|
|
16
15
|
validate<K>(schema: keyof T | DefaultSchemaType | Schema<K>, obj: any): Promise<ValidationResult>;
|
package/dist/schemaValidator.js
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const deep_1 = require("@cleverbrush/deep");
|
|
4
4
|
const validateNumber_1 = require("./validators/validateNumber");
|
|
5
|
+
const validateBoolean_1 = require("./validators/validateBoolean");
|
|
5
6
|
const validateString_1 = require("./validators/validateString");
|
|
6
7
|
const validateArray_1 = require("./validators/validateArray");
|
|
7
8
|
const validateObject_1 = require("./validators/validateObject");
|
|
8
|
-
const defaultSchemaNames = ['string', 'number', 'date', 'array'];
|
|
9
|
+
const defaultSchemaNames = ['string', 'boolean', 'number', 'date', 'array'];
|
|
9
10
|
const defaultSchemas = {
|
|
10
11
|
number: {
|
|
11
12
|
type: 'number',
|
|
@@ -14,6 +15,11 @@ const defaultSchemas = {
|
|
|
14
15
|
ensureNotNaN: true,
|
|
15
16
|
ensureIsFinite: true
|
|
16
17
|
},
|
|
18
|
+
boolean: {
|
|
19
|
+
type: 'boolean',
|
|
20
|
+
isRequired: true,
|
|
21
|
+
isNullable: false
|
|
22
|
+
},
|
|
17
23
|
string: {
|
|
18
24
|
type: 'string',
|
|
19
25
|
isNullable: false,
|
|
@@ -30,6 +36,7 @@ const defaultSchemas = {
|
|
|
30
36
|
};
|
|
31
37
|
const defaultSchemasValidationStrategies = {
|
|
32
38
|
number: (obj, schema, validator) => (0, validateNumber_1.validateNumber)(obj, schema, validator),
|
|
39
|
+
boolean: (obj, schema, validator) => (0, validateBoolean_1.validateBoolean)(obj, schema, validator),
|
|
33
40
|
string: (obj, schema, validator) => (0, validateString_1.validateString)(obj, schema, validator),
|
|
34
41
|
array: (obj, schema, validator) => (0, validateArray_1.validateArray)(obj, schema, validator)
|
|
35
42
|
};
|
|
@@ -74,10 +81,22 @@ class SchemaValidator {
|
|
|
74
81
|
return this._schemasCache;
|
|
75
82
|
const res = {};
|
|
76
83
|
for (const key of this._schemasMap.keys()) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
84
|
+
const parts = key.split('.');
|
|
85
|
+
let curr = res;
|
|
86
|
+
for (let i = 0; i < parts.length; i++) {
|
|
87
|
+
if (i === parts.length - 1) {
|
|
88
|
+
curr[parts[i]] = {
|
|
89
|
+
validate: (value) => this.validate(this._schemasMap.get(key), value),
|
|
90
|
+
schema: this._schemasMap.get(key)
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
if (typeof curr[parts[i]] === 'undefined') {
|
|
95
|
+
curr[parts[i]] = {};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
curr = curr[parts[i]];
|
|
99
|
+
}
|
|
81
100
|
}
|
|
82
101
|
this._schemasCache = res;
|
|
83
102
|
return this._schemasCache;
|
|
@@ -142,12 +161,11 @@ class SchemaValidator {
|
|
|
142
161
|
if (isDefaultType(schema)) {
|
|
143
162
|
return await this.validateDefaultType(schema, obj);
|
|
144
163
|
}
|
|
145
|
-
else if (typeof this.
|
|
146
|
-
if (Array.isArray(this.
|
|
147
|
-
return this.validate(this.
|
|
148
|
-
.schema, obj);
|
|
164
|
+
else if (typeof this._schemasMap.get(schema) !== 'undefined') {
|
|
165
|
+
if (Array.isArray(this._schemasMap.get(schema))) {
|
|
166
|
+
return this.validate(this._schemasMap.get(schema), obj);
|
|
149
167
|
}
|
|
150
|
-
const objSchema = (0, deep_1.deepExtend)(defaultSchemas.object, this.
|
|
168
|
+
const objSchema = (0, deep_1.deepExtend)(defaultSchemas.object, this._schemasMap.get(schema));
|
|
151
169
|
const res = await (0, validateObject_1.validateObject)(obj, objSchema, this);
|
|
152
170
|
if (!res.valid)
|
|
153
171
|
return res;
|
|
@@ -182,8 +200,10 @@ class SchemaValidator {
|
|
|
182
200
|
return await this.validateDefaultType(schema.type, obj, schema);
|
|
183
201
|
}
|
|
184
202
|
else if (schema.type === 'alias') {
|
|
185
|
-
const alias = this.
|
|
186
|
-
|
|
203
|
+
const alias = this._schemasMap.get(schema.schemaName);
|
|
204
|
+
if (typeof alias === 'undefined') {
|
|
205
|
+
throw new Error(`Unknown schema alias - ${schema.schemaName}`);
|
|
206
|
+
}
|
|
187
207
|
if (Array.isArray(alias)) {
|
|
188
208
|
if ((!schema.isRequired && typeof obj === 'undefined') ||
|
|
189
209
|
(schema.isNullable && obj === null)) {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateBoolean = void 0;
|
|
4
|
+
const validateBoolean = 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 !== 'boolean')
|
|
13
|
+
return {
|
|
14
|
+
valid: false,
|
|
15
|
+
errors: [`expected type boolean, but saw ${typeof obj}`]
|
|
16
|
+
};
|
|
17
|
+
if (typeof schema === 'boolean') {
|
|
18
|
+
return { valid: true };
|
|
19
|
+
}
|
|
20
|
+
const bool = obj;
|
|
21
|
+
if (typeof schema.equals === 'boolean') {
|
|
22
|
+
return schema.equals === bool
|
|
23
|
+
? { valid: true }
|
|
24
|
+
: {
|
|
25
|
+
valid: false,
|
|
26
|
+
errors: [`must be equal to ${schema.equals}`]
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
valid: true
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
exports.validateBoolean = validateBoolean;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { ValidationResult, ObjectSchemaDefinition, ISchemaValidator } from '../index';
|
|
2
|
-
export declare const validateObject: (obj: any, schema: ObjectSchemaDefinition<any>, validator: ISchemaValidator<any>) => Promise<ValidationResult>;
|
|
2
|
+
export declare const validateObject: (obj: any, schema: ObjectSchemaDefinition<any>, validator: ISchemaValidator<any, unknown[]>) => Promise<ValidationResult>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cleverbrush/schema",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
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.16"
|
|
23
23
|
},
|
|
24
24
|
"types": "./dist/index.d.ts"
|
|
25
25
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { Merge } from '@cleverbrush/deep';
|
|
1
2
|
import SchemaValidator from './schemaValidator';
|
|
2
3
|
|
|
3
4
|
export type DefaultSchemaType =
|
|
4
5
|
| 'object'
|
|
6
|
+
| 'boolean'
|
|
5
7
|
| 'function'
|
|
6
8
|
| 'number'
|
|
7
9
|
| 'string'
|
|
@@ -44,7 +46,7 @@ export type ObjectSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'> & {
|
|
|
44
46
|
?
|
|
45
47
|
| ((
|
|
46
48
|
value: unknown
|
|
47
|
-
) => PropType<T, S> | Promise<PropType<T, S>>)
|
|
49
|
+
) => undefined | PropType<T, S> | Promise<PropType<T, S>>)
|
|
48
50
|
| string
|
|
49
51
|
: (value: T) => void | Promise<void>;
|
|
50
52
|
}>;
|
|
@@ -72,6 +74,14 @@ export type FunctionSchemaDefinition<T extends (...args: any) => any> = Omit<
|
|
|
72
74
|
params?: ParamsValidators<T>;
|
|
73
75
|
};
|
|
74
76
|
|
|
77
|
+
export type BooleanSchemaDefinition<TObj> = Omit<
|
|
78
|
+
SchemaDefintion<TObj>,
|
|
79
|
+
'type'
|
|
80
|
+
> & {
|
|
81
|
+
type: 'boolean';
|
|
82
|
+
equals?: boolean;
|
|
83
|
+
};
|
|
84
|
+
|
|
75
85
|
export type NumberSchemaDefinition<TObj> = Omit<
|
|
76
86
|
SchemaDefintion<TObj>,
|
|
77
87
|
'type'
|
|
@@ -113,6 +123,7 @@ export type CompositeSchema<TObj> = TObj extends (...args: any) => any
|
|
|
113
123
|
: TObj extends string
|
|
114
124
|
? StringSchemaDefinition<TObj> | 'string'
|
|
115
125
|
:
|
|
126
|
+
| BooleanSchemaDefinition<TObj>
|
|
116
127
|
| NumberSchemaDefinition<TObj>
|
|
117
128
|
| StringSchemaDefinition<TObj>
|
|
118
129
|
| ArraySchemaDefinition<TObj>
|
|
@@ -127,18 +138,25 @@ export type SingleSchema<TObj = Record<string, never>> =
|
|
|
127
138
|
|
|
128
139
|
export type Schema<TObj> = SingleSchema<TObj> | Array<SingleSchema<TObj>>;
|
|
129
140
|
|
|
130
|
-
export
|
|
141
|
+
export type Cons<H, T extends unknown[] = []> = T['length'] extends 0
|
|
142
|
+
? [H]
|
|
143
|
+
: ((h: H, ...t: T) => void) extends (...r: infer R) => void
|
|
144
|
+
? R
|
|
145
|
+
: never;
|
|
146
|
+
|
|
147
|
+
export interface ISchemaActions<S> {
|
|
131
148
|
validate(value: any): Promise<ValidationResult>;
|
|
132
|
-
schema:
|
|
149
|
+
schema: S;
|
|
133
150
|
}
|
|
134
151
|
|
|
135
|
-
export interface ISchemasProvider<T
|
|
136
|
-
schemas:
|
|
137
|
-
[K in keyof T]: ISchemaActions<T, K>;
|
|
138
|
-
};
|
|
152
|
+
export interface ISchemasProvider<T extends unknown[]> {
|
|
153
|
+
schemas: Merge<T>;
|
|
139
154
|
}
|
|
140
155
|
|
|
141
|
-
export interface ISchemaValidator<
|
|
156
|
+
export interface ISchemaValidator<
|
|
157
|
+
T extends Record<string, never> = Record<string, never>,
|
|
158
|
+
SchemaTypesStructures extends unknown[] = []
|
|
159
|
+
> {
|
|
142
160
|
get preprocessors(): Map<
|
|
143
161
|
string,
|
|
144
162
|
(value: unknown) => unknown | Promise<unknown>
|
|
@@ -146,12 +164,19 @@ export interface ISchemaValidator<T = Record<string, never>> {
|
|
|
146
164
|
addPreprocessor(
|
|
147
165
|
name: string,
|
|
148
166
|
preprocessor: (value: unknown) => unknown | Promise<unknown>
|
|
149
|
-
): SchemaValidator<T>;
|
|
167
|
+
): SchemaValidator<T, SchemaTypesStructures>;
|
|
150
168
|
|
|
151
|
-
addSchemaType<
|
|
169
|
+
addSchemaType<
|
|
170
|
+
K,
|
|
171
|
+
L extends ObjectSchemaDefinitionParam<M> | Array<Schema<any>>,
|
|
172
|
+
M = any
|
|
173
|
+
>(
|
|
152
174
|
name: keyof K,
|
|
153
|
-
schema: L
|
|
154
|
-
): SchemaValidator<
|
|
175
|
+
schema: L
|
|
176
|
+
): SchemaValidator<
|
|
177
|
+
T & { [key in keyof K]: typeof schema },
|
|
178
|
+
Cons<Unfold<keyof K, ISchemaActions<L>>, SchemaTypesStructures>
|
|
179
|
+
>;
|
|
155
180
|
|
|
156
181
|
validate(
|
|
157
182
|
schema: keyof T | DefaultSchemaType | Schema<any>,
|
|
@@ -159,5 +184,15 @@ export interface ISchemaValidator<T = Record<string, never>> {
|
|
|
159
184
|
): Promise<ValidationResult>;
|
|
160
185
|
}
|
|
161
186
|
|
|
187
|
+
export type Unfold<T, K> = T extends string
|
|
188
|
+
? T extends `${infer F}.${infer L}`
|
|
189
|
+
? {
|
|
190
|
+
[k in F]: Unfold<L, K>;
|
|
191
|
+
}
|
|
192
|
+
: {
|
|
193
|
+
[k in T]: K;
|
|
194
|
+
}
|
|
195
|
+
: never;
|
|
196
|
+
|
|
162
197
|
export { SchemaValidator };
|
|
163
198
|
export default SchemaValidator;
|
|
@@ -170,7 +170,7 @@ test('Validate - no schema', async () => {
|
|
|
170
170
|
const validator = new SchemaValidator();
|
|
171
171
|
const cth = jest.fn();
|
|
172
172
|
validator
|
|
173
|
-
.validate(null, 10)
|
|
173
|
+
.validate(null as any, 10)
|
|
174
174
|
.catch(cth)
|
|
175
175
|
.then(() => {
|
|
176
176
|
expect(cth).toBeCalled();
|
|
@@ -554,6 +554,82 @@ test('Validate - number by schema - custom validators - 2', async () => {
|
|
|
554
554
|
expect(result).toHaveProperty('valid', false);
|
|
555
555
|
});
|
|
556
556
|
|
|
557
|
+
test('Validate - boolean - 1', async () => {
|
|
558
|
+
const validator = new SchemaValidator();
|
|
559
|
+
const result = await validator.validate(
|
|
560
|
+
{
|
|
561
|
+
type: 'boolean'
|
|
562
|
+
},
|
|
563
|
+
300
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
expect(result).toHaveProperty('valid', false);
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
test('Validate - boolean - 2', async () => {
|
|
570
|
+
const validator = new SchemaValidator();
|
|
571
|
+
const result = await validator.validate(
|
|
572
|
+
{
|
|
573
|
+
type: 'boolean'
|
|
574
|
+
},
|
|
575
|
+
true
|
|
576
|
+
);
|
|
577
|
+
|
|
578
|
+
expect(result).toHaveProperty('valid', true);
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
test('Validate - boolean - 3', async () => {
|
|
582
|
+
const validator = new SchemaValidator();
|
|
583
|
+
const result = await validator.validate(
|
|
584
|
+
{
|
|
585
|
+
type: 'boolean'
|
|
586
|
+
},
|
|
587
|
+
false
|
|
588
|
+
);
|
|
589
|
+
|
|
590
|
+
expect(result).toHaveProperty('valid', true);
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
test('Validate - boolean - 4', async () => {
|
|
594
|
+
const validator = new SchemaValidator();
|
|
595
|
+
const result = await validator.validate(
|
|
596
|
+
{
|
|
597
|
+
type: 'boolean',
|
|
598
|
+
equals: true
|
|
599
|
+
},
|
|
600
|
+
false
|
|
601
|
+
);
|
|
602
|
+
|
|
603
|
+
expect(result).toHaveProperty('valid', false);
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
test('Validate - boolean - 5', async () => {
|
|
607
|
+
const validator = new SchemaValidator();
|
|
608
|
+
const result = await validator.validate(
|
|
609
|
+
{
|
|
610
|
+
type: 'boolean',
|
|
611
|
+
equals: false
|
|
612
|
+
},
|
|
613
|
+
false
|
|
614
|
+
);
|
|
615
|
+
|
|
616
|
+
expect(result).toHaveProperty('valid', true);
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
test('Validate - boolean - 6', async () => {
|
|
620
|
+
const validator = new SchemaValidator();
|
|
621
|
+
const result = await validator.validate('boolean', false);
|
|
622
|
+
|
|
623
|
+
expect(result).toHaveProperty('valid', true);
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
test('Validate - boolean - 7', async () => {
|
|
627
|
+
const validator = new SchemaValidator();
|
|
628
|
+
const result = await validator.validate('boolean', '123');
|
|
629
|
+
|
|
630
|
+
expect(result).toHaveProperty('valid', false);
|
|
631
|
+
});
|
|
632
|
+
|
|
557
633
|
test('Validate - string - 1', async () => {
|
|
558
634
|
const validator = new SchemaValidator();
|
|
559
635
|
const result = await validator.validate('string', '12345');
|
|
@@ -868,7 +944,7 @@ test('Validate - object - 2', async () => {
|
|
|
868
944
|
};
|
|
869
945
|
}
|
|
870
946
|
]
|
|
871
|
-
})
|
|
947
|
+
}) as any as ObjectSchemaDefinition<any>
|
|
872
948
|
);
|
|
873
949
|
const user: User = {
|
|
874
950
|
id: 1,
|
|
@@ -1123,19 +1199,30 @@ test('Validate schema - 1', async () => {
|
|
|
1123
1199
|
});
|
|
1124
1200
|
|
|
1125
1201
|
test('Validate schema - 2', async () => {
|
|
1126
|
-
const validator = new SchemaValidator()
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1202
|
+
const validator = new SchemaValidator()
|
|
1203
|
+
.addSchemaType('Date', {
|
|
1204
|
+
validators: [
|
|
1205
|
+
(value) =>
|
|
1206
|
+
value instanceof Date && !Number.isNaN(value)
|
|
1207
|
+
? {
|
|
1208
|
+
valid: true
|
|
1209
|
+
}
|
|
1210
|
+
: {
|
|
1211
|
+
valid: false,
|
|
1212
|
+
errors: ['should be a valid Date object']
|
|
1213
|
+
}
|
|
1214
|
+
]
|
|
1215
|
+
})
|
|
1216
|
+
.addSchemaType('Module.Schema1', {
|
|
1217
|
+
properties: {
|
|
1218
|
+
a: 'string'
|
|
1219
|
+
}
|
|
1220
|
+
})
|
|
1221
|
+
.addSchemaType('Module.Schema2', {
|
|
1222
|
+
properties: {
|
|
1223
|
+
b: 'number'
|
|
1224
|
+
}
|
|
1225
|
+
});
|
|
1139
1226
|
|
|
1140
1227
|
const result = await validator.validate(
|
|
1141
1228
|
{
|
|
@@ -1225,8 +1312,10 @@ test('Preprocessors - 1', async () => {
|
|
|
1225
1312
|
bornAt: 'Date'
|
|
1226
1313
|
},
|
|
1227
1314
|
preprocessors: {
|
|
1228
|
-
bornAt: (value: unknown): Date => {
|
|
1229
|
-
const time = Date.parse(
|
|
1315
|
+
bornAt: (value: unknown): Date | undefined => {
|
|
1316
|
+
const time = Date.parse(
|
|
1317
|
+
(value as Record<string, unknown>).toString()
|
|
1318
|
+
);
|
|
1230
1319
|
if (Number.isNaN(time)) return undefined;
|
|
1231
1320
|
return new Date(time);
|
|
1232
1321
|
}
|
|
@@ -1264,18 +1353,28 @@ test('Preprocessors - 2', async () => {
|
|
|
1264
1353
|
}
|
|
1265
1354
|
};
|
|
1266
1355
|
|
|
1267
|
-
validator.addPreprocessor(
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
expect(() =>
|
|
1274
|
-
validator.addPreprocessor('StringToDate', (value: unknown): Date => {
|
|
1275
|
-
const time = Date.parse(value.toString());
|
|
1356
|
+
validator.addPreprocessor(
|
|
1357
|
+
'StringToDate',
|
|
1358
|
+
(value: unknown): Date | undefined => {
|
|
1359
|
+
const time = Date.parse(
|
|
1360
|
+
(value as Record<string, unknown>).toString()
|
|
1361
|
+
);
|
|
1276
1362
|
if (Number.isNaN(time)) return undefined;
|
|
1277
1363
|
return new Date(time);
|
|
1278
|
-
}
|
|
1364
|
+
}
|
|
1365
|
+
);
|
|
1366
|
+
|
|
1367
|
+
expect(() =>
|
|
1368
|
+
validator.addPreprocessor(
|
|
1369
|
+
'StringToDate',
|
|
1370
|
+
(value: unknown): Date | undefined => {
|
|
1371
|
+
const time = Date.parse(
|
|
1372
|
+
(value as Record<string, unknown>).toString()
|
|
1373
|
+
);
|
|
1374
|
+
if (Number.isNaN(time)) return undefined;
|
|
1375
|
+
return new Date(time);
|
|
1376
|
+
}
|
|
1377
|
+
)
|
|
1279
1378
|
).toThrow();
|
|
1280
1379
|
|
|
1281
1380
|
const result = await validator.validate(schema, {
|
|
@@ -1316,11 +1415,16 @@ test('Preprocessors - 3', async () => {
|
|
|
1316
1415
|
]
|
|
1317
1416
|
});
|
|
1318
1417
|
|
|
1319
|
-
validator.addPreprocessor(
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1418
|
+
validator.addPreprocessor(
|
|
1419
|
+
'StringToDate',
|
|
1420
|
+
(value: unknown): Date | undefined => {
|
|
1421
|
+
const time = Date.parse(
|
|
1422
|
+
(value as Record<string, unknown>).toString()
|
|
1423
|
+
);
|
|
1424
|
+
if (Number.isNaN(time)) return undefined;
|
|
1425
|
+
return new Date(time);
|
|
1426
|
+
}
|
|
1427
|
+
);
|
|
1324
1428
|
|
|
1325
1429
|
let obj = [new Date().toJSON()];
|
|
1326
1430
|
|
|
@@ -1337,8 +1441,10 @@ test('Preprocessors - 3', async () => {
|
|
|
1337
1441
|
obj = [new Date().toJSON()];
|
|
1338
1442
|
result = await validator.validate(
|
|
1339
1443
|
{
|
|
1340
|
-
preprocessor: (value: unknown): Date => {
|
|
1341
|
-
const time = Date.parse(
|
|
1444
|
+
preprocessor: (value: unknown): Date | undefined => {
|
|
1445
|
+
const time = Date.parse(
|
|
1446
|
+
(value as Record<string, unknown>).toString()
|
|
1447
|
+
);
|
|
1342
1448
|
if (Number.isNaN(time)) return undefined;
|
|
1343
1449
|
return new Date(time);
|
|
1344
1450
|
},
|
|
@@ -1352,8 +1458,10 @@ test('Preprocessors - 3', async () => {
|
|
|
1352
1458
|
obj = ['sdfsdf12', new Date().toJSON()];
|
|
1353
1459
|
result = await validator.validate(
|
|
1354
1460
|
{
|
|
1355
|
-
preprocessor: (value: unknown): Date => {
|
|
1356
|
-
const time = Date.parse(
|
|
1461
|
+
preprocessor: (value: unknown): Date | undefined => {
|
|
1462
|
+
const time = Date.parse(
|
|
1463
|
+
(value as Record<string, unknown>).toString()
|
|
1464
|
+
);
|
|
1357
1465
|
if (Number.isNaN(time)) return undefined;
|
|
1358
1466
|
return new Date(time);
|
|
1359
1467
|
},
|
|
@@ -1409,11 +1517,16 @@ test('Preprocessors - 4', async () => {
|
|
|
1409
1517
|
]
|
|
1410
1518
|
});
|
|
1411
1519
|
|
|
1412
|
-
validator.addPreprocessor(
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1520
|
+
validator.addPreprocessor(
|
|
1521
|
+
'StringToDate',
|
|
1522
|
+
(value: unknown): Date | undefined => {
|
|
1523
|
+
const time = Date.parse(
|
|
1524
|
+
(value as Record<string, unknown>).toString()
|
|
1525
|
+
);
|
|
1526
|
+
if (Number.isNaN(time)) return undefined;
|
|
1527
|
+
return new Date(time);
|
|
1528
|
+
}
|
|
1529
|
+
);
|
|
1417
1530
|
|
|
1418
1531
|
let obj = [new Date().toJSON()];
|
|
1419
1532
|
|
|
@@ -1430,8 +1543,10 @@ test('Preprocessors - 4', async () => {
|
|
|
1430
1543
|
obj = [new Date().toJSON()];
|
|
1431
1544
|
result = await validator.validate(
|
|
1432
1545
|
{
|
|
1433
|
-
preprocessor: (value: unknown): Date => {
|
|
1434
|
-
const time = Date.parse(
|
|
1546
|
+
preprocessor: (value: unknown): Date | undefined => {
|
|
1547
|
+
const time = Date.parse(
|
|
1548
|
+
(value as Record<string, unknown>).toString()
|
|
1549
|
+
);
|
|
1435
1550
|
if (Number.isNaN(time)) return undefined;
|
|
1436
1551
|
return new Date(time);
|
|
1437
1552
|
},
|
|
@@ -1445,8 +1560,10 @@ test('Preprocessors - 4', async () => {
|
|
|
1445
1560
|
obj = ['sdfsdf12', new Date().toJSON()];
|
|
1446
1561
|
result = await validator.validate(
|
|
1447
1562
|
{
|
|
1448
|
-
preprocessor: (value: unknown): Date => {
|
|
1449
|
-
const time = Date.parse(
|
|
1563
|
+
preprocessor: (value: unknown): Date | undefined => {
|
|
1564
|
+
const time = Date.parse(
|
|
1565
|
+
(value as Record<string, unknown>).toString()
|
|
1566
|
+
);
|
|
1450
1567
|
if (Number.isNaN(time)) return undefined;
|
|
1451
1568
|
return new Date(time);
|
|
1452
1569
|
},
|
|
@@ -1457,3 +1574,83 @@ test('Preprocessors - 4', async () => {
|
|
|
1457
1574
|
);
|
|
1458
1575
|
expect(result).toHaveProperty('valid', false);
|
|
1459
1576
|
});
|
|
1577
|
+
|
|
1578
|
+
test('Submodules - 1', async () => {
|
|
1579
|
+
const validator = new SchemaValidator().addSchemaType(
|
|
1580
|
+
'Module1.Schema1',
|
|
1581
|
+
{}
|
|
1582
|
+
);
|
|
1583
|
+
|
|
1584
|
+
const result = validator.schemas;
|
|
1585
|
+
|
|
1586
|
+
expect(result).toHaveProperty('Module1');
|
|
1587
|
+
expect(result).toHaveProperty('Module1.Schema1');
|
|
1588
|
+
});
|
|
1589
|
+
|
|
1590
|
+
test('Submodules - 2', async () => {
|
|
1591
|
+
const validator = new SchemaValidator()
|
|
1592
|
+
.addSchemaType('Module1.Schema1', {})
|
|
1593
|
+
.addSchemaType('Module1.Schema2', {
|
|
1594
|
+
properties: {
|
|
1595
|
+
a: 'number'
|
|
1596
|
+
}
|
|
1597
|
+
});
|
|
1598
|
+
|
|
1599
|
+
const result = validator.schemas;
|
|
1600
|
+
|
|
1601
|
+
expect(result).toHaveProperty('Module1');
|
|
1602
|
+
expect(result).toHaveProperty('Module1.Schema1');
|
|
1603
|
+
expect(result).toHaveProperty('Module1.Schema2');
|
|
1604
|
+
|
|
1605
|
+
const result2 = await validator.schemas.Module1.Schema2.validate({
|
|
1606
|
+
a: 234
|
|
1607
|
+
});
|
|
1608
|
+
expect(result2).toHaveProperty('valid', true);
|
|
1609
|
+
});
|
|
1610
|
+
|
|
1611
|
+
test('Submodules - 3', async () => {
|
|
1612
|
+
const validator = new SchemaValidator()
|
|
1613
|
+
.addSchemaType('Module1.Schema1', {
|
|
1614
|
+
properties: {
|
|
1615
|
+
b: 'number'
|
|
1616
|
+
}
|
|
1617
|
+
})
|
|
1618
|
+
.addSchemaType('Module1.Schema2', {
|
|
1619
|
+
properties: {
|
|
1620
|
+
a: {
|
|
1621
|
+
type: 'alias',
|
|
1622
|
+
schemaName: 'Module1.Schema1'
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
});
|
|
1626
|
+
|
|
1627
|
+
const result2 = await validator.schemas.Module1.Schema2.validate({
|
|
1628
|
+
a: {
|
|
1629
|
+
b: 20
|
|
1630
|
+
}
|
|
1631
|
+
});
|
|
1632
|
+
expect(result2).toHaveProperty('valid', true);
|
|
1633
|
+
});
|
|
1634
|
+
|
|
1635
|
+
test('Submodules - 4', async () => {
|
|
1636
|
+
const validator = new SchemaValidator()
|
|
1637
|
+
.addSchemaType('Module1.Schema1', {
|
|
1638
|
+
properties: {
|
|
1639
|
+
b: 'number'
|
|
1640
|
+
}
|
|
1641
|
+
})
|
|
1642
|
+
.addSchemaType('Module1.Schema2', {
|
|
1643
|
+
properties: {
|
|
1644
|
+
a: {
|
|
1645
|
+
type: 'alias',
|
|
1646
|
+
schemaName: 'Module1.Schema3'
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
});
|
|
1650
|
+
|
|
1651
|
+
await validator.schemas.Module1.Schema2.validate({
|
|
1652
|
+
a: {
|
|
1653
|
+
b: 20
|
|
1654
|
+
}
|
|
1655
|
+
}).catch((e) => expect(e).toBeInstanceOf(Error));
|
|
1656
|
+
});
|
package/src/schemaValidator.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { deepExtend } from '@cleverbrush/deep';
|
|
1
|
+
import { deepExtend, Merge } from '@cleverbrush/deep';
|
|
2
2
|
import {
|
|
3
3
|
ISchemasProvider,
|
|
4
4
|
Schema,
|
|
@@ -13,14 +13,17 @@ import {
|
|
|
13
13
|
ISchemaValidator,
|
|
14
14
|
DefaultSchemaType,
|
|
15
15
|
ObjectSchemaDefinition,
|
|
16
|
-
|
|
16
|
+
BooleanSchemaDefinition,
|
|
17
|
+
Cons,
|
|
18
|
+
Unfold
|
|
17
19
|
} from './index';
|
|
18
20
|
import { validateNumber } from './validators/validateNumber';
|
|
21
|
+
import { validateBoolean } from './validators/validateBoolean';
|
|
19
22
|
import { validateString } from './validators/validateString';
|
|
20
23
|
import { validateArray } from './validators/validateArray';
|
|
21
24
|
import { validateObject } from './validators/validateObject';
|
|
22
25
|
|
|
23
|
-
const defaultSchemaNames = ['string', 'number', 'date', 'array'];
|
|
26
|
+
const defaultSchemaNames = ['string', 'boolean', 'number', 'date', 'array'];
|
|
24
27
|
|
|
25
28
|
const defaultSchemas: { [key in DefaultSchemaType]?: Schema<any> } = {
|
|
26
29
|
number: {
|
|
@@ -30,6 +33,11 @@ const defaultSchemas: { [key in DefaultSchemaType]?: Schema<any> } = {
|
|
|
30
33
|
ensureNotNaN: true,
|
|
31
34
|
ensureIsFinite: true
|
|
32
35
|
},
|
|
36
|
+
boolean: {
|
|
37
|
+
type: 'boolean',
|
|
38
|
+
isRequired: true,
|
|
39
|
+
isNullable: false
|
|
40
|
+
},
|
|
33
41
|
string: {
|
|
34
42
|
type: 'string',
|
|
35
43
|
isNullable: false,
|
|
@@ -49,31 +57,40 @@ const defaultSchemasValidationStrategies = {
|
|
|
49
57
|
number: (
|
|
50
58
|
obj: any,
|
|
51
59
|
schema: NumberSchemaDefinition<any>,
|
|
52
|
-
validator: ISchemaValidator<any>
|
|
60
|
+
validator: ISchemaValidator<any, unknown[]>
|
|
53
61
|
): Promise<ValidationResult> => validateNumber(obj, schema, validator),
|
|
62
|
+
boolean: (
|
|
63
|
+
obj: any,
|
|
64
|
+
schema: BooleanSchemaDefinition<any>,
|
|
65
|
+
validator: ISchemaValidator<any, unknown[]>
|
|
66
|
+
): Promise<ValidationResult> => validateBoolean(obj, schema, validator),
|
|
54
67
|
string: (
|
|
55
68
|
obj: any,
|
|
56
69
|
schema: StringSchemaDefinition<any>,
|
|
57
|
-
validator: ISchemaValidator<any>
|
|
70
|
+
validator: ISchemaValidator<any, unknown[]>
|
|
58
71
|
): Promise<ValidationResult> => validateString(obj, schema, validator),
|
|
59
72
|
array: (
|
|
60
73
|
obj: any,
|
|
61
74
|
schema: ArraySchemaDefinition<any>,
|
|
62
|
-
validator: ISchemaValidator<any>
|
|
75
|
+
validator: ISchemaValidator<any, unknown[]>
|
|
63
76
|
): Promise<ValidationResult> => validateArray(obj, schema, validator)
|
|
64
77
|
};
|
|
65
78
|
|
|
66
79
|
const isDefaultType = (name: string): boolean =>
|
|
67
80
|
defaultSchemaNames.indexOf(name) !== -1;
|
|
68
81
|
|
|
69
|
-
export default class SchemaValidator<
|
|
70
|
-
|
|
82
|
+
export default class SchemaValidator<
|
|
83
|
+
T extends Record<string, never> = Record<string, never>,
|
|
84
|
+
SchemaTypesStructures extends unknown[] = []
|
|
85
|
+
> implements
|
|
86
|
+
ISchemasProvider<SchemaTypesStructures>,
|
|
87
|
+
ISchemaValidator<T, SchemaTypesStructures>
|
|
71
88
|
{
|
|
72
89
|
private _schemasMap = new Map<string, Schema<any>>();
|
|
73
|
-
private _schemasCache:
|
|
90
|
+
private _schemasCache: Merge<SchemaTypesStructures> = null;
|
|
74
91
|
private _preprocessorsMap = new Map<
|
|
75
92
|
string,
|
|
76
|
-
(value: unknown) => unknown | Promise<unknown>
|
|
93
|
+
(value: unknown) => unknown | Promise<unknown> | undefined
|
|
77
94
|
>();
|
|
78
95
|
|
|
79
96
|
public get preprocessors(): Map<string, (value: unknown) => unknown> {
|
|
@@ -83,17 +100,24 @@ export default class SchemaValidator<T = Record<string, never>>
|
|
|
83
100
|
public addPreprocessor(
|
|
84
101
|
name: string,
|
|
85
102
|
preprocessor: (value: unknown) => unknown | Promise<unknown>
|
|
86
|
-
): SchemaValidator<T> {
|
|
103
|
+
): SchemaValidator<T, SchemaTypesStructures> {
|
|
87
104
|
if (this._preprocessorsMap.has(name))
|
|
88
105
|
throw new Error(`Preprocessor '${name}' is already registered`);
|
|
89
106
|
this._preprocessorsMap.set(name, preprocessor);
|
|
90
107
|
return this;
|
|
91
108
|
}
|
|
92
109
|
|
|
93
|
-
public addSchemaType<
|
|
110
|
+
public addSchemaType<
|
|
111
|
+
K,
|
|
112
|
+
L extends ObjectSchemaDefinitionParam<M> | Array<Schema<any>>,
|
|
113
|
+
M = any
|
|
114
|
+
>(
|
|
94
115
|
name: keyof K,
|
|
95
|
-
schema: L
|
|
96
|
-
): SchemaValidator<
|
|
116
|
+
schema: L
|
|
117
|
+
): SchemaValidator<
|
|
118
|
+
T & { [key in keyof K]: L },
|
|
119
|
+
Cons<Unfold<keyof K, ISchemaActions<L>>, SchemaTypesStructures>
|
|
120
|
+
> {
|
|
97
121
|
if (typeof name !== 'string' || !name)
|
|
98
122
|
throw new Error('Name is required');
|
|
99
123
|
|
|
@@ -108,7 +132,10 @@ export default class SchemaValidator<T = Record<string, never>>
|
|
|
108
132
|
if (Array.isArray(schema)) {
|
|
109
133
|
this._schemasMap.set(name.toString(), schema as Schema<any>);
|
|
110
134
|
this._schemasCache = null;
|
|
111
|
-
return this as any as SchemaValidator<
|
|
135
|
+
return this as any as SchemaValidator<
|
|
136
|
+
T & { [key in keyof K]: L },
|
|
137
|
+
Cons<Unfold<keyof K, ISchemaActions<L>>, SchemaTypesStructures>
|
|
138
|
+
>;
|
|
112
139
|
}
|
|
113
140
|
|
|
114
141
|
if (typeof schema !== 'object')
|
|
@@ -119,20 +146,34 @@ export default class SchemaValidator<T = Record<string, never>>
|
|
|
119
146
|
} as Schema<any>);
|
|
120
147
|
this._schemasCache = null;
|
|
121
148
|
|
|
122
|
-
return this as any as SchemaValidator<
|
|
149
|
+
return this as any as SchemaValidator<
|
|
150
|
+
T & { [key in keyof K]: L },
|
|
151
|
+
Cons<Unfold<keyof K, ISchemaActions<L>>, SchemaTypesStructures>
|
|
152
|
+
>;
|
|
123
153
|
}
|
|
124
154
|
|
|
125
|
-
public get schemas():
|
|
155
|
+
public get schemas(): Merge<SchemaTypesStructures> {
|
|
126
156
|
if (this._schemasCache) return this._schemasCache;
|
|
127
157
|
const res = {};
|
|
128
158
|
for (const key of this._schemasMap.keys()) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
159
|
+
const parts = key.split('.');
|
|
160
|
+
let curr = res;
|
|
161
|
+
for (let i = 0; i < parts.length; i++) {
|
|
162
|
+
if (i === parts.length - 1) {
|
|
163
|
+
curr[parts[i]] = {
|
|
164
|
+
validate: (value: any): Promise<any> =>
|
|
165
|
+
this.validate(this._schemasMap.get(key), value),
|
|
166
|
+
schema: this._schemasMap.get(key)
|
|
167
|
+
};
|
|
168
|
+
} else {
|
|
169
|
+
if (typeof curr[parts[i]] === 'undefined') {
|
|
170
|
+
curr[parts[i]] = {};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
curr = curr[parts[i]];
|
|
174
|
+
}
|
|
134
175
|
}
|
|
135
|
-
this._schemasCache = res as
|
|
176
|
+
this._schemasCache = res as Merge<SchemaTypesStructures>;
|
|
136
177
|
return this._schemasCache;
|
|
137
178
|
}
|
|
138
179
|
|
|
@@ -144,14 +185,14 @@ export default class SchemaValidator<T = Record<string, never>>
|
|
|
144
185
|
const strategy = defaultSchemasValidationStrategies[name] as (
|
|
145
186
|
obj: any,
|
|
146
187
|
schema: Schema<any>,
|
|
147
|
-
validator: ISchemaValidator<any>
|
|
188
|
+
validator: ISchemaValidator<any, unknown[]>
|
|
148
189
|
) => ValidationResult;
|
|
149
190
|
let finalSchema = defaultSchemas[name] as CompositeSchema<
|
|
150
191
|
Record<string, never>
|
|
151
192
|
>;
|
|
152
193
|
if (strategy) {
|
|
153
194
|
if (typeof mergeSchema === 'object') {
|
|
154
|
-
finalSchema = deepExtend(finalSchema, mergeSchema);
|
|
195
|
+
finalSchema = deepExtend(finalSchema, mergeSchema) as any;
|
|
155
196
|
}
|
|
156
197
|
if (typeof mergeSchema === 'number') {
|
|
157
198
|
finalSchema = {
|
|
@@ -161,7 +202,11 @@ export default class SchemaValidator<T = Record<string, never>>
|
|
|
161
202
|
mergeSchema;
|
|
162
203
|
}
|
|
163
204
|
|
|
164
|
-
let preliminaryResult = await strategy(
|
|
205
|
+
let preliminaryResult = await strategy(
|
|
206
|
+
value,
|
|
207
|
+
finalSchema,
|
|
208
|
+
this as any
|
|
209
|
+
);
|
|
165
210
|
if (!preliminaryResult.valid) return preliminaryResult;
|
|
166
211
|
|
|
167
212
|
preliminaryResult = await this.checkValidators(finalSchema, value);
|
|
@@ -225,19 +270,15 @@ export default class SchemaValidator<T = Record<string, never>>
|
|
|
225
270
|
schema as DefaultSchemaType,
|
|
226
271
|
obj
|
|
227
272
|
);
|
|
228
|
-
} else if (typeof this.
|
|
229
|
-
if (Array.isArray(this.
|
|
230
|
-
return this.validate(
|
|
231
|
-
this.schemas[schema as keyof T]
|
|
232
|
-
.schema as any as Schema<any>,
|
|
233
|
-
obj
|
|
234
|
-
);
|
|
273
|
+
} else if (typeof this._schemasMap.get(schema) !== 'undefined') {
|
|
274
|
+
if (Array.isArray(this._schemasMap.get(schema))) {
|
|
275
|
+
return this.validate(this._schemasMap.get(schema), obj);
|
|
235
276
|
}
|
|
236
277
|
const objSchema = deepExtend(
|
|
237
278
|
defaultSchemas.object,
|
|
238
|
-
this.
|
|
279
|
+
this._schemasMap.get(schema)
|
|
239
280
|
) as ObjectSchemaDefinition<Record<string, never>>;
|
|
240
|
-
const res = await validateObject(obj, objSchema, this);
|
|
281
|
+
const res = await validateObject(obj, objSchema, this as any);
|
|
241
282
|
if (!res.valid) return res;
|
|
242
283
|
return await this.checkValidators(objSchema, obj);
|
|
243
284
|
} else {
|
|
@@ -276,8 +317,12 @@ export default class SchemaValidator<T = Record<string, never>>
|
|
|
276
317
|
schema
|
|
277
318
|
);
|
|
278
319
|
} else if (schema.type === 'alias') {
|
|
279
|
-
const alias = this.
|
|
280
|
-
|
|
320
|
+
const alias = this._schemasMap.get(schema.schemaName);
|
|
321
|
+
if (typeof alias === 'undefined') {
|
|
322
|
+
throw new Error(
|
|
323
|
+
`Unknown schema alias - ${schema.schemaName}`
|
|
324
|
+
);
|
|
325
|
+
}
|
|
281
326
|
if (Array.isArray(alias)) {
|
|
282
327
|
if (
|
|
283
328
|
(!schema.isRequired && typeof obj === 'undefined') ||
|
|
@@ -306,7 +351,7 @@ export default class SchemaValidator<T = Record<string, never>>
|
|
|
306
351
|
const preliminaryResult = await validateObject(
|
|
307
352
|
obj,
|
|
308
353
|
schema,
|
|
309
|
-
this
|
|
354
|
+
this as any
|
|
310
355
|
);
|
|
311
356
|
if (!preliminaryResult.valid) return preliminaryResult;
|
|
312
357
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ValidationResult,
|
|
3
|
+
BooleanSchemaDefinition,
|
|
4
|
+
ISchemaValidator
|
|
5
|
+
} from '../index';
|
|
6
|
+
|
|
7
|
+
export const validateBoolean = async (
|
|
8
|
+
obj: any,
|
|
9
|
+
schema: BooleanSchemaDefinition<any>,
|
|
10
|
+
validator: ISchemaValidator<any>
|
|
11
|
+
): Promise<ValidationResult> => {
|
|
12
|
+
if (
|
|
13
|
+
typeof obj === 'undefined' &&
|
|
14
|
+
typeof schema === 'object' &&
|
|
15
|
+
schema.isRequired === false
|
|
16
|
+
) {
|
|
17
|
+
return {
|
|
18
|
+
valid: true
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
if (typeof obj !== 'boolean')
|
|
22
|
+
return {
|
|
23
|
+
valid: false,
|
|
24
|
+
errors: [`expected type boolean, but saw ${typeof obj}`]
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (typeof schema === 'boolean') {
|
|
28
|
+
return { valid: true };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const bool = obj as boolean;
|
|
32
|
+
|
|
33
|
+
if (typeof schema.equals === 'boolean') {
|
|
34
|
+
return schema.equals === bool
|
|
35
|
+
? { valid: true }
|
|
36
|
+
: {
|
|
37
|
+
valid: false,
|
|
38
|
+
errors: [`must be equal to ${schema.equals}`]
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
valid: true
|
|
44
|
+
};
|
|
45
|
+
};
|