@cleverbrush/schema 0.0.7 → 0.0.8
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 -2
- package/dist/schemaValidator.js +18 -0
- package/package.json +2 -2
- package/src/index.ts +9 -2
- package/src/schemaValidator.test.ts +33 -1
- package/src/schemaValidator.ts +25 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import SchemaValidator from './schemaValidator';
|
|
2
|
-
export declare type DefaultSchemaType = 'object' | 'function' | 'number' | 'string' | 'array';
|
|
2
|
+
export declare type DefaultSchemaType = 'object' | 'function' | 'number' | 'string' | 'array' | 'alias';
|
|
3
3
|
export declare type PropType<TObj, TProp extends keyof TObj> = TObj[TProp];
|
|
4
4
|
export declare type DefaultPropertyDefinition = {
|
|
5
5
|
isRequired: boolean;
|
|
@@ -24,6 +24,10 @@ export declare type ObjectSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'>
|
|
|
24
24
|
[S in keyof T]: Schema<PropType<T, S>>;
|
|
25
25
|
}>;
|
|
26
26
|
};
|
|
27
|
+
export declare type AliasSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'> & {
|
|
28
|
+
type: 'alias';
|
|
29
|
+
schemaName: string;
|
|
30
|
+
};
|
|
27
31
|
export declare type ObjectSchemaDefinitionParam<T> = Omit<ObjectSchemaDefinition<T>, 'type'>;
|
|
28
32
|
export declare type ParamsValidators<TFunc extends (...args: any) => any> = {
|
|
29
33
|
[S in keyof Parameters<TFunc>]: SingleSchema<Parameters<TFunc>[S]>;
|
|
@@ -53,7 +57,7 @@ export declare type ArraySchemaDefinition<TObj> = Omit<SchemaDefintion<TObj>, 't
|
|
|
53
57
|
minLength?: number;
|
|
54
58
|
maxLength?: number;
|
|
55
59
|
};
|
|
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>;
|
|
60
|
+
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>;
|
|
57
61
|
export declare type SingleSchema<TObj = Record<string, never>> = number | string | DefaultSchemaType | CompositeSchema<TObj>;
|
|
58
62
|
export declare type Schema<TObj> = SingleSchema<TObj> | Array<SingleSchema<TObj>>;
|
|
59
63
|
export interface ISchemaActions<K, T extends keyof K> {
|
package/dist/schemaValidator.js
CHANGED
|
@@ -95,6 +95,11 @@ class SchemaValidator {
|
|
|
95
95
|
throw new Error('not implemented');
|
|
96
96
|
}
|
|
97
97
|
async checkValidators(schema, value) {
|
|
98
|
+
if (!schema.isRequired && typeof value === 'undefined') {
|
|
99
|
+
return {
|
|
100
|
+
valid: true
|
|
101
|
+
};
|
|
102
|
+
}
|
|
98
103
|
if (Array.isArray(schema.validators)) {
|
|
99
104
|
const validatorsResults = await Promise.allSettled(schema.validators.map((v) => Promise.resolve(v(value))));
|
|
100
105
|
const rejections = validatorsResults
|
|
@@ -166,6 +171,19 @@ class SchemaValidator {
|
|
|
166
171
|
if (isDefaultType(schema.type)) {
|
|
167
172
|
return await this.validateDefaultType(schema.type, obj, schema);
|
|
168
173
|
}
|
|
174
|
+
else if (schema.type === 'alias') {
|
|
175
|
+
const alias = this.schemas[schema.schemaName]
|
|
176
|
+
.schema;
|
|
177
|
+
if (Array.isArray(alias))
|
|
178
|
+
throw new Error('it is impossible to use alternative schema alias as "type" field');
|
|
179
|
+
if (typeof alias !== 'object')
|
|
180
|
+
throw new Error('it is only possible to use a full schema schema definition as alias');
|
|
181
|
+
const schemaToMerge = { ...schema };
|
|
182
|
+
delete schemaToMerge.type;
|
|
183
|
+
delete schemaToMerge.schemaName;
|
|
184
|
+
const finalSchema = (0, deep_1.deepExtend)(alias, schemaToMerge);
|
|
185
|
+
return await this.validate(finalSchema, obj);
|
|
186
|
+
}
|
|
169
187
|
else if (schema.type === 'object') {
|
|
170
188
|
const preliminaryResult = await (0, validateObject_1.validateObject)(obj, schema, this);
|
|
171
189
|
if (!preliminaryResult.valid)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cleverbrush/schema",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
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.8"
|
|
23
23
|
},
|
|
24
24
|
"types": "./dist/index.d.ts"
|
|
25
25
|
}
|
package/src/index.ts
CHANGED
|
@@ -5,7 +5,8 @@ export type DefaultSchemaType =
|
|
|
5
5
|
| 'function'
|
|
6
6
|
| 'number'
|
|
7
7
|
| 'string'
|
|
8
|
-
| 'array'
|
|
8
|
+
| 'array'
|
|
9
|
+
| 'alias';
|
|
9
10
|
|
|
10
11
|
export type PropType<TObj, TProp extends keyof TObj> = TObj[TProp];
|
|
11
12
|
|
|
@@ -40,6 +41,11 @@ export type ObjectSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'> & {
|
|
|
40
41
|
}>;
|
|
41
42
|
};
|
|
42
43
|
|
|
44
|
+
export type AliasSchemaDefinition<T> = Omit<SchemaDefintion<T>, 'type'> & {
|
|
45
|
+
type: 'alias';
|
|
46
|
+
schemaName: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
43
49
|
export type ObjectSchemaDefinitionParam<T> = Omit<
|
|
44
50
|
ObjectSchemaDefinition<T>,
|
|
45
51
|
'type'
|
|
@@ -100,7 +106,8 @@ export type CompositeSchema<TObj> = TObj extends (...args: any) => any
|
|
|
100
106
|
| NumberSchemaDefinition<TObj>
|
|
101
107
|
| StringSchemaDefinition<TObj>
|
|
102
108
|
| ArraySchemaDefinition<TObj>
|
|
103
|
-
| ObjectSchemaDefinition<TObj
|
|
109
|
+
| ObjectSchemaDefinition<TObj>
|
|
110
|
+
| AliasSchemaDefinition<TObj>;
|
|
104
111
|
|
|
105
112
|
export type SingleSchema<TObj = Record<string, never>> =
|
|
106
113
|
| number
|
|
@@ -913,7 +913,7 @@ test('Validate - one of - 1', async () => {
|
|
|
913
913
|
expect(result).toHaveProperty('valid', true);
|
|
914
914
|
});
|
|
915
915
|
|
|
916
|
-
test('Validate schema', async () => {
|
|
916
|
+
test('Validate schema - 1', async () => {
|
|
917
917
|
const authorsReportSpecificationSchema = {
|
|
918
918
|
properties: {
|
|
919
919
|
type: {
|
|
@@ -1120,3 +1120,35 @@ test('Validate schema', async () => {
|
|
|
1120
1120
|
|
|
1121
1121
|
expect(result).toHaveProperty('valid', true);
|
|
1122
1122
|
});
|
|
1123
|
+
|
|
1124
|
+
test('Validate schema - 2', async () => {
|
|
1125
|
+
const validator = new SchemaValidator().addSchemaType('Date', {
|
|
1126
|
+
validators: [
|
|
1127
|
+
(value) =>
|
|
1128
|
+
value instanceof Date && !Number.isNaN(value)
|
|
1129
|
+
? {
|
|
1130
|
+
valid: true
|
|
1131
|
+
}
|
|
1132
|
+
: {
|
|
1133
|
+
valid: false,
|
|
1134
|
+
errors: ['should be a valid Date object']
|
|
1135
|
+
}
|
|
1136
|
+
]
|
|
1137
|
+
});
|
|
1138
|
+
|
|
1139
|
+
const result = await validator.validate(
|
|
1140
|
+
{
|
|
1141
|
+
type: 'object',
|
|
1142
|
+
properties: {
|
|
1143
|
+
date: {
|
|
1144
|
+
type: 'alias',
|
|
1145
|
+
schemaName: 'Date',
|
|
1146
|
+
isRequired: false
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
},
|
|
1150
|
+
{}
|
|
1151
|
+
);
|
|
1152
|
+
|
|
1153
|
+
expect(result).toHaveProperty('valid', true);
|
|
1154
|
+
});
|
package/src/schemaValidator.ts
CHANGED
|
@@ -156,6 +156,11 @@ export default class SchemaValidator<T = Record<string, never>>
|
|
|
156
156
|
schema: CompositeSchema<Record<string, never>>,
|
|
157
157
|
value: any
|
|
158
158
|
): Promise<ValidationResult> {
|
|
159
|
+
if (!schema.isRequired && typeof value === 'undefined') {
|
|
160
|
+
return {
|
|
161
|
+
valid: true
|
|
162
|
+
};
|
|
163
|
+
}
|
|
159
164
|
if (Array.isArray(schema.validators)) {
|
|
160
165
|
const validatorsResults = await Promise.allSettled(
|
|
161
166
|
schema.validators.map((v) => Promise.resolve(v(value)))
|
|
@@ -251,6 +256,26 @@ export default class SchemaValidator<T = Record<string, never>>
|
|
|
251
256
|
obj,
|
|
252
257
|
schema
|
|
253
258
|
);
|
|
259
|
+
} else if (schema.type === 'alias') {
|
|
260
|
+
const alias = this.schemas[schema.schemaName]
|
|
261
|
+
.schema as Schema<any>;
|
|
262
|
+
if (Array.isArray(alias))
|
|
263
|
+
throw new Error(
|
|
264
|
+
'it is impossible to use alternative schema alias as "type" field'
|
|
265
|
+
);
|
|
266
|
+
if (typeof alias !== 'object')
|
|
267
|
+
throw new Error(
|
|
268
|
+
'it is only possible to use a full schema schema definition as alias'
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
const schemaToMerge = { ...schema };
|
|
272
|
+
delete schemaToMerge.type;
|
|
273
|
+
delete schemaToMerge.schemaName;
|
|
274
|
+
const finalSchema: Schema<any> = deepExtend(
|
|
275
|
+
alias,
|
|
276
|
+
schemaToMerge
|
|
277
|
+
);
|
|
278
|
+
return await this.validate(finalSchema, obj);
|
|
254
279
|
} else if (schema.type === 'object') {
|
|
255
280
|
const preliminaryResult = await validateObject(
|
|
256
281
|
obj,
|