New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

async-validate

Package Overview
Dependencies
Maintainers
1
Versions
97
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

async-validate - npm Package Compare versions

Comparing version 0.0.3 to 0.1.0

lib/rule/date.js

1

index.js
module.exports = require('./lib/index');
module.exports.error = require('./lib/error');

@@ -0,3 +1,6 @@

var util = require('util');
var async = require('async');
var validators = require('./validator');
var messages = require('./messages');
var ValidationError = require('./error');

@@ -12,2 +15,3 @@ /**

this.rules = null;
this._messages = messages;
this.define(descriptor);

@@ -17,2 +21,16 @@ }

/**
* Get or set the messages used for this schema.
*
* @param messages The validation messages.
*
* @return The validation messages.
*/
Schema.prototype.messages = function(messages) {
if(messages) {
this._messages = messages;
}
return this._messages;
}
/**
* Define rules on this schema.

@@ -27,6 +45,6 @@ *

throw new Error(
"Cannot configure a schema with no rule.");
"Cannot configure a schema with no rules");
}
if(!(typeof rules == 'object') || Array.isArray(rules)) {
throw new Error("Rules must be an object.")
throw new Error("Rules must be an object")
}

@@ -44,3 +62,3 @@ this.rules = {};

*
* @param values The object to validate.
* @param source The object to validate.
* @param options Validation options.

@@ -51,3 +69,3 @@ * @param callback A callback to invoke when validation is complete.

*/
Schema.prototype.validate = function(values, options, callback) {
Schema.prototype.validate = function(source, options, callback) {
if(!this.rules) {

@@ -62,3 +80,3 @@ throw new Error("Cannot validate with no rules.");

var complete = function(results) {
var errors = [], fields = {};
var i, field, errors = [], fields = {};
var add = function(e) {

@@ -71,3 +89,2 @@ if((e instanceof Error)) {

}
var i, field;
for(i = 0;i < results.length;i++) {

@@ -77,4 +94,3 @@ add(results[i]);

if(!errors.length) {
errors = null;
fields = null;
errors = null, fields = null;
}else{

@@ -92,10 +108,12 @@ if(options.single) {

}
var messages = options.messages || this.messages();
var j, z, arr, value, i, rule, validator, series = [];
var keys = options.keys || Object.keys(this.rules);
for(j = 0;j < keys.length;j++) {
z = keys[j];
arr = this.rules[z];
value = values[z];
z = keys[j]; arr = this.rules[z]; value = source[z];
for(i = 0;i < arr.length;i++) {
rule = arr[i];
if(typeof(rule.transform) == 'function') {
value = source[z] = rule.transform(value);
}
if(typeof(rule) == 'function') {

@@ -105,5 +123,8 @@ rule = {validator: rule};

rule.field = z;
rule.type = this.getType(rule);
rule.validator = this.getValidationMethod(rule);
if(!rule.validator) {
continue;
}
validator = function(callback) {
// mutate the async callback signature
var cb = function(errors) {

@@ -115,11 +136,17 @@ if(options.first) {

}
var rule = arguments.callee.rule;
var value = arguments.callee.value;
var values = arguments.callee.values;
rule.validator(rule, value, cb, values);
var data = arguments.callee.data;
//console.log("calling validator with messages %s", messages);
data.rule.validator(
data.rule, data.value, cb, data.source,
{
messages: messages
}
);
}
validator.rule = rule;
validator.value = value;
validator.values = values;
validator.data = {rule: rule, value: value, source: source};
series.push(validator);
if((rule.type == 'object' || rule.type == 'array')
&& typeof(rule.fields) == 'object') {
this.getDeepValidator(series, rule, value, options);
}
}

@@ -133,5 +160,26 @@ }

/**
* Infer the type of a rule when necessary.
*
* @param rule The validation rule.
*
* @api private
*/
Schema.prototype.getType = function(rule) {
if(rule.type == undefined
&& (rule.pattern instanceof RegExp)) {
rule.type = 'pattern';
}
if(typeof rule.validator == 'function') {
return 'function';
}
if( !rule.type || !validators.hasOwnProperty(rule.type)) {
throw new Error(util.format("Unknown rule type %s", rule.type));
}
return rule.type;
}
/**
* Retrieve a validation method from a rule.
*
* @param rule The field rule.
* @param rule The validation rule.
*

@@ -144,13 +192,49 @@ * @api private

}
if(rule.type == undefined
&& (rule.pattern instanceof RegExp)) {
rule.type = 'pattern';
return validators[rule.type] || false;
}
/**
* Handles creating deep validation rules.
*
* @param series The array of asynchronous functions.
* @param rule The validation rule.
* @param value The value on the source object.
* @param options The options passed to validate the object.
*
* @api private
*/
Schema.prototype.getDeepValidator = function(series, rule, value, options) {
if(value === undefined) {
return false;
}
return validators[rule.type]
|| function(rule, value, callback, values) {
// default validation function always passes
callback([]);
};
var messages = this.messages();
var deep = function(callback) {
var data = arguments.callee.data;
var schema = new Schema(data.rule.fields);
schema.messages(messages);
schema.validate(
data.value, data.rule.options || data.options, function(errors, fields) {
callback(null, errors);
});
}
deep.data = {rule: rule, value: value, options: options};
series.push(deep);
}
/**
* Register a validator function for a type.
*
* @param type The type for the validation rule.
* @param validator The validation function for the rule.
*
* @api public
*/
module.exports.register = function(type, validator) {
if(!(typeof validator == 'function')) {
throw new Error(
"Cannot register a validator by type, validator is not a function");
}
validators[type] = validator;
}
module.exports.rule = require('./rule');

@@ -165,2 +249,4 @@ module.exports.validators = validators;

module.exports.pattern = pattern;
module.exports.error = ValidationError;
module.exports.messages = messages;

@@ -167,0 +253,0 @@ module.exports.rules = {};

@@ -6,7 +6,11 @@ /**

default: 'Validation error on field %s',
required: 'Field %s is required',
required: '%s is required',
enum: '%s must be one of %s',
whitespace: '%s cannot be whitespace',
dateformat: "%s date %s is invalid for format %s",
date: "%s date %s is invalid",
types: {
string: 'Field %s is not a %s',
string: '%s is not a %s',
array: '%s is not an %s',
object: '%s is not an %s',
number: '%s is not a %s',

@@ -19,7 +23,9 @@ boolean: '%s is not a %s',

string: {
min: 'Field %s must be at least %s characters',
max: 'Field %s cannot be longer than %s characters',
range: 'Field %s must be between %s and %s characters'
len: '%s must be exactly %s characters',
min: '%s must be at least %s characters',
max: '%s cannot be longer than %s characters',
range: '%s must be between %s and %s characters'
},
number: {
len: '%s must equal %s',
min: '%s cannot be less than %s',

@@ -30,2 +36,3 @@ max: '%s cannot be greater than %s',

array: {
len: '%s must be exactly %s in length',
min: '%s cannot be less than %s in length',

@@ -36,5 +43,10 @@ max: '%s cannot be greater than %s in length',

pattern: {
mismatch: 'Field %s value %s does not match pattern %s'
mismatch: '%s value %s does not match pattern %s'
},
clone: function() {
var cloned = JSON.parse(JSON.stringify(this));
cloned.clone = this.clone;
return cloned;
}
}
module.exports = messages;

@@ -11,7 +11,6 @@ var util = require('util');

*
* @param rule The validation rule rule.
* @param rule The validation rule.
* @param message A custom messaage for the error.
*/
var getErrorMessage = function(rule, message) {
var err;
var error = function(rule, message) {
var msg = rule.message || message

@@ -24,2 +23,2 @@ || util.format(messages.default, rule.field);

module.exports = getErrorMessage;
module.exports = error;

@@ -7,3 +7,5 @@ module.exports = {

range: require('./range'),
enum: require('./enum'),
date: require('./date'),
pattern: require('./pattern')
}
var util = require('util');
var error = require('./error');
var messages = require('../messages');
var pattern = function(rule, value, values, errors) {
/**
* Rule for validating a regular expression pattern.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param source The source object being validated.
* @param errors An array of errors that this rule may add
* validation errors to.
* @param options The validation options.
* @param options.messages The validation messages.
*/
var pattern = function(rule, value, source, errors, options) {
if(rule.pattern instanceof RegExp) {
if(!rule.pattern.test(value)) {
errors.push(error(rule,
util.format(messages.pattern.mismatch,
util.format(options.messages.pattern.mismatch,
rule.field, value, rule.pattern)));

@@ -11,0 +21,0 @@ }

var util = require('util');
var error = require('./error');
var messages = require('../messages');
var range = function(rule, value, values, errors) {
/**
* Rule for validating minimum and maximum allowed values.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param source The source object being validated.
* @param errors An array of errors that this rule may add
* validation errors to.
* @param options The validation options.
* @param options.messages The validation messages.
*/
var range = function(rule, value, source, errors, options) {
var len = typeof rule.len == 'number';
var min = typeof rule.min == 'number';

@@ -29,13 +40,16 @@ var max = typeof rule.max == 'number';

}
if( min && !max && val < rule.min ) {
if(len) {
if(val !== rule.len) {
errors.push(error(rule,
util.format(options.messages[key].len, rule.field, rule.len)));
}
}else if( min && !max && val < rule.min ) {
errors.push(error(rule,
util.format(messages[key].min, rule.field, rule.min)));
}
if( max && !min && val > rule.max ) {
util.format(options.messages[key].min, rule.field, rule.min)));
}else if( max && !min && val > rule.max ) {
errors.push(error(rule,
util.format(messages[key].max, rule.field, rule.max)));
}
if(min && max && (val < min || val > max) ) {
util.format(options.messages[key].max, rule.field, rule.max)));
}else if(min && max && (val < min || val > max) ) {
errors.push(error(rule,
util.format(messages[key].range,
util.format(options.messages[key].range,
rule.field, rule.min, rule.max)));

@@ -42,0 +56,0 @@ }

var util = require('util');
var error = require('./error');
var messages = require('../messages');
var required = function(rule, value, values, errors) {
/**
* Rule for validating required fields.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param source The source object being validated.
* @param errors An array of errors that this rule may add
* validation errors to.
* @param options The validation options.
* @param options.messages The validation messages.
*/
var required = function(rule, value, source, errors, options) {
if(rule.required
&& !values.hasOwnProperty(rule.field)) {
&& !source.hasOwnProperty(rule.field)) {
errors.push(error(rule,
util.format(messages.required, rule.field)));
util.format(options.messages.required, rule.field)));
}

@@ -11,0 +21,0 @@ }

var util = require('util');
var error = require('./error');
var messages = require('../messages');
var types = {};

@@ -31,4 +29,24 @@ types.integer = function(value) {

var type = function(rule, value, values, errors) {
var custom = ['integer', 'float', 'array', 'regexp'];
types.object = function(value) {
return typeof(value) == 'object' && !types.array(value);
}
/**
* Rule for validating the type of a value.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param source The source object being validated.
* @param errors An array of errors that this rule may add
* validation errors to.
* @param options The validation options.
* @param options.messages The validation messages.
*/
var type = function(rule, value, source, errors, options) {
// if value is required and value is undefined
// no need to add this error message
if(rule.required && value == undefined ) {
return;
}
var custom = ['integer', 'float', 'array', 'regexp', 'object'];
var type = rule.type;

@@ -38,12 +56,8 @@ if(custom.indexOf(type) > -1) {

errors.push(error(rule,
util.format(messages.types[type], rule.field, rule.type)));
util.format(options.messages.types[type], rule.field, rule.type)));
}
// straight typeof check
}else if(type && !(typeof(value) == rule.type)) {
// if value is required and value is undefined
// no need to add this error message
if(!rule.required && value != undefined ) {
errors.push(error(rule,
util.format(messages.types[type], rule.field, rule.type)));
}
errors.push(error(rule,
util.format(options.messages.types[type], rule.field, rule.type)));
}

@@ -50,0 +64,0 @@ }

var util = require('util');
var error = require('./error');
var messages = require('../messages');
var whitespace = function(rule, value, values, errors) {
/**
* Rule for validating whitespace.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param source The source object being validated.
* @param errors An array of errors that this rule may add
* validation errors to.
* @param options The validation options.
* @param options.messages The validation messages.
*/
var whitespace = function(rule, value, source, errors, options) {
if(/^\s+$/) {
errors.push(error(rule,
util.format(messages.whitespace, rule.field)));
util.format(options.messages.whitespace, rule.field)));
}

@@ -10,0 +20,0 @@ }

@@ -1,11 +0,20 @@

var helper = require('../rule');
var rules = require('../rule');
/**
* Validates an array.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param callback The callback function.
* @param source The source object being validated.
* @param options The validation options.
* @param options.messages The validation messages.
*/
var array = function(rule, value, callback, values) {
var array = function(rule, value, callback, source, options) {
var errors = [];
helper.required(rule, value, values, errors);
helper.type(rule, value, values, errors);
helper.range(rule, value, values, errors);
rules.required(rule, value, source, errors, options);
if(rule.required || value != undefined) {
rules.type(rule, value, source, errors, options);
rules.range(rule, value, source, errors, options);
}
callback(errors);

@@ -12,0 +21,0 @@ }

@@ -1,10 +0,17 @@

var helper = require('../rule');
var rules = require('../rule');
/**
* Performs validation for boolean types.
* Validates a boolean.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param callback The callback function.
* @param source The source object being validated.
* @param options The validation options.
* @param options.messages The validation messages.
*/
var boolean = function(rule, value, callback, values) {
var boolean = function(rule, value, callback, source, options) {
var errors = [];
helper.required(rule, value, values, errors);
helper.type(rule, value, values, errors);
rules.required(rule, value, source, errors, options);
rules.type(rule, value, source, errors, options);
callback(errors);

@@ -11,0 +18,0 @@ }

@@ -1,11 +0,18 @@

var helper = require('../rule');
var rules = require('../rule');
/**
* Validates a number is a floating point number.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param callback The callback function.
* @param source The source object being validated.
* @param options The validation options.
* @param options.messages The validation messages.
*/
var float = function(rule, value, callback, values) {
var float = function(rule, value, callback, source, options) {
var errors = [];
helper.required(rule, value, values, errors);
helper.type(rule, value, values, errors);
helper.range(rule, value, values, errors);
rules.required(rule, value, source, errors, options);
rules.type(rule, value, source, errors, options);
rules.range(rule, value, source, errors, options);
callback(errors);

@@ -12,0 +19,0 @@ }

@@ -9,3 +9,6 @@ module.exports = {

array: require('./array'),
object: require('./object'),
enum: require('./enum'),
date: require('./date'),
pattern: require('./pattern')
}

@@ -1,11 +0,18 @@

var helper = require('../rule');
var rules = require('../rule');
/**
* Validates a number is an integer.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param callback The callback function.
* @param source The source object being validated.
* @param options The validation options.
* @param options.messages The validation messages.
*/
var integer = function(rule, value, callback, values) {
var integer = function(rule, value, callback, source, options) {
var errors = [];
helper.required(rule, value, values, errors);
helper.type(rule, value, values, errors);
helper.range(rule, value, values, errors);
rules.required(rule, value, source, errors, options);
rules.type(rule, value, source, errors, options);
rules.range(rule, value, source, errors, options);
callback(errors);

@@ -12,0 +19,0 @@ }

@@ -1,11 +0,18 @@

var helper = require('../rule');
var rules = require('../rule');
/**
* Performs validation for number types.
* Validates a number.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param callback The callback function.
* @param source The source object being validated.
* @param options The validation options.
* @param options.messages The validation messages.
*/
var number = function(rule, value, callback, values) {
var number = function(rule, value, callback, source, options) {
var errors = [];
helper.required(rule, value, values, errors);
helper.type(rule, value, values, errors);
helper.range(rule, value, values, errors);
rules.required(rule, value, source, errors, options);
rules.type(rule, value, source, errors, options);
rules.range(rule, value, source, errors, options);
callback(errors);

@@ -12,0 +19,0 @@ }

@@ -1,10 +0,19 @@

var helper = require('../rule');
var rules = require('../rule');
/**
* Validates a regular expression pattern.
*
* Performs validation when a rule only contains
* a pattern property but is not declared as a string type.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param callback The callback function.
* @param source The source object being validated.
* @param options The validation options.
* @param options.messages The validation messages.
*/
var pattern = function(rule, value, callback, values) {
var pattern = function(rule, value, callback, source, options) {
var errors = [];
helper.pattern(rule, value, values, errors);
rules.pattern(rule, value, source, errors, options);
callback(errors);

@@ -11,0 +20,0 @@ }

@@ -1,10 +0,17 @@

var helper = require('../rule');
var rules = require('../rule');
/**
* Performs validation for regexp types.
* Validates the regular expression type.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param callback The callback function.
* @param source The source object being validated.
* @param options The validation options.
* @param options.messages The validation messages.
*/
var regexp = function(rule, value, callback, values) {
var regexp = function(rule, value, callback, source, options) {
var errors = [];
helper.required(rule, value, values, errors);
helper.type(rule, value, values, errors);
rules.required(rule, value, source, errors, options);
rules.type(rule, value, source, errors, options);
callback(errors);

@@ -11,0 +18,0 @@ }

@@ -1,14 +0,21 @@

var helper = require('../rule');
var rules = require('../rule');
/**
* Performs validation for string types.
*
* @param rule The validation rule.
* @param value The value of the field on the source object.
* @param callback The callback function.
* @param source The source object being validated.
* @param options The validation options.
* @param options.messages The validation messages.
*/
var string = function(rule, value, callback, values) {
var string = function(rule, value, callback, source, options) {
var errors = [];
helper.required(rule, value, values, errors);
helper.type(rule, value, values, errors);
helper.range(rule, value, values, errors);
helper.pattern(rule, value, values, errors);
rules.required(rule, value, source, errors, options);
rules.type(rule, value, source, errors, options);
rules.range(rule, value, source, errors, options);
rules.pattern(rule, value, source, errors, options);
if(rule.whitespace === true) {
helper.whitespace(rule, value, values, errors);
rules.whitespace(rule, value, source, errors, options);
}

@@ -15,0 +22,0 @@ callback(errors);

{
"name": "async-validate",
"description": "Asynchronous validation for object properties.",
"version": "0.0.3",
"version": "0.1.0",
"author": "muji <noop@xpm.io>",

@@ -15,3 +15,4 @@ "repository": {

"dependencies": {
"async": ">= 0.2.9"
"async": ">= 0.2.9",
"moment": ">= 2.0.0"
},

@@ -21,4 +22,5 @@ "devDependencies": {

"mocha": ">= 1.9.0",
"chai": ">= 1.6.0"
"chai": ">= 1.6.0",
"validator": ">= 1.2.1"
}
}

@@ -17,2 +17,8 @@ # async-validate

## Synopsis
None of the existing validation packages met the requirement to asynchronously validate user input. The [validator](https://github.com/chriso/node-validator) package is a helpful utility while [validate](https://github.com/eivindfjeldstad/validate) was closer as it took a more declarative approach but does not support asynchronous operations such as checking for existence of a database or validating that an email address already exists in a database.
So this package was created to allow for asynchronous validation of user input using a declarative schema based approach.
## Usage

@@ -39,12 +45,42 @@

Rules may be functions that perform validation. The signature for a validation function is:
## Validate
```javascript
function(rule, value, callback, values)
function(source, [options], callback)
```
* `source`: The object to validate (required).
* `options`: An object describing processing options for the validation (optional).
* `callback`: A callback function to invoke when validation completes (required).
### Options
* `first`: Invoke `callback` when the first validation rule generates an error, no more validation rules are processed. If your validation involves multiple asynchronous calls (for example, database queries) and you only need the first error use this option.
* `single`: Only ever return a single error. Typically used in conjunction with `first` when a validation rule could generate multiple errors.
* `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.
Consider the rule:
```javascript
{name: {type: "string", required: true, min: 10, pattern: /^[^-].*$/}}
```
When supplied with a source object such as `{name: "-name"}` the validation rule would generate two errors, as the pattern does not match and the string length is less then the required minimum length for the field.
In this instance when you only want the first error encountered use the `single` option.
## Rules
Rules may be functions that perform validation.
```javascript
function(rule, value, callback, source, options)
```
* `rule`: The validation rule in the source descriptor that corresponds to the field name being validated. It is always assigned a `field` property with the name of the field being validated.
* `value`: The value of the source object property being validated.
* `callback`: A callback function to invoke once validation is complete. It expects to be passed an array of `Error` instances to indicate validation failure.
* `values`: The source object that was passed to the `validate` method.
* `source`: The source object that was passed to the `validate` method.
* `options`: Additional options.
* `options.messages`: The object containing validation error messages.

@@ -55,3 +91,3 @@ ```javascript

var descriptor = {
name: function(rule, value, callback, values) {
name: function(rule, value, callback, source, options) {
var errors = [];

@@ -61,3 +97,3 @@ if(!/^[a-z0-9]+$/.test(value)) {

new ValidationError(
util.format("Field %s must be lowercase alphanumeric characters",
util.format("%s must be lowercase alphanumeric characters",
rule.field)));

@@ -83,3 +119,3 @@ }

{type: "string", required: true, pattern: schema.pattern.email},
function(rule, value, callback, values) {
function(rule, value, callback, source, options) {
var errors = [];

@@ -94,72 +130,234 @@ // test if email address already exists in a database

## Validate
### Type
The validate method has the signature:
Indicates the `type` of validator to use. Recognised type values are:
* `string`: Must be of type `string`.
* `number`: Must be of type `number`.
* `boolean`: Must be of type `boolean`.
* `regexp`: Must be an instance of `RegExp` or a string that does not generate an exception when creating a new `RegExp`.
* `integer`: Must be of type `number` and an integer.
* `float`: Must be of type `number` and a floating point number.
* `array`: Must be an array as determined by `Array.isArray`.
* `object`: Must be of type `object` and not `Array.isArray`.
* `enum`: Value must exist in the `enum`.
* `date`: Value must be valid as determined by `moment().isValid()`.
### Required
The `required` rule property indicates that the field must exist on the source object being validated.
### Pattern
The `pattern` rule property indicates a regular expression that the value must match to pass validation.
### Range
A range is defined using the `min` and `max` properties. For `string` and `array` types comparison is performed against the `length`, for `number` types the number must not be less than `min` nor greater than `max`.
### Length
To validate an exact length of a field specify the `len` property. For `string` and `array` types comparison is performed on the `length` property, for the `number` type this property indicates an exact match for the `number`, ie, it may only be strictly equal to `len`.
If the `len` property is combined with the `min` and `max` range properties, `len` takes precedence.
### Enumerable
To validate a value from a list of possible values use the `enum` type with a `enum` property listing the valid values for the field, for example:
```javascript
function(source, [options], callback)
var descriptor = {
role: {type: "enum", enum: ['admin', 'user', 'guest']}
}
```
* `source`: The object to validate - required.
* `options`: An object describing processing options for the validation.
* `callback`: A callback function to invoke when validation completes.
### Date Format
### Options
Validating dates can be complex but using [moment](http://momentjs.com/) date validation is substantially easier.
* `first`: Invoke `callback` when the first validation rule generates an error, no more validation rules are processed. If your validation involves multiple asynchronous calls (for example, database queries) and you only need the first error use this option.
* `single`: Only ever return a single error typically used in conjunction with `first` when a validation rule could generate multiple errors.
* `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.
If no `format` is specified for a rule that is a `date` type then it is assumed the date is ISO 8601. If a format is specified then the date is validated according to the specified format.
Consider the rule:
It is recommended you read the [moment documentation](http://momentjs.com/docs/#/parsing/is-valid/) on the `isValid` method to understand what validation is performed.
The important part is:
> Note: It is not intended to be used to validate that the input string matches the format string. Because the strictness of format matching can vary depending on the application and business requirements, this sort of validation is not included in Moment.js.
This limitation may be overcome by combining a `pattern` in a date rule, for example:
```javascript
{type: "string", required: true, min: 10, pattern: /^[^-].*$/}
var descriptor = {
active: {
type: "date",
format: "YYYY-MM-DD",
pattern: /^([\d]{4})-([\d]{2})-([\d]{2})$/
}
}
```
When supplied with a source object such as `{name: "-name"}` the validation rule would generate two errors, as the pattern does not match and the string length is less then the required minimum length for the field.
### Whitespace
In this instance when you only want the first error encountered use the `single` option.
It is typical to treat required fields that only contain whitespace as errors. To add an additional test for a string that consists solely of whitespace add a `whitespace` property to a rule with a value of `true`. The rule must be a `string` type.
## Rules
You may wish to sanitize user input instead of testing for whitespace, see [transform](#transform) for an example that would allow you to strip whitespace.
#### Required
Add a `required` field to the rule to validate that the property exists.
### Deep Rules
#### Type
If you need to validate deep object properties you may do so for validation rules that are of the `object` or `array` type by assigning nested rules to a `fields` property of the rule.
Add a `type` field to a rule to indicate that the field must be of the specified type. Recognised type values are:
```javascript
var descriptor = {
address: {
type: "object", required: 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 validator = new schema(descriptor);
validator.validate({ address: {} }, function(errors, fields) {
// errors for street, city, zip and name
});
```
* `string`
* `number`
* `boolean`
* `regexp`
* `integer`
* `float`
* `array`
Note that if you do not specify the `required` property on the parent rule it is perfectly valid for the field not to be declared on the source object and the deep validation rules will not be executed as there is nothing to validate against.
#### Pattern
Deep rule validation creates a schema for the nested rules so you can also specify the `options` passed to the `schema.validate()` method.
The `pattern` field should be a valid `RegExp` to test the value against.
```javascript
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 validator = new schema(descriptor);
validator.validate({ address: {} }, function(errors, fields) {
// now only errors for street and name
});
```
#### Minimum
The parent rule is also validated so if you have a set of rules such as:
When testing with a `type` of `string` the `min` property determines the minimum number of characters for the string.
```javascript
var descriptor = {
roles: {
type: "array", required: true, len: 3,
fields: {
0: {type: "string", required: true},
1: {type: "string", required: true},
2: {type: "string", required: true}
}
}
}
```
When testing with a `type` of `number` the `min` property indicates the number may not be less than `min`.
And supply a source object of `{roles: ["admin", "user"]}` then two errors will be created. One for the array length mismatch and one for the missing required array entry at index 2.
#### Maximum
### Transform
When testing with a `type` of `string` the `max` property determines the maximum number of characters for the string.
Sometimes it is necessary to transform a value before validation, possibly to coerce the value or to sanitize it in some way. To do this add a `transform` function to the validation rule. The property is transformed prior to validation and re-assigned to the source object to mutate the value of the property in place.
When testing with a `type` of `number` the `max` property indicates the number may not be greater than `max`.
```javascript
var schema = require('async-validate');
var sanitize = require('validator').sanitize;
var descriptor = {
name: {
type: "string",
required: true, pattern: /^[a-z]+$/,
transform: function(value) {
return sanitize(value).trim();
}
}
}
var validator = new schema(descriptor);
var source = {name: " user "};
validator.validate(source, function(errors, fields) {
assert.equal(source.name, "user");
});
```
#### Range
Without the `transform` function validation would fail due to the pattern not matching as the input contains leading and trailing whitespace, but by adding the transform function validation passes and the field value is sanitized at the same time.
Combine the `min` and `max` properties to define a validation range.
## Register
#### Whitespace
To extend the recognised validation types you may `register` your own validation functions by type.
It is typical to treat required fields that only contain whitespace as errors. To add an additional test for a string that consists solely of whitespace add a `whitespace` property to a rule with a value of `true`. The rule must be a `string` type.
```javascript
function register(type, validator)
```
The `type` arguments should be a string indicating the `type` property of the validation rule and `validator` must be a function with the correct signature.
```javascript
var schema = require('async-validate');
var ValidationError = schema.error;
var validator = function(rule, value, callback, source) {
var errors = [];
var re = /^[^-][a-zA-Z0-9-]+$/;
if(!re.test(value)) {
errors.push(new ValidationError(
util.format("%s is not a valid identifier", rule.field)));
}
callback(errors);
}
schema.register('id', validator);
```
You can then use validation rules such as `{type: "id"}`.
## Messages
Depending upon your application requirements, you may need i18n support or you may prefer different validation error messages.
The easiest way to achieve this is to assign a `message` to a rule:
```javascript
{name:{type: "string", required: true, message: "Name is required"}}
```
If you just want to change the default messages:
```javascript
var schema = require('async-validate');
schema.messages.required = "%s is a required field"; // change the message
...
```
Potentially you may require the same schema validation rules for different languages, in which case duplicating the schema rules for each language does not make sense.
In this scenario you could just require your own messages file for the language and assign it to the schema:
```javascript
var schema = require('async-validate');
var es = require('messages-es');
var descriptor = {name:{type: "string", required: true}};
var validator = new schema(descriptor);
validator.messages(es);
...
```
Or you could clone a default messages instance and then assign language specific messages to the schema using the `messages` method.
```javascript
var schema = require('async-validate');
var es = schema.messages.clone();
es.required = "%s es un campo obligatorio"; // change the message
var descriptor = {name:{type: "string", required: true}};
var validator = new schema(descriptor);
validator.messages(es); // ensure this schema uses the altered messages
...
```
If you are defining your own validation functions it is better practice to assign the message strings to a messages object and then access the messages via the `options.messages` property within the validation function.
## Standard Rules

@@ -185,3 +383,3 @@

Note validating email addresses by regular expressions is fraught with pitfalls, use this with caution.
Note validating email addresses with a regular expression is [fraught with pitfalls](http://stackoverflow.com/questions/201323/using-a-regular-expression-to-validate-an-email-address/201378#201378), use this with caution.

@@ -204,1 +402,4 @@ ### URL

## License
Everything is [MIT](http://en.wikipedia.org/wiki/MIT_License). Read the [license](/freeformsystems/strike/blob/master/LICENSE) if you feel inclined.

@@ -16,2 +16,19 @@ var util = require('util');

});
// quick and dirty clone of the default messages
var clone = schema.messages.clone();
// change a message
clone.required = "%s is a required field";
test("validate using custom messages", function() {
var descriptor = {
name: {type: "string", required: true},
}
var validator = new schema(descriptor);
// assign to the schema
validator.messages(clone);
validator.validate({}, function(errors, fields) {
assert.equal(errors.length, 1);
assert.equal(errors[0].message, "name is a required field");
});
});
});

@@ -17,5 +17,5 @@ var util = require('util');

assert.equal(errors.length, 2);
assert.equal(errors[0].message, "Field email is required");
assert.equal(errors[0].message, "email is required");
assert.equal(errors[1].message,
"Field email value undefined does not match pattern "
"email value undefined does not match pattern "
+ schema.pattern.email);

@@ -35,3 +35,3 @@ });

assert.equal(errors[0].message,
"Field email value user@example does not match pattern "
"email value user@example does not match pattern "
+ schema.pattern.email);

@@ -38,0 +38,0 @@ });

@@ -25,3 +25,3 @@ var util = require('util');

new ValidationError(
util.format("Field %s must be lowercase alphanumeric characters",
util.format("%s must be lowercase alphanumeric characters",
descriptor.field)));

@@ -36,3 +36,3 @@ }

assert.equal(errors[0].message,
"Field name must be lowercase alphanumeric characters");
"name must be lowercase alphanumeric characters");
});

@@ -47,3 +47,3 @@ });

assert.equal(errors.length, 1);
assert.equal(errors[0].message, "Field name is required");
assert.equal(errors[0].message, "name is required");
assert.equal(fields.name.length, 1);

@@ -60,3 +60,3 @@ assert.isTrue((fields.name[0] instanceof ValidationError));

assert.equal(errors.length, 1);
assert.equal(errors[0].message, "Field name is not a string");
assert.equal(errors[0].message, "name is not a string");
});

@@ -71,3 +71,3 @@ });

assert.equal(errors.length, 1);
assert.equal(errors[0].message, "Field name must be at least 8 characters");
assert.equal(errors[0].message, "name must be at least 8 characters");
});

@@ -82,3 +82,3 @@ });

assert.equal(errors.length, 1);
assert.equal(errors[0].message, "Field name cannot be longer than 2 characters");
assert.equal(errors[0].message, "name cannot be longer than 2 characters");
});

@@ -96,3 +96,3 @@ });

errors[0].message,
"Field name must be between 6 and 8 characters");
"name must be between 6 and 8 characters");
});

@@ -111,3 +111,3 @@ }

errors[0].message,
"Field name must be between 2 and 4 characters");
"name must be between 2 and 4 characters");
});

@@ -127,3 +127,3 @@ }

errors[0].message,
"Field name value alpha does not match pattern /^[0-9]+$/");
"name value alpha does not match pattern /^[0-9]+$/");
});

@@ -130,0 +130,0 @@ }

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc