@cleverbrush/schema 0.0.16 → 1.0.0-beta.0
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 +224 -149
- package/dist/builders/AliasSchemaBuilder.d.ts +14 -0
- package/dist/builders/AliasSchemaBuilder.js +91 -0
- package/dist/builders/ArraySchemaBuilder.d.ts +15 -0
- package/dist/builders/ArraySchemaBuilder.js +141 -0
- package/dist/builders/BooleanSchemaBuilder.d.ts +31 -0
- package/dist/builders/BooleanSchemaBuilder.js +90 -0
- package/dist/builders/FunctionSchemaBuilder.d.ts +25 -0
- package/dist/builders/FunctionSchemaBuilder.js +66 -0
- package/dist/builders/NumberSchemaBuilder.d.ts +61 -0
- package/dist/builders/NumberSchemaBuilder.js +206 -0
- package/dist/builders/ObjectSchemaBuilder.d.ts +83 -0
- package/dist/builders/ObjectSchemaBuilder.js +344 -0
- package/dist/builders/SchemaBuilder.d.ts +36 -0
- package/dist/builders/SchemaBuilder.js +88 -0
- package/dist/builders/StringSchemaBuilder.d.ts +14 -0
- package/dist/builders/StringSchemaBuilder.js +140 -0
- package/dist/builders/UnionSchemaBuilder.d.ts +10 -0
- package/dist/builders/UnionSchemaBuilder.js +100 -0
- package/dist/defaultSchemas.d.ts +4 -0
- package/dist/defaultSchemas.js +45 -0
- package/dist/index.d.ts +38 -90
- package/dist/index.js +30 -4
- package/dist/schema.d.ts +242 -0
- package/dist/schema.js +2 -0
- package/dist/schemaRegistry.d.ts +54 -0
- package/dist/schemaRegistry.js +301 -0
- package/dist/validators/validateArray.d.ts +3 -2
- package/dist/validators/validateBoolean.d.ts +2 -2
- package/dist/validators/validateBoolean.js +1 -4
- package/dist/validators/validateFunction.d.ts +2 -0
- package/dist/validators/validateFunction.js +21 -0
- package/dist/validators/validateNumber.d.ts +2 -2
- package/dist/validators/validateNumber.js +1 -1
- package/dist/validators/validateObject.d.ts +3 -2
- package/dist/validators/validateObject.js +33 -11
- package/dist/validators/validateString.d.ts +2 -2
- package/dist/validators/validateString.js +1 -1
- package/dist/validators/validateUnion.d.ts +3 -0
- package/dist/validators/validateUnion.js +30 -0
- package/package.json +3 -3
- package/src/builders/AliasSchemaBuilder.test.ts +124 -0
- package/src/builders/AliasSchemaBuilder.ts +250 -0
- package/src/builders/ArraySchemaBuilder.test.ts +270 -0
- package/src/builders/ArraySchemaBuilder.ts +381 -0
- package/src/builders/BooleanSchemaBuilder.test.ts +196 -0
- package/src/builders/BooleanSchemaBuilder.ts +155 -0
- package/src/builders/FunctionSchemaBuilder.test.ts +134 -0
- package/src/builders/FunctionSchemaBuilder.ts +109 -0
- package/src/builders/NumberSchemaBuilder.test.ts +493 -0
- package/src/builders/NumberSchemaBuilder.ts +789 -0
- package/src/builders/ObjectSchemaBuilder.test.ts +657 -0
- package/src/builders/ObjectSchemaBuilder.ts +794 -0
- package/src/builders/SchemaBuilder.test.ts +73 -0
- package/src/builders/SchemaBuilder.ts +135 -0
- package/src/builders/StringSchemaBuilder.test.ts +318 -0
- package/src/builders/StringSchemaBuilder.ts +392 -0
- package/src/builders/UnionSchemaBuilder.test.ts +162 -0
- package/src/builders/UnionSchemaBuilder.ts +159 -0
- package/src/defaultSchemas.ts +44 -0
- package/src/index.ts +70 -190
- package/src/schema.ts +922 -0
- package/src/schemaRegistry.builders.test.ts +1438 -0
- package/src/{schemaValidator.test.ts → schemaRegistry.test.ts} +561 -185
- package/src/schemaRegistry.ts +532 -0
- package/src/validators/validateArray.ts +4 -7
- package/src/validators/validateBoolean.ts +2 -11
- package/src/validators/validateFunction.ts +25 -0
- package/src/validators/validateNumber.ts +2 -7
- package/src/validators/validateObject.ts +32 -21
- package/src/validators/validateString.ts +2 -7
- package/src/validators/validateUnion.ts +36 -0
- package/dist/schemaValidator.d.ts +0 -16
- package/dist/schemaValidator.js +0 -234
- package/src/schemaValidator.ts +0 -367
package/src/schemaValidator.ts
DELETED
|
@@ -1,367 +0,0 @@
|
|
|
1
|
-
import { deepExtend, Merge } from '@cleverbrush/deep';
|
|
2
|
-
import {
|
|
3
|
-
ISchemasProvider,
|
|
4
|
-
Schema,
|
|
5
|
-
ISchemaActions,
|
|
6
|
-
ObjectSchemaDefinitionParam,
|
|
7
|
-
ValidationResult,
|
|
8
|
-
NumberSchemaDefinition,
|
|
9
|
-
StringSchemaDefinition,
|
|
10
|
-
CompositeSchema,
|
|
11
|
-
ValidationResultRaw,
|
|
12
|
-
ArraySchemaDefinition,
|
|
13
|
-
ISchemaValidator,
|
|
14
|
-
DefaultSchemaType,
|
|
15
|
-
ObjectSchemaDefinition,
|
|
16
|
-
BooleanSchemaDefinition,
|
|
17
|
-
Cons,
|
|
18
|
-
Unfold
|
|
19
|
-
} from './index';
|
|
20
|
-
import { validateNumber } from './validators/validateNumber';
|
|
21
|
-
import { validateBoolean } from './validators/validateBoolean';
|
|
22
|
-
import { validateString } from './validators/validateString';
|
|
23
|
-
import { validateArray } from './validators/validateArray';
|
|
24
|
-
import { validateObject } from './validators/validateObject';
|
|
25
|
-
|
|
26
|
-
const defaultSchemaNames = ['string', 'boolean', 'number', 'date', 'array'];
|
|
27
|
-
|
|
28
|
-
const defaultSchemas: { [key in DefaultSchemaType]?: Schema<any> } = {
|
|
29
|
-
number: {
|
|
30
|
-
type: 'number',
|
|
31
|
-
isRequired: true,
|
|
32
|
-
isNullable: false,
|
|
33
|
-
ensureNotNaN: true,
|
|
34
|
-
ensureIsFinite: true
|
|
35
|
-
},
|
|
36
|
-
boolean: {
|
|
37
|
-
type: 'boolean',
|
|
38
|
-
isRequired: true,
|
|
39
|
-
isNullable: false
|
|
40
|
-
},
|
|
41
|
-
string: {
|
|
42
|
-
type: 'string',
|
|
43
|
-
isNullable: false,
|
|
44
|
-
isRequired: true
|
|
45
|
-
},
|
|
46
|
-
array: {
|
|
47
|
-
type: 'array'
|
|
48
|
-
},
|
|
49
|
-
object: {
|
|
50
|
-
type: 'object',
|
|
51
|
-
isNullable: false,
|
|
52
|
-
isRequired: true
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
const defaultSchemasValidationStrategies = {
|
|
57
|
-
number: (
|
|
58
|
-
obj: any,
|
|
59
|
-
schema: NumberSchemaDefinition<any>,
|
|
60
|
-
validator: ISchemaValidator<any, unknown[]>
|
|
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),
|
|
67
|
-
string: (
|
|
68
|
-
obj: any,
|
|
69
|
-
schema: StringSchemaDefinition<any>,
|
|
70
|
-
validator: ISchemaValidator<any, unknown[]>
|
|
71
|
-
): Promise<ValidationResult> => validateString(obj, schema, validator),
|
|
72
|
-
array: (
|
|
73
|
-
obj: any,
|
|
74
|
-
schema: ArraySchemaDefinition<any>,
|
|
75
|
-
validator: ISchemaValidator<any, unknown[]>
|
|
76
|
-
): Promise<ValidationResult> => validateArray(obj, schema, validator)
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const isDefaultType = (name: string): boolean =>
|
|
80
|
-
defaultSchemaNames.indexOf(name) !== -1;
|
|
81
|
-
|
|
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>
|
|
88
|
-
{
|
|
89
|
-
private _schemasMap = new Map<string, Schema<any>>();
|
|
90
|
-
private _schemasCache: Merge<SchemaTypesStructures> = null;
|
|
91
|
-
private _preprocessorsMap = new Map<
|
|
92
|
-
string,
|
|
93
|
-
(value: unknown) => unknown | Promise<unknown> | undefined
|
|
94
|
-
>();
|
|
95
|
-
|
|
96
|
-
public get preprocessors(): Map<string, (value: unknown) => unknown> {
|
|
97
|
-
return this._preprocessorsMap;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
public addPreprocessor(
|
|
101
|
-
name: string,
|
|
102
|
-
preprocessor: (value: unknown) => unknown | Promise<unknown>
|
|
103
|
-
): SchemaValidator<T, SchemaTypesStructures> {
|
|
104
|
-
if (this._preprocessorsMap.has(name))
|
|
105
|
-
throw new Error(`Preprocessor '${name}' is already registered`);
|
|
106
|
-
this._preprocessorsMap.set(name, preprocessor);
|
|
107
|
-
return this;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
public addSchemaType<
|
|
111
|
-
K,
|
|
112
|
-
L extends ObjectSchemaDefinitionParam<M> | Array<Schema<any>>,
|
|
113
|
-
M = any
|
|
114
|
-
>(
|
|
115
|
-
name: keyof K,
|
|
116
|
-
schema: L
|
|
117
|
-
): SchemaValidator<
|
|
118
|
-
T & { [key in keyof K]: L },
|
|
119
|
-
Cons<Unfold<keyof K, ISchemaActions<L>>, SchemaTypesStructures>
|
|
120
|
-
> {
|
|
121
|
-
if (typeof name !== 'string' || !name)
|
|
122
|
-
throw new Error('Name is required');
|
|
123
|
-
|
|
124
|
-
if (isDefaultType(name.toString()))
|
|
125
|
-
throw new Error(
|
|
126
|
-
`You can't add a schema named "${name}" because it's a name of a default schema, please consider another name to be used`
|
|
127
|
-
);
|
|
128
|
-
if (this._schemasMap.has(name.toString())) {
|
|
129
|
-
throw new Error(`Schema "${name}" already exists`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (Array.isArray(schema)) {
|
|
133
|
-
this._schemasMap.set(name.toString(), schema as Schema<any>);
|
|
134
|
-
this._schemasCache = null;
|
|
135
|
-
return this as any as SchemaValidator<
|
|
136
|
-
T & { [key in keyof K]: L },
|
|
137
|
-
Cons<Unfold<keyof K, ISchemaActions<L>>, SchemaTypesStructures>
|
|
138
|
-
>;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (typeof schema !== 'object')
|
|
142
|
-
throw new Error('Array or Object is required');
|
|
143
|
-
this._schemasMap.set(name.toString(), {
|
|
144
|
-
...schema,
|
|
145
|
-
type: 'object'
|
|
146
|
-
} as Schema<any>);
|
|
147
|
-
this._schemasCache = null;
|
|
148
|
-
|
|
149
|
-
return this as any as SchemaValidator<
|
|
150
|
-
T & { [key in keyof K]: L },
|
|
151
|
-
Cons<Unfold<keyof K, ISchemaActions<L>>, SchemaTypesStructures>
|
|
152
|
-
>;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
public get schemas(): Merge<SchemaTypesStructures> {
|
|
156
|
-
if (this._schemasCache) return this._schemasCache;
|
|
157
|
-
const res = {};
|
|
158
|
-
for (const key of this._schemasMap.keys()) {
|
|
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
|
-
}
|
|
175
|
-
}
|
|
176
|
-
this._schemasCache = res as Merge<SchemaTypesStructures>;
|
|
177
|
-
return this._schemasCache;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
private async validateDefaultType(
|
|
181
|
-
name: DefaultSchemaType,
|
|
182
|
-
value: any,
|
|
183
|
-
mergeSchema?: Schema<any>
|
|
184
|
-
): Promise<ValidationResult> {
|
|
185
|
-
const strategy = defaultSchemasValidationStrategies[name] as (
|
|
186
|
-
obj: any,
|
|
187
|
-
schema: Schema<any>,
|
|
188
|
-
validator: ISchemaValidator<any, unknown[]>
|
|
189
|
-
) => ValidationResult;
|
|
190
|
-
let finalSchema = defaultSchemas[name] as CompositeSchema<
|
|
191
|
-
Record<string, never>
|
|
192
|
-
>;
|
|
193
|
-
if (strategy) {
|
|
194
|
-
if (typeof mergeSchema === 'object') {
|
|
195
|
-
finalSchema = deepExtend(finalSchema, mergeSchema) as any;
|
|
196
|
-
}
|
|
197
|
-
if (typeof mergeSchema === 'number') {
|
|
198
|
-
finalSchema = {
|
|
199
|
-
...finalSchema,
|
|
200
|
-
equals: mergeSchema
|
|
201
|
-
} as NumberSchemaDefinition<any>;
|
|
202
|
-
mergeSchema;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
let preliminaryResult = await strategy(
|
|
206
|
-
value,
|
|
207
|
-
finalSchema,
|
|
208
|
-
this as any
|
|
209
|
-
);
|
|
210
|
-
if (!preliminaryResult.valid) return preliminaryResult;
|
|
211
|
-
|
|
212
|
-
preliminaryResult = await this.checkValidators(finalSchema, value);
|
|
213
|
-
|
|
214
|
-
return preliminaryResult;
|
|
215
|
-
}
|
|
216
|
-
throw new Error('not implemented');
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
private async checkValidators(
|
|
220
|
-
schema: CompositeSchema<Record<string, never>>,
|
|
221
|
-
value: any
|
|
222
|
-
): Promise<ValidationResult> {
|
|
223
|
-
if (!schema.isRequired && typeof value === 'undefined') {
|
|
224
|
-
return {
|
|
225
|
-
valid: true
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
if (Array.isArray(schema.validators)) {
|
|
229
|
-
const validatorsResults = await Promise.allSettled(
|
|
230
|
-
schema.validators.map((v) => Promise.resolve(v(value)))
|
|
231
|
-
);
|
|
232
|
-
const rejections = validatorsResults
|
|
233
|
-
.filter((f) => f.status === 'rejected')
|
|
234
|
-
.map((f: PromiseRejectedResult) => f.reason);
|
|
235
|
-
const errors = validatorsResults
|
|
236
|
-
.filter(
|
|
237
|
-
(f) =>
|
|
238
|
-
f.status === 'fulfilled' &&
|
|
239
|
-
typeof f.value !== 'boolean' &&
|
|
240
|
-
f.value.valid === false
|
|
241
|
-
)
|
|
242
|
-
.map(
|
|
243
|
-
(f: PromiseFulfilledResult<ValidationResultRaw>) => f.value
|
|
244
|
-
)
|
|
245
|
-
.map((f: ValidationResultRaw) => f.errors);
|
|
246
|
-
|
|
247
|
-
if (rejections.length === 0 && errors.length === 0) {
|
|
248
|
-
return {
|
|
249
|
-
valid: true
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
return {
|
|
253
|
-
valid: false,
|
|
254
|
-
errors: [...rejections, ...errors]
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
return {
|
|
258
|
-
valid: true
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
public async validate<K>(
|
|
263
|
-
schema: keyof T | DefaultSchemaType | Schema<K>,
|
|
264
|
-
obj: any
|
|
265
|
-
): Promise<ValidationResult> {
|
|
266
|
-
if (!schema) throw new Error('schemaName is required');
|
|
267
|
-
if (typeof schema === 'string') {
|
|
268
|
-
if (isDefaultType(schema)) {
|
|
269
|
-
return await this.validateDefaultType(
|
|
270
|
-
schema as DefaultSchemaType,
|
|
271
|
-
obj
|
|
272
|
-
);
|
|
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);
|
|
276
|
-
}
|
|
277
|
-
const objSchema = deepExtend(
|
|
278
|
-
defaultSchemas.object,
|
|
279
|
-
this._schemasMap.get(schema)
|
|
280
|
-
) as ObjectSchemaDefinition<Record<string, never>>;
|
|
281
|
-
const res = await validateObject(obj, objSchema, this as any);
|
|
282
|
-
if (!res.valid) return res;
|
|
283
|
-
return await this.checkValidators(objSchema, obj);
|
|
284
|
-
} else {
|
|
285
|
-
return await this.validateDefaultType('string', obj, {
|
|
286
|
-
type: 'string',
|
|
287
|
-
equals: schema
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
if (Array.isArray(schema)) {
|
|
293
|
-
for (let i = 0; i < schema.length; i++) {
|
|
294
|
-
const res = await this.validate(schema[i], obj);
|
|
295
|
-
if (res.valid) {
|
|
296
|
-
return res;
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
return {
|
|
300
|
-
valid: false,
|
|
301
|
-
errors: ['object does not match any schema']
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
if (typeof schema === 'number') {
|
|
306
|
-
return await this.validateDefaultType('number', obj, schema);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
if (typeof schema === 'object') {
|
|
310
|
-
if (typeof schema.type !== 'string')
|
|
311
|
-
throw new Error('Schema has no type');
|
|
312
|
-
|
|
313
|
-
if (isDefaultType(schema.type)) {
|
|
314
|
-
return await this.validateDefaultType(
|
|
315
|
-
schema.type as DefaultSchemaType,
|
|
316
|
-
obj,
|
|
317
|
-
schema
|
|
318
|
-
);
|
|
319
|
-
} else if (schema.type === 'alias') {
|
|
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
|
-
}
|
|
326
|
-
if (Array.isArray(alias)) {
|
|
327
|
-
if (
|
|
328
|
-
(!schema.isRequired && typeof obj === 'undefined') ||
|
|
329
|
-
(schema.isNullable && obj === null)
|
|
330
|
-
) {
|
|
331
|
-
return {
|
|
332
|
-
valid: true
|
|
333
|
-
};
|
|
334
|
-
}
|
|
335
|
-
return await this.validate(alias, obj);
|
|
336
|
-
}
|
|
337
|
-
if (typeof alias !== 'object')
|
|
338
|
-
throw new Error(
|
|
339
|
-
'it is only possible to use a full schema schema definition as alias'
|
|
340
|
-
);
|
|
341
|
-
|
|
342
|
-
const schemaToMerge = { ...(schema as any) };
|
|
343
|
-
delete schemaToMerge.type;
|
|
344
|
-
delete schemaToMerge.schemaName;
|
|
345
|
-
const finalSchema: Schema<any> = deepExtend(
|
|
346
|
-
alias,
|
|
347
|
-
schemaToMerge
|
|
348
|
-
);
|
|
349
|
-
return await this.validate(finalSchema, obj);
|
|
350
|
-
} else if (schema.type === 'object') {
|
|
351
|
-
const preliminaryResult = await validateObject(
|
|
352
|
-
obj,
|
|
353
|
-
schema,
|
|
354
|
-
this as any
|
|
355
|
-
);
|
|
356
|
-
if (!preliminaryResult.valid) return preliminaryResult;
|
|
357
|
-
|
|
358
|
-
return await this.checkValidators(
|
|
359
|
-
schema as CompositeSchema<Record<string, never>>,
|
|
360
|
-
obj
|
|
361
|
-
);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
throw new Error("Coldn't understand the Schema provided");
|
|
366
|
-
}
|
|
367
|
-
}
|