isvalid 3.0.1 → 3.1.1
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 +25 -8
- package/lib/index.js +1 -0
- package/lib/plugins.js +54 -0
- package/lib/utils.js +1 -1
- package/lib/validate.js +18 -1
- package/package.json +3 -2
- package/test/formalize.js +6 -0
- package/test/index.js +18 -1
- package/test/validate.js +16 -0
package/lib/formalize.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
const merge = require('merge'),
|
|
4
4
|
SchemaError = require('./errors/schema.js'),
|
|
5
5
|
utils = require('./utils.js'),
|
|
6
|
-
ranges = require('./ranges.js')
|
|
6
|
+
ranges = require('./ranges.js'),
|
|
7
|
+
plugins = require('./plugins');
|
|
7
8
|
|
|
8
9
|
const finalize = (formalizedSchema, nonFormalizedSchema) => {
|
|
9
10
|
|
|
@@ -45,7 +46,7 @@ const formalizeObject = (formalizedSchema, nonFormalizedSchema, options) => {
|
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
return
|
|
49
|
+
return formalizedSchema;
|
|
49
50
|
|
|
50
51
|
};
|
|
51
52
|
|
|
@@ -64,7 +65,7 @@ const formalizeArray = (formalizedSchema, nonFormalizedSchema, options) => {
|
|
|
64
65
|
if (formalizedSchema.schema.required === true) formalizedSchema.required = true;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
return
|
|
68
|
+
return formalizedSchema;
|
|
68
69
|
|
|
69
70
|
};
|
|
70
71
|
|
|
@@ -75,11 +76,11 @@ const formalizeAny = (schema, options = {}) => {
|
|
|
75
76
|
|
|
76
77
|
if (!schema.type && !schema.post && !schema.pre && !schema.equal) {
|
|
77
78
|
if ('object' == utils.instanceTypeName(schema)) {
|
|
78
|
-
return
|
|
79
|
+
return formalizeAny({ type: Object, schema: schema }, schema, options);
|
|
79
80
|
}
|
|
80
81
|
if ('array' == utils.instanceTypeName(schema)) {
|
|
81
82
|
if (schema.length === 0) return formalizeAny({ type: Array }, schema. options);
|
|
82
|
-
return
|
|
83
|
+
return formalizeAny({ type: Array, schema: schema[0] }, schema, options);
|
|
83
84
|
}
|
|
84
85
|
if ((typeof schema === 'string' && schema.length) || (typeof schema === 'function' && utils.typeName(schema) !== undefined)) {
|
|
85
86
|
return formalizeAny({ type: schema }, schema, options);
|
|
@@ -131,6 +132,10 @@ const formalizeAny = (schema, options = {}) => {
|
|
|
131
132
|
});
|
|
132
133
|
}
|
|
133
134
|
|
|
135
|
+
const pluginValidators = plugins.validatorsForType(type);
|
|
136
|
+
|
|
137
|
+
merge(validators, pluginValidators);
|
|
138
|
+
|
|
134
139
|
// If post validator is provided allow for options.
|
|
135
140
|
if (formalizedSchema.pre !== undefined || formalizedSchema.post !== undefined) {
|
|
136
141
|
merge(validators, { 'options': 'any' });
|
|
@@ -150,6 +155,7 @@ const formalizeAny = (schema, options = {}) => {
|
|
|
150
155
|
|
|
151
156
|
// Test for - and transform - errors in validator.
|
|
152
157
|
if (Array.isArray(test) &&
|
|
158
|
+
|
|
153
159
|
test.length === 2 &&
|
|
154
160
|
validator.includes(utils.instanceTypeName(test[0]))) {
|
|
155
161
|
|
|
@@ -260,10 +266,21 @@ const formalizeAny = (schema, options = {}) => {
|
|
|
260
266
|
// Finalize objects and arrays if necessary.
|
|
261
267
|
if (formalizedSchema.type) {
|
|
262
268
|
if (utils.isSameType('object', utils.typeName(formalizedSchema.type))) {
|
|
263
|
-
|
|
269
|
+
formalizedSchema = formalizeObject(formalizedSchema, schema, options);
|
|
264
270
|
}
|
|
265
|
-
if (utils.isSameType('array', utils.typeName(formalizedSchema.type))) {
|
|
266
|
-
|
|
271
|
+
else if (utils.isSameType('array', utils.typeName(formalizedSchema.type))) {
|
|
272
|
+
formalizedSchema = formalizeArray(formalizedSchema, schema, options);
|
|
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);
|
|
267
284
|
}
|
|
268
285
|
}
|
|
269
286
|
|
package/lib/index.js
CHANGED
package/lib/plugins.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const
|
|
4
|
+
merge = require('merge'),
|
|
5
|
+
utils = require('./utils');
|
|
6
|
+
|
|
7
|
+
exports = module.exports = {
|
|
8
|
+
_plugins: []
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
exports.use = function(plugin) {
|
|
12
|
+
this._plugins.push(merge(plugin(utils), {
|
|
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
|
+
|
|
54
|
+
};
|
package/lib/utils.js
CHANGED
|
@@ -13,5 +13,5 @@ exports.isSameType = function(obj1, obj2) {
|
|
|
13
13
|
if (typeof obj1 === 'undefined' || typeof obj2 === 'undefined') {
|
|
14
14
|
return typeof obj1 === typeof obj2;
|
|
15
15
|
}
|
|
16
|
-
return obj1.toLowerCase() == obj2.toLowerCase();
|
|
16
|
+
return exports.typeName(obj1).toLowerCase() == exports.typeName(obj2).toLowerCase();
|
|
17
17
|
};
|
package/lib/validate.js
CHANGED
|
@@ -5,7 +5,8 @@ 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')
|
|
8
|
+
equals = require('./equals.js'),
|
|
9
|
+
plugins = require('./plugins.js');
|
|
9
10
|
|
|
10
11
|
const checkBoolValue = (name, schema, defaults) => {
|
|
11
12
|
if (schema[name] === undefined) return defaults[name] === true;
|
|
@@ -403,6 +404,22 @@ const validateAny = async (data, schema, options, keyPath, validatedData) => {
|
|
|
403
404
|
}
|
|
404
405
|
}
|
|
405
406
|
|
|
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
|
+
|
|
406
423
|
return await validatePost(data, schema, options, keyPath, validatedData);
|
|
407
424
|
|
|
408
425
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "isvalid",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.1",
|
|
4
4
|
"description": "Async JSON validation library for node.js.",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"keywords": [
|
|
@@ -18,10 +18,11 @@
|
|
|
18
18
|
"merge": "^2.1.1"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
+
"@trenskow/caseit": "^1.2.0",
|
|
21
22
|
"body-parser": "^1.20.0",
|
|
22
23
|
"chai": "^4.3.6",
|
|
23
24
|
"chai-as-promised": "^7.1.1",
|
|
24
|
-
"eslint": "^8.
|
|
25
|
+
"eslint": "^8.13.0",
|
|
25
26
|
"express": "^4.17.3",
|
|
26
27
|
"mocha": "^9.2.2",
|
|
27
28
|
"supertest": "^6.2.2"
|
package/test/formalize.js
CHANGED
|
@@ -179,5 +179,11 @@ describe('schema', function() {
|
|
|
179
179
|
it ('should throw error if array len is negative.', () => {
|
|
180
180
|
expect(f({ type: Array, len: '-2-' })).to.throw(SchemaError);
|
|
181
181
|
});
|
|
182
|
+
it ('should throw error if validator is not supported', () => {
|
|
183
|
+
expect(f({ type: String, nonExistingValidator: 'myValue' })).to.throw(SchemaError);
|
|
184
|
+
});
|
|
185
|
+
it ('should throw error if plugin validator fails formalizing.', () => {
|
|
186
|
+
expect(f({ type: String, casing: 'not-supported' })).to.throw(SchemaError);
|
|
187
|
+
});
|
|
182
188
|
});
|
|
183
189
|
});
|
package/test/index.js
CHANGED
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const chai = require('chai'),
|
|
4
|
-
chaiAsPromised = require('chai-as-promised')
|
|
4
|
+
chaiAsPromised = require('chai-as-promised'),
|
|
5
|
+
caseit = require('@trenskow/caseit'),
|
|
6
|
+
isvalid = require('../');
|
|
5
7
|
|
|
6
8
|
chai.use(chaiAsPromised);
|
|
7
9
|
|
|
10
|
+
isvalid.plugins.use(function (utils) {
|
|
11
|
+
return {
|
|
12
|
+
supportsType: (type) => utils.isSameType(type, String),
|
|
13
|
+
validatorsForType: () => { return { ensureCase: String }; },
|
|
14
|
+
formalizeValidator: (_, __, config) => {
|
|
15
|
+
if (!config) return;
|
|
16
|
+
if (!caseit.supported.includes(config)) throw new Error(`Only case types: ${caseit.supported.map((casing) => `\`${casing}\``).join(', ')} are supported.`);
|
|
17
|
+
},
|
|
18
|
+
validate: (_, __, config, data) => {
|
|
19
|
+
if (caseit(data, config) !== data) throw new Error(`Is not ${config} case.`);
|
|
20
|
+
return data;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
});
|
|
24
|
+
|
|
8
25
|
require('./ranges.js');
|
|
9
26
|
require('./equals.js');
|
|
10
27
|
require('./unique.js');
|
package/test/validate.js
CHANGED
|
@@ -756,4 +756,20 @@ describe('validate', function() {
|
|
|
756
756
|
describe('other validator', function() {
|
|
757
757
|
commonTests.all(Test, new Test(), 123);
|
|
758
758
|
});
|
|
759
|
+
describe('plugin validators', function() {
|
|
760
|
+
it ('should throw error if casing does not match.', function() {
|
|
761
|
+
return expect(isvalid('my-string', { type: String, ensureCase: 'camel' }))
|
|
762
|
+
.to.eventually.rejectedWith(ValidationError)
|
|
763
|
+
.and.to.have.property('message', 'Is not camel case.');
|
|
764
|
+
});
|
|
765
|
+
it ('should throw error with custom message if casing does not match.', function() {
|
|
766
|
+
return expect(isvalid('my-string', { type: String, ensureCase: ['camel', 'Something is not right!'] }))
|
|
767
|
+
.to.eventually.rejectedWith(ValidationError)
|
|
768
|
+
.and.to.have.property('message', 'Something is not right!');
|
|
769
|
+
});
|
|
770
|
+
it ('should come back with correct value.', function() {
|
|
771
|
+
return expect(isvalid('myString', { type: String, ensureCase: 'camel' }))
|
|
772
|
+
.to.eventually.equal('myString');
|
|
773
|
+
});
|
|
774
|
+
});
|
|
759
775
|
});
|