UNPKG

validator.js

Version:

Powerful object and string validation in Javascript.

87 lines (86 loc) 18.4 kB
/*! * validator.js * Guillaume Potier - <guillaume@wisembly.com> * Version 2.0.4 - built Thu Jan 30 2020 15:34:17 * MIT Licensed * */ !function(){/** * Validator */ function a(b){return this instanceof a?(this.__class__="Validator",this.__version__="2.0.4",this.options=b||{},void(this.bindingKey=this.options.bindingKey||"_validatorjsConstraint")):new a(b)}/** * Constraint */ function b(a,c){if(!(this instanceof b))return new b(a,c);if(this.__class__="Constraint",this.options=c||{},this.nodes={},a)try{this._bootstrap(a)}catch(d){throw new Error("Should give a valid mapping object to Constraint",d,a)}}/** * Violation */ function c(a,b,e){if(!(this instanceof c))return new c(a,b,e);if(this.__class__="Violation",!(a instanceof d||"Assert"===a.__parentClass__))throw new Error("Should give an assertion implementing the Assert interface");this.assert=a,this.value=b,"undefined"!=typeof e&&(this.violation=e)}/** * Assert */ function d(a){return this instanceof d?(this.__class__="Assert",this.__parentClass__=this.__class__,this.groups=[],void("undefined"!=typeof a&&this.addGroup(a))):new d(a)}var e={};a.prototype={constructor:a,/* * 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(a,b,c){if("string"!=typeof a&&"object"!=typeof a)throw new Error("You must validate an object or a string"); // string / array validation // string / array validation // binded object validation return"string"==typeof a||g(a)?this._validateString(a,b,c):this.isBinded(a)?this._validateBindedObject(a,b):this._validateObject(a,b,c)},bind:function(a,c){if("object"!=typeof a)throw new Error("Must bind a Constraint to an object");return a[this.bindingKey]=new b(c),this},unbind:function(a){return"undefined"==typeof a._validatorjsConstraint?this:(delete a[this.bindingKey],this)},isBinded:function(a){return"undefined"!=typeof a[this.bindingKey]},getBinded:function(a){return this.isBinded(a)?a[this.bindingKey]:null},_validateString:function(a,b,c){var e,f=[];g(b)||(b=[b]);for(var h=0;h<b.length;h++){if(!(b[h]instanceof d))throw new Error("You must give an Assert or an Asserts array to validate a string");e=b[h].check(a,c,a),!0!==e&&f.push(e)}return!f.length||f},_validateObject:function(a,c,e){if("object"!=typeof c)throw new Error("You must give a constraint to validate an object");return c instanceof d?c.check(a,e,a):c instanceof b?c.check(a,e,a):new b(c).check(a,e)},_validateBindedObject:function(a,b){return a[this.bindingKey].check(a,b,a)}},a.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"},b.prototype={constructor:b,isRequired:function(a,c,d){for(var e=this.get(a),f=g(e)?e:[e],h=f.length-1;h>=0;h--){if(e=f[h],"Required"===e.__class__&&f[h].requiresValidation(c))return!0;if(d&&("Collection"===e.__class__&&(e=e.constraint),e instanceof b)){ // ensure constraint of collection gets the same deepRequired option e.options.deepRequired=d;for(var i in e.nodes)if(e.isRequired(i,c,d))return!0}}return!1},check:function(a,b){var c,e={}; // check all constraint nodes. for(var h in this.nodes){var i=this.isRequired(h,b,this.options.deepRequired);if(this.has(h,a)||this.options.strict||i)try{this.has(h,this.options.strict||i?a:void 0)|| // we trigger here a HaveProperty Assert violation to have uniform Violation object in the end (new d).HaveProperty(h).validate(a),c=this._check(h,a[h],b,a), // check returned an array of Violations or an object mapping Violations (g(c)&&c.length>0||!g(c)&&!f(c))&&(e[h]=c)}catch(j){e[h]=j}}return!!f(e)||e},add:function(a,c){if(c instanceof d||g(c)&&c[0]instanceof d)return this.nodes[a]=c,this;if("object"==typeof c&&!g(c))return this.nodes[a]=c instanceof b?c:new b(c,this.options),this;throw new Error("Should give an Assert, an Asserts array, a Constraint",c)},has:function(a,b){return b="undefined"!=typeof b?b:this.nodes,"undefined"!=typeof b[a]},get:function(a,b){return this.has(a)?this.nodes[a]:b||null},remove:function(a){var b=[];for(var c in this.nodes)c!==a&&(b[c]=this.nodes[c]);return this.nodes=b,this},_bootstrap:function(a){if(a instanceof b)return this.nodes=a.nodes;for(var c in a)this.add(c,a[c])},_check:function(a,c,e,f){ // Assert if(this.nodes[a]instanceof d)return this._checkAsserts(c,[this.nodes[a]],e,f); // Asserts if(g(this.nodes[a]))return this._checkAsserts(c,this.nodes[a],e,f); // Constraint -> check api if(this.nodes[a]instanceof b)return this.nodes[a].check(c,e,f);throw new Error("Invalid node",this.nodes[a])},_checkAsserts:function(a,b,c,d){for(var e,f=[],g=0;g<b.length;g++)e=b[g].check(a,c,d),"undefined"!=typeof e&&!0!==e&&f.push(e);return f}},c.prototype={show:function(){var a={assert:this.assert.__class__,value:this.value};return this.violation&&(a.violation=this.violation),a},__toString:function(){var a="";return"undefined"!=typeof this.violation&&(this.violation=this.getViolation().constraint+" expected was "+this.getViolation().expected,a=", "+this.violation),this.assert.__class__+' assert failed for "'+this.value+'"'+a},getViolation:function(){var a,b;for(a in this.violation)b=this.violation[a];return{constraint:a,expected:b}}},/** * Extend Assert */ d.extend=function(a){ // Inherit from Assert. function b(a){return this instanceof b?void d.apply(this,arguments):new b(a)}if("object"!=typeof a)throw new Error("Invalid parameter: `asserts` should be an object");if(0===Object.keys(a).length)throw new Error("Invalid parameter: `asserts` should have at least one property");b.prototype=Object.create(d.prototype),b.prototype.constructor=b, // Copy all the static methods. Object.keys(d).forEach(function(a){b[a]=d[a]}); // Extend with custom asserts. for(var c in a){if("function"!=typeof a[c])throw new Error("The extension assert must be a function");b.prototype[c]=a[c]}return k(b)},d.prototype={construct:d,requiresValidation:function(a){return!(a&&!this.hasGroup(a))&&!(!a&&this.hasGroups())},check:function(a,b,c){if(!this.requiresValidation(b))return!0;try{return this.validate(a,b,c)}catch(d){return d}},hasGroup:function(a){ // All Asserts respond to "Any" group // Asserts with no group also respond to "Default" group. Else return false return g(a)?this.hasOneOf(a):"Any"===a||(this.hasGroups()?-1!==this.groups.indexOf(a):"Default"===a)},hasOneOf:function(a){for(var b=0;b<a.length;b++)if(this.hasGroup(a[b]))return!0;return!1},hasGroups:function(){return this.groups.length>0},addGroup:function(a){return g(a)?this.addGroups(a):(this.hasGroup(a)||this.groups.push(a),this)},removeGroup:function(a){for(var b=[],c=0;c<this.groups.length;c++)a!==this.groups[c]&&b.push(this.groups[c]);return this.groups=b,this},addGroups:function(a){for(var b=0;b<a.length;b++)this.addGroup(a[b]);return this},/** * Asserts definitions */ HaveProperty:function(a){return this.__class__="HaveProperty",this.node=a,this.validate=function(a){if("undefined"==typeof a[this.node])throw new c(this,a,{value:this.node});return!0},this},Blank:function(){return this.__class__="Blank",this.validate=function(b){if("string"!=typeof b)throw new c(this,b,{value:a.errorCode.must_be_a_string});if(""!==b.replace(/^\s+/g,"").replace(/\s+$/g,""))throw new c(this,b);return!0},this},Callback:function(a){if(this.__class__="Callback",this.arguments=Array.prototype.slice.call(arguments),1===this.arguments.length?this.arguments=[]:this.arguments.splice(0,1),"function"!=typeof a)throw new Error("Callback must be instanciated with a function");return this.fn=a,this.validate=function(a){var b;try{b=this.fn.apply(this,[a].concat(this.arguments))}catch(d){throw new c(this,a,{error:d})}if(!0!==b)throw new c(this,a,{result:b});return!0},this},Choice:function(a){if(this.__class__="Choice",!g(a)&&"function"!=typeof a)throw new Error("Choice must be instanciated with an array or a function");return this.list=a,this.validate=function(a){for(var b="function"==typeof this.list?this.list():this.list,d=0;d<b.length;d++)if(a===b[d])return!0;throw new c(this,a,{choices:b})},this},Collection:function(d){return this.__class__="Collection",this.constraint=h(d)?new b(d):d,this.validate=function(b,d){var e,h=new a,i=0,j={},k=this.groups.length?this.groups:d;if(!g(b))throw new c(this,b,{value:a.errorCode.must_be_an_array});for(var l=0;l<b.length;l++)e=this.constraint?h.validate(b[l],this.constraint,k):h.validate(b[l],k),f(e)||(j[i]=e),i++;return!!f(j)||j},this},Count:function(b){return this.__class__="Count",this.count=b,this.validate=function(b){if(!g(b))throw new c(this,b,{value:a.errorCode.must_be_an_array});var d="function"==typeof this.count?this.count(b):this.count;if(isNaN(Number(d)))throw new Error("Count must be a valid interger",d);if(d!==b.length)throw new c(this,b,{count:d});return!0},this},Email:function(){return this.__class__="Email",this.validate=function(b){var d=/^((([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 b)throw new c(this,b,{value:a.errorCode.must_be_a_string});if(!d.test(b))throw new c(this,b);return!0},this},EqualTo:function(a){if(this.__class__="EqualTo","undefined"==typeof a)throw new Error("EqualTo must be instanciated with a value or a function");return this.reference=a,this.validate=function(a){var b="function"==typeof this.reference?this.reference(a):this.reference;if(b!==a)throw new c(this,a,{value:b});return!0},this},GreaterThan:function(b){if(this.__class__="GreaterThan","undefined"==typeof b)throw new Error("Should give a threshold value");return this.threshold=b,this.validate=function(b){if(""===b||isNaN(Number(b)))throw new c(this,b,{value:a.errorCode.must_be_a_number});if(this.threshold>=b)throw new c(this,b,{threshold:this.threshold});return!0},this},GreaterThanOrEqual:function(b){if(this.__class__="GreaterThanOrEqual","undefined"==typeof b)throw new Error("Should give a threshold value");return this.threshold=b,this.validate=function(b){if(""===b||isNaN(Number(b)))throw new c(this,b,{value:a.errorCode.must_be_a_number});if(this.threshold>b)throw new c(this,b,{threshold:this.threshold});return!0},this},InstanceOf:function(a){if(this.__class__="InstanceOf","undefined"==typeof a)throw new Error("InstanceOf must be instanciated with a value");return this.classRef=a,this.validate=function(a){if(!0!=a instanceof this.classRef)throw new c(this,a,{classRef:this.classRef});return!0},this},IsString:function(){return this.__class__="IsString",this.validate=function(b){if(!i(b))throw new c(this,b,{value:a.errorCode.must_be_a_string});return!0},this},Length:function(b){if(this.__class__="Length",!b.min&&!b.max)throw new Error("Length assert must be instanciated with a { min: x, max: y } object");return this.min=parseInt(b.min),this.max=parseInt(b.max),this.validate=function(b){if("string"!=typeof b&&!g(b))throw new c(this,b,{value:a.errorCode.must_be_a_string_or_array});if("undefined"!=typeof this.min&&this.min===this.max&&b.length!==this.min)throw new c(this,b,{min:this.min,max:this.max});if("undefined"!=typeof this.max&&b.length>this.max)throw new c(this,b,{max:this.max});if("undefined"!=typeof this.min&&b.length<this.min)throw new c(this,b,{min:this.min});return!0},this},LessThan:function(b){if(this.__class__="LessThan","undefined"==typeof b)throw new Error("Should give a threshold value");return this.threshold=b,this.validate=function(b){if(""===b||isNaN(Number(b)))throw new c(this,b,{value:a.errorCode.must_be_a_number});if(this.threshold<=b)throw new c(this,b,{threshold:this.threshold});return!0},this},LessThanOrEqual:function(b){if(this.__class__="LessThanOrEqual","undefined"==typeof b)throw new Error("Should give a threshold value");return this.threshold=b,this.validate=function(b){if(""===b||isNaN(Number(b)))throw new c(this,b,{value:a.errorCode.must_be_a_number});if(this.threshold<b)throw new c(this,b,{threshold:this.threshold});return!0},this},NotNull:function(){return this.__class__="NotNull",this.validate=function(a){if(null===a||"undefined"==typeof a)throw new c(this,a);return!0},this},NotBlank:function(){return this.__class__="NotBlank",this.validate=function(b){if("string"!=typeof b)throw new c(this,b,{value:a.errorCode.must_be_a_string});if(""===b.replace(/^\s+/g,"").replace(/\s+$/g,""))throw new c(this,b);return!0},this},NotEqualTo:function(a){if(this.__class__="NotEqualTo","undefined"==typeof a)throw new Error("NotEqualTo must be instanciated with a value or a function");return this.reference=a,this.validate=function(a){var b="function"==typeof this.reference?this.reference(a):this.reference;if(b===a)throw new c(this,a,{value:b});return!0},this},Null:function(){return this.__class__="Null",this.validate=function(a){if(null!==a)throw new c(this,a);return!0},this},Range:function(a,b){if(this.__class__="Range","undefined"==typeof a||"undefined"==typeof b)throw new Error("Range assert expects min and max values");return this.min=a,this.max=b,this.validate=function(a){try{ // validate strings and objects with their Length return"string"==typeof a&&isNaN(Number(a))||g(a)?(new d).Length({min:this.min,max:this.max}).validate(a):(new d).GreaterThanOrEqual(this.min).validate(a)&&(new d).LessThanOrEqual(this.max).validate(a),!0}catch(b){throw new c(this,a,b.violation)}return!0},this},Regexp:function(b,d){if(this.__class__="Regexp","undefined"==typeof b)throw new Error("You must give a regexp");return this.regexp=b,this.flag=d,this.validate=function(b){if("string"!=typeof b)throw new c(this,b,{value:a.errorCode.must_be_a_string});if(!new RegExp(this.regexp,this.flag).test(b))throw new c(this,b,{regexp:this.regexp,flag:this.flag});return!0},this},Required:function(){return this.__class__="Required",this.validate=function(a){if("undefined"==typeof a)throw new c(this,a);return!0},this}, // Unique() or Unique ( { key: foo } ) Unique:function(b){return this.__class__="Unique","object"==typeof b&&(this.key=b.key),this.validate=function(b){var d,e=[];if(!g(b))throw new c(this,b,{value:a.errorCode.must_be_an_array});for(var f=0;f<b.length;f++)if(d="object"==typeof b[f]?b[f][this.key]:b[f],"undefined"!=typeof d){if(-1!==e.indexOf(d))throw new c(this,b,{value:d});e.push(d)}return!0},this}, // When assert When:function(c,d){if(this.__class__="When","string"!=typeof c)throw new Error("When assert expects ref to be a string");if(!h(d))throw new Error("When assert expects options to be a plain object");if("undefined"==typeof d.is)throw new Error("When assert expects an is constraint");if("undefined"==typeof d.otherwise&&"undefined"==typeof d.then)throw new Error("When assert expects a otherwise constraint or a then constraint or both");return this.options={is:h(d.is)?new b(d.is):d.is,otherwise:h(d.otherwise)?new b(d.otherwise):d.otherwise,then:h(d.then)?new b(d.then):d.then},this.ref=c,this.validate=function(b,c,d){if("undefined"==typeof d)throw new Error("When assert expects context to be defined");if("undefined"!=typeof d[this.ref]){var e={},g=new a;try{if(e=g.validate(d[this.ref],this.options.is),!f(e))throw new Error;this.options.then&&(e=g.validate(b,this.options.then))}catch(h){this.options.otherwise&&(e=g.validate(b,this.options.otherwise))}}return!!f(e)||e},this}},/** * Some useful object prototypes / functions here */ // IE8<= compatibility // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf Array.prototype.indexOf||(Array.prototype.indexOf=function(a){"use strict";if(null===this)throw new TypeError;var b=Object(this),c=b.length>>>0;if(0===c)return-1;var d=0;if(arguments.length>1&&(d=Number(arguments[1]),d!=d?// shortcut for verifying if it's NaN d=0:0!==d&&d!=1/0&&d!=-(1/0)&&(d=(d>0||-1)*Math.floor(Math.abs(d)))),d>=c)return-1;for(var e=d>=0?d:Math.max(c-Math.abs(d),0);e<c;e++)if(e in b&&b[e]===a)return e;return-1}); // Test if object is empty, useful for Constraint violations check var f=function(a){for(var b in a)return!1;return!0},g=function(a){return"[object Array]"===Object.prototype.toString.call(a)},h=function(a){return"object"==typeof a&&Object.getPrototypeOf(a)===Object.prototype},i=function(a){return"[object String]"===Object.prototype.toString.call(a)},j=function(a){return a.replace(/\s(.)/g,function(a){return a.toUpperCase()}).replace(/\s/g,"").replace(/^(.)/,function(a){return a.toLowerCase()})},k=function(a){ // Copy prototype properties. for(var b in a.prototype){var c=b.match(/^(.*?[A-Z]{2,})(.*)$/),d=j(b);null!==c&&(d=c[1]+j(c[2])),d!==b&&( // Create `camelCase` aliases. l(a.prototype,b,d), // Add static methods as aliases. a[d]=function(b){return function(){var c=new a;return c[b].apply(c,arguments)}}(b),l(a,d,b))}return a},l=function(a,b,c){a[c]=a[b]}; // aliases l(d.prototype,"Length","OfLength"),l(d.prototype,"HaveProperty","PropertyDefined"),l(d.prototype,"IsString","String"), // prettify k(d), // expose to the world these awesome classes e.Assert=d,e.Constraint=b,e.Validator=a,e.Violation=c,e.assert=function(a){return new d(a)},e.constraint=function(a,c){return new b(a,c)},e.validator=function(b){return new a(b)},e.violation=function(a,b,d){return new c(a,b,d)}, // AMD export "function"==typeof define&&define.amd?define(function(){return e}):"undefined"!=typeof module&&module.exports?module.exports=e:window["undefined"!=typeof validatorjs_ns?validatorjs_ns:"Validator"]=e}();