isvalid 3.1.1 → 3.2.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/lib/formalize.js +51 -30
- package/lib/plugins.js +2 -44
- package/lib/validate.js +32 -24
- package/package.json +1 -1
- package/test/formalize.js +4 -2
- package/test/index.js +3 -4
package/lib/formalize.js
CHANGED
|
@@ -27,7 +27,9 @@ const formalizeObject = (formalizedSchema, nonFormalizedSchema, options) => {
|
|
|
27
27
|
|
|
28
28
|
formalizedSchema.schema = formalizedSchema.schema || {};
|
|
29
29
|
|
|
30
|
-
if (utils.instanceTypeName(formalizedSchema.schema) !== 'object')
|
|
30
|
+
if (utils.instanceTypeName(formalizedSchema.schema) !== 'object') {
|
|
31
|
+
throw new SchemaError(formalizedSchema.schema, 'Object schemas must be an object.');
|
|
32
|
+
}
|
|
31
33
|
|
|
32
34
|
// Build new formalized schema into this.
|
|
33
35
|
let formalizedSubSchema = {};
|
|
@@ -38,7 +40,7 @@ const formalizeObject = (formalizedSchema, nonFormalizedSchema, options) => {
|
|
|
38
40
|
formalizedSubSchema[key] = formalizeAny(formalizedSchema.schema[key], options);
|
|
39
41
|
});
|
|
40
42
|
|
|
41
|
-
formalizedSchema.schema = formalizedSubSchema;
|
|
43
|
+
formalizedSchema.schema = finalize(formalizedSubSchema, nonFormalizedSchema.schema);
|
|
42
44
|
|
|
43
45
|
if (typeof formalizedSchema.required === 'undefined') {
|
|
44
46
|
if (Object.keys(formalizedSubSchema).some((key) => formalizedSubSchema[key].required === true || formalizedSubSchema[key].required === 'implicit')) {
|
|
@@ -50,13 +52,13 @@ const formalizeObject = (formalizedSchema, nonFormalizedSchema, options) => {
|
|
|
50
52
|
|
|
51
53
|
};
|
|
52
54
|
|
|
53
|
-
const formalizeArray = (formalizedSchema,
|
|
55
|
+
const formalizeArray = (formalizedSchema, options) => {
|
|
54
56
|
|
|
55
57
|
// formalizedSchema has been pre-processed by formalizeAny, so
|
|
56
58
|
// we only need to formalize the sub-schema.
|
|
57
59
|
|
|
58
60
|
// If no sub-schema is provided we consider the schema final.
|
|
59
|
-
if (typeof formalizedSchema.schema === 'undefined') return
|
|
61
|
+
if (typeof formalizedSchema.schema === 'undefined') return formalizedSchema;
|
|
60
62
|
|
|
61
63
|
formalizedSchema.schema = formalizeAny(formalizedSchema.schema, options);
|
|
62
64
|
|
|
@@ -76,14 +78,14 @@ const formalizeAny = (schema, options = {}) => {
|
|
|
76
78
|
|
|
77
79
|
if (!schema.type && !schema.post && !schema.pre && !schema.equal) {
|
|
78
80
|
if ('object' == utils.instanceTypeName(schema)) {
|
|
79
|
-
return formalizeAny({ type: Object, schema: schema },
|
|
81
|
+
return formalizeAny({ type: Object, schema: schema }, options);
|
|
80
82
|
}
|
|
81
83
|
if ('array' == utils.instanceTypeName(schema)) {
|
|
82
|
-
if (schema.length === 0) return formalizeAny({ type: Array },
|
|
83
|
-
return formalizeAny({ type: Array, schema: schema[0] },
|
|
84
|
+
if (schema.length === 0) return formalizeAny({ type: Array }, options);
|
|
85
|
+
return formalizeAny({ type: Array, schema: schema[0] }, options);
|
|
84
86
|
}
|
|
85
87
|
if ((typeof schema === 'string' && schema.length) || (typeof schema === 'function' && utils.typeName(schema) !== undefined)) {
|
|
86
|
-
return formalizeAny({ type: schema },
|
|
88
|
+
return formalizeAny({ type: schema }, options);
|
|
87
89
|
}
|
|
88
90
|
throw new SchemaError(schema, 'Schemas must have at least on validator of `type`, `post`/`pre` and/or `equal`.');
|
|
89
91
|
}
|
|
@@ -132,10 +134,6 @@ const formalizeAny = (schema, options = {}) => {
|
|
|
132
134
|
});
|
|
133
135
|
}
|
|
134
136
|
|
|
135
|
-
const pluginValidators = plugins.validatorsForType(type);
|
|
136
|
-
|
|
137
|
-
merge(validators, pluginValidators);
|
|
138
|
-
|
|
139
137
|
// If post validator is provided allow for options.
|
|
140
138
|
if (formalizedSchema.pre !== undefined || formalizedSchema.post !== undefined) {
|
|
141
139
|
merge(validators, { 'options': 'any' });
|
|
@@ -146,12 +144,34 @@ const formalizeAny = (schema, options = {}) => {
|
|
|
146
144
|
for (let key in formalizedSchema) {
|
|
147
145
|
|
|
148
146
|
let validator = validators[key];
|
|
147
|
+
let test = formalizedSchema[key];
|
|
149
148
|
|
|
150
|
-
if (validator === undefined) {
|
|
151
|
-
throw new SchemaError(schema, `Validator \`${key}\` is unknown in this context.`);
|
|
152
|
-
}
|
|
149
|
+
if (typeof validator === 'undefined') {
|
|
153
150
|
|
|
154
|
-
|
|
151
|
+
let plugin;
|
|
152
|
+
|
|
153
|
+
[plugin, validator] = options.plugins
|
|
154
|
+
.filter((plugin) => plugin.supportsType(type))
|
|
155
|
+
.map((plugin) => [plugin, plugin.validatorsForType(type)])
|
|
156
|
+
.reduce((plugins, [plugin, validators]) => {
|
|
157
|
+
if (Object.keys(validators).includes(key)) {
|
|
158
|
+
validators = validators[key];
|
|
159
|
+
if (!Array.isArray(validators)) validators = [validators];
|
|
160
|
+
return [plugin, validators.map((validator) => utils.typeName(validator))];
|
|
161
|
+
}
|
|
162
|
+
return plugins;
|
|
163
|
+
}, []);
|
|
164
|
+
|
|
165
|
+
if (typeof plugin === 'undefined') throw new SchemaError(schema, `Validator \`${key}\` is unknown in this context.`);
|
|
166
|
+
|
|
167
|
+
formalizedSchema.plugins = formalizedSchema.plugins || {};
|
|
168
|
+
formalizedSchema.plugins[key] = {
|
|
169
|
+
phase: plugin.phase || 'post',
|
|
170
|
+
validator: plugin.validate,
|
|
171
|
+
formalize: plugin.formalize
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
}
|
|
155
175
|
|
|
156
176
|
// Test for - and transform - errors in validator.
|
|
157
177
|
if (Array.isArray(test) &&
|
|
@@ -171,13 +191,21 @@ const formalizeAny = (schema, options = {}) => {
|
|
|
171
191
|
}
|
|
172
192
|
|
|
173
193
|
// Ensure validator is of correct type.
|
|
174
|
-
if (validator !== 'any' && validator.indexOf(utils.instanceTypeName(test)) == -1) {
|
|
194
|
+
if (typeof validator !== 'undefined' && validator !== 'any' && validator.indexOf(utils.instanceTypeName(test)) == -1) {
|
|
175
195
|
throw new SchemaError(
|
|
176
196
|
schema,
|
|
177
197
|
`Validator '${key}' must be of type(s) ${validators[key].join(', ')}.`
|
|
178
198
|
);
|
|
179
199
|
}
|
|
180
200
|
|
|
201
|
+
if (typeof (formalizedSchema.plugins || {})[key] !== 'undefined') {
|
|
202
|
+
try {
|
|
203
|
+
formalizedSchema[key] = formalizedSchema.plugins[key].formalize(formalizedSchema[key], key, type) || formalizedSchema[key];
|
|
204
|
+
} catch (error) {
|
|
205
|
+
throw new SchemaError(schema, error.message);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
181
209
|
if (typeof (options.transform || {}).post === 'function') {
|
|
182
210
|
const transformed = options.transform.post(key, formalizedSchema[key], { schema: formalizedSchema }) || formalizedSchema[key];
|
|
183
211
|
formalizedSchema[key] = typeof transformed !== 'undefined' ? transformed : formalizedSchema[key];
|
|
@@ -269,18 +297,7 @@ const formalizeAny = (schema, options = {}) => {
|
|
|
269
297
|
formalizedSchema = formalizeObject(formalizedSchema, schema, options);
|
|
270
298
|
}
|
|
271
299
|
else if (utils.isSameType('array', utils.typeName(formalizedSchema.type))) {
|
|
272
|
-
formalizedSchema = formalizeArray(formalizedSchema,
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
for (const validator of Object.keys(pluginValidators)) {
|
|
277
|
-
try {
|
|
278
|
-
const result = plugins.formalizeValidator(type, validator, formalizedSchema[validator]) || formalizedSchema[validator];
|
|
279
|
-
if (typeof result !== 'undefined') formalizedSchema[validator] = result;
|
|
280
|
-
} catch (error) {
|
|
281
|
-
throw new SchemaError(
|
|
282
|
-
schema,
|
|
283
|
-
error.message);
|
|
300
|
+
formalizedSchema = formalizeArray(formalizedSchema, options);
|
|
284
301
|
}
|
|
285
302
|
}
|
|
286
303
|
|
|
@@ -288,7 +305,11 @@ const formalizeAny = (schema, options = {}) => {
|
|
|
288
305
|
|
|
289
306
|
};
|
|
290
307
|
|
|
291
|
-
exports = module.exports =
|
|
308
|
+
exports = module.exports = (schema, options = {}) => {
|
|
309
|
+
return formalizeAny(schema, Object.assign({}, options, {
|
|
310
|
+
plugins: plugins._plugins.concat(options.plugins || [])
|
|
311
|
+
}));
|
|
312
|
+
};
|
|
292
313
|
|
|
293
314
|
exports.strip = (schema) => {
|
|
294
315
|
return Object.keys(schema)
|
package/lib/plugins.js
CHANGED
|
@@ -1,54 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const
|
|
4
|
-
merge = require('merge'),
|
|
5
4
|
utils = require('./utils');
|
|
6
5
|
|
|
7
6
|
exports = module.exports = {
|
|
8
7
|
_plugins: []
|
|
9
8
|
};
|
|
10
9
|
|
|
11
|
-
exports.use =
|
|
12
|
-
|
|
13
|
-
_validatorsForType: function(type) {
|
|
14
|
-
return Object.fromEntries(
|
|
15
|
-
Object.entries(
|
|
16
|
-
this.validatorsForType(type))
|
|
17
|
-
.map(([key, value]) => {
|
|
18
|
-
if (typeof value !== 'string') value = utils.typeName(value);
|
|
19
|
-
return [key, !Array.isArray(value) ? [value] : value];
|
|
20
|
-
})
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
}));
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
exports.validatorsForType = function(type) {
|
|
27
|
-
return Object.fromEntries(Object.entries(merge(...this._plugins
|
|
28
|
-
.filter((plugin) => plugin.supportsType(type))
|
|
29
|
-
.map((plugin) => plugin._validatorsForType(type)))));
|
|
30
|
-
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
exports.formalizeValidator = function(type, identifier, config) {
|
|
34
|
-
return this._plugins
|
|
35
|
-
.filter((plugin) => plugin.supportsType(type))
|
|
36
|
-
.filter((plugin) => Object.keys(plugin._validatorsForType(type)).includes(identifier))
|
|
37
|
-
.reduce((config, plugin) => {
|
|
38
|
-
if (typeof plugin.formalizeValidator !== 'function') return config;
|
|
39
|
-
return plugin.formalizeValidator(type, identifier, config);
|
|
40
|
-
}, config);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
exports.validate = async function(type, identifier, config, data) {
|
|
44
|
-
|
|
45
|
-
const plugins = this._plugins
|
|
46
|
-
.filter((plugin) => plugin.supportsType(type));
|
|
47
|
-
|
|
48
|
-
for (const plugin of plugins) {
|
|
49
|
-
data = await plugin.validate(type, identifier, config, data);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return data;
|
|
53
|
-
|
|
10
|
+
exports.use = (plugin) => {
|
|
11
|
+
exports._plugins.push(plugin(utils));
|
|
54
12
|
};
|
package/lib/validate.js
CHANGED
|
@@ -5,8 +5,7 @@ const ValidationError = require('./errors/validation.js'),
|
|
|
5
5
|
unique = require('./unique.js'),
|
|
6
6
|
formalize = require('./formalize.js'),
|
|
7
7
|
utils = require('./utils.js'),
|
|
8
|
-
equals = require('./equals.js')
|
|
9
|
-
plugins = require('./plugins.js');
|
|
8
|
+
equals = require('./equals.js');
|
|
10
9
|
|
|
11
10
|
const checkBoolValue = (name, schema, defaults) => {
|
|
12
11
|
if (schema[name] === undefined) return defaults[name] === true;
|
|
@@ -299,16 +298,39 @@ const validateOther = async (data, schema, options, keyPath) => {
|
|
|
299
298
|
|
|
300
299
|
};
|
|
301
300
|
|
|
302
|
-
const validateCustom = async (
|
|
301
|
+
const validateCustom = async (phase, data, schema, options, keyPath, validatedData) => {
|
|
303
302
|
|
|
304
|
-
if (!schema[
|
|
303
|
+
if (!schema[phase]) return data;
|
|
305
304
|
|
|
306
|
-
for (let idx = 0 ; idx < schema[
|
|
305
|
+
for (let idx = 0 ; idx < schema[phase].length ; idx++) {
|
|
307
306
|
try {
|
|
308
|
-
let result = await Promise.resolve(schema[
|
|
307
|
+
let result = await Promise.resolve(schema[phase][idx](data, schema, { options, keyPath, data: validatedData }));
|
|
309
308
|
if (typeof result !== 'undefined') data = result;
|
|
310
309
|
} catch (error) {
|
|
311
|
-
throw ValidationError.fromError(keyPath, schema._nonFormalizedSchema,
|
|
310
|
+
throw ValidationError.fromError(keyPath, schema._nonFormalizedSchema, phase, error);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return data;
|
|
315
|
+
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
const validatePlugins = async (phase, data, schema, options, keyPath) => {
|
|
319
|
+
|
|
320
|
+
const plugins = Object.keys(schema.plugins || {})
|
|
321
|
+
.filter((key) => schema.plugins[key].phase === phase)
|
|
322
|
+
.map((key) => [key, schema.plugins[key].validator]);
|
|
323
|
+
|
|
324
|
+
for (let idx = 0 ; idx < plugins.length ; idx++) {
|
|
325
|
+
const [key, validator] = plugins[idx];
|
|
326
|
+
try {
|
|
327
|
+
data = await validator(data, schema[key], key, schema.type);
|
|
328
|
+
} catch (error) {
|
|
329
|
+
throw new ValidationError(
|
|
330
|
+
keyPath,
|
|
331
|
+
schema._nonFormalizedSchema,
|
|
332
|
+
key,
|
|
333
|
+
(schema.errors || {})[key] || customErrorMessage((options.errorMessages || {})[key] || error.message));
|
|
312
334
|
}
|
|
313
335
|
}
|
|
314
336
|
|
|
@@ -317,10 +339,12 @@ const validateCustom = async (type, data, schema, options, keyPath, validatedDat
|
|
|
317
339
|
};
|
|
318
340
|
|
|
319
341
|
const validatePre = async (data, schema, options, keyPath, validatedData) => {
|
|
320
|
-
|
|
342
|
+
data = await validateCustom('pre', data, schema, options, keyPath, validatedData);
|
|
343
|
+
return await validatePlugins('pre', data, schema, options, keyPath);
|
|
321
344
|
};
|
|
322
345
|
|
|
323
346
|
const validatePost = async (data, schema, options, keyPath, validatedData) => {
|
|
347
|
+
data = await validatePlugins('post', data, schema, options, keyPath);
|
|
324
348
|
return await validateCustom('post', data, schema, options, keyPath, validatedData);
|
|
325
349
|
};
|
|
326
350
|
|
|
@@ -404,22 +428,6 @@ const validateAny = async (data, schema, options, keyPath, validatedData) => {
|
|
|
404
428
|
}
|
|
405
429
|
}
|
|
406
430
|
|
|
407
|
-
const pluginValidators = Object.keys(plugins.validatorsForType(schema.type))
|
|
408
|
-
.filter((validator) => typeof schema[validator] !== 'undefined');
|
|
409
|
-
|
|
410
|
-
for (const pluginValidator of pluginValidators) {
|
|
411
|
-
try {
|
|
412
|
-
data = await plugins.validate(schema.type, pluginValidator, schema[pluginValidator], data);
|
|
413
|
-
} catch (error) {
|
|
414
|
-
throw new ValidationError(
|
|
415
|
-
keyPath,
|
|
416
|
-
schema._nonFormalizedSchema,
|
|
417
|
-
pluginValidator,
|
|
418
|
-
(schema.errors || {})[pluginValidator] || customErrorMessage((options.errorMessages || {})[pluginValidator] || error.message)
|
|
419
|
-
);
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
431
|
return await validatePost(data, schema, options, keyPath, validatedData);
|
|
424
432
|
|
|
425
433
|
};
|
package/package.json
CHANGED
package/test/formalize.js
CHANGED
|
@@ -6,7 +6,7 @@ const expect = require('chai').expect,
|
|
|
6
6
|
|
|
7
7
|
const f = (...args) => {
|
|
8
8
|
return () => {
|
|
9
|
-
formalize(...args);
|
|
9
|
+
return formalize(...args);
|
|
10
10
|
};
|
|
11
11
|
};
|
|
12
12
|
|
|
@@ -183,7 +183,9 @@ describe('schema', function() {
|
|
|
183
183
|
expect(f({ type: String, nonExistingValidator: 'myValue' })).to.throw(SchemaError);
|
|
184
184
|
});
|
|
185
185
|
it ('should throw error if plugin validator fails formalizing.', () => {
|
|
186
|
-
expect(f({ type: String,
|
|
186
|
+
expect(f({ type: String, ensureCase: 'not-supported' }))
|
|
187
|
+
.to.throw(SchemaError)
|
|
188
|
+
.with.property('message', 'Only case types: `camel`, `domain`, `http`, `kebab`, `lower`, `pascal`, `snake`, `title`, `upper` are supported.');
|
|
187
189
|
});
|
|
188
190
|
});
|
|
189
191
|
});
|
package/test/index.js
CHANGED
|
@@ -11,11 +11,10 @@ isvalid.plugins.use(function (utils) {
|
|
|
11
11
|
return {
|
|
12
12
|
supportsType: (type) => utils.isSameType(type, String),
|
|
13
13
|
validatorsForType: () => { return { ensureCase: String }; },
|
|
14
|
-
|
|
15
|
-
if (!config)
|
|
16
|
-
if (!caseit.supported.includes(config)) throw new Error(`Only case types: ${caseit.supported.map((casing) => `\`${casing}\``).join(', ')} are supported.`);
|
|
14
|
+
formalize: (config) => {
|
|
15
|
+
if (config && !caseit.supported.includes(config)) throw new Error(`Only case types: ${caseit.supported.map((casing) => `\`${casing}\``).join(', ')} are supported.`);
|
|
17
16
|
},
|
|
18
|
-
validate: (
|
|
17
|
+
validate: (data, config) => {
|
|
19
18
|
if (caseit(data, config) !== data) throw new Error(`Is not ${config} case.`);
|
|
20
19
|
return data;
|
|
21
20
|
}
|