UNPKG

validator.js

Version:

Powerful object and string validation in Javascript.

1,158 lines (844 loc) 33.1 kB
/*! * validator.js * Guillaume Potier - <guillaume@wisembly.com> * Version 2.0.4 - built Thu Jan 30 2020 15:34:17 * MIT Licensed * */ ( function ( ) { var exports = {}; /** * Validator */ function Validator ( options ) { if ( ! ( this instanceof Validator ) ) { return new Validator( options ); } this.__class__ = 'Validator'; this.__version__ = '2.0.4'; this.options = options || {}; this.bindingKey = this.options.bindingKey || '_validatorjsConstraint'; }; Validator.prototype = { constructor: Validator, /* * Validate string: validate( string, Assert, string ) || validate( string, [ Assert, Assert ], [ string, string ] ) * Validate object: validate( object, Constraint, string ) || validate( object, Constraint, [ string, string ] ) * Validate binded object: validate( object, string ) || validate( object, [ string, string ] ) */ validate: function ( objectOrString, AssertsOrConstraintOrGroup, group ) { if ( 'string' !== typeof objectOrString && 'object' !== typeof objectOrString ) throw new Error( 'You must validate an object or a string' ); // string / array validation if ( 'string' === typeof objectOrString || _isArray(objectOrString) ) return this._validateString( objectOrString, AssertsOrConstraintOrGroup, group ); // binded object validation if ( this.isBinded( objectOrString ) ) return this._validateBindedObject( objectOrString, AssertsOrConstraintOrGroup ); // regular object validation return this._validateObject( objectOrString, AssertsOrConstraintOrGroup, group ); }, bind: function ( object, constraint ) { if ( 'object' !== typeof object ) throw new Error( 'Must bind a Constraint to an object' ); object[ this.bindingKey ] = new Constraint( constraint ); return this; }, unbind: function ( object ) { if ( 'undefined' === typeof object._validatorjsConstraint ) return this; delete object[ this.bindingKey ]; return this; }, isBinded: function ( object ) { return 'undefined' !== typeof object[ this.bindingKey ]; }, getBinded: function ( object ) { return this.isBinded( object ) ? object[ this.bindingKey ] : null; }, _validateString: function ( string, assert, group ) { var result, failures = []; if ( !_isArray( assert ) ) assert = [ assert ]; for ( var i = 0; i < assert.length; i++ ) { if ( ! ( assert[ i ] instanceof Assert) ) throw new Error( 'You must give an Assert or an Asserts array to validate a string' ); result = assert[ i ].check( string, group, string ); if ( true !== result ) failures.push( result ); } return failures.length ? failures : true; }, _validateObject: function ( object, constraint, group ) { if ( 'object' !== typeof constraint ) throw new Error( 'You must give a constraint to validate an object' ); if ( constraint instanceof Assert ) return constraint.check( object, group, object ); if ( constraint instanceof Constraint ) return constraint.check( object, group, object ); return new Constraint( constraint ).check( object, group ); }, _validateBindedObject: function ( object, group ) { return object[ this.bindingKey ].check( object, group, object); } }; Validator.errorCode = { must_be_a_string: 'must_be_a_string', must_be_an_array: 'must_be_an_array', must_be_a_number: 'must_be_a_number', must_be_a_string_or_array: 'must_be_a_string_or_array' }; /** * Constraint */ function Constraint ( data, options ) { if ( ! ( this instanceof Constraint ) ) { return new Constraint( data, options ); } this.__class__ = 'Constraint'; this.options = options || {}; this.nodes = {}; if ( data ) { try { this._bootstrap( data ); } catch ( err ) { throw new Error( 'Should give a valid mapping object to Constraint', err, data ); } } }; Constraint.prototype = { constructor: Constraint, isRequired: function( property, group, deepRequired ) { var constraint = this.get( property ); var constraints = _isArray( constraint ) ? constraint : [constraint]; for ( var i = constraints.length - 1; i >= 0; i-- ) { constraint = constraints[i]; if ( 'Required' === constraint.__class__ ) { if ( constraints[i].requiresValidation( group ) ) { return true; } } if ( deepRequired ) { if ( 'Collection' === constraint.__class__ ) { constraint = constraint.constraint; } if ( constraint instanceof Constraint ) { // ensure constraint of collection gets the same deepRequired option constraint.options.deepRequired = deepRequired; for ( var node in constraint.nodes ) { if ( constraint.isRequired( node, group, deepRequired ) ) { return true; } } } } } return false; }, check: function ( object, group ) { var result, failures = {}; // check all constraint nodes. for ( var property in this.nodes ) { var isRequired = this.isRequired( property, group, this.options.deepRequired ); if ( ! this.has( property, object ) && ! this.options.strict && ! isRequired ) { continue; } try { if (! this.has( property, this.options.strict || isRequired ? object : undefined ) ) { // we trigger here a HaveProperty Assert violation to have uniform Violation object in the end new Assert().HaveProperty( property ).validate( object ); } result = this._check( property, object[ property ], group, object ); // check returned an array of Violations or an object mapping Violations if ( ( _isArray( result ) && result.length > 0 ) || ( !_isArray( result ) && !_isEmptyObject( result ) ) ) { failures[ property ] = result; } } catch ( violation ) { failures[ property ] = violation; } } return _isEmptyObject(failures) ? true : failures; }, add: function ( node, object ) { if ( object instanceof Assert || ( _isArray( object ) && object[ 0 ] instanceof Assert ) ) { this.nodes[ node ] = object; return this; } if ( 'object' === typeof object && !_isArray( object ) ) { this.nodes[ node ] = object instanceof Constraint ? object : new Constraint( object, this.options ); return this; } throw new Error( 'Should give an Assert, an Asserts array, a Constraint', object ); }, has: function ( node, nodes ) { nodes = 'undefined' !== typeof nodes ? nodes : this.nodes; return 'undefined' !== typeof nodes[ node ]; }, get: function ( node, placeholder ) { return this.has( node ) ? this.nodes[ node ] : placeholder || null; }, remove: function ( node ) { var _nodes = []; for ( var i in this.nodes ) if ( i !== node ) _nodes[ i ] = this.nodes[ i ]; this.nodes = _nodes; return this; }, _bootstrap: function ( data ) { if ( data instanceof Constraint ) return this.nodes = data.nodes; for ( var node in data ) this.add( node, data[ node ] ); }, _check: function ( node, value, group, context ) { // Assert if ( this.nodes[ node ] instanceof Assert ) return this._checkAsserts( value, [ this.nodes[ node ] ], group, context ); // Asserts if ( _isArray( this.nodes[ node ] ) ) return this._checkAsserts( value, this.nodes[ node ], group, context ); // Constraint -> check api if ( this.nodes[ node ] instanceof Constraint ) return this.nodes[ node ].check( value, group, context ); throw new Error( 'Invalid node', this.nodes[ node ] ); }, _checkAsserts: function ( value, asserts, group, context ) { var result, failures = []; for ( var i = 0; i < asserts.length; i++ ) { result = asserts[ i ].check( value, group, context ); if ( 'undefined' !== typeof result && true !== result ) failures.push( result ); // Some asserts (Collection for example) could return an object // if ( result && ! ( result instanceof Violation ) ) // return result; // // // Vast assert majority return Violation // if ( result instanceof Violation ) // failures.push( result ); } return failures; } }; /** * Violation */ function Violation ( assert, value, violation ) { if ( ! ( this instanceof Violation ) ) { return new Violation( assert, value, violation ); } this.__class__ = 'Violation'; if ( ! ( assert instanceof Assert || assert.__parentClass__ === 'Assert' ) ) throw new Error( 'Should give an assertion implementing the Assert interface' ); this.assert = assert; this.value = value; if ( 'undefined' !== typeof violation ) this.violation = violation; }; Violation.prototype = { show: function () { var show = { assert: this.assert.__class__, value: this.value }; if ( this.violation ) show.violation = this.violation; return show; }, __toString: function () { var v = ''; if ( 'undefined' !== typeof this.violation ) { this.violation = this.getViolation().constraint + ' expected was ' + this.getViolation().expected; v = ", " + this.violation; } return this.assert.__class__ + ' assert failed for "' + this.value + '"' + v; }, getViolation: function () { var constraint, expected; for ( constraint in this.violation ) expected = this.violation[ constraint ]; return { constraint: constraint, expected: expected }; } }; /** * Assert */ function Assert ( group ) { if ( ! ( this instanceof Assert ) ) return new Assert( group ); this.__class__ = 'Assert'; this.__parentClass__ = this.__class__; this.groups = []; if ( 'undefined' !== typeof group ) this.addGroup( group ); }; /** * Extend Assert */ Assert.extend = function ( asserts ) { if ( 'object' !== typeof asserts ) throw new Error( 'Invalid parameter: `asserts` should be an object' ); if ( 0 === Object.keys( asserts ).length ) throw new Error( 'Invalid parameter: `asserts` should have at least one property' ); // Inherit from Assert. function Extended( group ) { if ( ! ( this instanceof Extended ) ) return new Extended( group ); Assert.apply( this, arguments ); } Extended.prototype = Object.create( Assert.prototype ); Extended.prototype.constructor = Extended; // Copy all the static methods. Object.keys( Assert ).forEach( function( key ) { Extended[ key ] = Assert[ key ]; } ); // Extend with custom asserts. for ( var key in asserts ) { if ( 'function' !== typeof asserts[ key ] ) throw new Error( 'The extension assert must be a function' ); Extended.prototype[ key ] = asserts[ key ]; } return _prettify( Extended ); }; Assert.prototype = { construct: Assert, requiresValidation: function ( group ) { if ( group && !this.hasGroup( group ) ) return false; if ( !group && this.hasGroups() ) return false; return true; }, check: function ( value, group, context ) { if ( !this.requiresValidation( group ) ) return true; try { return this.validate( value, group, context ); } catch ( violation ) { return violation; } }, hasGroup: function ( group ) { if ( _isArray( group ) ) return this.hasOneOf( group ); // All Asserts respond to "Any" group if ( 'Any' === group ) return true; // Asserts with no group also respond to "Default" group. Else return false if ( !this.hasGroups() ) return 'Default' === group; return -1 !== this.groups.indexOf( group ); }, hasOneOf: function ( groups ) { for ( var i = 0; i < groups.length; i++ ) if ( this.hasGroup( groups[ i ] ) ) return true; return false; }, hasGroups: function () { return this.groups.length > 0; }, addGroup: function ( group ) { if ( _isArray( group ) ) return this.addGroups( group ); if ( !this.hasGroup( group ) ) this.groups.push( group ); return this; }, removeGroup: function ( group ) { var _groups = []; for ( var i = 0; i < this.groups.length; i++ ) if ( group !== this.groups[ i ] ) _groups.push( this.groups[ i ] ); this.groups = _groups; return this; }, addGroups: function ( groups ) { for ( var i = 0; i < groups.length; i++ ) this.addGroup( groups[ i ] ); return this; }, /** * Asserts definitions */ HaveProperty: function ( node ) { this.__class__ = 'HaveProperty'; this.node = node; this.validate = function ( object ) { if ( 'undefined' === typeof object[ this.node ] ) throw new Violation( this, object, { value: this.node } ); return true; }; return this; }, Blank: function () { this.__class__ = 'Blank'; this.validate = function ( value ) { if ( 'string' !== typeof value ) throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } ); if ( '' !== value.replace( /^\s+/g, '' ).replace( /\s+$/g, '' ) ) throw new Violation( this, value ); return true; }; return this; }, Callback: function ( fn ) { this.__class__ = 'Callback'; this.arguments = Array.prototype.slice.call( arguments ); if ( 1 === this.arguments.length ) this.arguments = []; else this.arguments.splice( 0, 1 ); if ( 'function' !== typeof fn ) throw new Error( 'Callback must be instanciated with a function' ); this.fn = fn; this.validate = function ( value ) { var result; try { result = this.fn.apply( this, [ value ].concat( this.arguments ) ); } catch(err) { throw new Violation( this, value, { error: err } ); } if ( true !== result ) throw new Violation( this, value, { result: result } ); return true; }; return this; }, Choice: function ( list ) { this.__class__ = 'Choice'; if ( !_isArray( list ) && 'function' !== typeof list ) throw new Error( 'Choice must be instanciated with an array or a function' ); this.list = list; this.validate = function ( value ) { var list = 'function' === typeof this.list ? this.list() : this.list; for ( var i = 0; i < list.length; i++ ) if ( value === list[ i ] ) return true; throw new Violation( this, value, { choices: list } ); }; return this; }, Collection: function ( assertOrConstraint ) { this.__class__ = 'Collection'; this.constraint = _isPlainObject( assertOrConstraint ) ? new Constraint( assertOrConstraint ) : assertOrConstraint; this.validate = function ( collection, group ) { var result, validator = new Validator(), count = 0, failures = {}, groups = this.groups.length ? this.groups : group; if ( !_isArray( collection ) ) throw new Violation( this, collection, { value: Validator.errorCode.must_be_an_array } ); for ( var i = 0; i < collection.length; i++ ) { result = this.constraint ? validator.validate( collection[ i ], this.constraint, groups ) : validator.validate( collection[ i ], groups ); if ( !_isEmptyObject( result ) ) failures[ count ] = result; count++; } return !_isEmptyObject( failures ) ? failures : true; }; return this; }, Count: function ( count ) { this.__class__ = 'Count'; this.count = count; this.validate = function ( array ) { if ( !_isArray( array ) ) throw new Violation( this, array, { value: Validator.errorCode.must_be_an_array } ); var count = 'function' === typeof this.count ? this.count( array ) : this.count; if ( isNaN( Number( count ) ) ) throw new Error( 'Count must be a valid interger', count ); if ( count !== array.length ) throw new Violation( this, array, { count: count } ); return true; }; return this; }, Email: function () { this.__class__ = 'Email'; this.validate = function ( value ) { var regExp = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i; if ( 'string' !== typeof value ) throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } ); if ( !regExp.test( value ) ) throw new Violation( this, value ); return true; }; return this; }, EqualTo: function ( reference ) { this.__class__ = 'EqualTo'; if ( 'undefined' === typeof reference ) throw new Error( 'EqualTo must be instanciated with a value or a function' ); this.reference = reference; this.validate = function ( value ) { var reference = 'function' === typeof this.reference ? this.reference( value ) : this.reference; if ( reference !== value ) throw new Violation( this, value, { value: reference } ); return true; }; return this; }, GreaterThan: function ( threshold ) { this.__class__ = 'GreaterThan'; if ( 'undefined' === typeof threshold ) throw new Error( 'Should give a threshold value' ); this.threshold = threshold; this.validate = function ( value ) { if ( '' === value || isNaN( Number( value ) ) ) throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } ); if ( this.threshold >= value ) throw new Violation( this, value, { threshold: this.threshold } ); return true; }; return this; }, GreaterThanOrEqual: function ( threshold ) { this.__class__ = 'GreaterThanOrEqual'; if ( 'undefined' === typeof threshold ) throw new Error( 'Should give a threshold value' ); this.threshold = threshold; this.validate = function ( value ) { if ( '' === value || isNaN( Number( value ) ) ) throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } ); if ( this.threshold > value ) throw new Violation( this, value, { threshold: this.threshold } ); return true; }; return this; }, InstanceOf: function ( classRef ) { this.__class__ = 'InstanceOf'; if ( 'undefined' === typeof classRef ) throw new Error( 'InstanceOf must be instanciated with a value' ); this.classRef = classRef; this.validate = function ( value ) { if ( true !== (value instanceof this.classRef) ) throw new Violation( this, value, { classRef: this.classRef } ); return true; }; return this; }, IsString: function () { this.__class__ = 'IsString'; this.validate = function ( value ) { if ( !_isString( value ) ) throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } ); return true; }; return this; }, Length: function ( boundaries ) { this.__class__ = 'Length'; if ( !boundaries.min && !boundaries.max ) throw new Error( 'Length assert must be instanciated with a { min: x, max: y } object' ); this.min = parseInt(boundaries.min); this.max = parseInt(boundaries.max); this.validate = function ( value ) { if ( 'string' !== typeof value && !_isArray( value ) ) throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string_or_array } ); if ( 'undefined' !== typeof this.min && this.min === this.max && value.length !== this.min ) throw new Violation( this, value, { min: this.min, max: this.max } ); if ( 'undefined' !== typeof this.max && value.length > this.max ) throw new Violation( this, value, { max: this.max } ); if ( 'undefined' !== typeof this.min && value.length < this.min ) throw new Violation( this, value, { min: this.min } ); return true; }; return this; }, LessThan: function ( threshold ) { this.__class__ = 'LessThan'; if ( 'undefined' === typeof threshold ) throw new Error( 'Should give a threshold value' ); this.threshold = threshold; this.validate = function ( value ) { if ( '' === value || isNaN( Number( value ) ) ) throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } ); if ( this.threshold <= value ) throw new Violation( this, value, { threshold: this.threshold } ); return true; }; return this; }, LessThanOrEqual: function ( threshold ) { this.__class__ = 'LessThanOrEqual'; if ( 'undefined' === typeof threshold ) throw new Error( 'Should give a threshold value' ); this.threshold = threshold; this.validate = function ( value ) { if ( '' === value || isNaN( Number( value ) ) ) throw new Violation( this, value, { value: Validator.errorCode.must_be_a_number } ); if ( this.threshold < value ) throw new Violation( this, value, { threshold: this.threshold } ); return true; }; return this; }, NotNull: function () { this.__class__ = 'NotNull'; this.validate = function ( value ) { if ( null === value || 'undefined' === typeof value ) throw new Violation( this, value ); return true; }; return this; }, NotBlank: function () { this.__class__ = 'NotBlank'; this.validate = function ( value ) { if ( 'string' !== typeof value ) throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } ); if ( '' === value.replace( /^\s+/g, '' ).replace( /\s+$/g, '' ) ) throw new Violation( this, value ); return true; }; return this; }, NotEqualTo: function ( reference ) { this.__class__ = 'NotEqualTo'; if ( 'undefined' === typeof reference ) throw new Error( 'NotEqualTo must be instanciated with a value or a function' ); this.reference = reference; this.validate = function ( value ) { var reference = 'function' === typeof this.reference ? this.reference( value ) : this.reference; if ( reference === value ) throw new Violation( this, value, { value: reference } ); return true; }; return this; }, Null: function () { this.__class__ = 'Null'; this.validate = function ( value ) { if ( null !== value ) throw new Violation( this, value ); return true; }; return this; }, Range: function ( min, max ) { this.__class__ = 'Range'; if ( 'undefined' === typeof min || 'undefined' === typeof max ) throw new Error( 'Range assert expects min and max values' ); this.min = min; this.max = max; this.validate = function ( value ) { try { // validate strings and objects with their Length if ( ( 'string' === typeof value && isNaN( Number( value ) ) ) || _isArray( value ) ) new Assert().Length( { min: this.min, max: this.max } ).validate( value ); // validate numbers with their value else new Assert().GreaterThanOrEqual( this.min ).validate( value ) && new Assert().LessThanOrEqual( this.max ).validate( value ); return true; } catch ( violation ) { throw new Violation( this, value, violation.violation ); } return true; }; return this; }, Regexp: function ( regexp, flag ) { this.__class__ = 'Regexp'; if ( 'undefined' === typeof regexp ) throw new Error( 'You must give a regexp' ); this.regexp = regexp; this.flag = flag; this.validate = function ( value ) { if ( 'string' !== typeof value ) throw new Violation( this, value, { value: Validator.errorCode.must_be_a_string } ); if ( !new RegExp( this.regexp, this.flag ).test( value ) ) throw new Violation( this, value, { regexp: this.regexp, flag: this.flag } ); return true; }; return this; }, Required: function () { this.__class__ = 'Required'; this.validate = function ( value ) { if ( 'undefined' === typeof value ) throw new Violation( this, value ); return true; }; return this; }, // Unique() or Unique ( { key: foo } ) Unique: function ( object ) { this.__class__ = 'Unique'; if ( 'object' === typeof object ) this.key = object.key; this.validate = function ( array ) { var value, store = []; if ( !_isArray( array ) ) throw new Violation( this, array, { value: Validator.errorCode.must_be_an_array } ); for ( var i = 0; i < array.length; i++ ) { value = 'object' === typeof array[ i ] ? array[ i ][ this.key ] : array[ i ]; if ( 'undefined' === typeof value ) continue; if ( -1 !== store.indexOf( value ) ) throw new Violation( this, array, { value: value } ); store.push( value ); } return true; }; return this; }, // When assert When: function( ref, options ) { this.__class__ = 'When'; if ( 'string' !== typeof ref ) throw new Error( 'When assert expects ref to be a string' ); if ( !_isPlainObject( options ) ) throw new Error( 'When assert expects options to be a plain object' ); if ( 'undefined' === typeof options.is ) throw new Error( 'When assert expects an is constraint' ); if ( 'undefined' === typeof options.otherwise && 'undefined' === typeof options.then ) throw new Error( 'When assert expects a otherwise constraint or a then constraint or both' ); this.options = { is: _isPlainObject( options.is ) ? new Constraint( options.is ) : options.is, otherwise: _isPlainObject( options.otherwise ) ? new Constraint( options.otherwise ) : options.otherwise, then: _isPlainObject( options.then ) ? new Constraint( options.then ) : options.then }; this.ref = ref; this.validate = function ( value, group, context ) { if ( 'undefined' === typeof context ) throw new Error( 'When assert expects context to be defined' ); if ( 'undefined' !== typeof context[ this.ref ] ) { var failures = {}, validator = new Validator(); try { failures = validator.validate( context[ this.ref ], this.options.is ); if ( !_isEmptyObject( failures ) ) throw new Error(); if ( this.options.then ) failures = validator.validate( value, this.options.then ); } catch ( e ) { if ( this.options.otherwise ) failures = validator.validate( value, this.options.otherwise ); } } return !_isEmptyObject( failures ) ? failures : true; }; return this; } }; /** * Some useful object prototypes / functions here */ // IE8<= compatibility // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf if (!Array.prototype.indexOf) Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { "use strict"; if (this === null) { throw new TypeError(); } var t = Object(this); var len = t.length >>> 0; if (len === 0) { return -1; } var n = 0; if (arguments.length > 1) { n = Number(arguments[1]); if (n != n) { // shortcut for verifying if it's NaN n = 0; } else if (n !== 0 && n != Infinity && n != -Infinity) { n = (n > 0 || -1) * Math.floor(Math.abs(n)); } } if (n >= len) { return -1; } var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); for (; k < len; k++) { if (k in t && t[k] === searchElement) { return k; } } return -1; }; // Test if object is empty, useful for Constraint violations check var _isEmptyObject = function ( obj ) { for ( var property in obj ) return false; return true; }; var _isArray = function ( obj ) { return Object.prototype.toString.call( obj ) === '[object Array]'; }; var _isPlainObject = function ( obj ) { return typeof obj === 'object' && Object.getPrototypeOf( obj ) === Object.prototype; }; var _isString = function ( str ) { return Object.prototype.toString.call( str ) === '[object String]'; }; var _toCamelCase = function ( str ) { return str .replace(/\s(.)/g, function( $1 ) { return $1.toUpperCase(); }) .replace(/\s/g, '') .replace(/^(.)/, function( $1 ) { return $1.toLowerCase(); }); }; var _prettify = function _prettify ( Fn ) { // Copy prototype properties. for ( var property in Fn.prototype ) { var matches = property.match(/^(.*?[A-Z]{2,})(.*)$/); var camelCaseProperty = _toCamelCase( property ); if ( matches !== null ) { camelCaseProperty = matches[1] + _toCamelCase( matches[2] ); } if (camelCaseProperty === property) { continue; } // Create `camelCase` aliases. _alias( Fn.prototype, property, camelCaseProperty ); // Add static methods as aliases. Fn[ camelCaseProperty ] = (function( prop ) { return function() { var assert = new Fn(); return assert[ prop ].apply( assert, arguments ); } })( property ); _alias( Fn, camelCaseProperty, property ); } return Fn; }; var _alias = function _alias ( object, from, to ) { object[ to ] = object[ from ]; } // aliases _alias( Assert.prototype, 'Length', 'OfLength' ); _alias( Assert.prototype, 'HaveProperty', 'PropertyDefined' ); _alias( Assert.prototype, 'IsString', 'String' ); // prettify _prettify( Assert ); // expose to the world these awesome classes exports.Assert = Assert; exports.Constraint = Constraint; exports.Validator = Validator; exports.Violation = Violation; exports.assert = function( group ) { return new Assert( group ); }; exports.constraint = function( data, options ) { return new Constraint( data, options ); }; exports.validator = function( options ) { return new Validator( options ); }; exports.violation = function( assert, value, violation ) { return new Violation( assert, value, violation ); }; // AMD export if ( typeof define === 'function' && define.amd ) { define( function() { return exports; } ); // commonjs export } else if ( typeof module !== 'undefined' && module.exports ) { module.exports = exports; // browser } else { window[ 'undefined' !== typeof validatorjs_ns ? validatorjs_ns : 'Validator' ] = exports; } } )( );