@cleverbrush/schema 1.0.0-beta.2 → 1.0.0-beta.4
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/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 +95 -0
- package/dist/defaultSchemas.d.ts +4 -0
- package/dist/defaultSchemas.js +45 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +32 -0
- package/dist/schema.d.ts +230 -0
- package/dist/schema.js +2 -0
- package/dist/schemaRegistry.d.ts +49 -0
- package/dist/schemaRegistry.js +278 -0
- package/dist/validators/validateArray.d.ts +3 -0
- package/dist/validators/validateArray.js +60 -0
- package/dist/validators/validateBoolean.d.ts +2 -0
- package/dist/validators/validateBoolean.js +30 -0
- package/dist/validators/validateFunction.d.ts +2 -0
- package/dist/validators/validateFunction.js +21 -0
- package/dist/validators/validateNumber.d.ts +2 -0
- package/dist/validators/validateNumber.js +69 -0
- package/dist/validators/validateObject.d.ts +3 -0
- package/dist/validators/validateObject.js +95 -0
- package/dist/validators/validateString.d.ts +2 -0
- package/dist/validators/validateString.js +50 -0
- package/dist/validators/validateUnion.d.ts +3 -0
- package/dist/validators/validateUnion.js +30 -0
- package/package.json +6 -2
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const validateNumber_js_1 = require("./validators/validateNumber.js");
|
|
4
|
+
const validateBoolean_js_1 = require("./validators/validateBoolean.js");
|
|
5
|
+
const validateString_js_1 = require("./validators/validateString.js");
|
|
6
|
+
const validateArray_js_1 = require("./validators/validateArray.js");
|
|
7
|
+
const validateObject_js_1 = require("./validators/validateObject.js");
|
|
8
|
+
const validateUnion_js_1 = require("./validators/validateUnion.js");
|
|
9
|
+
const validateFunction_js_1 = require("./validators/validateFunction.js");
|
|
10
|
+
const NumberSchemaBuilder_js_1 = require("./builders/NumberSchemaBuilder.js");
|
|
11
|
+
const UnionSchemaBuilder_js_1 = require("./builders/UnionSchemaBuilder.js");
|
|
12
|
+
const ObjectSchemaBuilder_js_1 = require("./builders/ObjectSchemaBuilder.js");
|
|
13
|
+
const StringSchemaBuilder_js_1 = require("./builders/StringSchemaBuilder.js");
|
|
14
|
+
const BooleanSchemaBuilder_js_1 = require("./builders/BooleanSchemaBuilder.js");
|
|
15
|
+
const ArraySchemaBuilder_js_1 = require("./builders/ArraySchemaBuilder.js");
|
|
16
|
+
const FunctionSchemaBuilder_js_1 = require("./builders/FunctionSchemaBuilder.js");
|
|
17
|
+
const defaultSchemas_js_1 = require("./defaultSchemas.js");
|
|
18
|
+
const SchemaBuilder_js_1 = require("./builders/SchemaBuilder.js");
|
|
19
|
+
const defaultSchemaNames = ['string', 'boolean', 'number', 'array', 'function'];
|
|
20
|
+
const defaultSchemasValidationStrategies = {
|
|
21
|
+
number: (obj, schema) => (0, validateNumber_js_1.validateNumber)(obj, schema),
|
|
22
|
+
boolean: (obj, schema) => (0, validateBoolean_js_1.validateBoolean)(obj, schema),
|
|
23
|
+
string: (obj, schema) => (0, validateString_js_1.validateString)(obj, schema),
|
|
24
|
+
array: (obj, schema, validator) => (0, validateArray_js_1.validateArray)(obj, schema, validator),
|
|
25
|
+
function: (obj, schema) => (0, validateFunction_js_1.validateFunction)(obj, schema)
|
|
26
|
+
};
|
|
27
|
+
const isDefaultType = (name) => defaultSchemaNames.indexOf(name) !== -1;
|
|
28
|
+
class SchemaRegistry {
|
|
29
|
+
_schemasMap = new Map();
|
|
30
|
+
_schemasCache = null;
|
|
31
|
+
_preprocessorsMap = new Map();
|
|
32
|
+
get preprocessors() {
|
|
33
|
+
return this._preprocessorsMap;
|
|
34
|
+
}
|
|
35
|
+
addPreprocessor(name, preprocessor) {
|
|
36
|
+
if (this._preprocessorsMap.has(name))
|
|
37
|
+
throw new Error(`Preprocessor '${name}' is already registered`);
|
|
38
|
+
if (typeof preprocessor !== 'function') {
|
|
39
|
+
throw new Error('preprocessor must be a function');
|
|
40
|
+
}
|
|
41
|
+
this._preprocessorsMap.set(name, preprocessor);
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
_aliasBuilder = (schemaName) => {
|
|
45
|
+
if (typeof schemaName !== 'string' || !schemaName)
|
|
46
|
+
throw new Error('schemaName must be non-empty string');
|
|
47
|
+
const aliasSchema = this._schemasMap.get(schemaName.toString());
|
|
48
|
+
if (!aliasSchema)
|
|
49
|
+
throw new Error(`Schema name ${schemaName} is not defined.`);
|
|
50
|
+
return aliasSchema;
|
|
51
|
+
};
|
|
52
|
+
_externalAlias = (registry, schemaName) => {
|
|
53
|
+
if (typeof schemaName !== 'string' || !schemaName)
|
|
54
|
+
throw new Error('schemaName must be non-empty string');
|
|
55
|
+
// TODO: accessing private property here...
|
|
56
|
+
const externalSchema = registry._schemasMap.get(schemaName);
|
|
57
|
+
if (!externalSchema)
|
|
58
|
+
throw new Error(`Schema name ${schemaName} is not defined.`);
|
|
59
|
+
return externalSchema;
|
|
60
|
+
};
|
|
61
|
+
addSchemaFrom(oldName, name, param) {
|
|
62
|
+
if (!this._schemasMap.has(oldName.toString())) {
|
|
63
|
+
throw new Error(`unknown schema name ${oldName.toString()}`);
|
|
64
|
+
}
|
|
65
|
+
const oldSchema = this._schemasMap.get(oldName.toString());
|
|
66
|
+
const schema = typeof param === 'function'
|
|
67
|
+
? param({
|
|
68
|
+
base: oldSchema,
|
|
69
|
+
alias: this._aliasBuilder,
|
|
70
|
+
array: ArraySchemaBuilder_js_1.array,
|
|
71
|
+
boolean: BooleanSchemaBuilder_js_1.boolean,
|
|
72
|
+
func: FunctionSchemaBuilder_js_1.func,
|
|
73
|
+
number: NumberSchemaBuilder_js_1.number,
|
|
74
|
+
object: ObjectSchemaBuilder_js_1.object,
|
|
75
|
+
string: StringSchemaBuilder_js_1.string,
|
|
76
|
+
union: UnionSchemaBuilder_js_1.union
|
|
77
|
+
})
|
|
78
|
+
: param;
|
|
79
|
+
if (Array.isArray(schema)) {
|
|
80
|
+
this._schemasMap.set(name.toString(), schema);
|
|
81
|
+
this._schemasCache = null;
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
if (typeof schema !== 'object')
|
|
85
|
+
throw new Error('Array or Object is required');
|
|
86
|
+
this._schemasMap.set(name.toString(), {
|
|
87
|
+
...(schema instanceof SchemaBuilder_js_1.SchemaBuilder
|
|
88
|
+
? schema._schema
|
|
89
|
+
: schema)
|
|
90
|
+
});
|
|
91
|
+
this._schemasCache = null;
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
addSchema(name, param) {
|
|
95
|
+
if (typeof name !== 'string' || !name)
|
|
96
|
+
throw new Error('Name is required');
|
|
97
|
+
if (isDefaultType(name.toString()))
|
|
98
|
+
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`);
|
|
99
|
+
if (this._schemasMap.has(name.toString())) {
|
|
100
|
+
throw new Error(`Schema "${name}" already exists`);
|
|
101
|
+
}
|
|
102
|
+
const schema = typeof param === 'function'
|
|
103
|
+
? param({
|
|
104
|
+
alias: this._aliasBuilder,
|
|
105
|
+
external: this._externalAlias,
|
|
106
|
+
array: ArraySchemaBuilder_js_1.array,
|
|
107
|
+
boolean: BooleanSchemaBuilder_js_1.boolean,
|
|
108
|
+
number: NumberSchemaBuilder_js_1.number,
|
|
109
|
+
object: ObjectSchemaBuilder_js_1.object,
|
|
110
|
+
string: StringSchemaBuilder_js_1.string,
|
|
111
|
+
union: UnionSchemaBuilder_js_1.union,
|
|
112
|
+
func: FunctionSchemaBuilder_js_1.func
|
|
113
|
+
})
|
|
114
|
+
: param;
|
|
115
|
+
if (Array.isArray(schema)) {
|
|
116
|
+
this._schemasMap.set(name.toString(), schema);
|
|
117
|
+
this._schemasCache = null;
|
|
118
|
+
return this;
|
|
119
|
+
}
|
|
120
|
+
if (typeof schema !== 'object')
|
|
121
|
+
throw new Error('Array or Object is required');
|
|
122
|
+
this._schemasMap.set(name.toString(), schema instanceof SchemaBuilder_js_1.SchemaBuilder ? schema.clone() : schema);
|
|
123
|
+
this._schemasCache = null;
|
|
124
|
+
return this;
|
|
125
|
+
}
|
|
126
|
+
get schemas() {
|
|
127
|
+
if (this._schemasCache)
|
|
128
|
+
return this._schemasCache;
|
|
129
|
+
const res = {};
|
|
130
|
+
for (const key of this._schemasMap.keys()) {
|
|
131
|
+
const parts = key.split('.');
|
|
132
|
+
let curr = res;
|
|
133
|
+
for (let i = 0; i < parts.length; i++) {
|
|
134
|
+
if (i === parts.length - 1) {
|
|
135
|
+
curr[parts[i]] = {
|
|
136
|
+
validate: async (value) => {
|
|
137
|
+
const result = await this.validate(this._schemasMap.get(key), value);
|
|
138
|
+
if (!result.valid) {
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
...result,
|
|
143
|
+
object: value
|
|
144
|
+
};
|
|
145
|
+
},
|
|
146
|
+
schema: this._schemasMap.get(key)
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
if (typeof curr[parts[i]] === 'undefined') {
|
|
151
|
+
curr[parts[i]] = {};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
curr = curr[parts[i]];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
this._schemasCache = res;
|
|
158
|
+
return this._schemasCache;
|
|
159
|
+
}
|
|
160
|
+
async validateDefaultType(name, value, mergeSchema) {
|
|
161
|
+
const strategy = defaultSchemasValidationStrategies[name];
|
|
162
|
+
let finalSchema = defaultSchemas_js_1.defaultSchemas[name];
|
|
163
|
+
if (strategy) {
|
|
164
|
+
if (typeof mergeSchema === 'object' && mergeSchema) {
|
|
165
|
+
finalSchema = Object.assign({}, finalSchema, mergeSchema);
|
|
166
|
+
}
|
|
167
|
+
if (typeof mergeSchema === 'number') {
|
|
168
|
+
finalSchema = {
|
|
169
|
+
...finalSchema,
|
|
170
|
+
equals: mergeSchema
|
|
171
|
+
};
|
|
172
|
+
mergeSchema;
|
|
173
|
+
}
|
|
174
|
+
let preliminaryResult = await strategy(value, finalSchema, this);
|
|
175
|
+
if (!preliminaryResult.valid)
|
|
176
|
+
return preliminaryResult;
|
|
177
|
+
preliminaryResult = await this.checkValidators(finalSchema, value);
|
|
178
|
+
return preliminaryResult;
|
|
179
|
+
}
|
|
180
|
+
throw new Error('not implemented');
|
|
181
|
+
}
|
|
182
|
+
async checkValidators(schema, value) {
|
|
183
|
+
if (!schema.isRequired && typeof value === 'undefined') {
|
|
184
|
+
return {
|
|
185
|
+
valid: true
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
if (Array.isArray(schema.validators)) {
|
|
189
|
+
const validatorsResults = await Promise.allSettled(schema.validators.map((v) => Promise.resolve(v(value))));
|
|
190
|
+
const rejections = validatorsResults
|
|
191
|
+
.filter((f) => f.status === 'rejected')
|
|
192
|
+
.map((f) => f.reason);
|
|
193
|
+
const errors = validatorsResults
|
|
194
|
+
.filter((f) => f.status === 'fulfilled' &&
|
|
195
|
+
typeof f.value !== 'boolean' &&
|
|
196
|
+
f.value.valid === false)
|
|
197
|
+
.map((f) => f.value)
|
|
198
|
+
.map((f) => f.errors);
|
|
199
|
+
if (rejections.length === 0 && errors.length === 0) {
|
|
200
|
+
return {
|
|
201
|
+
valid: true
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
valid: false,
|
|
206
|
+
errors: [...rejections, ...errors]
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
valid: true
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
async validate(schemaToValidate, obj) {
|
|
214
|
+
if (!schemaToValidate)
|
|
215
|
+
throw new Error('schemaName is required');
|
|
216
|
+
const schema = schemaToValidate instanceof SchemaBuilder_js_1.SchemaBuilder
|
|
217
|
+
? schemaToValidate._schema
|
|
218
|
+
: schemaToValidate;
|
|
219
|
+
if (typeof schema === 'string') {
|
|
220
|
+
if (isDefaultType(schema)) {
|
|
221
|
+
return await this.validateDefaultType(schema, obj);
|
|
222
|
+
}
|
|
223
|
+
else if (typeof this._schemasMap.get(schema) !== 'undefined') {
|
|
224
|
+
if (Array.isArray(this._schemasMap.get(schema))) {
|
|
225
|
+
return this.validate(this._schemasMap.get(schema), obj);
|
|
226
|
+
}
|
|
227
|
+
const objSchema = Object.assign({}, defaultSchemas_js_1.defaultSchemas.object, this._schemasMap.get(schema));
|
|
228
|
+
const res = await (0, validateObject_js_1.validateObject)(obj, objSchema, this);
|
|
229
|
+
if (!res.valid)
|
|
230
|
+
return res;
|
|
231
|
+
return await this.checkValidators(objSchema, obj);
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
return await this.validateDefaultType('string', obj, {
|
|
235
|
+
type: 'string',
|
|
236
|
+
equals: schema
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (Array.isArray(schema)) {
|
|
241
|
+
for (let i = 0; i < schema.length; i++) {
|
|
242
|
+
const res = await this.validate(schema[i], obj);
|
|
243
|
+
if (res.valid) {
|
|
244
|
+
return res;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
valid: false,
|
|
249
|
+
errors: ['object does not match any schema']
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
if (typeof schema === 'number') {
|
|
253
|
+
return await this.validateDefaultType('number', obj, schema);
|
|
254
|
+
}
|
|
255
|
+
if (typeof schema === 'object') {
|
|
256
|
+
const spec = schema;
|
|
257
|
+
if (typeof spec.type !== 'string')
|
|
258
|
+
throw new Error('Schema has no type');
|
|
259
|
+
if (isDefaultType(spec.type)) {
|
|
260
|
+
return await this.validateDefaultType(spec.type, obj, schema);
|
|
261
|
+
}
|
|
262
|
+
else if (spec.type === 'union') {
|
|
263
|
+
return await (0, validateUnion_js_1.validateUnion)(obj, spec, this);
|
|
264
|
+
}
|
|
265
|
+
else if (spec.type === 'object') {
|
|
266
|
+
const preliminaryResult = await (0, validateObject_js_1.validateObject)(obj, schema, this);
|
|
267
|
+
if (!preliminaryResult.valid)
|
|
268
|
+
return preliminaryResult;
|
|
269
|
+
return await this.checkValidators(schema, obj);
|
|
270
|
+
}
|
|
271
|
+
else if (spec.type === 'function') {
|
|
272
|
+
return await (0, validateFunction_js_1.validateFunction)(obj, spec);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
throw new Error("Couldn't understand the Schema provided");
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
exports.default = SchemaRegistry;
|
|
@@ -0,0 +1,60 @@
|
|
|
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 (schema.preprocessor) {
|
|
18
|
+
const preprocessor = typeof schema.preprocessor === 'function'
|
|
19
|
+
? schema.preprocessor
|
|
20
|
+
: validator.preprocessors.get(schema.preprocessor);
|
|
21
|
+
if (typeof preprocessor !== 'function') {
|
|
22
|
+
throw new Error(`unknown preprocessor '${schema.preprocessor}'`);
|
|
23
|
+
}
|
|
24
|
+
for (let i = 0; i < obj.length; i++) {
|
|
25
|
+
obj[i] = await Promise.resolve(preprocessor(obj[i]));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (typeof schema.minLength === 'number' && obj.length < schema.minLength) {
|
|
29
|
+
return {
|
|
30
|
+
valid: false,
|
|
31
|
+
errors: [`expected to be at least ${schema.minLength} chars long`]
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (typeof schema.maxLength === 'number' && obj.length > schema.maxLength) {
|
|
35
|
+
return {
|
|
36
|
+
valid: false,
|
|
37
|
+
errors: [`expected to be at most ${schema.maxLength} chars long`]
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (typeof schema.ofType !== 'undefined') {
|
|
41
|
+
const results = await Promise.all(obj.map((i) => validator.validate(schema.ofType, i)));
|
|
42
|
+
const errors = results
|
|
43
|
+
.filter((r) => !r.valid)
|
|
44
|
+
.map((r) => r.errors)
|
|
45
|
+
.flat(Infinity);
|
|
46
|
+
if (errors.length) {
|
|
47
|
+
return {
|
|
48
|
+
valid: false,
|
|
49
|
+
errors
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
valid: true
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
valid: true
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
exports.validateArray = validateArray;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateBoolean = void 0;
|
|
4
|
+
const validateBoolean = async (obj, schema) => {
|
|
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
|
+
const bool = obj;
|
|
18
|
+
if (typeof schema.equals === 'boolean') {
|
|
19
|
+
return schema.equals === bool
|
|
20
|
+
? { valid: true }
|
|
21
|
+
: {
|
|
22
|
+
valid: false,
|
|
23
|
+
errors: [`must be equal to ${schema.equals}`]
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
valid: true
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
exports.validateBoolean = validateBoolean;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateFunction = void 0;
|
|
4
|
+
const validateFunction = async (obj, schema) => {
|
|
5
|
+
if (typeof obj === 'undefined' &&
|
|
6
|
+
typeof schema === 'object' &&
|
|
7
|
+
schema.isRequired === false) {
|
|
8
|
+
return {
|
|
9
|
+
valid: true
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
if (typeof obj !== 'function')
|
|
13
|
+
return {
|
|
14
|
+
valid: false,
|
|
15
|
+
errors: [`expected type function, but saw ${typeof obj}`]
|
|
16
|
+
};
|
|
17
|
+
return {
|
|
18
|
+
valid: true
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
exports.validateFunction = validateFunction;
|
|
@@ -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) => {
|
|
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;
|
|
@@ -0,0 +1,95 @@
|
|
|
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.preprocessors === 'object' && schema.preprocessors) {
|
|
21
|
+
await Promise.all(Object.keys(schema.preprocessors).map(async (key) => {
|
|
22
|
+
if (key === '*')
|
|
23
|
+
return;
|
|
24
|
+
if (typeof schema.preprocessors[key] === 'function') {
|
|
25
|
+
const res = await Promise.resolve(schema.preprocessors[key](obj[key]));
|
|
26
|
+
if (typeof res !== 'undefined') {
|
|
27
|
+
obj[key] = res;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
delete obj[key];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
const preprocessor = validator.preprocessors.get(schema.preprocessors[key]);
|
|
35
|
+
if (typeof preprocessor !== 'function') {
|
|
36
|
+
throw new Error(`preprocessor '${schema.preprocessors[key]}' is unknown`);
|
|
37
|
+
}
|
|
38
|
+
const res = await Promise.resolve(preprocessor(obj[key]));
|
|
39
|
+
if (typeof res !== 'undefined') {
|
|
40
|
+
obj[key] = res;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
delete obj[key];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}));
|
|
47
|
+
if ('*' in schema.preprocessors) {
|
|
48
|
+
const objectPreprocessor = schema.preprocessors['*'];
|
|
49
|
+
if (typeof objectPreprocessor === 'function') {
|
|
50
|
+
await Promise.resolve(objectPreprocessor(obj));
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const preprocessor = validator.preprocessors.get(objectPreprocessor);
|
|
54
|
+
if (typeof preprocessor !== 'function') {
|
|
55
|
+
throw new Error(`preprocessor '${objectPreprocessor}' is unknown`);
|
|
56
|
+
}
|
|
57
|
+
await Promise.resolve(preprocessor(obj));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (typeof schema.properties === 'object' && schema.properties) {
|
|
62
|
+
const errors = [
|
|
63
|
+
...(await Promise.all(Object.entries(schema.properties).map(async ([name, schema]) => {
|
|
64
|
+
const result = await validator.validate(schema, obj[name]);
|
|
65
|
+
if (result.valid)
|
|
66
|
+
return result;
|
|
67
|
+
return {
|
|
68
|
+
valid: false,
|
|
69
|
+
errors: (result.errors || []).map((e) => `->${name} ${e}`)
|
|
70
|
+
};
|
|
71
|
+
}))),
|
|
72
|
+
...(schema.noUnknownProperties === false
|
|
73
|
+
? []
|
|
74
|
+
: Object.keys(obj)
|
|
75
|
+
.filter((k) => !(k in schema.properties))
|
|
76
|
+
.map((k) => ({
|
|
77
|
+
valid: false,
|
|
78
|
+
errors: [`-> ${k} - unknown field`]
|
|
79
|
+
})))
|
|
80
|
+
]
|
|
81
|
+
.filter((r) => !r.valid)
|
|
82
|
+
.map((r) => r.errors)
|
|
83
|
+
.flat(Infinity);
|
|
84
|
+
if (errors.length) {
|
|
85
|
+
return {
|
|
86
|
+
valid: false,
|
|
87
|
+
errors
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
valid: true
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
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) => {
|
|
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;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateUnion = void 0;
|
|
4
|
+
const validateUnion = async (obj, schema, validator) => {
|
|
5
|
+
if (typeof obj === 'undefined' && schema.isRequired === false) {
|
|
6
|
+
return {
|
|
7
|
+
valid: true
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
if (obj === null && schema.isNullable) {
|
|
11
|
+
return {
|
|
12
|
+
valid: true
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
if (Array.isArray(schema.variants) && schema.variants.length > 0) {
|
|
16
|
+
for (let i = 0; i < schema.variants.length; i++) {
|
|
17
|
+
const variant = schema.variants[i];
|
|
18
|
+
const result = await validator.validate(variant, obj);
|
|
19
|
+
if (result.valid) {
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
valid: false,
|
|
25
|
+
errors: ['object does not satisfy any scheme']
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
throw new Error('variants should be non empty array');
|
|
29
|
+
};
|
|
30
|
+
exports.validateUnion = validateUnion;
|