@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
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateObject = void 0;
|
|
4
|
+
const validateObject = 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 !== 'object') {
|
|
13
|
+
return {
|
|
14
|
+
valid: false,
|
|
15
|
+
errors: [
|
|
16
|
+
`expected to have type='object', but saw '${typeof obj}' instead`
|
|
17
|
+
]
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (typeof schema.properties === 'object' && schema.properties) {
|
|
21
|
+
const errors = (await Promise.all(Object.entries(schema.properties).map(async ([name, schema]) => {
|
|
22
|
+
const result = await validator.validate(schema, obj[name]);
|
|
23
|
+
if (result.valid)
|
|
24
|
+
return result;
|
|
25
|
+
return {
|
|
26
|
+
valid: false,
|
|
27
|
+
errors: (result.errors || []).map((e) => `->${name} ${e}`)
|
|
28
|
+
};
|
|
29
|
+
})))
|
|
30
|
+
.filter((r) => !r.valid)
|
|
31
|
+
.map((r) => r.errors)
|
|
32
|
+
.flat(Infinity);
|
|
33
|
+
if (errors.length) {
|
|
34
|
+
return {
|
|
35
|
+
valid: false,
|
|
36
|
+
errors
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
valid: true
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
exports.validateObject = validateObject;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateString = void 0;
|
|
4
|
+
const validateString = 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 !== 'string')
|
|
13
|
+
return {
|
|
14
|
+
valid: false,
|
|
15
|
+
errors: [`expected type string, but saw ${typeof obj}`]
|
|
16
|
+
};
|
|
17
|
+
if (typeof schema === 'string') {
|
|
18
|
+
return obj === schema
|
|
19
|
+
? { valid: true }
|
|
20
|
+
: {
|
|
21
|
+
valid: false,
|
|
22
|
+
errors: [`should be equal to ${schema}`]
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const str = obj;
|
|
26
|
+
if (typeof schema.equals === 'string' && str !== schema.equals) {
|
|
27
|
+
return {
|
|
28
|
+
valid: false,
|
|
29
|
+
errors: [
|
|
30
|
+
`expected to be equal to '${schema.equals}' but saw '${str}'`
|
|
31
|
+
]
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (typeof schema.minLength === 'number' && str.length < schema.minLength) {
|
|
35
|
+
return {
|
|
36
|
+
valid: false,
|
|
37
|
+
errors: [`expected to be at least ${schema.minLength} chars long`]
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (typeof schema.maxLength === 'number' && str.length > schema.maxLength) {
|
|
41
|
+
return {
|
|
42
|
+
valid: false,
|
|
43
|
+
errors: [`expected to be at most ${schema.maxLength} chars long`]
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
valid: true
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
exports.validateString = validateString;
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cleverbrush/schema",
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"keywords": [
|
|
5
|
+
"object schema validator",
|
|
6
|
+
"schema",
|
|
7
|
+
"validate object"
|
|
8
|
+
],
|
|
9
|
+
"author": "Andrew Zolotukhin <andrew_zol@cleverbrush.com>",
|
|
10
|
+
"license": "BSD",
|
|
11
|
+
"main": "./dist/index.js",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"watch": "tsc --watch",
|
|
14
|
+
"build": "tsc"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@cleverbrush/deep": "0.0.3"
|
|
18
|
+
},
|
|
19
|
+
"types": "./dist/index.d.ts"
|
|
20
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import SchemaValidator from './schemaValidator';
|
|
2
|
+
|
|
3
|
+
export type DefaultSchemaType =
|
|
4
|
+
| 'object'
|
|
5
|
+
| 'function'
|
|
6
|
+
| 'number'
|
|
7
|
+
| 'string'
|
|
8
|
+
| 'array';
|
|
9
|
+
|
|
10
|
+
export type PropType<TObj, TProp extends keyof TObj> = TObj[TProp];
|
|
11
|
+
|
|
12
|
+
export type DefaultPropertyDefinition = {
|
|
13
|
+
isRequired: boolean;
|
|
14
|
+
isNullable: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type ValidationResultRaw = {
|
|
18
|
+
valid: boolean;
|
|
19
|
+
errors?: Array<string>;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type ValidationResult =
|
|
23
|
+
| ValidationResultRaw
|
|
24
|
+
| Promise<ValidationResultRaw>;
|
|
25
|
+
|
|
26
|
+
export type Validator<TObj> = (value: TObj) => ValidationResult;
|
|
27
|
+
|
|
28
|
+
export type SchemaDefintion<TObj> = {
|
|
29
|
+
type: DefaultSchemaType;
|
|
30
|
+
isRequired?: boolean;
|
|
31
|
+
isNullable?: boolean;
|
|
32
|
+
validators?: Array<Validator<TObj>>;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type ObjectSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'> & {
|
|
36
|
+
type: 'object';
|
|
37
|
+
extends?: string;
|
|
38
|
+
properties?: Partial<{
|
|
39
|
+
[S in keyof T]: Schema<PropType<T, S>>;
|
|
40
|
+
}>;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type ObjectSchemaDefinitionParam<T> = Omit<
|
|
44
|
+
ObjectSchemaDefinition<T>,
|
|
45
|
+
'type'
|
|
46
|
+
>;
|
|
47
|
+
|
|
48
|
+
export type ParamsValidators<TFunc extends (...args: any) => any> = {
|
|
49
|
+
[S in keyof Parameters<TFunc>]: SingleSchema<Parameters<TFunc>[S]>;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export type FunctionSchemaDefinition<T extends (...args: any) => any> = Omit<
|
|
53
|
+
SchemaDefintion<T>,
|
|
54
|
+
'type'
|
|
55
|
+
> & {
|
|
56
|
+
type: 'function';
|
|
57
|
+
params?: ParamsValidators<T>;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export type NumberSchemaDefinition<TObj> = Omit<
|
|
61
|
+
SchemaDefintion<TObj>,
|
|
62
|
+
'type'
|
|
63
|
+
> & {
|
|
64
|
+
type: 'number';
|
|
65
|
+
min?: number;
|
|
66
|
+
max?: number;
|
|
67
|
+
equals?: number;
|
|
68
|
+
isInteger?: boolean;
|
|
69
|
+
ensureNotNaN?: boolean;
|
|
70
|
+
ensureIsFinite?: boolean;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export type StringSchemaDefinition<TObj> = Omit<
|
|
74
|
+
SchemaDefintion<TObj>,
|
|
75
|
+
'type'
|
|
76
|
+
> & {
|
|
77
|
+
type: 'string';
|
|
78
|
+
equals?: string;
|
|
79
|
+
minLength?: number;
|
|
80
|
+
maxLength?: number;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type ArraySchemaDefinition<TObj> = Omit<
|
|
84
|
+
SchemaDefintion<TObj>,
|
|
85
|
+
'type'
|
|
86
|
+
> & {
|
|
87
|
+
type: 'array';
|
|
88
|
+
ofType?: Schema<any>;
|
|
89
|
+
minLength?: number;
|
|
90
|
+
maxLength?: number;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export type CompositeSchema<TObj> = TObj extends (...args: any) => any
|
|
94
|
+
? FunctionSchemaDefinition<TObj>
|
|
95
|
+
: TObj extends number
|
|
96
|
+
? NumberSchemaDefinition<TObj>
|
|
97
|
+
: TObj extends string
|
|
98
|
+
? StringSchemaDefinition<TObj> | 'string'
|
|
99
|
+
:
|
|
100
|
+
| NumberSchemaDefinition<TObj>
|
|
101
|
+
| StringSchemaDefinition<TObj>
|
|
102
|
+
| ArraySchemaDefinition<TObj>
|
|
103
|
+
| ObjectSchemaDefinition<TObj>;
|
|
104
|
+
|
|
105
|
+
export type SingleSchema<TObj = Record<string, never>> =
|
|
106
|
+
| number
|
|
107
|
+
| string
|
|
108
|
+
| DefaultSchemaType
|
|
109
|
+
| CompositeSchema<TObj>;
|
|
110
|
+
|
|
111
|
+
export type Schema<TObj> = SingleSchema<TObj> | Array<SingleSchema<TObj>>;
|
|
112
|
+
|
|
113
|
+
export interface ISchemaActions<K, T extends keyof K> {
|
|
114
|
+
validate(value: any): Promise<ValidationResult>;
|
|
115
|
+
schema: PropType<K, T>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface ISchemasProvider<T = Record<string, never>> {
|
|
119
|
+
schemas: {
|
|
120
|
+
[K in keyof T]: ISchemaActions<T, K>;
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface ISchemaValidator<T = Record<string, never>> {
|
|
125
|
+
addSchemaType<K, L extends ObjectSchemaDefinitionParam<M>, M = any>(
|
|
126
|
+
name: keyof K,
|
|
127
|
+
schema: L
|
|
128
|
+
): SchemaValidator<T & { [key in keyof K]: L }>;
|
|
129
|
+
|
|
130
|
+
validate(
|
|
131
|
+
schema: keyof T | DefaultSchemaType | Schema<any>,
|
|
132
|
+
obj: any
|
|
133
|
+
): Promise<ValidationResult>;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export { SchemaValidator };
|
|
137
|
+
export default SchemaValidator;
|