async-validate
Advanced tools
Comparing version 0.6.4 to 0.7.1
@@ -36,6 +36,4 @@ ### API | ||
* `bail`: Shorthand for `single` and `first`. | ||
* `keys`: Specifies the keys on the source object to be validated. Use this option to validate fields in a determinate order or to validate a subset of the rules assigned to a schema. | ||
* `parallel`: A boolean indicating that the validation should be executed in parallel. | ||
* `field`: Field name for the root object, default is `source` when not specified. | ||
* `rules`: Rules to apply to the root source object, may be an array or a single rule object. | ||
* `field`: Field name for the source object, default is `source` when not specified. | ||
@@ -123,6 +121,6 @@ ##### Schema.plugin | ||
##### shouldValidate | ||
##### validates | ||
```javascript | ||
function shouldValidate() | ||
function validates() | ||
``` | ||
@@ -129,0 +127,0 @@ |
@@ -203,11 +203,24 @@ ## Guide | ||
Adding a reason allows associating an identifier with an error and optional meta data about the error reason. | ||
Adding a reason allows associating an identifier with an error and optional meta data about the error. | ||
### Plugins | ||
To use schema types you should load plugins for the types you wish to validate: | ||
Plugins are modules defining functions that allow users to only load functionality specific to the rule types being used which allows builds for the browser to be as lean as possible. | ||
See [zephyr][] for plugin system documentation. | ||
#### Loading Plugins | ||
To load all plugins: | ||
```javascript | ||
var schema = require('async-validate'); | ||
schema.plugin([ | ||
require('async-validate/plugin/all'); | ||
``` | ||
It is preferable to only use plugins for the types you are using: | ||
```javascript | ||
var Schema = require('async-validate'); | ||
Schema.plugin([ | ||
require('async-validate/plugin/util'), | ||
require('async-validate/plugin/array'), | ||
@@ -220,15 +233,11 @@ require('async-validate/plugin/boolean'), | ||
As a shortcut you may use all available types with: | ||
#### Creating Plugins | ||
```javascript | ||
require('async-validate/plugin/all'); | ||
``` | ||
Static plugins are mapped to [type identifiers](#type-identifiers) and instance plugins may be used to extend [Rule](#rule) which is useful for sharing functionality across rule plugins, see the [util plugins](/plugin/util). | ||
See [plugins](/plugin) for the type plugins that ship with this module and [zephyr][] for documentation on the plugin system. | ||
See [plugin rule](#plugin-rule) for an example and [plugin](/plugin) contains the plugins that ship with this package. | ||
The [plugin fixture](/test/fixtures/plugin.js) and the [plugin test](/test/spec/plugin.js) provide an example of creating a type plugin. | ||
### Rule Properties | ||
This section describes the recognised rule properties and their behaviour, if you are using an [assigned rule](#assigned-rule) or [plugin rule](#plugin-rule) you can define properties on the rule object and they are available to the rule function via `this.rule`. | ||
This section describes the recognised rule properties and their behaviour, if you are using an [assigned rule](#assigned-rule) or [plugin rule](#plugin-rule) you can define properties on the rule object and they are available to the rule function via `this`. | ||
@@ -246,3 +255,3 @@ #### Type Identifier | ||
* `null`: Must strictly equal `null`. | ||
* `regexp`: Must be an instance of `RegExp` or a string that does not generate an exception when creating a new `RegExp`. | ||
* `regexp`: Must be an instance of `RegExp` or a valid string regexp. | ||
* `integer`: Must be of type `number` and an integer. | ||
@@ -249,0 +258,0 @@ * `float`: Must be of type `number` and a floating point number. |
@@ -42,2 +42,4 @@ var plugin = require('zephyr') | ||
} | ||
//console.dir(this.field); | ||
@@ -96,3 +98,3 @@ if(typeof this.rule.message === 'function') { | ||
*/ | ||
function shouldValidate() { | ||
function validates() { | ||
if(this.isRoot()) { | ||
@@ -139,5 +141,5 @@ return true; | ||
Rule.prototype.isRoot = isRoot; | ||
Rule.prototype.shouldValidate = shouldValidate; | ||
Rule.prototype.validates = validates; | ||
Rule.prototype.diff = diff; | ||
module.exports = plugin({type: Rule, proto: Rule.prototype}); |
@@ -15,19 +15,18 @@ var iterator = require('./iterator') | ||
if(!rules) { | ||
if(rules === undefined) { | ||
throw new Error('Cannot configure a schema with no rules'); | ||
} | ||
if(typeof rules !== 'object' || Array.isArray(rules)) { | ||
if(!rules || typeof rules !== 'object' && typeof rules !== 'function') { | ||
throw new Error('Rules must be an object') | ||
} | ||
this.rules = {}; | ||
rules = clone(rules); | ||
var z, item; | ||
for(z in rules) { | ||
item = clone(rules[z]); | ||
this.rules[z] = Array.isArray(item) ? item : [item]; | ||
// wrap shorthand declaration without `fields` | ||
if(!rules.fields && !opts.deep) { | ||
rules = {fields: rules}; | ||
} | ||
this.keys = Object.keys(rules); | ||
this.rules = rules; | ||
} | ||
@@ -63,5 +62,3 @@ | ||
if(!this.keys.length) { | ||
throw new Error('Cannot validate with no rules.'); | ||
}else if(!source) { | ||
if(!source && !options.deep) { | ||
throw new Error('Cannot validate with no source.'); | ||
@@ -72,11 +69,6 @@ }else if(typeof cb !== 'function') { | ||
var i | ||
, j | ||
, z | ||
, arr | ||
, value | ||
var value | ||
, rule | ||
, validator | ||
, series = [] | ||
, keys | ||
, func | ||
@@ -89,5 +81,2 @@ , messages; | ||
// schema keys to iterate over | ||
keys = options.keys || this.keys; | ||
// iterator function series/parallel | ||
@@ -99,97 +88,81 @@ func = options.parallel ? iterator.map : iterator.mapSeries; | ||
options.messages = messages; | ||
series = Array.isArray(this.rules) ? this.rules : [this.rules]; | ||
series = series.map(function(rule) { | ||
var value = source; | ||
// rules for the root object | ||
if(options.rules && !options._root) { | ||
var rules = Array.isArray(options.rules) ? options.rules : [options.rules]; | ||
rule.field = options.field || 'source'; | ||
rules = clone(rules); | ||
for(i = 0;i < rules.length;i++) { | ||
rule = rules[i]; | ||
rule.field = options.field || 'source'; | ||
rule.type = getType(rule); | ||
rule.validator = getValidationMethod(rule); | ||
rule.keys = this.keys; | ||
rule.value = source; | ||
rule.source = source; | ||
series.push(rule); | ||
// handle transformation | ||
if(typeof(rule.transform) === 'function') { | ||
value = source = rule.transform(value); | ||
if(options.parent && rule.field) { | ||
options.parent[rule.field] = value; | ||
} | ||
} | ||
Object.defineProperty(options, '_root', { | ||
value: true, | ||
enumerable: false | ||
}) | ||
} | ||
if(!rule.type && !options.deep) { | ||
rule.type = typeof(source); | ||
} | ||
// convert map into iterable array | ||
// assigning field name to rule and perform transform | ||
for(j = 0;j < keys.length;j++) { | ||
z = keys[j]; | ||
arr = this.rules[z]; | ||
value = source[z]; | ||
// infer rule type | ||
if(rule.type === undefined | ||
&& (rule.pattern instanceof RegExp)) { | ||
rule.type = 'pattern'; | ||
} | ||
for(i = 0;i < arr.length;i++) { | ||
rule = arr[i]; | ||
// handle instanceof tests for object type | ||
if(typeof rule.type === 'function') { | ||
rule.Type = rule.type; | ||
rule.type = 'object'; | ||
} | ||
// handle transformation | ||
if(typeof(rule.transform) === 'function') { | ||
value = source[z] = rule.transform(value); | ||
} | ||
if(typeof rule === 'function') { | ||
rule.validator = rule; | ||
}else if(typeof rule.validator !== 'function') { | ||
// validator plugin functions are static methods | ||
rule.validator = Rule[rule.type]; | ||
} | ||
// wrap inline functions | ||
if(typeof(rule) === 'function') { | ||
rule = {validator: rule}; | ||
} | ||
rule.value = value; | ||
rule.source = options.source || source; | ||
rule.keys = options.keys; | ||
rule.field = z; | ||
rule.type = getType(rule); | ||
rule.validator = getValidationMethod(rule); | ||
rule.value = value; | ||
rule.source = source; | ||
series.push(rule); | ||
if(typeof rule.validator !== 'function') { | ||
throw new Error(format('Unknown rule type %s', rule.type)); | ||
} | ||
} | ||
return rule; | ||
}) | ||
//var keys = options.keys || Object.keys(this.rules.fields || this.rules); | ||
// iterate list data | ||
func(series, function(rule, callback) { | ||
var validator = getValidationOptions(rule, options) | ||
, len | ||
, i; | ||
if(rule.type === 'array' && typeof rule.values === 'object') { | ||
len = Array.isArray(rule.values) | ||
? rule.values.length : Array.isArray(rule.value) | ||
? rule.value.length : 0; | ||
var validator = Rule({ | ||
rule: rule, | ||
field: rule.field, | ||
value: rule.value, | ||
source: rule.source, | ||
errors: [], | ||
options: options, | ||
messages: options.messages | ||
}); | ||
if(len) { | ||
rule.fields = {}; | ||
} | ||
// object declaration applies to all array values | ||
if(!Array.isArray(rule.values)) { | ||
for(i = 0;i < len;i++) { | ||
rule.fields[i] = rule.values; | ||
} | ||
}else{ | ||
for(i = 0;i < len;i++) { | ||
rule.fields[i] = rule.values[i]; | ||
} | ||
} | ||
} | ||
var deep = (rule.type === 'object' || rule.type === 'array') | ||
&& typeof(rule.fields) === 'object'; | ||
deep = deep && (rule.required || (!rule.required && rule.value)); | ||
function onValidate(err) { | ||
var errors = validator.errors; | ||
var i | ||
, errors = validator.errors; | ||
// bail on first error | ||
if(options.first && errors && errors.length) { | ||
return complete(err, errors, options, cb); | ||
} | ||
//if(options.first && errors && errors.length) { | ||
//return complete(err, errors, options, cb); | ||
//} | ||
// not deep so continue on to next in series | ||
if(!deep) { | ||
callback(err, errors); | ||
return callback(err, errors); | ||
@@ -199,22 +172,80 @@ // generate temp schema for nested rules | ||
// if rule is required but the target object | ||
// does not exist fail at the rule level and don't | ||
// go deeper | ||
if(rule.required && !rule.value) { | ||
return callback(null, [ | ||
new Error( | ||
format(options.messages.required, rule.field)) | ||
]); | ||
} | ||
var keys = options.keys || Object.keys(rule.fields); | ||
var schema = new Schema(rule.fields, {messages: options.messages}); | ||
schema.validate( | ||
rule.value, rule.options || options, function(err, res) { | ||
if(res) { | ||
errors = errors.concat(res.errors); | ||
func(keys, function iterator(key, cb) { | ||
//console.log('field key %s', key); | ||
var opts = clone(options) | ||
, descriptor = rule.fields[key] | ||
, value = rule.value[key] | ||
, schema; | ||
if(descriptor.type === 'array' | ||
&& typeof descriptor.values === 'object') { | ||
// wrap objects as arrays | ||
var values = Array.isArray(descriptor.values) | ||
? descriptor.values : [descriptor.values] | ||
, len; | ||
len = Array.isArray(descriptor.values) | ||
? descriptor.values.length : Array.isArray(value) | ||
? value.length : 0; | ||
if(len) { | ||
descriptor.fields = {}; | ||
} | ||
// object declaration applies to all array values | ||
if(!Array.isArray(descriptor.values)) { | ||
for(i = 0;i < len;i++) { | ||
descriptor.fields[i] = descriptor.values; | ||
} | ||
}else{ | ||
for(i = 0;i < len;i++) { | ||
descriptor.fields[i] = descriptor.values[i]; | ||
} | ||
} | ||
} | ||
callback(err, errors); | ||
}); | ||
// if rule is required but the target object | ||
// does not exist fail at the rule level and don't | ||
// go deeper | ||
if(descriptor.required && value === undefined) { | ||
errors.push( | ||
validator.error.call({field: key, rule: descriptor}, | ||
options.messages.required, key)); | ||
return cb(); | ||
} | ||
schema = new Schema( | ||
descriptor, {messages: options.messages, deep: true}); | ||
opts.parent = rule.value; | ||
opts.deep = true; | ||
opts.field = key; | ||
// important to maintain original source for isRoot() | ||
opts.source = source; | ||
schema.validate(value, opts, function(err, res) { | ||
if(res && res.errors.length) { | ||
errors = errors.concat(res.errors); | ||
} | ||
cb(err, null); | ||
}); | ||
}, function(err, result) { | ||
// bail on first error | ||
if(options.first && errors && errors.length) { | ||
return complete(err, errors, options, cb); | ||
} | ||
callback(err, errors); | ||
}) | ||
} | ||
} | ||
rule.validator.call(validator, onValidate); | ||
@@ -230,61 +261,2 @@ | ||
* | ||
* Get a validator with public fields. | ||
*/ | ||
function getValidationOptions(rule, options) { | ||
return Rule({ | ||
rule: rule, | ||
field: rule.field, | ||
value: rule.value, | ||
source: rule.source, | ||
errors: [], | ||
options: options, | ||
messages: options.messages | ||
}); | ||
} | ||
/** | ||
* @private | ||
* | ||
* Infer the type of a rule. | ||
* | ||
* @param rule The validation rule. | ||
*/ | ||
function getType(rule) { | ||
if(rule.type == undefined | ||
&& (rule.pattern instanceof RegExp)) { | ||
rule.type = 'pattern'; | ||
} | ||
// handle instanceof tests for object type | ||
if(typeof rule.type === 'function') { | ||
rule.Type = rule.type; | ||
rule.type = 'object'; | ||
} | ||
// validator plugin functions are static methods | ||
if(typeof(rule.validator) !== 'function' | ||
&& (!rule.type || !Rule.hasOwnProperty(rule.type))) { | ||
throw new Error(format('Unknown rule type %s', rule.type)); | ||
} | ||
return rule.type; | ||
} | ||
/** | ||
* @private | ||
* | ||
* Retrieve a validation method for a rule. | ||
* | ||
* @param rule The validation rule. | ||
*/ | ||
function getValidationMethod(rule) { | ||
if(typeof rule.validator === 'function') { | ||
return rule.validator; | ||
} | ||
// validator plugin functions are static methods | ||
return Rule[rule.type]; | ||
} | ||
/** | ||
* @private | ||
* | ||
* Collates the errors arrays and maps field names to errors | ||
@@ -316,5 +288,2 @@ * specific to the field. | ||
// clean up flags | ||
delete options._root; | ||
callback(err, !errors.length ? null : {errors: errors, fields: fields}); | ||
@@ -321,0 +290,0 @@ } |
{ | ||
"name": "async-validate", | ||
"description": "Asynchronous validation for node and the browser", | ||
"version": "0.6.4", | ||
"version": "0.7.1", | ||
"author": "muji <noop@xpm.io>", | ||
@@ -6,0 +6,0 @@ "license": "MIT", |
@@ -9,3 +9,3 @@ module.exports = function() { | ||
this.main.array = function array(cb) { | ||
if(this.shouldValidate()) { | ||
if(this.validates()) { | ||
this.required(); | ||
@@ -12,0 +12,0 @@ if(!Array.isArray(this.value)) { |
@@ -9,3 +9,3 @@ module.exports = function() { | ||
this.main.boolean = function bool(cb) { | ||
if(this.shouldValidate()) { | ||
if(this.validates()) { | ||
this.required(); | ||
@@ -12,0 +12,0 @@ |
@@ -9,3 +9,3 @@ module.exports = function() { | ||
this.main.enum = function enumerable(cb) { | ||
if(this.shouldValidate()) { | ||
if(this.validates()) { | ||
this.required(); | ||
@@ -12,0 +12,0 @@ var list = this.rule.list; |
@@ -9,3 +9,3 @@ module.exports = function() { | ||
this.main.float = function fraction(cb) { | ||
if(this.shouldValidate()) { | ||
if(this.validates()) { | ||
this.required(); | ||
@@ -12,0 +12,0 @@ |
@@ -9,3 +9,3 @@ module.exports = function() { | ||
this.main.integer = function integer(cb) { | ||
if(this.shouldValidate()) { | ||
if(this.validates()) { | ||
this.required(); | ||
@@ -12,0 +12,0 @@ |
@@ -9,3 +9,3 @@ module.exports = function() { | ||
this.main.method = function method(cb) { | ||
if(this.shouldValidate()) { | ||
if(this.validates()) { | ||
this.required(); | ||
@@ -12,0 +12,0 @@ this.range(); |
@@ -9,3 +9,3 @@ module.exports = function() { | ||
this.main.null = function validate(cb) { | ||
if(this.shouldValidate()) { | ||
if(this.validates()) { | ||
this.required(); | ||
@@ -12,0 +12,0 @@ if(this.value !== null) { |
@@ -9,3 +9,3 @@ module.exports = function() { | ||
this.main.number = function number(cb) { | ||
if(this.shouldValidate()) { | ||
if(this.validates()) { | ||
this.required(); | ||
@@ -12,0 +12,0 @@ // straight typeof check |
@@ -18,3 +18,3 @@ function isObject(value, Type) { | ||
if(this.shouldValidate()) { | ||
if(this.validates()) { | ||
this.required(); | ||
@@ -34,4 +34,3 @@ | ||
// NOTE: for the `object` type but do not declare nested `fields` object | ||
expected = Array.isArray(this.rule.keys) | ||
? this.rule.keys : Object.keys(this.rule.fields); | ||
expected = Object.keys(this.rule.fields); | ||
@@ -38,0 +37,0 @@ additional = this.diff( |
@@ -12,3 +12,3 @@ module.exports = function() { | ||
this.main.pattern = function pattern(cb) { | ||
if(this.shouldValidate()) { | ||
if(this.validates()) { | ||
this.pattern(); | ||
@@ -15,0 +15,0 @@ } |
@@ -20,3 +20,3 @@ function isRegExp(value) { | ||
this.main.regexp = function regexp(cb) { | ||
if(this.shouldValidate()) { | ||
if(this.validates()) { | ||
this.required(); | ||
@@ -23,0 +23,0 @@ if(!isRegExp(this.value)) { |
@@ -9,3 +9,3 @@ module.exports = function() { | ||
this.main.string = function string(cb) { | ||
if(this.shouldValidate()) { | ||
if(this.validates()) { | ||
this.required(); | ||
@@ -12,0 +12,0 @@ |
@@ -20,2 +20,4 @@ Table of Contents | ||
* [Plugins](#plugins) | ||
* [Loading Plugins](#loading-plugins) | ||
* [Creating Plugins](#creating-plugins) | ||
* [Rule Properties](#rule-properties) | ||
@@ -48,3 +50,3 @@ * [Type Identifier](#type-identifier) | ||
* [format](#format) | ||
* [shouldValidate](#shouldvalidate) | ||
* [validates](#validates) | ||
* [diff](#diff) | ||
@@ -86,3 +88,3 @@ * [required](#required) | ||
Schema.plugin([ | ||
require('../plugin/util/required'), | ||
require('../plugin/util'), | ||
require('../plugin/string')]); | ||
@@ -305,11 +307,24 @@ | ||
Adding a reason allows associating an identifier with an error and optional meta data about the error reason. | ||
Adding a reason allows associating an identifier with an error and optional meta data about the error. | ||
### Plugins | ||
To use schema types you should load plugins for the types you wish to validate: | ||
Plugins are modules defining functions that allow users to only load functionality specific to the rule types being used which allows builds for the browser to be as lean as possible. | ||
See [zephyr](https://github.com/socialally/zephyr) for plugin system documentation. | ||
#### Loading Plugins | ||
To load all plugins: | ||
```javascript | ||
var schema = require('async-validate'); | ||
schema.plugin([ | ||
require('async-validate/plugin/all'); | ||
``` | ||
It is preferable to only use plugins for the types you are using: | ||
```javascript | ||
var Schema = require('async-validate'); | ||
Schema.plugin([ | ||
require('async-validate/plugin/util'), | ||
require('async-validate/plugin/array'), | ||
@@ -322,15 +337,11 @@ require('async-validate/plugin/boolean'), | ||
As a shortcut you may use all available types with: | ||
#### Creating Plugins | ||
```javascript | ||
require('async-validate/plugin/all'); | ||
``` | ||
Static plugins are mapped to [type identifiers](#type-identifiers) and instance plugins may be used to extend [Rule](#rule) which is useful for sharing functionality across rule plugins, see the [util plugins](https://github.com/freeformsystems/async-validate/blob/master/plugin/util). | ||
See [plugins](https://github.com/freeformsystems/async-validate/blob/master/plugin) for the type plugins that ship with this module and [zephyr](https://github.com/socialally/zephyr) for documentation on the plugin system. | ||
See [plugin rule](#plugin-rule) for an example and [plugin](https://github.com/freeformsystems/async-validate/blob/master/plugin) contains the plugins that ship with this package. | ||
The [plugin fixture](https://github.com/freeformsystems/async-validate/blob/master/test/fixtures/plugin.js) and the [plugin test](https://github.com/freeformsystems/async-validate/blob/master/test/spec/plugin.js) provide an example of creating a type plugin. | ||
### Rule Properties | ||
This section describes the recognised rule properties and their behaviour, if you are using an [assigned rule](#assigned-rule) or [plugin rule](#plugin-rule) you can define properties on the rule object and they are available to the rule function via `this.rule`. | ||
This section describes the recognised rule properties and their behaviour, if you are using an [assigned rule](#assigned-rule) or [plugin rule](#plugin-rule) you can define properties on the rule object and they are available to the rule function via `this`. | ||
@@ -348,3 +359,3 @@ #### Type Identifier | ||
* `null`: Must strictly equal `null`. | ||
* `regexp`: Must be an instance of `RegExp` or a string that does not generate an exception when creating a new `RegExp`. | ||
* `regexp`: Must be an instance of `RegExp` or a valid string regexp. | ||
* `integer`: Must be of type `number` and an integer. | ||
@@ -506,3 +517,3 @@ * `float`: Must be of type `number` and a floating point number. | ||
Schema.plugin([ | ||
require('../plugin/util/required'), | ||
require('../plugin/util'), | ||
require('../plugin/string')]); | ||
@@ -550,6 +561,4 @@ | ||
* `bail`: Shorthand for `single` and `first`. | ||
* `keys`: Specifies the keys on the source object to be validated. Use this option to validate fields in a determinate order or to validate a subset of the rules assigned to a schema. | ||
* `parallel`: A boolean indicating that the validation should be executed in parallel. | ||
* `field`: Field name for the root object, default is `source` when not specified. | ||
* `rules`: Rules to apply to the root source object, may be an array or a single rule object. | ||
* `field`: Field name for the source object, default is `source` when not specified. | ||
@@ -637,6 +646,6 @@ ##### Schema.plugin | ||
##### shouldValidate | ||
##### validates | ||
```javascript | ||
function shouldValidate() | ||
function validates() | ||
``` | ||
@@ -643,0 +652,0 @@ |
@@ -7,10 +7,14 @@ var expect = require('chai').expect | ||
var descriptor = { | ||
address: { | ||
type: 'object', | ||
required: true, | ||
additional: false, | ||
fields: { | ||
street: {type: 'string', required: true}, | ||
city: {type: 'string', required: true}, | ||
zip: {type: 'string', required: true, len: 8, message: 'Invalid zip'} | ||
type: 'object', | ||
additional: false, | ||
fields: { | ||
address: { | ||
type: 'object', | ||
required: true, | ||
additional: false, | ||
fields: { | ||
street: {type: 'string', required: true}, | ||
city: {type: 'string', required: true}, | ||
zip: {type: 'string', required: true, len: 8, message: 'Invalid zip'} | ||
} | ||
} | ||
@@ -22,3 +26,2 @@ } | ||
var opts = { | ||
rules: {type: 'object', additional: false}, | ||
// set root source object field name | ||
@@ -28,3 +31,3 @@ field: 'root' | ||
var source = { | ||
name: 'Opps', | ||
name: 'Oops', | ||
address: { | ||
@@ -50,5 +53,2 @@ name: 'Oops', | ||
it('should validate with no additional properties', function(done) { | ||
var opts = { | ||
rules: {type: 'object', additional: false} | ||
} | ||
var source = { | ||
@@ -62,3 +62,3 @@ address: { | ||
var validator = new Schema(descriptor); | ||
validator.validate(source, opts, function(err, res) { | ||
validator.validate(source, function(err, res) { | ||
expect(err).to.eql(null); | ||
@@ -65,0 +65,0 @@ expect(res).to.eql(null); |
@@ -31,3 +31,4 @@ var expect = require('chai').expect | ||
address: { | ||
type: 'object', required: true, | ||
type: 'object', | ||
required: true, | ||
fields: { | ||
@@ -41,2 +42,25 @@ street: {type: 'string', required: true}, | ||
//it('should error on deep rule (with bail out options)', function(done) { | ||
//var descriptor = { | ||
//name: {type: 'string', required: true}, | ||
//address: { | ||
//type: 'object', required: true, options: {single: true, first: true}, | ||
//fields: { | ||
//street: {type: 'string', required: true}, | ||
//city: {type: 'string', required: true}, | ||
//zip: {type: 'string', required: true, len: 8, message: 'invalid zip'} | ||
//} | ||
//} | ||
//} | ||
//var schema = new Schema(descriptor); | ||
//schema.validate({address: {}}, function(err, res) { | ||
//expect(res.errors.length).to.eql(2); | ||
//expect(res.errors[0].message).to.eql('name is required'); | ||
//expect(res.errors[1].message).to.eql('street is required'); | ||
////expect(res.errors[2].message).to.eql('city is required'); | ||
////expect(res.errors[3].message).to.eql('invalid zip'); | ||
//done(); | ||
//}); | ||
//}); | ||
it('should error on invalid deep rule (required/no matching property)', | ||
@@ -66,22 +90,2 @@ function(done) { | ||
); | ||
it('should error on deep rule (with bail out options)', function(done) { | ||
var descriptor = { | ||
address: { | ||
type: 'object', required: true, options: {single: true, first: true}, | ||
fields: { | ||
street: {type: 'string', required: true}, | ||
city: {type: 'string', required: true}, | ||
zip: {type: 'string', required: true, len: 8, message: 'invalid zip'} | ||
} | ||
}, | ||
name: {type: 'string', required: true} | ||
} | ||
var schema = new Schema(descriptor); | ||
schema.validate({ address: {} }, function(err, res) { | ||
expect(res.errors.length).to.eql(2); | ||
expect(res.errors[0].message).to.eql('street is required'); | ||
expect(res.errors[1].message).to.eql('name is required'); | ||
done(); | ||
}); | ||
}); | ||
@@ -88,0 +92,0 @@ it('should error on deep rule (array type length mismatch)', function(done) { |
@@ -19,10 +19,12 @@ var expect = require('chai').expect | ||
it("should error on invalid object (required but not specified)", function(done) { | ||
var schema = new Schema(descriptor); | ||
schema.validate({}, function(err, res) { | ||
expect(res.errors.length).to.eql(2); | ||
expect(res.errors[0].message).to.eql('address is required'); | ||
done(); | ||
}); | ||
}); | ||
it("should error on invalid object (required but not specified)", | ||
function(done) { | ||
var schema = new Schema(descriptor); | ||
schema.validate({}, function(err, res) { | ||
expect(res.errors.length).to.eql(1); | ||
expect(res.errors[0].message).to.eql('address is required'); | ||
done(); | ||
}); | ||
} | ||
); | ||
@@ -29,0 +31,0 @@ it("should validate object (empty object)", function(done) { |
@@ -30,3 +30,3 @@ var expect = require('chai').expect | ||
schema.validate({}, {first: true}, function(err, res) { | ||
expect(res.errors.length).to.eql(1); | ||
expect(res.errors.length).to.eql(2); | ||
done(); | ||
@@ -33,0 +33,0 @@ }); |
var expect = require('chai').expect | ||
, schema = require('../../index'); | ||
, Schema = require('../../index'); | ||
describe("async-validate:", function() { | ||
it("should define with fields", function(done) { | ||
var schema = new Schema({fields: {name: {type: 'string'}}}); | ||
expect(schema.rules).to.be.an('object'); | ||
expect(schema.rules.fields).to.be.an('object'); | ||
done(); | ||
}); | ||
it("should define without fields", function(done) { | ||
var schema = new Schema({name: {type: 'string'}}); | ||
expect(schema.rules).to.be.an('object'); | ||
expect(schema.rules.fields).to.be.an('object'); | ||
done(); | ||
}); | ||
it("should error with no rules", function(done) { | ||
function fn() { | ||
var validator = new schema(); | ||
var schema = new Schema(); | ||
} | ||
@@ -16,5 +30,5 @@ expect(fn).throws(Error); | ||
it("should error with rules as array", function(done) { | ||
it("should error with rules as null", function(done) { | ||
function fn() { | ||
var validator = new schema([]); | ||
var schema = new Schema(null); | ||
} | ||
@@ -26,16 +40,16 @@ expect(fn).throws(Error); | ||
it("should error on validate with no rules", function(done) { | ||
var validator = new schema({}); | ||
function fn() { | ||
validator.validate({}); | ||
} | ||
expect(fn).throws(Error); | ||
expect(fn).throws(/cannot validate with no rules/i); | ||
done(); | ||
}); | ||
//it("should error on validate with no rules", function(done) { | ||
//var schema = new Schema({}); | ||
//function fn() { | ||
//schema.validate({}); | ||
//} | ||
//expect(fn).throws(Error); | ||
//expect(fn).throws(/cannot validate with no rules/i); | ||
//done(); | ||
//}); | ||
it("should error on validate with no source", function(done) { | ||
var validator = new schema({name: function(cb){cb()}}); | ||
var schema = new Schema({name: function(cb){cb()}}); | ||
function fn() { | ||
validator.validate(); | ||
schema.validate(); | ||
} | ||
@@ -48,5 +62,5 @@ expect(fn).throws(Error); | ||
it("should error on validate with no callback", function(done) { | ||
var validator = new schema({name: function(cb){cb()}}); | ||
var schema = new Schema({name: function(cb){cb()}}); | ||
function fn() { | ||
validator.validate({}); | ||
schema.validate({}); | ||
} | ||
@@ -60,5 +74,5 @@ expect(fn).throws(Error); | ||
it("should error on validate with unknown type", function(done) { | ||
var validator = new schema({name: {type: 'unknown-type'}}); | ||
var schema = new Schema({name: {type: 'unknown-type'}}); | ||
function fn() { | ||
validator.validate({}, function noop(){}); | ||
schema.validate({}, function noop(){}); | ||
} | ||
@@ -65,0 +79,0 @@ expect(fn).throws(Error); |
@@ -6,7 +6,11 @@ var expect = require('chai').expect | ||
it("should error on invalid source object (additional properties)", function(done) { | ||
var opts = { | ||
rules: {type: 'object', additional: false} | ||
} | ||
var descriptor = { | ||
var descriptor = { | ||
type: 'object', | ||
additional: false, | ||
// trigger code path whereby transform cannot assign inline | ||
// on root object as there is no parent object to assign to | ||
transform: function(value) { | ||
return value; | ||
}, | ||
fields: { | ||
address: { | ||
@@ -17,27 +21,22 @@ type: "object", | ||
} | ||
var source = { | ||
name: 'Oops', | ||
address: {} | ||
} | ||
it("should error on invalid source object (additional properties)", | ||
function(done) { | ||
var source = { | ||
name: 'Oops', | ||
address: {} | ||
} | ||
var validator = new schema(descriptor); | ||
validator.validate(source, function(err, res) { | ||
// NOTE: `source` is the default field name for root object | ||
var expected = 'extraneous fields (name) found in source'; | ||
expect(res.errors.length).to.eql(1); | ||
expect(res.errors[0].message).to.eql(expected); | ||
done(); | ||
}); | ||
} | ||
var validator = new schema(descriptor); | ||
validator.validate(source, opts, function(err, res) { | ||
// NOTE: `source` is the default field name for root object | ||
var expected = 'extraneous fields (name) found in source'; | ||
expect(res.errors.length).to.eql(1); | ||
expect(res.errors[0].message).to.eql(expected); | ||
done(); | ||
}); | ||
}); | ||
); | ||
it("should validate with no additional properties", function(done) { | ||
var opts = { | ||
// NOTE: use array of rules to trigger code path | ||
rules: [{type: 'object', additional: false}] | ||
} | ||
var descriptor = { | ||
address: { | ||
type: "object", | ||
required: true | ||
} | ||
} | ||
var source = { | ||
@@ -47,3 +46,3 @@ address: {} | ||
var validator = new schema(descriptor); | ||
validator.validate(source, opts, function(err, res) { | ||
validator.validate(source, function(err, res) { | ||
expect(err).to.eql(null); | ||
@@ -50,0 +49,0 @@ expect(res).to.eql(null); |
130639
746
2826