fastest-validator
Advanced tools
Comparing version 0.6.19 to 1.0.0-beta1
-------------------------------------------------- | ||
<a name="1.0.0"></a> | ||
# 1.0.0 (2019-11-xx) | ||
The full library has been rewritten. It uses code generators in order to be much faster. | ||
## Breaking changes | ||
This new version contains several breaking changes. | ||
### Rule logic changed | ||
The rule codes have been rewritten to code generator functions. Therefore if you use custom validators, you should rewrite them after upgrading. | ||
### Convert values | ||
The `number`, `boolean` and `date` rules have a `convert: true` property. In the previous version it doesn't modify the value in the checked object, just converted the value to the rules. In the version 1.0 this property converts the values in the checked object, as well. | ||
## New | ||
### Sanitizations | ||
The sanitization function is implemented. There are several rules which contains sanitizers. **Please note, the sanitizers change the original checked object values.** | ||
| Rule | Property | Description | | ||
| ---- | -------- | ----------- | | ||
`boolean` | `convert` | Convert the value to a boolean. | ||
`number` | `convert` | Convert the value to a number. | ||
`date` | `convert` | Convert the value to a date. | ||
`string` | `trim` | Trim the value. | ||
`string` | `trimLeft` | Left trim the value. | ||
`string` | `trimRight` | Right trim the value. | ||
`string` | `lowercase` | Lowercase the value. | ||
`string` | `uppercase` | Uppercase the value. | ||
`string` | `localeLowercase` | Lowercase the value with `String.toLocaleLowerCase`. | ||
`string` | `localeUppercase` | Uppercase the value with `String.toLocaleUpperCase`. | ||
`string` | `padStart` | Left padding the value. | ||
`string` | `padEnd` | Right padding the value. | ||
`string` | `convert` | Convert the value to a string. | ||
`email` | `normalize` | Trim & lowercase the value. | ||
`forbidden` | `remove` | Remove the forbidden field. | ||
`object` | `strict: "remove"` | Remove additional properties in the object. | ||
`*` | `default` | Use this default value if the value is `null` or `undefined`. | ||
### Root element validation | ||
Basically the validator expects that you want to validate a Javascript object. If you want others, you can define the root level schema, as well. In this case set the `$$root: true` property. | ||
**Example to validate a `string` variable instead of `object`** | ||
```js | ||
const schema = { | ||
$$root: true, | ||
type: "string", | ||
min: 3, | ||
max: 6 | ||
}; | ||
v.validate("John", schema); // Valid | ||
v.validate("Al", schema); // Fail, too short. | ||
``` | ||
### Enhanced shorthand types | ||
You can use string-based shorthand validation definitions in the schema with properties. | ||
```js | ||
{ | ||
password: "string|min:6", | ||
age: "number|optional|integer|positive|min:0|max:99", | ||
retry: ["number|integer|min:0", "boolean"] // multiple types | ||
} | ||
``` | ||
## Other changes | ||
### New `equal` rule | ||
It checks the value equal (`==`) to a static value or another property. The `strict` property uses `===` to check values. | ||
**Example with static value**: | ||
```js | ||
const schema = { | ||
agreeTerms: { type: "equal", value: true, strict: true } // strict means `===` | ||
} | ||
v.validate({ agreeTerms: true }, schema); // Valid | ||
v.validate({ agreeTerms: false }, schema); // Fail | ||
``` | ||
**Example with other field**: | ||
```js | ||
const schema = { | ||
password: { type: "string", min: 6 }, | ||
confirmPassword: { type: "equal", field: "password" } | ||
} | ||
v.validate({ password: "123456", confirmPassword: "123456" }, schema); // Valid | ||
v.validate({ password: "123456", confirmPassword: "pass1234" }, schema); // Fail | ||
``` | ||
### `properties` in object rule | ||
You can use the `properties` property besides the `props` property in the object rule. | ||
-------------------------------------------------- | ||
<a name="0.6.19"></a> | ||
@@ -3,0 +100,0 @@ # 0.6.19 (2019-10-25) |
@@ -416,3 +416,2 @@ (function (global, factory) { | ||
* @param {Object} schema | ||
* @throws {Error} Invalid schema | ||
*/ | ||
@@ -422,18 +421,19 @@ Validator.prototype.compile = function(schema) { | ||
var self = this; | ||
var rules; | ||
if (Array.isArray(schema)) { | ||
// Multiple schemas | ||
if (schema.length == 0) { | ||
throw new Error("If the schema is an Array, must contain at least one element!"); | ||
} | ||
if (schema.length == 0) | ||
{ throw new Error("If the schema is an Array, must contain at least one element!"); } | ||
var rules = flatten_1(schema.map(function (r) { return this$1._processRule(r, null, false); })); | ||
return this._checkWrapper(rules, true); | ||
return this._checkWrapper(flatten_1(schema.map(function (r) { return this$1._processRule(r, null, false); })), true); | ||
} else if (schema != null && typeof schema === "object") { | ||
var rules$1 = flatten_1(Object.keys(schema).map(function (name) { return this$1._processRule(schema[name], name, false); })); | ||
return this._checkWrapper(rules$1); | ||
rules = flatten_1(Object.keys(schema).map(function (name) { return self._processRule(schema[name], name, false); })); | ||
} else | ||
{ throw new Error("Invalid schema!"); } | ||
} | ||
throw new Error("Invalid schema!"); | ||
return this._checkWrapper(rules); | ||
}; | ||
@@ -451,2 +451,8 @@ | ||
if (typeof rule === "string") { | ||
rule = { | ||
type: rule | ||
}; | ||
} | ||
if (Array.isArray(rule)) { | ||
@@ -465,20 +471,13 @@ // Compile the multiple schemas | ||
if (typeof rule === "string") { | ||
rule = { | ||
type: rule | ||
}; | ||
} | ||
if (this.rules[rule.type]) { | ||
checks.push({ | ||
fn: this.rules[rule.type], | ||
type: rule.type, | ||
name: name, | ||
schema: rule, | ||
iterate: iterate | ||
}); | ||
} else | ||
{ throw new Error("Invalid '" + rule.type + "' type in validator schema!"); } | ||
if (!this.rules[rule.type]) { | ||
throw new Error("Invalid '" + rule.type + "' type in validator schema!"); | ||
} | ||
checks.push({ | ||
fn: this.rules[rule.type], | ||
type: rule.type, | ||
name: name, | ||
schema: rule, | ||
iterate: iterate | ||
}); | ||
// Nested schema | ||
@@ -485,0 +484,0 @@ if (rule.type === "object" && rule.props) { |
@@ -1,1 +0,1 @@ | ||
"use strict";function u(){function e(e){return"string"!=typeof e?this.makeError("string"):!!E.test(e)||this.makeError("url")}function t(e,t){if("string"!=typeof e)return this.makeError("string");var r=e.length;return!1===t.empty&&0===r?this.makeError("stringEmpty"):null!=t.min&&r<t.min?this.makeError("stringMin",t.min,r):null!=t.max&&r>t.max?this.makeError("stringMax",t.max,r):null!=t.length&&r!==t.length?this.makeError("stringLength",t.length,r):null==t.pattern||t.pattern.test(e)?null!=t.contains&&-1===e.indexOf(t.contains)?this.makeError("stringContains",t.contains):null==t.enum||-1!==t.enum.indexOf(e)||this.makeError("stringEnum",t.enum):this.makeError("stringPattern",t.pattern)}function r(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)||this.makeError("object")}function n(e,t){return!0===t.convert&&"number"!=typeof e&&(e=Number(e)),"number"!=typeof e||isNaN(e)||!isFinite(e)?this.makeError("number"):null!=t.min&&e<t.min?this.makeError("numberMin",t.min,e):null!=t.max&&e>t.max?this.makeError("numberMax",t.max,e):null!=t.equal&&e!==t.equal?this.makeError("numberEqual",t.equal,e):null!=t.notEqual&&e===t.notEqual?this.makeError("numberNotEqual",t.notEqual):!0===t.integer&&0!=e%1?this.makeError("numberInteger",e):!0===t.positive&&0>=e?this.makeError("numberPositive",e):!(!0===t.negative&&0<=e)||this.makeError("numberNegative",e)}function i(e){return"function"==typeof e||this.makeError("function")}function a(e){return null===e||void 0===e||this.makeError("forbidden")}function o(e,t){return"string"!=typeof e?this.makeError("string"):!!("precise"==t.mode?b:g).test(e)||this.makeError("email")}function l(e,t){return!0!==t.convert||e instanceof Date||(e=new Date(e)),e instanceof Date&&!isNaN(e.getTime())||this.makeError("date")}function u(e,t){return t.check.call(this,e,t)}function s(e,t){return!0===t.convert&&"boolean"!=typeof e&&(1===e||0===e||"true"===e||"false"===e||"1"===e||"0"===e||"on"===e||"off"===e)||("boolean"==typeof e||this.makeError("boolean"))}function f(e,t){if(!Array.isArray(e))return this.makeError("array");var r=e.length;if(!1===t.empty&&0===r)return this.makeError("arrayEmpty");if(null!=t.min&&r<t.min)return this.makeError("arrayMin",t.min,r);if(null!=t.max&&r>t.max)return this.makeError("arrayMax",t.max,r);if(null!=t.length&&r!==t.length)return this.makeError("arrayLength",t.length,r);if(null!=t.contains&&-1===e.indexOf(t.contains))return this.makeError("arrayContains",t.contains);if(null!=t.enum)for(r=0;r<e.length;r++)if(-1===t.enum.indexOf(e[r]))return this.makeError("arrayEnum",e[r],t.enum);return!0}function m(){return!0}function h(e,t){t=t||[];for(var r=0;r<e.length;++r)Array.isArray(e[r])?h(e[r],t):t.push(e[r]);return t}function c(e,t){for(var r in t)"object"==typeof t[r]&&null!==t[r]?(e[r]=e[r]||{},c(e[r],t[r])):e[r]=t[r];return e}function d(h){this.opts={messages:y},h&&p(this.opts,h),this.messages=this.opts.messages,this.rules={any:m,array:f,boolean:s,custom:u,date:l,email:o,forbidden:a,function:i,number:n,object:r,string:t,url:e}}var p=c,y={required:"The '{field}' field is required!",string:"The '{field}' field must be a string!",stringEmpty:"The '{field}' field must not be empty!",stringMin:"The '{field}' field length must be larger than or equal to {expected} characters long!",stringMax:"The '{field}' field length must be less than or equal to {expected} characters long!",stringLength:"The '{field}' field length must be {expected} characters long!",stringPattern:"The '{field}' field fails to match the required pattern!",stringContains:"The '{field}' field must contain the '{expected}' text!",stringEnum:"The '{field}' field does not match any of the allowed values!",number:"The '{field}' field must be a number!",numberMin:"The '{field}' field must be larger than or equal to {expected}!",numberMax:"The '{field}' field must be less than or equal to {expected}!",numberEqual:"The '{field}' field must be equal with {expected}!",numberNotEqual:"The '{field}' field can't be equal with {expected}!",numberInteger:"The '{field}' field must be an integer!",numberPositive:"The '{field}' field must be a positive number!",numberNegative:"The '{field}' field must be a negative number!",array:"The '{field}' field must be an array!",arrayEmpty:"The '{field}' field must not be an empty array!",arrayMin:"The '{field}' field must contain at least {expected} items!",arrayMax:"The '{field}' field must contain less than or equal to {expected} items!",arrayLength:"The '{field}' field must contain {expected} items!",arrayContains:"The '{field}' field must contain the '{expected}' item!",arrayEnum:"The '{field} field value '{expected}' does not match any of the allowed values!",boolean:"The '{field}' field must be a boolean!",function:"The '{field}' field must be a function!",date:"The '{field}' field must be a Date!",dateMin:"The '{field}' field must be larger than or equal to {expected}!",dateMax:"The '{field}' field must be less than or equal to {expected}!",forbidden:"The '{field}' field is forbidden!",email:"The '{field}' field must be a valid e-mail!"},b=/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,g=/^\S+@\S+\.\S+$/,E=/^https?:\/\/\S+/;return d.prototype.validate=function(e,t){return this.compile(t)(e)},d.prototype.compile=function(e){var t=this;if(Array.isArray(e)){if(0==e.length)throw Error("If the schema is an Array, must contain at least one element!");var r=h(e.map(function(e){return t._processRule(e,null,!1)}));return this._checkWrapper(r,!0)}if(null!=e&&"object"==typeof e)return r=h(Object.keys(e).map(function(r){return t._processRule(e[r],r,!1)})),this._checkWrapper(r);throw Error("Invalid schema!")},d.prototype._processRule=function(e,t,r){var n=[];if(Array.isArray(e))return n.push({fn:this.compile(e),type:"_multi",name:t,schema:e,iterate:r}),n;if("string"==typeof e&&(e={type:e}),!this.rules[e.type])throw Error("Invalid '"+e.type+"' type in validator schema!");return n.push({fn:this.rules[e.type],type:e.type,name:t,schema:e,iterate:r}),"object"===e.type&&e.props&&n.push({fn:this.compile(e.props),type:e.type,name:t,schema:e,iterate:r}),"array"===e.type&&e.items&&n.push({fn:this._checkWrapper(this._processRule(e.items,null,!1)),type:e.type,name:t,schema:e,iterate:!0}),n},d.prototype._checkWrapper=function(e,t){var r=this;return function(n,i,a){i=[];for(var o=e.length,l=0;l<o;l++){var u=e[l],s=u.schema;if(u.name)var f=n[u.name],m=(a?a+".":"")+u.name;else f=n,m=a||"";if(void 0!==f&&null!==f||"forbidden"===u.type)if(u.iterate)for(var h=f.length,c=0;c<h;c++){var d=m+"["+c+"]",p=u.fn.call(r,f[c],s,d);!0!==p&&r.handleResult(i,d,p)}else{if(u=u.fn.call(r,f,s,m),t&&!0===u)return!0;!0!==u&&r.handleResult(i,m,u)}else!0!==s.optional&&r.handleResult(i,m,r.makeError("required"))}return 0===i.length||i}},d.prototype.handleResult=function(e,t,r){var n=this;(Array.isArray(r)?r:[r]).forEach(function(r){r.field||(r.field=t),r.message||(r.message=n.resolveMessage(r)),e.push(r)})},d.prototype.makeError=function(e,t,r){return{type:e,expected:t,actual:r}},d.prototype.resolveMessage=function(e){var t=this.messages[e.type];if(null!=t){var r=null!=e.expected?e.expected:"",n=null!=e.actual?e.actual:"";return t.replace(/\{field\}/g,e.field).replace(/\{expected\}/g,r).replace(/\{actual\}/g,n)}},d.prototype.add=function(e,t){this.rules[e]=t},d}var e=e||{};e.scope={},e.ASSUME_ES5=!1,e.ASSUME_NO_NATIVE_MAP=!1,e.ASSUME_NO_NATIVE_SET=!1,e.defineProperty=e.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(e,t,r){e!=Array.prototype&&e!=Object.prototype&&(e[t]=r.value)},e.getGlobal=function(e){return"undefined"!=typeof window&&window===e?e:"undefined"!=typeof global&&null!=global?global:e},e.global=e.getGlobal(this),e.SYMBOL_PREFIX="jscomp_symbol_",e.initSymbol=function(){e.initSymbol=function(){},e.global.Symbol||(e.global.Symbol=e.Symbol)},e.Symbol=function(){var t=0;return function(r){return e.SYMBOL_PREFIX+(r||"")+t++}}(),e.initSymbolIterator=function(){e.initSymbol();var t=e.global.Symbol.iterator;t||(t=e.global.Symbol.iterator=e.global.Symbol("iterator")),"function"!=typeof Array.prototype[t]&&e.defineProperty(Array.prototype,t,{configurable:!0,writable:!0,value:function(){return e.arrayIterator(this)}}),e.initSymbolIterator=function(){}},e.arrayIterator=function(t){var r=0;return e.iteratorPrototype(function(){return r<t.length?{done:!1,value:t[r++]}:{done:!0}})},e.iteratorPrototype=function(t){return e.initSymbolIterator(),t={next:t},t[e.global.Symbol.iterator]=function(){return this},t},e.iteratorFromArray=function(t,r){e.initSymbolIterator(),t instanceof String&&(t+="");var n=0,i={next:function(){if(n<t.length){var e=n++;return{value:r(e,t[e]),done:!1}}return i.next=function(){return{done:!0,value:void 0}},i.next()}};return i[Symbol.iterator]=function(){return i},i},e.polyfill=function(t,r){if(r){var n=e.global;t=t.split(".");for(var i=0;i<t.length-1;i++){var a=t[i];a in n||(n[a]={}),n=n[a]}(r=r(i=n[t=t[t.length-1]]))!=i&&null!=r&&e.defineProperty(n,t,{configurable:!0,writable:!0,value:r})}},e.polyfill("Array.prototype.keys",function(t){return t||function(){return e.iteratorFromArray(this,function(e){return e})}},"es6","es3"),"object"==typeof exports&&"undefined"!=typeof module?module.exports=u():"function"==typeof define&&define.amd?define(u):this.FastestValidator=u(); | ||
"use strict";function u(){function e(e){return"string"!=typeof e?this.makeError("string"):!!E.test(e)||this.makeError("url")}function t(e,t){if("string"!=typeof e)return this.makeError("string");var r=e.length;return!1===t.empty&&0===r?this.makeError("stringEmpty"):null!=t.min&&r<t.min?this.makeError("stringMin",t.min,r):null!=t.max&&r>t.max?this.makeError("stringMax",t.max,r):null!=t.length&&r!==t.length?this.makeError("stringLength",t.length,r):null==t.pattern||t.pattern.test(e)?null!=t.contains&&-1===e.indexOf(t.contains)?this.makeError("stringContains",t.contains):null==t.enum||-1!==t.enum.indexOf(e)||this.makeError("stringEnum",t.enum):this.makeError("stringPattern",t.pattern)}function r(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)||this.makeError("object")}function n(e,t){return!0===t.convert&&"number"!=typeof e&&(e=Number(e)),"number"!=typeof e||isNaN(e)||!isFinite(e)?this.makeError("number"):null!=t.min&&e<t.min?this.makeError("numberMin",t.min,e):null!=t.max&&e>t.max?this.makeError("numberMax",t.max,e):null!=t.equal&&e!==t.equal?this.makeError("numberEqual",t.equal,e):null!=t.notEqual&&e===t.notEqual?this.makeError("numberNotEqual",t.notEqual):!0===t.integer&&0!=e%1?this.makeError("numberInteger",e):!0===t.positive&&0>=e?this.makeError("numberPositive",e):!(!0===t.negative&&0<=e)||this.makeError("numberNegative",e)}function i(e){return"function"==typeof e||this.makeError("function")}function a(e){return null===e||void 0===e||this.makeError("forbidden")}function o(e,t){return"string"!=typeof e?this.makeError("string"):!!("precise"==t.mode?b:g).test(e)||this.makeError("email")}function l(e,t){return!0!==t.convert||e instanceof Date||(e=new Date(e)),e instanceof Date&&!isNaN(e.getTime())||this.makeError("date")}function u(e,t){return t.check.call(this,e,t)}function s(e,t){return!0===t.convert&&"boolean"!=typeof e&&(1===e||0===e||"true"===e||"false"===e||"1"===e||"0"===e||"on"===e||"off"===e)||("boolean"==typeof e||this.makeError("boolean"))}function f(e,t){if(!Array.isArray(e))return this.makeError("array");var r=e.length;if(!1===t.empty&&0===r)return this.makeError("arrayEmpty");if(null!=t.min&&r<t.min)return this.makeError("arrayMin",t.min,r);if(null!=t.max&&r>t.max)return this.makeError("arrayMax",t.max,r);if(null!=t.length&&r!==t.length)return this.makeError("arrayLength",t.length,r);if(null!=t.contains&&-1===e.indexOf(t.contains))return this.makeError("arrayContains",t.contains);if(null!=t.enum)for(r=0;r<e.length;r++)if(-1===t.enum.indexOf(e[r]))return this.makeError("arrayEnum",e[r],t.enum);return!0}function m(){return!0}function h(e,t){t=t||[];for(var r=0;r<e.length;++r)Array.isArray(e[r])?h(e[r],t):t.push(e[r]);return t}function c(e,t){for(var r in t)"object"==typeof t[r]&&null!==t[r]?(e[r]=e[r]||{},c(e[r],t[r])):e[r]=t[r];return e}function d(h){this.opts={messages:y},h&&p(this.opts,h),this.messages=this.opts.messages,this.rules={any:m,array:f,boolean:s,custom:u,date:l,email:o,forbidden:a,function:i,number:n,object:r,string:t,url:e}}var p=c,y={required:"The '{field}' field is required!",string:"The '{field}' field must be a string!",stringEmpty:"The '{field}' field must not be empty!",stringMin:"The '{field}' field length must be larger than or equal to {expected} characters long!",stringMax:"The '{field}' field length must be less than or equal to {expected} characters long!",stringLength:"The '{field}' field length must be {expected} characters long!",stringPattern:"The '{field}' field fails to match the required pattern!",stringContains:"The '{field}' field must contain the '{expected}' text!",stringEnum:"The '{field}' field does not match any of the allowed values!",number:"The '{field}' field must be a number!",numberMin:"The '{field}' field must be larger than or equal to {expected}!",numberMax:"The '{field}' field must be less than or equal to {expected}!",numberEqual:"The '{field}' field must be equal with {expected}!",numberNotEqual:"The '{field}' field can't be equal with {expected}!",numberInteger:"The '{field}' field must be an integer!",numberPositive:"The '{field}' field must be a positive number!",numberNegative:"The '{field}' field must be a negative number!",array:"The '{field}' field must be an array!",arrayEmpty:"The '{field}' field must not be an empty array!",arrayMin:"The '{field}' field must contain at least {expected} items!",arrayMax:"The '{field}' field must contain less than or equal to {expected} items!",arrayLength:"The '{field}' field must contain {expected} items!",arrayContains:"The '{field}' field must contain the '{expected}' item!",arrayEnum:"The '{field} field value '{expected}' does not match any of the allowed values!",boolean:"The '{field}' field must be a boolean!",function:"The '{field}' field must be a function!",date:"The '{field}' field must be a Date!",dateMin:"The '{field}' field must be larger than or equal to {expected}!",dateMax:"The '{field}' field must be less than or equal to {expected}!",forbidden:"The '{field}' field is forbidden!",email:"The '{field}' field must be a valid e-mail!"},b=/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,g=/^\S+@\S+\.\S+$/,E=/^https?:\/\/\S+/;return d.prototype.validate=function(e,t){return this.compile(t)(e)},d.prototype.compile=function(e){var t=this,r=this;if(Array.isArray(e)){if(0==e.length)throw Error("If the schema is an Array, must contain at least one element!");return this._checkWrapper(h(e.map(function(e){return t._processRule(e,null,!1)})),!0)}if(null==e||"object"!=typeof e)throw Error("Invalid schema!");var n=h(Object.keys(e).map(function(t){return r._processRule(e[t],t,!1)}));return this._checkWrapper(n)},d.prototype._processRule=function(e,t,r){var n=[];if("string"==typeof e&&(e={type:e}),Array.isArray(e))return n.push({fn:this.compile(e),type:"_multi",name:t,schema:e,iterate:r}),n;if(!this.rules[e.type])throw Error("Invalid '"+e.type+"' type in validator schema!");return n.push({fn:this.rules[e.type],type:e.type,name:t,schema:e,iterate:r}),"object"===e.type&&e.props&&n.push({fn:this.compile(e.props),type:e.type,name:t,schema:e,iterate:r}),"array"===e.type&&e.items&&n.push({fn:this._checkWrapper(this._processRule(e.items,null,!1)),type:e.type,name:t,schema:e,iterate:!0}),n},d.prototype._checkWrapper=function(e,t){var r=this;return function(n,i,a){i=[];for(var o=e.length,l=0;l<o;l++){var u=e[l],s=u.schema;if(u.name)var f=n[u.name],m=(a?a+".":"")+u.name;else f=n,m=a||"";if(void 0!==f&&null!==f||"forbidden"===u.type)if(u.iterate)for(var h=f.length,c=0;c<h;c++){var d=m+"["+c+"]",p=u.fn.call(r,f[c],s,d);!0!==p&&r.handleResult(i,d,p)}else{if(u=u.fn.call(r,f,s,m),t&&!0===u)return!0;!0!==u&&r.handleResult(i,m,u)}else!0!==s.optional&&r.handleResult(i,m,r.makeError("required"))}return 0===i.length||i}},d.prototype.handleResult=function(e,t,r){var n=this;(Array.isArray(r)?r:[r]).forEach(function(r){r.field||(r.field=t),r.message||(r.message=n.resolveMessage(r)),e.push(r)})},d.prototype.makeError=function(e,t,r){return{type:e,expected:t,actual:r}},d.prototype.resolveMessage=function(e){var t=this.messages[e.type];if(null!=t){var r=null!=e.expected?e.expected:"",n=null!=e.actual?e.actual:"";return t.replace(/\{field\}/g,e.field).replace(/\{expected\}/g,r).replace(/\{actual\}/g,n)}},d.prototype.add=function(e,t){this.rules[e]=t},d}var e=e||{};e.scope={},e.ASSUME_ES5=!1,e.ASSUME_NO_NATIVE_MAP=!1,e.ASSUME_NO_NATIVE_SET=!1,e.defineProperty=e.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(e,t,r){e!=Array.prototype&&e!=Object.prototype&&(e[t]=r.value)},e.getGlobal=function(e){return"undefined"!=typeof window&&window===e?e:"undefined"!=typeof global&&null!=global?global:e},e.global=e.getGlobal(this),e.SYMBOL_PREFIX="jscomp_symbol_",e.initSymbol=function(){e.initSymbol=function(){},e.global.Symbol||(e.global.Symbol=e.Symbol)},e.Symbol=function(){var t=0;return function(r){return e.SYMBOL_PREFIX+(r||"")+t++}}(),e.initSymbolIterator=function(){e.initSymbol();var t=e.global.Symbol.iterator;t||(t=e.global.Symbol.iterator=e.global.Symbol("iterator")),"function"!=typeof Array.prototype[t]&&e.defineProperty(Array.prototype,t,{configurable:!0,writable:!0,value:function(){return e.arrayIterator(this)}}),e.initSymbolIterator=function(){}},e.arrayIterator=function(t){var r=0;return e.iteratorPrototype(function(){return r<t.length?{done:!1,value:t[r++]}:{done:!0}})},e.iteratorPrototype=function(t){return e.initSymbolIterator(),t={next:t},t[e.global.Symbol.iterator]=function(){return this},t},e.iteratorFromArray=function(t,r){e.initSymbolIterator(),t instanceof String&&(t+="");var n=0,i={next:function(){if(n<t.length){var e=n++;return{value:r(e,t[e]),done:!1}}return i.next=function(){return{done:!0,value:void 0}},i.next()}};return i[Symbol.iterator]=function(){return i},i},e.polyfill=function(t,r){if(r){var n=e.global;t=t.split(".");for(var i=0;i<t.length-1;i++){var a=t[i];a in n||(n[a]={}),n=n[a]}(r=r(i=n[t=t[t.length-1]]))!=i&&null!=r&&e.defineProperty(n,t,{configurable:!0,writable:!0,value:r})}},e.polyfill("Array.prototype.keys",function(t){return t||function(){return e.iteratorFromArray(this,function(e){return e})}},"es6","es3"),"object"==typeof exports&&"undefined"!=typeof module?module.exports=u():"function"==typeof define&&define.amd?define(u):this.FastestValidator=u(); |
1345
dist/index.js
@@ -7,25 +7,2 @@ (function (global, factory) { | ||
/** | ||
* Flatten an array | ||
* @param {Array} array | ||
* @param {Array} target | ||
* @returns Array flattened array | ||
*/ | ||
function flatten(array, target) { | ||
var result = target || []; | ||
for (var i = 0; i < array.length; ++i) { | ||
if (Array.isArray(array[i])) { | ||
flatten(array[i], result); | ||
} | ||
else { | ||
result.push(array[i]); | ||
} | ||
} | ||
return result; | ||
} | ||
var flatten_1 = flatten; | ||
function deepExtend(destination, source) { | ||
@@ -47,141 +24,192 @@ for (var property in source) { | ||
var messages = { | ||
required: "The '{field}' field is required!", | ||
required: "The '{field}' field is required.", | ||
string: "The '{field}' field must be a string!", | ||
stringEmpty: "The '{field}' field must not be empty!", | ||
stringMin: "The '{field}' field length must be greater than or equal to {expected} characters long!", | ||
stringMax: "The '{field}' field length must be less than or equal to {expected} characters long!", | ||
stringLength: "The '{field}' field length must be {expected} characters long!", | ||
stringPattern: "The '{field}' field fails to match the required pattern!", | ||
stringContains: "The '{field}' field must contain the '{expected}' text!", | ||
stringEnum: "The '{field}' field does not match any of the allowed values!", | ||
stringNumeric: "The '{field}' field must be a numeric string", | ||
stringAlpha: "The '{field}' field must be an alphabetic string", | ||
stringAlphanum: "The '{field}' field must be an alphanumeric string", | ||
stringAlphadash: "The '{field}' field must be an alphadash string", | ||
string: "The '{field}' field must be a string.", | ||
stringEmpty: "The '{field}' field must not be empty.", | ||
stringMin: "The '{field}' field length must be greater than or equal to {expected} characters long.", | ||
stringMax: "The '{field}' field length must be less than or equal to {expected} characters long.", | ||
stringLength: "The '{field}' field length must be {expected} characters long.", | ||
stringPattern: "The '{field}' field fails to match the required pattern.", | ||
stringContains: "The '{field}' field must contain the '{expected}' text.", | ||
stringEnum: "The '{field}' field does not match any of the allowed values.", | ||
stringNumeric: "The '{field}' field must be a numeric string.", | ||
stringAlpha: "The '{field}' field must be an alphabetic string.", | ||
stringAlphanum: "The '{field}' field must be an alphanumeric string.", | ||
stringAlphadash: "The '{field}' field must be an alphadash string.", | ||
number: "The '{field}' field must be a number!", | ||
numberMin: "The '{field}' field must be greater than or equal to {expected}!", | ||
numberMax: "The '{field}' field must be less than or equal to {expected}!", | ||
numberEqual: "The '{field}' field must be equal with {expected}!", | ||
numberNotEqual: "The '{field}' field can't be equal with {expected}!", | ||
numberInteger: "The '{field}' field must be an integer!", | ||
numberPositive: "The '{field}' field must be a positive number!", | ||
numberNegative: "The '{field}' field must be a negative number!", | ||
number: "The '{field}' field must be a number.", | ||
numberMin: "The '{field}' field must be greater than or equal to {expected}.", | ||
numberMax: "The '{field}' field must be less than or equal to {expected}.", | ||
numberEqual: "The '{field}' field must be equal to {expected}.", | ||
numberNotEqual: "The '{field}' field can't be equal to {expected}.", | ||
numberInteger: "The '{field}' field must be an integer.", | ||
numberPositive: "The '{field}' field must be a positive number.", | ||
numberNegative: "The '{field}' field must be a negative number.", | ||
array: "The '{field}' field must be an array!", | ||
arrayEmpty: "The '{field}' field must not be an empty array!", | ||
arrayMin: "The '{field}' field must contain at least {expected} items!", | ||
arrayMax: "The '{field}' field must contain less than or equal to {expected} items!", | ||
arrayLength: "The '{field}' field must contain {expected} items!", | ||
arrayContains: "The '{field}' field must contain the '{expected}' item!", | ||
arrayEnum: "The '{field} field value '{expected}' does not match any of the allowed values!", | ||
array: "The '{field}' field must be an array.", | ||
arrayEmpty: "The '{field}' field must not be an empty array.", | ||
arrayMin: "The '{field}' field must contain at least {expected} items.", | ||
arrayMax: "The '{field}' field must contain less than or equal to {expected} items.", | ||
arrayLength: "The '{field}' field must contain {expected} items.", | ||
arrayContains: "The '{field}' field must contain the '{expected}' item.", | ||
arrayEnum: "The '{actual}' value in '{field}' field does not match any of the '{expected}' values.", | ||
boolean: "The '{field}' field must be a boolean!", | ||
boolean: "The '{field}' field must be a boolean.", | ||
function: "The '{field}' field must be a function!", | ||
date: "The '{field}' field must be a Date.", | ||
dateMin: "The '{field}' field must be greater than or equal to {expected}.", | ||
dateMax: "The '{field}' field must be less than or equal to {expected}.", | ||
date: "The '{field}' field must be a Date!", | ||
dateMin: "The '{field}' field must be greater than or equal to {expected}!", | ||
dateMax: "The '{field}' field must be less than or equal to {expected}!", | ||
enumValue: "The '{field}' field value '{expected}' does not match any of the allowed values.", | ||
forbidden: "The '{field}' field is forbidden!", | ||
equalValue: "The '{field}' field value must be equal to '{expected}'.", | ||
equalField: "The '{field}' field value must be equal to '{expected}' field value.", | ||
email: "The '{field}' field must be a valid e-mail!", | ||
forbidden: "The '{field}' field is forbidden.", | ||
url: "The '{field}' field must be a valid URL!", | ||
function: "The '{field}' field must be a function.", | ||
enumValue: "The '{field} field value '{expected}' does not match any of the allowed values!", | ||
email: "The '{field}' field must be a valid e-mail.", | ||
object: "The '{field}' must be an Object!", | ||
objectStrict: "The object '{field}' contains invalid keys: '{actual}'!", | ||
uuid: "The {field} field must be a valid UUID", | ||
uuidVersion: "The {field} field must be a valid version provided", | ||
mac: "The {field} field must be a valid MAC address", | ||
luhn: "The {field} field must be a valid checksum luhn", | ||
luhn: "The '{field}' field must be a valid checksum luhn.", | ||
mac: "The '{field}' field must be a valid MAC address.", | ||
object: "The '{field}' must be an Object.", | ||
objectStrict: "The object '{field}' contains forbidden keys: '{actual}'.", | ||
url: "The '{field}' field must be a valid URL.", | ||
uuid: "The '{field}' field must be a valid UUID.", | ||
uuidVersion: "The '{field}' field must be a valid UUID version provided.", | ||
}; | ||
var any = function checkAny() { | ||
return true; | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var any = function(/*{ schema, messages }, path, context*/) { | ||
return {}; | ||
}; | ||
var array = function checkArray(value, schema) { | ||
if (!Array.isArray(value)) { | ||
return this.makeError("array"); | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var array = function(ref, path, context) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
var src = []; | ||
src.push(("\n\t\tif (!Array.isArray(value)) {\n\t\t\t" + (this.makeError({ type: "array", actual: "value", messages: messages })) + "\n\t\t\treturn value;\n\t\t}\n\n\t\tvar len = value.length;\n\t")); | ||
if (schema.empty === false) { | ||
src.push(("\n\t\t\tif (len === 0) {\n\t\t\t\t" + (this.makeError({ type: "arrayEmpty", actual: "value", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
var arrLength = value.length; | ||
if (schema.min != null) { | ||
src.push(("\n\t\t\tif (len < " + (schema.min) + ") {\n\t\t\t\t" + (this.makeError({ type: "arrayMin", expected: schema.min, actual: "len", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
if (schema.empty === false && arrLength === 0) { | ||
return this.makeError("arrayEmpty"); | ||
if (schema.max != null) { | ||
src.push(("\n\t\t\tif (len > " + (schema.max) + ") {\n\t\t\t\t" + (this.makeError({ type: "arrayMax", expected: schema.max, actual: "len", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
if (schema.min != null && arrLength < schema.min) { | ||
return this.makeError("arrayMin", schema.min, arrLength); | ||
if (schema.length != null) { | ||
src.push(("\n\t\t\tif (len !== " + (schema.length) + ") {\n\t\t\t\t" + (this.makeError({ type: "arrayLength", expected: schema.length, actual: "len", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
if (schema.max != null && arrLength > schema.max) { | ||
return this.makeError("arrayMax", schema.max, arrLength); | ||
if (schema.contains != null) { | ||
src.push(("\n\t\t\tif (value.indexOf(" + (JSON.stringify(schema.contains)) + ") === -1) {\n\t\t\t\t" + (this.makeError({ type: "arrayContains", expected: JSON.stringify(schema.contains), actual: "value", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
// Check fix length | ||
if (schema.length != null && arrLength !== schema.length) { | ||
return this.makeError("arrayLength", schema.length, arrLength); | ||
} | ||
if (schema.enum != null) { | ||
var enumStr = JSON.stringify(schema.enum); | ||
src.push(("\n\t\t\tfor (var i = 0; i < value.length; i++) {\n\t\t\t\tif (" + enumStr + ".indexOf(value[i]) === -1) {\n\t\t\t\t\t" + (this.makeError({ type: "arrayEnum", expected: "\"" + schema.enum.join(", ") + "\"", actual: "value[i]", messages: messages })) + "\n\t\t\t\t}\n\t\t\t}\n\t\t")); | ||
} | ||
if (schema.contains != null && value.indexOf(schema.contains) === -1) { | ||
return this.makeError("arrayContains", schema.contains); | ||
} | ||
if (schema.items != null) { | ||
if (schema.enum != null) { | ||
for (var i = 0; i < value.length; i++) { | ||
if (schema.enum.indexOf(value[i]) === -1) { | ||
return this.makeError("arrayEnum", value[i], schema.enum); | ||
} | ||
src.push("\n\t\t\tvar arr = value;\n\t\t\tvar parentField = field;\n\t\t\tfor (var i = 0; i < arr.length; i++) {\n\t\t"); | ||
var rule = this.getRuleFromSchema(schema.items); | ||
src.push(this.compileRule(rule, context, path, "arr[i] = context.fn[%%INDEX%%](arr[i], (parentField ? parentField : \"\") + \"[\" + i + \"]\", parent, errors, context);", "arr[i]")); | ||
/* | ||
const res = rule.ruleFunction.call(this, rule, path, context); | ||
context.rules[context.index] = rule; | ||
if (res.source) { | ||
const fn = new Function("value", "field", "parent", "errors", "context", res.source); | ||
context.fn[context.index] = fn; | ||
src.push(`arr[i] = context.fn[${context.index}](arr[i], (parentField ? parentField : "") + "[" + i + "]", parent, errors, context);`); | ||
} | ||
} | ||
context.index++; | ||
*/ | ||
src.push("\n\t\t\t}\n\t\t"); | ||
} | ||
return true; | ||
return { | ||
source: src.join("\n") | ||
}; | ||
}; | ||
var boolean_1 = function checkBoolean(value, schema) { | ||
if (schema.convert === true && typeof value !== "boolean") { | ||
if ( | ||
value === 1 | ||
|| value === 0 | ||
|| value === "true" | ||
|| value === "false" | ||
|| value === "1" | ||
|| value === "0" | ||
|| value === "on" | ||
|| value === "off" | ||
) | ||
{ return true; } | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var boolean_1 = function(ref, path) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
var src = []; | ||
var sanitized = false; | ||
src.push("\n\t\tvar origValue = value;\n\t"); | ||
if (schema.convert === true) { | ||
sanitized = true; | ||
src.push("\n\t\t\tif (typeof value !== \"boolean\") {\n\t\t\t\tif (\n\t\t\t\tvalue === 1\n\t\t\t\t|| value === \"true\"\n\t\t\t\t|| value === \"1\"\n\t\t\t\t|| value === \"on\"\n\t\t\t\t) {\n\t\t\t\t\tvalue = true;\n\t\t\t\t} else if (\n\t\t\t\tvalue === 0\n\t\t\t\t|| value === \"false\"\n\t\t\t\t|| value === \"0\"\n\t\t\t\t|| value === \"off\"\n\t\t\t\t) {\n\t\t\t\t\tvalue = false;\n\t\t\t\t}\n\t\t\t}\n\t\t"); | ||
} | ||
if (typeof value !== "boolean") { | ||
return this.makeError("boolean"); | ||
} | ||
return true; | ||
}; | ||
src.push(("\n\t\tif (typeof value !== \"boolean\")\n\t\t\t" + (this.makeError({ type: "boolean", actual: "origValue", messages: messages })) + "\n\n\t\treturn value;\n\t")); | ||
var custom = function customCheck(value, schema) { | ||
return schema.check.call(this, value, schema); | ||
return { | ||
sanitized: sanitized, | ||
source: src.join("\n") | ||
}; | ||
}; | ||
var date = function checkDate(value, schema) { | ||
if (schema.convert === true && !(value instanceof Date)) { | ||
value = new Date(value); | ||
var custom = function(ref, path, context) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
var src = []; | ||
if (typeof schema.check == "function") { | ||
context.customs[path] = { schema: schema, messages: messages }; | ||
src.push(("\n\t\t\tconst rule = context.customs[\"" + path + "\"];\n\t\t\tconst res = rule.schema.check.call(this, value, rule.schema, \"" + path + "\", parent, context);\n\t\t\tif (Array.isArray(res)) {\n\t\t\t\tres.forEach(err => errors.push(Object.assign({ message: rule.messages[err.type] }, err)));\n\t\t\t}\n\n\t\t\treturn value;\n\t\t")); | ||
} | ||
if (!(value instanceof Date)) { | ||
return this.makeError("date"); | ||
} | ||
if (isNaN(value.getTime())) { | ||
return this.makeError("date"); | ||
return { | ||
source: src.join("\n") | ||
}; | ||
}; | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var date = function(ref, path) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
var src = []; | ||
var sanitized = false; | ||
src.push("\n\t\tvar origValue = value;\n\t"); | ||
if (schema.convert === true) { | ||
sanitized = true; | ||
src.push("\n\t\t\tif (!(value instanceof Date)) {\n\t\t\t\tvalue = new Date(value);\n\t\t\t}\n\t\t"); | ||
} | ||
return true; | ||
src.push(("\n\t\tif (!(value instanceof Date) || isNaN(value.getTime()))\n\t\t\t" + (this.makeError({ type: "date", actual: "origValue", messages: messages })) + "\n\n\t\treturn value;\n\t")); | ||
return { | ||
sanitized: sanitized, | ||
source: src.join("\n") | ||
}; | ||
}; | ||
@@ -192,115 +220,273 @@ | ||
var email = function checkEmail(value, schema) { | ||
if (typeof value !== "string") { | ||
return this.makeError("string"); | ||
} | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var email = function(ref, path) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
var pattern; | ||
if (schema.mode == "precise") | ||
{ pattern = PRECISE_PATTERN; } | ||
else | ||
{ pattern = BASIC_PATTERN; } | ||
var src = []; | ||
if (!pattern.test(value)) { | ||
return this.makeError("email"); | ||
var pattern = schema.mode == "precise" ? PRECISE_PATTERN : BASIC_PATTERN; | ||
var sanitized = false; | ||
src.push(("\n\t\tif (typeof value !== \"string\") {\n\t\t\t" + (this.makeError({ type: "string", actual: "value", messages: messages })) + "\n\t\t\treturn value;\n\t\t}\n\t")); | ||
if (schema.normalize) { | ||
sanitized = true; | ||
src.push("\n\t\t\tvalue = value.trim().toLowerCase();\n\t\t"); | ||
} | ||
return true; | ||
src.push(("\n\t\tif (!" + (pattern.toString()) + ".test(value))\n\t\t\t" + (this.makeError({ type: "email", actual: "value", messages: messages })) + "\n\n\t\treturn value;\n\t")); | ||
return { | ||
sanitized: sanitized, | ||
source: src.join("\n") | ||
}; | ||
}; | ||
var _enum = function checkEnum(value, schema) { | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var _enum = function(ref, path) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
if (schema.values != null && schema.values.indexOf(value) === -1) { | ||
return this.makeError("enumValue", schema.values, value); | ||
var enumStr = JSON.stringify(schema.values || []); | ||
return { | ||
source: ("\n\t\t\tif (" + enumStr + ".indexOf(value) === -1)\n\t\t\t\t" + (this.makeError({ type: "enumValue", expected: "\"" + schema.values.join(", ") + "\"", actual: "value", messages: messages })) + "\n\n\t\t\treturn value;\n\t\t") | ||
}; | ||
}; | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var equal = function(ref, path) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
var src = []; | ||
if (schema.field) { | ||
if (schema.strict) { | ||
src.push(("\n\t\t\t\tif (value !== parent[\"" + (schema.field) + "\"])\n\t\t\t")); | ||
} else { | ||
src.push(("\n\t\t\t\tif (value != parent[\"" + (schema.field) + "\"])\n\t\t\t")); | ||
} | ||
src.push(("\n\t\t\t\t" + (this.makeError({ type: "equalField", actual: "value", expected: JSON.stringify(schema.field), messages: messages })) + "\n\t\t")); | ||
} else { | ||
if (schema.strict) { | ||
src.push(("\n\t\t\t\tif (value !== " + (JSON.stringify(schema.value)) + ")\n\t\t\t")); | ||
} else { | ||
src.push(("\n\t\t\t\tif (value != " + (JSON.stringify(schema.value)) + ")\n\t\t\t")); | ||
} | ||
src.push(("\n\t\t\t\t" + (this.makeError({ type: "equalValue", actual: "value", expected: JSON.stringify(schema.value), messages: messages })) + "\n\t\t")); | ||
} | ||
return true; | ||
src.push("\n\t\treturn value;\n\t"); | ||
return { | ||
source: src.join("\n") | ||
}; | ||
}; | ||
var forbidden = function checkForbidden(value) { | ||
if (value !== null && value !== undefined) { | ||
return this.makeError("forbidden"); | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var forbidden = function checkForbidden(ref, path) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
var src = []; | ||
src.push("\n\t\tif (value !== null && value !== undefined) {\n\t"); | ||
if (schema.remove) { | ||
src.push("\n\t\t\treturn undefined;\n\t\t"); | ||
} else { | ||
src.push(("\n\t\t\t" + (this.makeError({ type: "forbidden", actual: "value", messages: messages })) + "\n\t\t")); | ||
} | ||
return true; | ||
src.push("\n\t\t}\n\t\treturn value;\n\t"); | ||
return { | ||
source: src.join("\n") | ||
}; | ||
}; | ||
var _function = function checkFunction(value) { | ||
if (typeof value !== "function") { | ||
return this.makeError("function"); | ||
} | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var _function = function(ref, path) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
return true; | ||
return { | ||
source: ("\n\t\t\tif (typeof value !== \"function\")\n\t\t\t\t" + (this.makeError({ type: "function", actual: "value", messages: messages })) + "\n\n\t\t\treturn value;\n\t\t") | ||
}; | ||
}; | ||
var number = function checkNumber(value, schema) { | ||
if (schema.convert === true && typeof value !== "number") { | ||
value = Number(value); | ||
} | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var multi = function(ref, path, context) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
if (typeof value !== "number") { | ||
return this.makeError("number"); | ||
var src = []; | ||
src.push("\n\t\tvar prevErrLen = errors.length;\n\t\tvar errBefore;\n\t\tvar hasValid = false;\n\t\tvar newVal = value;\n\t"); | ||
for (var i = 0; i < schema.rules.length; i++) { | ||
src.push("\n\t\t\tif (!hasValid) {\n\t\t\t\terrBefore = errors.length;\n\t\t"); | ||
var rule = this.getRuleFromSchema(schema.rules[i]); | ||
src.push(this.compileRule(rule, context, path, "var tmpVal = context.fn[%%INDEX%%](value, field, parent, errors, context);", "tmpVal")); | ||
src.push("\n\t\t\t\tif (errors.length == errBefore) {\n\t\t\t\t\thasValid = true;\n\t\t\t\t\tnewVal = tmpVal;\n\t\t\t\t}\n\t\t\t}\n\t\t"); | ||
} | ||
if (isNaN(value) || !isFinite(value)) { | ||
return this.makeError("number"); | ||
src.push("\n\t\tif (hasValid) {\n\t\t\terrors.length = prevErrLen;\n\t\t}\n\n\t\treturn newVal;\n\t"); | ||
return { | ||
source: src.join("\n") | ||
}; | ||
}; | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var number = function(ref, path) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
var src = []; | ||
src.push("\n\t\tvar origValue = value;\n\t"); | ||
var sanitized = false; | ||
if (schema.convert === true) { | ||
sanitized = true; | ||
src.push("\n\t\t\tif (typeof value !== \"number\") {\n\t\t\t\tvalue = Number(value);\n\t\t\t}\n\t\t"); | ||
} | ||
if (schema.min != null && value < schema.min) { | ||
return this.makeError("numberMin", schema.min, value); | ||
src.push(("\n\t\tif (typeof value !== \"number\" || isNaN(value) || !isFinite(value)) {\n\t\t\t" + (this.makeError({ type: "number", actual: "origValue", messages: messages })) + "\n\t\t\treturn value;\n\t\t}\n\t")); | ||
if (schema.min != null) { | ||
src.push(("\n\t\t\tif (value < " + (schema.min) + ") {\n\t\t\t\t" + (this.makeError({ type: "numberMin", expected: schema.min, actual: "origValue", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
if (schema.max != null && value > schema.max) { | ||
return this.makeError("numberMax", schema.max, value); | ||
if (schema.max != null) { | ||
src.push(("\n\t\t\tif (value > " + (schema.max) + ") {\n\t\t\t\t" + (this.makeError({ type: "numberMax", expected: schema.max, actual: "origValue", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
// Check fix value | ||
if (schema.equal != null && value !== schema.equal) { | ||
return this.makeError("numberEqual", schema.equal, value); | ||
} | ||
if (schema.equal != null) { | ||
src.push(("\n\t\t\tif (value !== " + (schema.equal) + ") {\n\t\t\t\t" + (this.makeError({ type: "numberEqual", expected: schema.equal, actual: "origValue", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
// Check not fix value | ||
if (schema.notEqual != null && value === schema.notEqual) { | ||
return this.makeError("numberNotEqual", schema.notEqual); | ||
} | ||
if (schema.notEqual != null) { | ||
src.push(("\n\t\t\tif (value === " + (schema.notEqual) + ") {\n\t\t\t\t" + (this.makeError({ type: "numberNotEqual", expected: schema.notEqual, actual: "origValue", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
// Check integer | ||
if (schema.integer === true && value % 1 !== 0) { | ||
return this.makeError("numberInteger", value); | ||
} | ||
if (schema.integer === true) { | ||
src.push(("\n\t\t\tif (value % 1 !== 0) {\n\t\t\t\t" + (this.makeError({ type: "numberInteger", actual: "origValue", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
// Check positive | ||
if (schema.positive === true && value <= 0) { | ||
return this.makeError("numberPositive", value); | ||
} | ||
if (schema.positive === true) { | ||
src.push(("\n\t\t\tif (value <= 0) {\n\t\t\t\t" + (this.makeError({ type: "numberPositive", actual: "origValue", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
// Check negative | ||
if (schema.negative === true && value >= 0) { | ||
return this.makeError("numberNegative", value); | ||
if (schema.negative === true) { | ||
src.push(("\n\t\t\tif (value >= 0) {\n\t\t\t\t" + (this.makeError({ type: "numberNegative", actual: "origValue", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
return true; | ||
src.push("\n\t\treturn value;\n\t"); | ||
return { | ||
sanitized: sanitized, | ||
source: src.join("\n") | ||
}; | ||
}; | ||
var object = function checkObject(value, schema) { | ||
if (typeof value !== "object" || value === null || Array.isArray(value)) { | ||
return this.makeError("object"); | ||
} | ||
// Quick regex to match most common unquoted JavaScript property names. Note the spec allows Unicode letters. | ||
// Unmatched property names will be quoted and validate slighly slower. https://www.ecma-international.org/ecma-262/5.1/#sec-7.6 | ||
var identifierRegex = /^[_$a-zA-Z][_$a-zA-Z0-9]*$/; | ||
if (schema.strict === true && schema.props) { | ||
var allowedProps = Object.keys(schema.props); | ||
var invalidProps = []; | ||
var props = Object.keys(value); | ||
// Regex to escape quoted property names for eval/new Function | ||
var escapeEvalRegex = /["'\\\n\r\u2028\u2029]/g; | ||
for (var i = 0; i < props.length; i++) { | ||
if (allowedProps.indexOf(props[i]) === -1) { | ||
invalidProps.push(props[i]); | ||
/* istanbul ignore next */ | ||
function escapeEvalString(str) { | ||
// Based on https://github.com/joliss/js-string-escape | ||
return str.replace(escapeEvalRegex, function(character) { | ||
switch (character) { | ||
case "\"": | ||
case "'": | ||
case "\\": | ||
return "\\" + character; | ||
// Four possible LineTerminator characters need to be escaped: | ||
case "\n": | ||
return "\\n"; | ||
case "\r": | ||
return "\\r"; | ||
case "\u2028": | ||
return "\\u2028"; | ||
case "\u2029": | ||
return "\\u2029"; | ||
} | ||
}); | ||
} | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var object = function(ref, path, context) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
var sourceCode = []; | ||
sourceCode.push(("\n\t\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n\t\t\t" + (this.makeError({ type: "object", actual: "value", messages: messages })) + "\n\t\t\treturn value;\n\t\t}\n\t")); | ||
var subSchema = schema.properties || schema.props; | ||
if (subSchema) { | ||
sourceCode.push("var parentObj = value;"); | ||
sourceCode.push("var parentField = field;"); | ||
var keys = Object.keys(subSchema); | ||
for (var i = 0; i < keys.length; i++) { | ||
var property = keys[i]; | ||
var name = escapeEvalString(property); | ||
var safeSubName = identifierRegex.test(name) ? ("." + name) : ("['" + name + "']"); | ||
var safePropName = "parentObj" + safeSubName; | ||
var newPath = (path ? path + "." : "") + property; | ||
sourceCode.push(("\n// Field: " + (escapeEvalString(newPath)))); | ||
sourceCode.push(("field = parentField ? parentField + \"" + safeSubName + "\" : \"" + name + "\";")); | ||
sourceCode.push(("value = " + safePropName + ";")); | ||
var rule = this.getRuleFromSchema(subSchema[property]); | ||
sourceCode.push(this.compileRule(rule, context, newPath, (safePropName + " = context.fn[%%INDEX%%](value, field, parentObj, errors, context);"), safePropName)); | ||
} | ||
// Strict handler | ||
if (schema.strict) { | ||
var allowedProps = Object.keys(subSchema); | ||
sourceCode.push(("\n\t\t\t\tfield = parentField;\n\t\t\t\tvar invalidProps = [];\n\t\t\t\tvar props = Object.keys(parentObj);\n\n\t\t\t\tfor (let i = 0; i < props.length; i++) {\n\t\t\t\t\tif (" + (JSON.stringify(allowedProps)) + ".indexOf(props[i]) === -1) {\n\t\t\t\t\t\tinvalidProps.push(props[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (invalidProps.length) {\n\t\t\t")); | ||
if (schema.strict == "remove") { | ||
sourceCode.push("\n\t\t\t\t\tinvalidProps.forEach(function(field) {\n\t\t\t\t\t\tdelete parentObj[field];\n\t\t\t\t\t});\n\t\t\t\t"); | ||
} else { | ||
sourceCode.push(("\n\t\t\t\t\t" + (this.makeError({ type: "objectStrict", expected: "\"" + allowedProps.join(", ") + "\"", actual: "invalidProps.join(', ')", messages: messages })) + "\n\t\t\t\t")); | ||
} | ||
sourceCode.push("\n\t\t\t\t}\n\t\t\t"); | ||
} | ||
if (invalidProps.length !== 0) { | ||
return this.makeError("objectStrict", undefined, invalidProps.join(", ")); | ||
} | ||
sourceCode.push("\n\t\t\treturn parentObj;\n\t\t"); | ||
} else { | ||
sourceCode.push("\n\t\t\treturn value;\n\t\t"); | ||
} | ||
return true; | ||
return { | ||
source: sourceCode.join("\n") | ||
}; | ||
}; | ||
@@ -313,56 +499,122 @@ | ||
var string = function checkString(value, schema) { | ||
if (typeof value !== "string") { | ||
return this.makeError("string"); | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var string = function checkString(ref, path, context) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
var src = []; | ||
var sanitized = false; | ||
if (schema.convert === true) { | ||
sanitized = true; | ||
src.push("\n\t\t\tif (typeof value !== \"string\") {\n\t\t\t\tvalue = String(value);\n\t\t\t}\n\t\t"); | ||
} | ||
var valueLength = value.length; | ||
src.push(("\n\t\tif (typeof value !== \"string\") {\n\t\t\t" + (this.makeError({ type: "string", actual: "value", messages: messages })) + "\n\t\t\treturn value;\n\t\t}\n\n\t\tvar origValue = value;\n\t")); | ||
if (schema.empty === false && valueLength === 0) { | ||
return this.makeError("stringEmpty"); | ||
if (schema.trim) { | ||
sanitized = true; | ||
src.push("\n\t\t\tvalue = value.trim();\n\t\t"); | ||
} | ||
if (schema.min != null && valueLength < schema.min) { | ||
return this.makeError("stringMin", schema.min, valueLength); | ||
if (schema.trimLeft) { | ||
sanitized = true; | ||
src.push("\n\t\t\tvalue = value.trimLeft();\n\t\t"); | ||
} | ||
if (schema.max != null && valueLength > schema.max) { | ||
return this.makeError("stringMax", schema.max, valueLength); | ||
if (schema.trimRight) { | ||
sanitized = true; | ||
src.push("\n\t\t\tvalue = value.trimRight();\n\t\t"); | ||
} | ||
if (schema.length != null && valueLength !== schema.length) { | ||
return this.makeError("stringLength", schema.length, valueLength); | ||
if (schema.padStart) { | ||
sanitized = true; | ||
var padChar = schema.padChar != null ? schema.padChar : " "; | ||
src.push(("\n\t\t\tvalue = value.padStart(" + (schema.padStart) + ", " + (JSON.stringify(padChar)) + ");\n\t\t")); | ||
} | ||
if (schema.padEnd) { | ||
sanitized = true; | ||
var padChar$1 = schema.padChar != null ? schema.padChar : " "; | ||
src.push(("\n\t\t\tvalue = value.padEnd(" + (schema.padEnd) + ", " + (JSON.stringify(padChar$1)) + ");\n\t\t")); | ||
} | ||
if (schema.lowercase) { | ||
sanitized = true; | ||
src.push("\n\t\t\tvalue = value.toLowerCase();\n\t\t"); | ||
} | ||
if (schema.uppercase) { | ||
sanitized = true; | ||
src.push("\n\t\t\tvalue = value.toUpperCase();\n\t\t"); | ||
} | ||
if (schema.localeLowercase) { | ||
sanitized = true; | ||
src.push("\n\t\t\tvalue = value.toLocaleLowerCase();\n\t\t"); | ||
} | ||
if (schema.localeUppercase) { | ||
sanitized = true; | ||
src.push("\n\t\t\tvalue = value.toLocaleUpperCase();\n\t\t"); | ||
} | ||
src.push("\n\t\t\tvar len = value.length;\n\t"); | ||
if (schema.empty === false) { | ||
src.push(("\n\t\t\tif (len === 0) {\n\t\t\t\t" + (this.makeError({ type: "stringEmpty", actual: "value", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
if (schema.min != null) { | ||
src.push(("\n\t\t\tif (len < " + (schema.min) + ") {\n\t\t\t\t" + (this.makeError({ type: "stringMin", expected: schema.min, actual: "len", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
if (schema.max != null) { | ||
src.push(("\n\t\t\tif (len > " + (schema.max) + ") {\n\t\t\t\t" + (this.makeError({ type: "stringMax", expected: schema.max, actual: "len", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
if (schema.length != null) { | ||
src.push(("\n\t\t\tif (len !== " + (schema.length) + ") {\n\t\t\t\t" + (this.makeError({ type: "stringLength", expected: schema.length, actual: "len", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
if (schema.pattern != null) { | ||
var pattern = typeof schema.pattern == "string" ? new RegExp(schema.pattern, schema.patternFlags) : schema.pattern; | ||
if (!pattern.test(value)) | ||
{ return this.makeError("stringPattern", pattern, value); } | ||
var pattern = schema.pattern; | ||
if (typeof schema.pattern == "string") | ||
{ pattern = new RegExp(schema.pattern, schema.patternFlags); } | ||
src.push(("\n\t\t\tif (!" + (pattern.toString()) + ".test(value))\n\t\t\t\t" + (this.makeError({ type: "stringPattern", expected: "\"" + pattern.toString() + "\"", actual: "origValue", messages: messages })) + "\n\t\t")); | ||
} | ||
if (schema.contains != null && value.indexOf(schema.contains) === -1) { | ||
return this.makeError("stringContains", schema.contains, value); | ||
if (schema.contains != null) { | ||
src.push(("\n\t\t\tif (value.indexOf(\"" + (schema.contains) + "\") === -1) {\n\t\t\t\t" + (this.makeError({ type: "stringContains", expected: "\"" + schema.contains + "\"", actual: "origValue", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
if (schema.enum != null && schema.enum.indexOf(value) === -1) { | ||
return this.makeError("stringEnum", schema.enum, value); | ||
if (schema.enum != null) { | ||
var enumStr = JSON.stringify(schema.enum); | ||
src.push(("\n\t\t\tif (" + enumStr + ".indexOf(value) === -1) {\n\t\t\t\t" + (this.makeError({ type: "stringEnum", expected: "\"" + schema.enum.join(", ") + "\"", actual: "origValue", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
if (schema.numeric === true && !NUMERIC_PATTERN.test(value) ) { | ||
return this.makeError("stringNumeric", "A numeric string", value); | ||
if (schema.numeric === true) { | ||
src.push(("\n\t\t\tif (!" + (NUMERIC_PATTERN.toString()) + ".test(value) ) {\n\t\t\t\t" + (this.makeError({ type: "stringNumeric", actual: "origValue", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
if(schema.alpha === true && !ALPHA_PATTERN.test(value)) { | ||
return this.makeError("stringAlpha", "An alphabetic string", value); | ||
if(schema.alpha === true) { | ||
src.push(("\n\t\t\tif(!" + (ALPHA_PATTERN.toString()) + ".test(value)) {\n\t\t\t\t" + (this.makeError({ type: "stringAlpha", actual: "origValue", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
if(schema.alphanum === true && !ALPHANUM_PATTERN.test(value)) { | ||
return this.makeError("stringAlphanum", "An alphanumeric string", value); | ||
if(schema.alphanum === true) { | ||
src.push(("\n\t\t\tif(!" + (ALPHANUM_PATTERN.toString()) + ".test(value)) {\n\t\t\t\t" + (this.makeError({ type: "stringAlphanum", actual: "origValue", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
if(schema.alphadash === true && !ALPHADASH_PATTERN.test(value)) { | ||
return this.makeError("stringAlphadash", "An alphadash string", value); | ||
if(schema.alphadash === true) { | ||
src.push(("\n\t\t\tif(!" + (ALPHADASH_PATTERN.toString()) + ".test(value)) {\n\t\t\t\t" + (this.makeError({ type: "stringAlphadash", actual: "origValue", messages: messages })) + "\n\t\t\t}\n\t\t")); | ||
} | ||
return true; | ||
src.push("\n\t\treturn value;\n\t"); | ||
return { | ||
sanitized: sanitized, | ||
source: src.join("\n") | ||
}; | ||
}; | ||
@@ -374,12 +626,14 @@ | ||
var url = function checkUrl(value) { | ||
if (typeof value !== "string") { | ||
return this.makeError("string"); | ||
} | ||
if (!PATTERN.test(value)) { | ||
return this.makeError("url"); | ||
} | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var url = function(ref, path) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
return true; | ||
var src = []; | ||
src.push(("\n\t\tif (typeof value !== \"string\") {\n\t\t\t" + (this.makeError({ type: "string", actual: "value", messages: messages })) + "\n\t\t\treturn value;\n\t\t}\n\n\t\tif (!" + (PATTERN.toString()) + ".test(value)) {\n\t\t\t" + (this.makeError({ type: "url", actual: "value", messages: messages })) + "\n\t\t}\n\n\t\treturn value;\n\t")); | ||
return { | ||
source: src.join("\n") | ||
}; | ||
}; | ||
@@ -389,23 +643,20 @@ | ||
var uuid = function checkUUID(value, schema) { | ||
if (typeof value !== "string") | ||
{ return this.makeError("string"); } | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var uuid = function(ref, path) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
value = value.toLowerCase(); | ||
if (!PATTERN$1.test(value)) | ||
{ return this.makeError("uuid"); } | ||
var src = []; | ||
src.push(("\n\t\tif (typeof value !== \"string\") {\n\t\t\t" + (this.makeError({ type: "string", actual: "value", messages: messages })) + "\n\t\t\treturn value;\n\t\t}\n\n\t\tvar val = value.toLowerCase();\n\t\tif (!" + (PATTERN$1.toString()) + ".test(val)) {\n\t\t\t" + (this.makeError({ type: "uuid", actual: "value", messages: messages })) + "\n\t\t\treturn value;\n\t\t}\n\n\t\tconst version = val.charAt(14) | 0;\n\t")); | ||
var version = value.charAt(14)|0; | ||
if(schema.version && schema.version !== version) | ||
{ return this.makeError("uuidVersion", schema.version, version); } | ||
if(schema.version) { | ||
src.push(("\n\t\t\tif (" + (schema.version) + " !== version) {\n\t\t\t\t" + (this.makeError({ type: "uuidVersion", expected: schema.version, actual: "version", messages: messages })) + "\n\t\t\t\treturn value;\n\t\t\t}\n\t\t")); | ||
} | ||
switch (version) { | ||
case 1: | ||
case 2: | ||
return true; | ||
case 3: | ||
case 4: | ||
case 5: | ||
return ["8", "9", "a", "b"].indexOf(value.charAt(19)) !== -1 || this.makeError("uuid"); | ||
} | ||
src.push(("\n\t\tswitch (version) {\n\t\tcase 1:\n\t\tcase 2:\n\t\t\tbreak;\n\t\tcase 3:\n\t\tcase 4:\n\t\tcase 5:\n\t\t\tif ([\"8\", \"9\", \"a\", \"b\"].indexOf(value.charAt(19)) === -1) {\n\t\t\t\t" + (this.makeError({ type: "uuid", actual: "value", messages: messages })) + "\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t")); | ||
return { | ||
source: src.join("\n") | ||
}; | ||
}; | ||
@@ -415,11 +666,11 @@ | ||
var mac = function checkMAC(value, schema) { | ||
if (typeof value !== "string") | ||
{ return this.makeError("string"); } | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var mac = function(ref, path) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
value = value.toLowerCase(); | ||
if (!PATTERN$2.test(value)) | ||
{ return this.makeError("mac"); } | ||
return true; | ||
return { | ||
source: ("\n\t\t\tif (typeof value !== \"string\") {\n\t\t\t\t" + (this.makeError({ type: "string", actual: "value", messages: messages })) + "\n\t\t\t\treturn value;\n\t\t\t}\n\n\t\t\tvar v = value.toLowerCase();\n\t\t\tif (!" + (PATTERN$2.toString()) + ".test(v)) {\n\t\t\t\t" + (this.makeError({ type: "mac", actual: "value", messages: messages })) + "\n\t\t\t}\n\n\t\t\treturn value;\n\t\t") | ||
}; | ||
}; | ||
@@ -433,28 +684,65 @@ | ||
* @return {boolean|{actual, expected, type}|ValidationError} | ||
* | ||
* Signature: function(value, field, parent, errors, context) | ||
*/ | ||
var luhn = function checkLuhn(value, schema) { | ||
var luhn = function(ref, path) { | ||
var schema = ref.schema; | ||
var messages = ref.messages; | ||
if(typeof value !== "number" && typeof value !== "string") | ||
{ return this.makeError("string"); } | ||
return { | ||
source: ("\n\t\t\tif (typeof value !== \"string\") {\n\t\t\t\t" + (this.makeError({ type: "string", actual: "value", messages: messages })) + "\n\t\t\t\treturn value;\n\t\t\t}\n\n\t\t\tif (typeof value !== \"string\")\n\t\t\t\tvalue = String(value);\n\n\t\t\tval = value.replace(/\\D+/g, \"\");\n\n\t\t\tvar array = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9];\n\t\t\tvar len = val ? val.length : 0,\n\t\t\t\tbit = 1,\n\t\t\t\tsum = 0;\n\t\t\twhile (len--) {\n\t\t\t\tsum += !(bit ^= 1) ? parseInt(val[len], 10) : array[val[len]];\n\t\t\t}\n\n\t\t\tif (!(sum % 10 === 0 && sum > 0)) {\n\t\t\t\t" + (this.makeError({ type: "luhn", actual: "value", messages: messages })) + "\n\t\t\t}\n\n\t\t\treturn value;\n\t\t") | ||
}; | ||
}; | ||
if (typeof value !== "string") | ||
{ value = String(value); } | ||
function commonjsRequire () { | ||
throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs'); | ||
} | ||
value = value.replace(/\D+/g, ""); | ||
// globals window | ||
var prettier, prettierOpts; | ||
var hljs, hljsOpts; | ||
var check = function (array) { | ||
return function (number) { | ||
var len = number ? number.length : 0, | ||
bit = 1, | ||
sum = 0; | ||
while (len--) { | ||
sum += !(bit ^= 1) ? parseInt(number[len], 10) : array[number[len]]; | ||
} | ||
return sum % 10 === 0 && sum > 0; | ||
var prettier_1 = function(source) { | ||
if (!prettier) { | ||
prettier = commonjsRequire(); | ||
prettierOpts = { | ||
parser: "babel", | ||
useTabs: false, | ||
printWidth: 120, | ||
trailingComma: "none", | ||
tabWidth: 4, | ||
singleQuote: false, | ||
semi: true, | ||
bracketSpacing: true | ||
}; | ||
}([0, 2, 4, 6, 8, 1, 3, 5, 7, 9]); | ||
return check(value) || this.makeError("luhn"); | ||
hljs = commonjsRequire(); | ||
hljsOpts = { | ||
language: "js", | ||
theme: hljs.fromJson({ | ||
keyword: ["white", "bold"], | ||
built_in: "magenta", | ||
literal: "cyan", | ||
number: "magenta", | ||
regexp: "red", | ||
string: ["yellow", "bold"], | ||
symbol: "plain", | ||
class: "blue", | ||
attr: "plain", | ||
function: ["white", "bold"], | ||
title: "plain", | ||
params: "green", | ||
comment: "grey" | ||
}) | ||
}; | ||
} | ||
var res = prettier.format(source, prettierOpts); | ||
return hljs.highlight(res, hljsOpts); | ||
}; | ||
//const flatten = require("./helpers/flatten"); | ||
function loadRules() { | ||
@@ -469,4 +757,6 @@ return { | ||
enum: _enum, | ||
equal: equal, | ||
forbidden: forbidden, | ||
function: _function, | ||
multi: multi, | ||
number: number, | ||
@@ -482,36 +772,6 @@ object: object, | ||
// Quick regex to match most common unquoted JavaScript property names. Note the spec allows Unicode letters. | ||
// Unmatched property names will be quoted and validate slighly slower. https://www.ecma-international.org/ecma-262/5.1/#sec-7.6 | ||
var identifierRegex = /^[_$a-zA-Z][_$a-zA-Z0-9]*$/; | ||
// Regex to escape quoted property names for eval/new Function | ||
var escapeEvalRegex = /["'\\\n\r\u2028\u2029]/g; | ||
function escapeEvalString(str) { | ||
// Based on https://github.com/joliss/js-string-escape | ||
return str.replace(escapeEvalRegex, function(character) { | ||
switch (character) { | ||
case "\"": | ||
case "'": | ||
case "\\": | ||
return "\\" + character; | ||
// Four possible LineTerminator characters need to be escaped: | ||
case "\n": | ||
return "\\n"; | ||
case "\r": | ||
return "\\r"; | ||
case "\u2028": | ||
return "\\u2028"; | ||
case "\u2029": | ||
return "\\u2029"; | ||
} | ||
}); | ||
} | ||
/** | ||
* Validator class constructor | ||
* | ||
* @param {Object} opts | ||
* Fastest Validator | ||
*/ | ||
function Validator(opts) { | ||
var Validator = function Validator(opts) { | ||
this.opts = { | ||
@@ -525,3 +785,2 @@ messages: deepExtend_1({}, messages) | ||
this.messages = this.opts.messages; | ||
this.messageKeys = Object.keys(this.messages); | ||
@@ -531,11 +790,12 @@ // Load rules | ||
this.cache = new Map(); | ||
} | ||
}; | ||
/** | ||
* Validate an object by schema | ||
* | ||
* @param {Object} obj | ||
* @param {Object} schema | ||
*/ | ||
Validator.prototype.validate = function(obj, schema) { | ||
* Validate an object by schema | ||
* | ||
* @param {Object} obj | ||
* @param {Object} schema | ||
* @returns {Array<Object>|boolean} | ||
*/ | ||
Validator.prototype.validate = function validate (obj, schema) { | ||
var check = this.compile(schema); | ||
@@ -546,332 +806,243 @@ return check(obj); | ||
/** | ||
* Compile a schema | ||
* | ||
* @param {Object} schema | ||
* @throws {Error} Invalid schema | ||
*/ | ||
Validator.prototype.compile = function(schema) { | ||
var self = this; | ||
if (Array.isArray(schema)) { | ||
// Multiple schemas | ||
if (schema.length == 0) { | ||
throw new Error("If the schema is an Array, must contain at least one element!"); | ||
* Wrap a source code with `required` & `optional` checker codes. | ||
* @param {Object} rule | ||
* @param {String} innerSrc | ||
* @param {String?} resVar | ||
* @returns {String} | ||
*/ | ||
Validator.prototype.wrapRequiredCheckSourceCode = function wrapRequiredCheckSourceCode (rule, innerSrc, resVar) { | ||
var src = []; | ||
var defaultValue = rule.schema.default != null ? JSON.stringify(rule.schema.default) : null; | ||
// Required, optional, forbidden | ||
src.push("\n\t\t\tif (value === undefined || value === null) {\n\t\t"); | ||
if (rule.schema.optional === true || rule.schema.type == "forbidden") { | ||
// Optional field | ||
if (defaultValue != null && resVar) { | ||
src.push((resVar + " = " + defaultValue + ";")); | ||
} else { | ||
src.push("// Do nothing, it's an optional field"); | ||
} | ||
var rules = this.compileSchemaType(schema); | ||
this.cache.clear(); | ||
return function(value, path, parent) { | ||
return self.checkSchemaType(value, rules, path, parent || null); | ||
}; | ||
} | ||
var rule = this.compileSchemaObject(schema); | ||
this.cache.clear(); | ||
return function(value, path, parent) { | ||
return self.checkSchemaObject(value, rule, path, parent || null); | ||
}; | ||
}; | ||
Validator.prototype.compileSchemaObject = function(schemaObject) { | ||
var this$1 = this; | ||
if (schemaObject === null || typeof schemaObject !== "object" || Array.isArray(schemaObject)) { | ||
throw new Error("Invalid schema!"); | ||
} | ||
var compiledObject = this.cache.get(schemaObject); | ||
if (compiledObject) { | ||
compiledObject.cycle = true; | ||
return compiledObject; | ||
} else { | ||
compiledObject = { cycle: false, properties: null, compiledObjectFunction: null, objectStack: [] }; | ||
this.cache.set(schemaObject, compiledObject); | ||
} | ||
compiledObject.properties = Object.keys(schemaObject) | ||
.filter(function (name) { | ||
return name !== "$$strict"; | ||
}) | ||
.map(function (name) { | ||
var compiledType = this$1.compileSchemaType(schemaObject[name]); | ||
return { name: name, compiledType: compiledType }; | ||
}); | ||
var sourceCode = []; | ||
sourceCode.push("let res;"); | ||
sourceCode.push("let propertyPath;"); | ||
sourceCode.push("const errors = [];"); | ||
if (schemaObject.$$strict === true) { | ||
sourceCode.push("const givenProps = new Map(Object.keys(value).map(key => [key, true]));"); | ||
} | ||
for (var i = 0; i < compiledObject.properties.length; i++) { | ||
var property = compiledObject.properties[i]; | ||
var name = escapeEvalString(property.name); | ||
var propertyValueExpr = identifierRegex.test(name) ? ("value." + name) : ("value[\"" + name + "\"]"); | ||
sourceCode.push(("propertyPath = (path !== undefined ? path + \"." + name + "\" : \"" + name + "\");")); | ||
if (Array.isArray(property.compiledType)) { | ||
sourceCode.push(("res = this.checkSchemaType(" + propertyValueExpr + ", properties[" + i + "].compiledType, propertyPath, value);")); | ||
// Required field | ||
if (defaultValue != null && resVar) { | ||
src.push((resVar + " = " + defaultValue + ";")); | ||
} else { | ||
sourceCode.push(("res = this.checkSchemaRule(" + propertyValueExpr + ", properties[" + i + "].compiledType, propertyPath, value);")); | ||
src.push(this.makeError({ type: "required", actual: "value", messages: rule.messages })); | ||
} | ||
sourceCode.push("if (res !== true) {"); | ||
sourceCode.push(("\tthis.handleResult(errors, propertyPath, res, properties[" + i + "].compiledType.messages);")); | ||
sourceCode.push("}"); | ||
if (schemaObject.$$strict === true) { | ||
sourceCode.push(("givenProps.delete(\"" + name + "\");")); | ||
} | ||
} | ||
src.push("} else {"); | ||
if (schemaObject.$$strict === true) { | ||
sourceCode.push("if (givenProps.size !== 0) {"); | ||
sourceCode.push("\tthis.handleResult(errors, path || 'rootObject', this.makeError('objectStrict', undefined, [...givenProps.keys()].join(', ')), this.messages);"); | ||
sourceCode.push("}"); | ||
} | ||
if (innerSrc) | ||
{ src.push(innerSrc); } | ||
sourceCode.push("return errors.length === 0 ? true : errors;"); | ||
src.push("\t\t}"); // Required, optional | ||
compiledObject.compiledObjectFunction = new Function("value", "properties", "path", "parent", sourceCode.join("\n")); | ||
return compiledObject; | ||
return src.join("\n"); | ||
}; | ||
Validator.prototype.compileSchemaType = function(schemaType) { | ||
var this$1 = this; | ||
/** | ||
* Compile a schema | ||
* | ||
* @param {Object} schema | ||
* @throws {Error} Invalid schema | ||
* @returns {Function} | ||
*/ | ||
Validator.prototype.compile = function compile (schema) { | ||
if (schema === null || typeof schema !== "object") { | ||
throw new Error("Invalid schema."); | ||
} | ||
var self = this; | ||
var context = { | ||
index: 0, | ||
rules: [], | ||
fn: [], | ||
customs: {} | ||
}; | ||
this.cache.clear(); | ||
if (Array.isArray(schemaType)) { | ||
if (schema.$$root !== true) { | ||
if (Array.isArray(schema)) { | ||
var rule$1 = this.getRuleFromSchema(schema); | ||
schema = rule$1.schema; | ||
} else { | ||
var prevSchema = Object.assign({}, schema); | ||
schema = { | ||
type: "object", | ||
strict: prevSchema.$$strict, | ||
properties: prevSchema | ||
}; | ||
// Multiple rules, flatten to array of compiled SchemaRule | ||
var rules = flatten_1(schemaType.map(function (r) { return this$1.compileSchemaType(r); })); | ||
if (rules.length == 1) { | ||
return rules[0]; | ||
delete prevSchema.$$strict; | ||
} | ||
return rules; | ||
} | ||
return this.compileSchemaRule(schemaType); | ||
var sourceCode = [ | ||
"var errors = [];", | ||
"var field;" ]; | ||
}; | ||
var rule = this.getRuleFromSchema(schema); | ||
sourceCode.push(this.compileRule(rule, context, null, "context.fn[%%INDEX%%](value, field, null, errors, context);", "value")); | ||
Validator.prototype.compileMessages = function(schemaType) { | ||
if (schemaType.messages) | ||
{ return Object.assign({}, this.messages, schemaType.messages); } | ||
sourceCode.push("if (errors.length) {"); | ||
sourceCode.push("\n\t\t\treturn errors.map(err => {\n\t\t\t\tif (err.message)\n\t\t\t\t\terr.message = err.message\n\t\t\t\t\t\t.replace(/\\{field\\}/g, err.field || \"\")\n\t\t\t\t\t\t.replace(/\\{expected\\}/g, err.expected != null ? err.expected : \"\")\n\t\t\t\t\t\t.replace(/\\{actual\\}/g, err.actual != null ? err.actual : \"\");\n\n\t\t\t\treturn err;\n\t\t\t});\n\t\t"); | ||
return this.messages; | ||
}; | ||
sourceCode.push("}"); | ||
sourceCode.push("return true;"); | ||
Validator.prototype.compileSchemaRule = function(schemaRule) { | ||
var src = sourceCode.join("\n"); | ||
if (typeof schemaRule === "string") { | ||
schemaRule = { | ||
type: schemaRule | ||
}; | ||
} | ||
var checkFn = new Function("value", "context", src); | ||
var ruleFunction = this.rules[schemaRule.type]; | ||
/* istanbul ignore next */ | ||
if (this.opts.debug) { | ||
var formatter = function(code) { return code; }; | ||
if (typeof window === "undefined") // eslint-disable-line no-undef | ||
{ formatter = prettier_1; } | ||
if (!ruleFunction) { | ||
throw new Error("Invalid '" + schemaRule.type + "' type in validator schema!"); | ||
context.fn.forEach(function (fn, i) { return console.log(formatter("// Context.fn[" + i + "]\n" + fn.toString())); }); // eslint-disable-line no-console | ||
console.log(formatter("// Main check function\n" + checkFn.toString())); // eslint-disable-line no-console | ||
} | ||
var messages = this.compileMessages(schemaRule); | ||
this.cache.clear(); | ||
var dataParameter = null; | ||
var dataFunction = null; | ||
if (schemaRule.type === "object" && schemaRule.props) { | ||
dataParameter = this.compileSchemaObject(schemaRule.props); | ||
dataFunction = this.checkSchemaObject; | ||
} else if (schemaRule.type === "array" && schemaRule.items) { | ||
dataParameter = this.compileSchemaType(schemaRule.items); | ||
dataFunction = this.checkSchemaArray; | ||
} | ||
return { | ||
messages: messages, | ||
schemaRule: schemaRule, | ||
ruleFunction: ruleFunction, | ||
dataFunction: dataFunction, | ||
dataParameter: dataParameter | ||
return function(data) { | ||
context.data = data; | ||
return checkFn.call(self, data, context); | ||
}; | ||
}; | ||
Validator.prototype.checkSchemaObject = function(value, compiledObject, path, parent) { | ||
if (compiledObject.cycle) { | ||
if (compiledObject.objectStack.indexOf(value) !== -1) { | ||
return true; | ||
} | ||
/** | ||
* Compile a rule to source code. | ||
* @param {Object} rule | ||
* @param {Object} context | ||
* @param {String} path | ||
* @param {String} innerSrc | ||
* @param {String} resVar | ||
* @returns {String} | ||
*/ | ||
Validator.prototype.compileRule = function compileRule (rule, context, path, innerSrc, resVar) { | ||
var sourceCode = []; | ||
compiledObject.objectStack.push(value); | ||
var result = this.checkSchemaObjectInner(value, compiledObject, path, parent); | ||
compiledObject.objectStack.pop(); | ||
return result; | ||
var item = this.cache.get(rule.schema); | ||
if (item) { | ||
// Handle cyclic schema | ||
rule = item; | ||
rule.cycle = true; | ||
rule.cycleStack = []; | ||
sourceCode.push(this.wrapRequiredCheckSourceCode(rule, ("\n\t\t\t\tvar rule = context.rules[" + (rule.index) + "];\n\t\t\t\tif (rule.cycleStack.indexOf(value) === -1) {\n\t\t\t\t\trule.cycleStack.push(value);\n\t\t\t\t\t" + (innerSrc.replace("%%INDEX%%", rule.index)) + "\n\t\t\t\t\trule.cycleStack.pop(value);\n\t\t\t\t}\n\t\t\t"), resVar)); | ||
} else { | ||
return this.checkSchemaObjectInner(value, compiledObject, path, parent); | ||
this.cache.set(rule.schema, rule); | ||
rule.index = context.index; | ||
context.rules[context.index] = rule; | ||
context.index++; | ||
var res = rule.ruleFunction.call(this, rule, path, context); | ||
if (res.source) { | ||
var fn = new Function("value", "field", "parent", "errors", "context", res.source); | ||
context.fn[rule.index] = fn; | ||
sourceCode.push(this.wrapRequiredCheckSourceCode(rule, innerSrc.replace("%%INDEX%%", rule.index), resVar)); | ||
} else { | ||
sourceCode.push(this.wrapRequiredCheckSourceCode(rule)); | ||
} | ||
} | ||
}; | ||
Validator.prototype.checkSchemaObjectInner = function(value, compiledObject, path, parent) { | ||
return compiledObject.compiledObjectFunction.call(this, value, compiledObject.properties, path, parent); | ||
/* | ||
// Reference implementation of the object checker | ||
const errors = []; | ||
const propertiesLength = compiledObject.properties.length; | ||
for (let i = 0; i < propertiesLength; i++) { | ||
const property = compiledObject.properties[i]; | ||
const propertyPath = (path !== undefined ? path + "." : "") + property.name; | ||
const res = this.checkSchemaType(value[property.name], property.compiledType, propertyPath, value); | ||
if (res !== true) { | ||
this.handleResult(errors, propertyPath, res); | ||
} | ||
} | ||
return errors.length === 0 ? true : errors; | ||
*/ | ||
return sourceCode.join("\n"); | ||
}; | ||
Validator.prototype.checkSchemaType = function(value, compiledType, path, parent) { | ||
if (Array.isArray(compiledType)) { | ||
var errors = []; | ||
var checksLength = compiledType.length; | ||
for (var i = 0; i < checksLength; i++) { | ||
// Always compiled to list of rules | ||
var res = this.checkSchemaRule(value, compiledType[i], path, parent); | ||
if (res !== true) { | ||
this.handleResult(errors, path, res, compiledType.messages); | ||
/** | ||
* Create a rule instance from schema definition. | ||
* @param {Object} schema | ||
* @returns {Object} rule | ||
*/ | ||
Validator.prototype.getRuleFromSchema = function getRuleFromSchema (schema) { | ||
if (typeof schema === "string") { | ||
var str = schema; | ||
var p = str.split("|").map(function (s) { return s.trim(); }); | ||
schema = { | ||
type: p[0] | ||
}; | ||
p.slice(1).map(function (s) { | ||
var idx = s.indexOf(":"); | ||
if (idx !== -1) { | ||
var key = s.substr(0, idx).trim(); | ||
var value = s.substr(idx + 1).trim(); | ||
if (value === "true" || value === "false") | ||
{ value = value === "true"; } | ||
else if (!Number.isNaN(Number(value))) { | ||
value = Number(value); | ||
} | ||
schema[key] = value; | ||
} else { | ||
// Jump out after first success and clear previous errors | ||
return true; | ||
// boolean value | ||
if (s.startsWith("no-")) | ||
{ schema[s.slice(3)] = false; } | ||
else | ||
{ schema[s] = true; } | ||
} | ||
} | ||
}); | ||
return errors; | ||
} | ||
} else if (Array.isArray(schema)) { | ||
if (schema.length == 0) | ||
{ throw new Error("Invalid schema."); } | ||
return this.checkSchemaRule(value, compiledType, path, parent); | ||
}; | ||
Validator.prototype.checkSchemaArray = function(value, compiledArray, path, parent) { | ||
var errors = []; | ||
var valueLength = value.length; | ||
for (var i = 0; i < valueLength; i++) { | ||
var itemPath = (path !== undefined ? path : "") + "[" + i + "]"; | ||
var res = this.checkSchemaType(value[i], compiledArray, itemPath, value, parent); | ||
if (res !== true) { | ||
this.handleResult(errors, itemPath, res, compiledArray.messages); | ||
} | ||
schema = { | ||
type: "multi", | ||
rules: schema | ||
}; | ||
} | ||
return errors.length === 0 ? true : errors; | ||
}; | ||
var ruleFunction = this.rules[schema.type]; | ||
if (!ruleFunction) | ||
{ throw new Error("Invalid '" + schema.type + "' type in validator schema."); } | ||
Validator.prototype.checkSchemaRule = function(value, compiledRule, path, parent) { | ||
var schemaRule = compiledRule.schemaRule; | ||
var rule = { | ||
messages: Object.assign({}, this.messages, schema.messages), | ||
schema: schema, | ||
ruleFunction: ruleFunction | ||
}; | ||
if (value === undefined || value === null) { | ||
if (schemaRule.type === "forbidden") | ||
{ return true; } | ||
if (schemaRule.optional === true) | ||
{ return true; } | ||
var errors = []; | ||
this.handleResult(errors, path, this.makeError("required"), compiledRule.messages); | ||
return errors; | ||
} | ||
var res = compiledRule.ruleFunction.call(this, value, schemaRule, path, parent); | ||
if (res !== true) { | ||
var errors$1 = []; | ||
this.handleResult(errors$1, path, res, compiledRule.messages); | ||
return errors$1; | ||
} | ||
if (compiledRule.dataFunction !== null) { | ||
return compiledRule.dataFunction.call(this, value, compiledRule.dataParameter, path, parent); | ||
} | ||
return true; | ||
return rule; | ||
}; | ||
/** | ||
* Handle results from validator functions | ||
* | ||
* @param {Array} errors | ||
* @param {String} fieldPath | ||
* @param {Array|Object} res | ||
*/ | ||
Validator.prototype.handleResult = function(errors, fieldPath, res, messages) { | ||
var this$1 = this; | ||
* Generate error source code. | ||
* @param {Object} opts | ||
* @param {String} opts.type | ||
* @param {String} opts.field | ||
* @param {any} opts.expected | ||
* @param {any} opts.actual | ||
* @param {Object} opts.messages | ||
*/ | ||
Validator.prototype.makeError = function makeError (ref) { | ||
var type = ref.type; | ||
var field = ref.field; | ||
var expected = ref.expected; | ||
var actual = ref.actual; | ||
var messages = ref.messages; | ||
var items; | ||
if (!Array.isArray(res)) | ||
{ items = [res]; } | ||
else | ||
{ items = res; } | ||
items.forEach(function (err) { | ||
if (!err.field) | ||
{ err.field = fieldPath; } | ||
if (!err.message) | ||
{ err.message = this$1.resolveMessage(err, messages[err.type]); } | ||
errors.push(err); | ||
}); | ||
}; | ||
/** | ||
* Create a validation error object | ||
* | ||
* @param {String} type | ||
* @param {Any} expected | ||
* @param {Any} actual | ||
*/ | ||
Validator.prototype.makeError = function(type, expected, actual) { | ||
return { | ||
type: type, | ||
expected: expected, | ||
actual: actual | ||
var o = { | ||
type: ("\"" + type + "\""), | ||
message: ("\"" + (messages[type]) + "\""), | ||
}; | ||
}; | ||
if (field) { o.field = "\"" + field + "\""; } | ||
else { o.field = "field"; } | ||
if (expected) { o.expected = expected; } | ||
if (actual) { o.actual = actual; } | ||
/** | ||
* Resolve message string from a validation error object | ||
* | ||
* @param {Object} err Validation error object | ||
*/ | ||
Validator.prototype.resolveMessage = function(err, msg) { | ||
if ( msg === void 0 ) msg = null; | ||
var s = Object.keys(o) | ||
.map(function (key) { return (key + ": " + (o[key])); }) | ||
.join(", "); | ||
if (msg != null) { | ||
var expected = err.expected != null ? err.expected : ""; | ||
var actual = err.actual != null ? err.actual : ""; | ||
return msg.replace(/\{field\}/g, err.field).replace(/\{expected\}/g, expected).replace(/\{actual\}/g, actual); | ||
} | ||
return ("errors.push({ " + s + " });"); | ||
}; | ||
/** | ||
* Add a custom validator rule | ||
* | ||
* @param {String} type | ||
* @param {Function} fn | ||
*/ | ||
Validator.prototype.add = function(type, fn) { | ||
* Add a custom rule | ||
* | ||
* @param {String} type | ||
* @param {Function} fn | ||
*/ | ||
Validator.prototype.add = function add (type, fn) { | ||
this.rules[type] = fn; | ||
@@ -878,0 +1049,0 @@ }; |
@@ -1,1 +0,1 @@ | ||
"use strict";function t(){function e(e){return"number"!=typeof e&&"string"!=typeof e?this.makeError("string"):("string"!=typeof e&&(e=String(e)),e=e.replace(/\D+/g,""),function(e){return function(t){for(var r=t?t.length:0,n=1,i=0;r--;)i+=(n^=1)?e[t[r]]:parseInt(t[r],10);return 0==i%10&&0<i}}([0,2,4,6,8,1,3,5,7,9])(e)||this.makeError("luhn"))}function t(e){return"string"!=typeof e?this.makeError("string"):(e=e.toLowerCase(),!!w.test(e)||this.makeError("mac"))}function r(e,t){if("string"!=typeof e)return this.makeError("string");if(e=e.toLowerCase(),!M.test(e))return this.makeError("uuid");var r=0|e.charAt(14);if(t.version&&t.version!==r)return this.makeError("uuidVersion",t.version,r);switch(r){case 1:case 2:return!0;case 3:case 4:case 5:return-1!==["8","9","a","b"].indexOf(e.charAt(19))||this.makeError("uuid")}}function n(e){return"string"!=typeof e?this.makeError("string"):!!j.test(e)||this.makeError("url")}function i(e,t){if("string"!=typeof e)return this.makeError("string");var r=e.length;return!1===t.empty&&0===r?this.makeError("stringEmpty"):null!=t.min&&r<t.min?this.makeError("stringMin",t.min,r):null!=t.max&&r>t.max?this.makeError("stringMax",t.max,r):null!=t.length&&r!==t.length?this.makeError("stringLength",t.length,r):null==t.pattern||(r="string"==typeof t.pattern?new RegExp(t.pattern,t.patternFlags):t.pattern).test(e)?null!=t.contains&&-1===e.indexOf(t.contains)?this.makeError("stringContains",t.contains,e):null!=t.enum&&-1===t.enum.indexOf(e)?this.makeError("stringEnum",t.enum,e):!0!==t.numeric||O.test(e)?!0!==t.alpha||_.test(e)?!0!==t.alphanum||A.test(e)?!(!0===t.alphadash&&!T.test(e))||this.makeError("stringAlphadash","An alphadash string",e):this.makeError("stringAlphanum","An alphanumeric string",e):this.makeError("stringAlpha","An alphabetic string",e):this.makeError("stringNumeric","A numeric string",e):this.makeError("stringPattern",r,e)}function a(e,t){if("object"!=typeof e||null===e||Array.isArray(e))return this.makeError("object");if(!0===t.strict&&t.props){t=Object.keys(t.props);var r=[];e=Object.keys(e);for(var n=0;n<e.length;n++)-1===t.indexOf(e[n])&&r.push(e[n]);if(0!==r.length)return this.makeError("objectStrict",void 0,r.join(", "))}return!0}function o(e,t){return!0===t.convert&&"number"!=typeof e&&(e=Number(e)),"number"!=typeof e||isNaN(e)||!isFinite(e)?this.makeError("number"):null!=t.min&&e<t.min?this.makeError("numberMin",t.min,e):null!=t.max&&e>t.max?this.makeError("numberMax",t.max,e):null!=t.equal&&e!==t.equal?this.makeError("numberEqual",t.equal,e):null!=t.notEqual&&e===t.notEqual?this.makeError("numberNotEqual",t.notEqual):!0===t.integer&&0!=e%1?this.makeError("numberInteger",e):!0===t.positive&&0>=e?this.makeError("numberPositive",e):!(!0===t.negative&&0<=e)||this.makeError("numberNegative",e)}function s(e){return"function"==typeof e||this.makeError("function")}function u(e){return null===e||void 0===e||this.makeError("forbidden")}function l(e,t){return null==t.values||-1!==t.values.indexOf(e)||this.makeError("enumValue",t.values,e)}function f(e,t){return"string"!=typeof e?this.makeError("string"):!!("precise"==t.mode?S:x).test(e)||this.makeError("email")}function c(e,t){return!0!==t.convert||e instanceof Date||(e=new Date(e)),e instanceof Date&&!isNaN(e.getTime())||this.makeError("date")}function h(e,t){return t.check.call(this,e,t)}function p(e,t){return!0===t.convert&&"boolean"!=typeof e&&(1===e||0===e||"true"===e||"false"===e||"1"===e||"0"===e||"on"===e||"off"===e)||("boolean"==typeof e||this.makeError("boolean"))}function m(e,t){if(!Array.isArray(e))return this.makeError("array");var r=e.length;if(!1===t.empty&&0===r)return this.makeError("arrayEmpty");if(null!=t.min&&r<t.min)return this.makeError("arrayMin",t.min,r);if(null!=t.max&&r>t.max)return this.makeError("arrayMax",t.max,r);if(null!=t.length&&r!==t.length)return this.makeError("arrayLength",t.length,r);if(null!=t.contains&&-1===e.indexOf(t.contains))return this.makeError("arrayContains",t.contains);if(null!=t.enum)for(r=0;r<e.length;r++)if(-1===t.enum.indexOf(e[r]))return this.makeError("arrayEnum",e[r],t.enum);return!0}function d(){return!0}function y(e,t){t=t||[];for(var r=0;r<e.length;++r)Array.isArray(e[r])?y(e[r],t):t.push(e[r]);return t}function g(e,t){for(var r in t)"object"==typeof t[r]&&null!==t[r]?(e[r]=e[r]||{},g(e[r],t[r])):e[r]=t[r];return e}function b(e){return e.replace(R,function(e){switch(e){case'"':case"'":case"\\":return"\\"+e;case"\n":return"\\n";case"\r":return"\\r";case"\u2028":return"\\u2028";case"\u2029":return"\\u2029"}})}function v(y){this.opts={messages:E({},k)},y&&E(this.opts,y),this.messages=this.opts.messages,this.messageKeys=Object.keys(this.messages),this.rules={any:d,array:m,boolean:p,custom:h,date:c,email:f,enum:l,forbidden:u,function:s,number:o,object:a,string:i,url:n,uuid:r,mac:t,luhn:e},this.cache=new Map}var E=g,k={required:"The '{field}' field is required!",string:"The '{field}' field must be a string!",stringEmpty:"The '{field}' field must not be empty!",stringMin:"The '{field}' field length must be greater than or equal to {expected} characters long!",stringMax:"The '{field}' field length must be less than or equal to {expected} characters long!",stringLength:"The '{field}' field length must be {expected} characters long!",stringPattern:"The '{field}' field fails to match the required pattern!",stringContains:"The '{field}' field must contain the '{expected}' text!",stringEnum:"The '{field}' field does not match any of the allowed values!",stringNumeric:"The '{field}' field must be a numeric string",stringAlpha:"The '{field}' field must be an alphabetic string",stringAlphanum:"The '{field}' field must be an alphanumeric string",stringAlphadash:"The '{field}' field must be an alphadash string",number:"The '{field}' field must be a number!",numberMin:"The '{field}' field must be greater than or equal to {expected}!",numberMax:"The '{field}' field must be less than or equal to {expected}!",numberEqual:"The '{field}' field must be equal with {expected}!",numberNotEqual:"The '{field}' field can't be equal with {expected}!",numberInteger:"The '{field}' field must be an integer!",numberPositive:"The '{field}' field must be a positive number!",numberNegative:"The '{field}' field must be a negative number!",array:"The '{field}' field must be an array!",arrayEmpty:"The '{field}' field must not be an empty array!",arrayMin:"The '{field}' field must contain at least {expected} items!",arrayMax:"The '{field}' field must contain less than or equal to {expected} items!",arrayLength:"The '{field}' field must contain {expected} items!",arrayContains:"The '{field}' field must contain the '{expected}' item!",arrayEnum:"The '{field} field value '{expected}' does not match any of the allowed values!",boolean:"The '{field}' field must be a boolean!",function:"The '{field}' field must be a function!",date:"The '{field}' field must be a Date!",dateMin:"The '{field}' field must be greater than or equal to {expected}!",dateMax:"The '{field}' field must be less than or equal to {expected}!",forbidden:"The '{field}' field is forbidden!",email:"The '{field}' field must be a valid e-mail!",url:"The '{field}' field must be a valid URL!",enumValue:"The '{field} field value '{expected}' does not match any of the allowed values!",object:"The '{field}' must be an Object!",objectStrict:"The object '{field}' contains invalid keys: '{actual}'!",uuid:"The {field} field must be a valid UUID",uuidVersion:"The {field} field must be a valid version provided",mac:"The {field} field must be a valid MAC address",luhn:"The {field} field must be a valid checksum luhn"},S=/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,x=/^\S+@\S+\.\S+$/,O=/^-?[0-9]\d*(\.\d+)?$/,_=/^[a-zA-Z]+$/,A=/^[a-zA-Z0-9]+$/,T=/^[a-zA-Z0-9_-]+$/,j=/^https?:\/\/\S+/,M=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$/i,w=/^((([a-f0-9][a-f0-9]+[-]){5}|([a-f0-9][a-f0-9]+[:]){5})([a-f0-9][a-f0-9])$)|(^([a-f0-9][a-f0-9][a-f0-9][a-f0-9]+[.]){2}([a-f0-9][a-f0-9][a-f0-9][a-f0-9]))$/i,P=/^[_$a-zA-Z][_$a-zA-Z0-9]*$/,R=/["'\\\n\r\u2028\u2029]/g;return v.prototype.validate=function(e,t){return this.compile(t)(e)},v.prototype.compile=function(e){var t=this;if(Array.isArray(e)){if(0==e.length)throw Error("If the schema is an Array, must contain at least one element!");var r=this.compileSchemaType(e);return this.cache.clear(),function(e,n,i){return t.checkSchemaType(e,r,n,i||null)}}var n=this.compileSchemaObject(e);return this.cache.clear(),function(e,r,i){return t.checkSchemaObject(e,n,r,i||null)}},v.prototype.compileSchemaObject=function(e){var t=this;if(null===e||"object"!=typeof e||Array.isArray(e))throw Error("Invalid schema!");var r=this.cache.get(e);if(r)return r.cycle=!0,r;r={cycle:!1,properties:null,compiledObjectFunction:null,objectStack:[]},this.cache.set(e,r),r.properties=Object.keys(e).filter(function(e){return"$$strict"!==e}).map(function(r){return{name:r,compiledType:t.compileSchemaType(e[r])}});var n=[];n.push("let res;"),n.push("let propertyPath;"),n.push("const errors = [];"),!0===e.$$strict&&n.push("const givenProps = new Map(Object.keys(value).map(key => [key, true]));");for(var i=0;i<r.properties.length;i++){var a=r.properties[i],o=b(a.name),s=P.test(o)?"value."+o:'value["'+o+'"]';n.push('propertyPath = (path !== undefined ? path + ".'+o+'" : "'+o+'");'),Array.isArray(a.compiledType)?n.push("res = this.checkSchemaType("+s+", properties["+i+"].compiledType, propertyPath, value);"):n.push("res = this.checkSchemaRule("+s+", properties["+i+"].compiledType, propertyPath, value);"),n.push("if (res !== true) {"),n.push("\tthis.handleResult(errors, propertyPath, res, properties["+i+"].compiledType.messages);"),n.push("}"),!0===e.$$strict&&n.push('givenProps.delete("'+o+'");')}return!0===e.$$strict&&(n.push("if (givenProps.size !== 0) {"),n.push("\tthis.handleResult(errors, path || 'rootObject', this.makeError('objectStrict', undefined, [...givenProps.keys()].join(', ')), this.messages);"),n.push("}")),n.push("return errors.length === 0 ? true : errors;"),r.compiledObjectFunction=new Function("value","properties","path","parent",n.join("\n")),r},v.prototype.compileSchemaType=function(e){var t=this;return Array.isArray(e)?(e=y(e.map(function(e){return t.compileSchemaType(e)})),1==e.length?e[0]:e):this.compileSchemaRule(e)},v.prototype.compileMessages=function(e){return e.messages?Object.assign({},this.messages,e.messages):this.messages},v.prototype.compileSchemaRule=function(e){"string"==typeof e&&(e={type:e});var t=this.rules[e.type];if(!t)throw Error("Invalid '"+e.type+"' type in validator schema!");var r=this.compileMessages(e),n=null,i=null;return"object"===e.type&&e.props?(n=this.compileSchemaObject(e.props),i=this.checkSchemaObject):"array"===e.type&&e.items&&(n=this.compileSchemaType(e.items),i=this.checkSchemaArray),{messages:r,schemaRule:e,ruleFunction:t,dataFunction:i,dataParameter:n}},v.prototype.checkSchemaObject=function(e,t,r,n){return t.cycle?-1!==t.objectStack.indexOf(e)||(t.objectStack.push(e),e=this.checkSchemaObjectInner(e,t,r,n),t.objectStack.pop(),e):this.checkSchemaObjectInner(e,t,r,n)},v.prototype.checkSchemaObjectInner=function(e,t,r,n){return t.compiledObjectFunction.call(this,e,t.properties,r,n)},v.prototype.checkSchemaType=function(e,t,r,n){if(Array.isArray(t)){for(var i=[],a=t.length,o=0;o<a;o++){var s=this.checkSchemaRule(e,t[o],r,n);if(!0===s)return!0;this.handleResult(i,r,s,t.messages)}return i}return this.checkSchemaRule(e,t,r,n)},v.prototype.checkSchemaArray=function(e,t,r,n){for(var i=[],a=e.length,o=0;o<a;o++){var s=(void 0!==r?r:"")+"["+o+"]",u=this.checkSchemaType(e[o],t,s,e,n);!0!==u&&this.handleResult(i,s,u,t.messages)}return 0===i.length||i},v.prototype.checkSchemaRule=function(e,t,r,n){var i=t.schemaRule;return void 0===e||null===e?"forbidden"===i.type||!0===i.optional||(e=[],this.handleResult(e,r,this.makeError("required"),t.messages),e):(i=t.ruleFunction.call(this,e,i,r,n),!0!==i?(e=[],this.handleResult(e,r,i,t.messages),e):null===t.dataFunction||t.dataFunction.call(this,e,t.dataParameter,r,n))},v.prototype.handleResult=function(e,t,r,n){var i=this;(Array.isArray(r)?r:[r]).forEach(function(r){r.field||(r.field=t),r.message||(r.message=i.resolveMessage(r,n[r.type])),e.push(r)})},v.prototype.makeError=function(e,t,r){return{type:e,expected:t,actual:r}},v.prototype.resolveMessage=function(e,t){if(void 0===t&&(t=null),null!=t){var r=null!=e.expected?e.expected:"",n=null!=e.actual?e.actual:"";return t.replace(/\{field\}/g,e.field).replace(/\{expected\}/g,r).replace(/\{actual\}/g,n)}},v.prototype.add=function(e,t){this.rules[e]=t},v}var f=f||{};f.scope={},f.ASSUME_ES5=!1,f.ASSUME_NO_NATIVE_MAP=!1,f.ASSUME_NO_NATIVE_SET=!1,f.defineProperty=f.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(e,t,r){e!=Array.prototype&&e!=Object.prototype&&(e[t]=r.value)},f.getGlobal=function(e){return"undefined"!=typeof window&&window===e?e:"undefined"!=typeof global&&null!=global?global:e},f.global=f.getGlobal(this),f.SYMBOL_PREFIX="jscomp_symbol_",f.initSymbol=function(){f.initSymbol=function(){},f.global.Symbol||(f.global.Symbol=f.Symbol)},f.Symbol=function(){var e=0;return function(t){return f.SYMBOL_PREFIX+(t||"")+e++}}(),f.initSymbolIterator=function(){f.initSymbol();var e=f.global.Symbol.iterator;e||(e=f.global.Symbol.iterator=f.global.Symbol("iterator")),"function"!=typeof Array.prototype[e]&&f.defineProperty(Array.prototype,e,{configurable:!0,writable:!0,value:function(){return f.arrayIterator(this)}}),f.initSymbolIterator=function(){}},f.arrayIterator=function(e){var t=0;return f.iteratorPrototype(function(){return t<e.length?{done:!1,value:e[t++]}:{done:!0}})},f.iteratorPrototype=function(e){return f.initSymbolIterator(),e={next:e},e[f.global.Symbol.iterator]=function(){return this},e},f.iteratorFromArray=function(e,t){f.initSymbolIterator(),e instanceof String&&(e+="");var r=0,n={next:function(){if(r<e.length){var i=r++;return{value:t(i,e[i]),done:!1}}return n.next=function(){return{done:!0,value:void 0}},n.next()}};return n[Symbol.iterator]=function(){return n},n},f.polyfill=function(e,t){if(t){var r=f.global;e=e.split(".");for(var n=0;n<e.length-1;n++){var i=e[n];i in r||(r[i]={}),r=r[i]}(t=t(n=r[e=e[e.length-1]]))!=n&&null!=t&&f.defineProperty(r,e,{configurable:!0,writable:!0,value:t})}},f.polyfill("Array.prototype.keys",function(e){return e||function(){return f.iteratorFromArray(this,function(e){return e})}},"es6","es3"),f.checkEs6ConformanceViaProxy=function(){try{var e={},t=Object.create(new f.global.Proxy(e,{get:function(r,n,i){return r==e&&"q"==n&&i==t}}));return!0===t.q}catch(e){return!1}},f.USE_PROXY_FOR_ES6_CONFORMANCE_CHECKS=!1,f.ES6_CONFORMANCE=f.USE_PROXY_FOR_ES6_CONFORMANCE_CHECKS&&f.checkEs6ConformanceViaProxy(),f.makeIterator=function(e){f.initSymbolIterator();var t=e[Symbol.iterator];return t?t.call(e):f.arrayIterator(e)},f.owns=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},f.polyfill("WeakMap",function(e){function t(e){if(this.id_=(a+=Math.random()+1).toString(),e){f.initSymbol(),f.initSymbolIterator(),e=f.makeIterator(e);for(var t;!(t=e.next()).done;)t=t.value,this.set(t[0],t[1])}}function r(e){f.owns(e,i)||f.defineProperty(e,i,{value:{}})}function n(e){var t=Object[e];t&&(Object[e]=function(e){return r(e),t(e)})}if(f.USE_PROXY_FOR_ES6_CONFORMANCE_CHECKS){if(e&&f.ES6_CONFORMANCE)return e}else if(function(){if(!e||!Object.seal)return!1;try{var t=Object.seal({}),r=Object.seal({}),n=new e([[t,2],[r,3]]);return 2==n.get(t)&&3==n.get(r)&&(n.delete(t),n.set(r,4),!n.has(t)&&4==n.get(r))}catch(e){return!1}}())return e;var i="$jscomp_hidden_"+Math.random();n("freeze"),n("preventExtensions"),n("seal");var a=0;return t.prototype.set=function(e,t){if(r(e),!f.owns(e,i))throw Error("WeakMap key fail: "+e);return e[i][this.id_]=t,this},t.prototype.get=function(e){return f.owns(e,i)?e[i][this.id_]:void 0},t.prototype.has=function(e){return f.owns(e,i)&&f.owns(e[i],this.id_)},t.prototype.delete=function(e){return!(!f.owns(e,i)||!f.owns(e[i],this.id_))&&delete e[i][this.id_]},t},"es6","es3"),f.MapEntry=function(){},f.polyfill("Map",function(e){function t(){var e={};return e.previous=e.next=e.head=e}function r(e,t){var r=e.head_;return f.iteratorPrototype(function(){if(r){for(;r.head!=e.head_;)r=r.previous;for(;r.next!=r.head;)return r=r.next,{done:!1,value:t(r)};r=null}return{done:!0,value:void 0}})}function n(e,t){var r=t&&typeof t;"object"==r||"function"==r?a.has(t)?r=a.get(t):(r=""+ ++o,a.set(t,r)):r="p_"+t;var n=e.data_[r];if(n&&f.owns(e.data_,r))for(e=0;e<n.length;e++){var i=n[e];if(t!==t&&i.key!==i.key||t===i.key)return{id:r,list:n,index:e,entry:i}}return{id:r,list:n,index:-1,entry:void 0}}function i(e){if(this.data_={},this.head_=t(),this.size=0,e){e=f.makeIterator(e);for(var r;!(r=e.next()).done;)r=r.value,this.set(r[0],r[1])}}if(f.USE_PROXY_FOR_ES6_CONFORMANCE_CHECKS){if(e&&f.ES6_CONFORMANCE)return e}else if(function(){if(f.ASSUME_NO_NATIVE_MAP||!e||"function"!=typeof e||!e.prototype.entries||"function"!=typeof Object.seal)return!1;try{var t=Object.seal({x:4}),r=new e(f.makeIterator([[t,"s"]]));if("s"!=r.get(t)||1!=r.size||r.get({x:4})||r.set({x:4},"t")!=r||2!=r.size)return!1;var n=r.entries(),i=n.next();return!i.done&&i.value[0]==t&&"s"==i.value[1]&&!((i=n.next()).done||4!=i.value[0].x||"t"!=i.value[1]||!n.next().done)}catch(e){return!1}}())return e;f.initSymbol(),f.initSymbolIterator();var a=new WeakMap;i.prototype.set=function(e,t){var r=n(this,e);return r.list||(r.list=this.data_[r.id]=[]),r.entry?r.entry.value=t:(r.entry={next:this.head_,previous:this.head_.previous,head:this.head_,key:e,value:t},r.list.push(r.entry),this.head_.previous.next=r.entry,this.head_.previous=r.entry,this.size++),this},i.prototype.delete=function(e){return!(!(e=n(this,e)).entry||!e.list)&&(e.list.splice(e.index,1),e.list.length||delete this.data_[e.id],e.entry.previous.next=e.entry.next,e.entry.next.previous=e.entry.previous,e.entry.head=null,this.size--,!0)},i.prototype.clear=function(){this.data_={},this.head_=this.head_.previous=t(),this.size=0},i.prototype.has=function(e){return!!n(this,e).entry},i.prototype.get=function(e){return(e=n(this,e).entry)&&e.value},i.prototype.entries=function(){return r(this,function(e){return[e.key,e.value]})},i.prototype.keys=function(){return r(this,function(e){return e.key})},i.prototype.values=function(){return r(this,function(e){return e.value})},i.prototype.forEach=function(e,t){for(var r,n=this.entries();!(r=n.next()).done;)r=r.value,e.call(t,r[1],r[0],this)},i.prototype[Symbol.iterator]=i.prototype.entries;var o=0;return i},"es6","es3"),f.assign="function"==typeof Object.assign?Object.assign:function(e,t){for(var r=1;r<arguments.length;r++){var n=arguments[r];if(n)for(var i in n)f.owns(n,i)&&(e[i]=n[i])}return e},f.polyfill("Object.assign",function(e){return e||f.assign},"es6","es3");var r=this;"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(r=r||self,r.FastestValidator=t()); | ||
"use strict";function u(){function t(t){this.opts={messages:x({},w)},t&&x(this.opts,t),this.messages=this.opts.messages,this.rules={any:b,array:y,boolean:g,custom:v,date:d,email:m,enum:h,equal:p,forbidden:c,function:f,multi:o,number:l,object:u,string:s,url:i,uuid:a,mac:r,luhn:n},this.cache=new Map}function e(t){return k||(k=S(),O={parser:"babel",useTabs:!1,printWidth:120,trailingComma:"none",tabWidth:4,singleQuote:!1,semi:!0,bracketSpacing:!0},j=S(),_={language:"js",theme:j.fromJson({keyword:["white","bold"],built_in:"magenta",literal:"cyan",number:"magenta",regexp:"red",string:["yellow","bold"],symbol:"plain",class:"blue",attr:"plain",function:["white","bold"],title:"plain",params:"green",comment:"grey"})}),t=k.format(t,O),j.highlight(t,_)}function n(t){return t=t.messages,{source:'\n\t\t\tif (typeof value !== "string") {\n\t\t\t\t'+this.makeError({type:"string",actual:"value",messages:t})+'\n\t\t\t\treturn value;\n\t\t\t}\n\n\t\t\tif (typeof value !== "string")\n\t\t\t\tvalue = String(value);\n\n\t\t\tval = value.replace(/\\D+/g, "");\n\n\t\t\tvar array = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9];\n\t\t\tvar len = val ? val.length : 0,\n\t\t\t\tbit = 1,\n\t\t\t\tsum = 0;\n\t\t\twhile (len--) {\n\t\t\t\tsum += !(bit ^= 1) ? parseInt(val[len], 10) : array[val[len]];\n\t\t\t}\n\n\t\t\tif (!(sum % 10 === 0 && sum > 0)) {\n\t\t\t\t'+this.makeError({type:"luhn",actual:"value",messages:t})+"\n\t\t\t}\n\n\t\t\treturn value;\n\t\t"}}function r(t){return t=t.messages,{source:'\n\t\t\tif (typeof value !== "string") {\n\t\t\t\t'+this.makeError({type:"string",actual:"value",messages:t})+"\n\t\t\t\treturn value;\n\t\t\t}\n\n\t\t\tvar v = value.toLowerCase();\n\t\t\tif (!"+P.toString()+".test(v)) {\n\t\t\t\t"+this.makeError({type:"mac",actual:"value",messages:t})+"\n\t\t\t}\n\n\t\t\treturn value;\n\t\t"}}function a(t){var e=t.schema;t=t.messages;var n=[];return n.push('\n\t\tif (typeof value !== "string") {\n\t\t\t'+this.makeError({type:"string",actual:"value",messages:t})+"\n\t\t\treturn value;\n\t\t}\n\n\t\tvar val = value.toLowerCase();\n\t\tif (!"+I.toString()+".test(val)) {\n\t\t\t"+this.makeError({type:"uuid",actual:"value",messages:t})+"\n\t\t\treturn value;\n\t\t}\n\n\t\tconst version = val.charAt(14) | 0;\n\t"),e.version&&n.push("\n\t\t\tif ("+e.version+" !== version) {\n\t\t\t\t"+this.makeError({type:"uuidVersion",expected:e.version,actual:"version",messages:t})+"\n\t\t\t\treturn value;\n\t\t\t}\n\t\t"),n.push('\n\t\tswitch (version) {\n\t\tcase 1:\n\t\tcase 2:\n\t\t\tbreak;\n\t\tcase 3:\n\t\tcase 4:\n\t\tcase 5:\n\t\t\tif (["8", "9", "a", "b"].indexOf(value.charAt(19)) === -1) {\n\t\t\t\t'+this.makeError({type:"uuid",actual:"value",messages:t})+"\n\t\t\t}\n\t\t}\n\n\t\treturn value;\n\t"),{source:n.join("\n")}}function i(t){t=t.messages;var e=[];return e.push('\n\t\tif (typeof value !== "string") {\n\t\t\t'+this.makeError({type:"string",actual:"value",messages:t})+"\n\t\t\treturn value;\n\t\t}\n\n\t\tif (!"+R.toString()+".test(value)) {\n\t\t\t"+this.makeError({type:"url",actual:"value",messages:t})+"\n\t\t}\n\n\t\treturn value;\n\t"),{source:e.join("\n")}}function s(t){var e=t.schema;t=t.messages;var n=[],r=!1;if(!0===e.convert&&(r=!0,n.push('\n\t\t\tif (typeof value !== "string") {\n\t\t\t\tvalue = String(value);\n\t\t\t}\n\t\t')),n.push('\n\t\tif (typeof value !== "string") {\n\t\t\t'+this.makeError({type:"string",actual:"value",messages:t})+"\n\t\t\treturn value;\n\t\t}\n\n\t\tvar origValue = value;\n\t"),e.trim&&(r=!0,n.push("\n\t\t\tvalue = value.trim();\n\t\t")),e.trimLeft&&(r=!0,n.push("\n\t\t\tvalue = value.trimLeft();\n\t\t")),e.trimRight&&(r=!0,n.push("\n\t\t\tvalue = value.trimRight();\n\t\t")),e.padStart&&(r=!0,n.push("\n\t\t\tvalue = value.padStart("+e.padStart+", "+JSON.stringify(null!=e.padChar?e.padChar:" ")+");\n\t\t")),e.padEnd&&(r=!0,n.push("\n\t\t\tvalue = value.padEnd("+e.padEnd+", "+JSON.stringify(null!=e.padChar?e.padChar:" ")+");\n\t\t")),e.lowercase&&(r=!0,n.push("\n\t\t\tvalue = value.toLowerCase();\n\t\t")),e.uppercase&&(r=!0,n.push("\n\t\t\tvalue = value.toUpperCase();\n\t\t")),e.localeLowercase&&(r=!0,n.push("\n\t\t\tvalue = value.toLocaleLowerCase();\n\t\t")),e.localeUppercase&&(r=!0,n.push("\n\t\t\tvalue = value.toLocaleUpperCase();\n\t\t")),n.push("\n\t\t\tvar len = value.length;\n\t"),!1===e.empty&&n.push("\n\t\t\tif (len === 0) {\n\t\t\t\t"+this.makeError({type:"stringEmpty",actual:"value",messages:t})+"\n\t\t\t}\n\t\t"),null!=e.min&&n.push("\n\t\t\tif (len < "+e.min+") {\n\t\t\t\t"+this.makeError({type:"stringMin",expected:e.min,actual:"len",messages:t})+"\n\t\t\t}\n\t\t"),null!=e.max&&n.push("\n\t\t\tif (len > "+e.max+") {\n\t\t\t\t"+this.makeError({type:"stringMax",expected:e.max,actual:"len",messages:t})+"\n\t\t\t}\n\t\t"),null!=e.length&&n.push("\n\t\t\tif (len !== "+e.length+") {\n\t\t\t\t"+this.makeError({type:"stringLength",expected:e.length,actual:"len",messages:t})+"\n\t\t\t}\n\t\t"),null!=e.pattern){var a=e.pattern;"string"==typeof e.pattern&&(a=new RegExp(e.pattern,e.patternFlags)),n.push("\n\t\t\tif (!"+a.toString()+".test(value))\n\t\t\t\t"+this.makeError({type:"stringPattern",expected:'"'+a.toString()+'"',actual:"origValue",messages:t})+"\n\t\t")}return null!=e.contains&&n.push('\n\t\t\tif (value.indexOf("'+e.contains+'") === -1) {\n\t\t\t\t'+this.makeError({type:"stringContains",expected:'"'+e.contains+'"',actual:"origValue",messages:t})+"\n\t\t\t}\n\t\t"),null!=e.enum&&(a=JSON.stringify(e.enum),n.push("\n\t\t\tif ("+a+".indexOf(value) === -1) {\n\t\t\t\t"+this.makeError({type:"stringEnum",expected:'"'+e.enum.join(", ")+'"',actual:"origValue",messages:t})+"\n\t\t\t}\n\t\t")),!0===e.numeric&&n.push("\n\t\t\tif (!"+V.toString()+".test(value) ) {\n\t\t\t\t"+this.makeError({type:"stringNumeric",actual:"origValue",messages:t})+"\n\t\t\t}\n\t\t"),!0===e.alpha&&n.push("\n\t\t\tif(!"+M.toString()+".test(value)) {\n\t\t\t\t"+this.makeError({type:"stringAlpha",actual:"origValue",messages:t})+"\n\t\t\t}\n\t\t"),!0===e.alphanum&&n.push("\n\t\t\tif(!"+F.toString()+".test(value)) {\n\t\t\t\t"+this.makeError({type:"stringAlphanum",actual:"origValue",messages:t})+"\n\t\t\t}\n\t\t"),!0===e.alphadash&&n.push("\n\t\t\tif(!"+q.toString()+".test(value)) {\n\t\t\t\t"+this.makeError({type:"stringAlphadash",actual:"origValue",messages:t})+"\n\t\t\t}\n\t\t"),n.push("\n\t\treturn value;\n\t"),{sanitized:r,source:n.join("\n")}}function u(t,e,n){var r=t.schema;t=t.messages;var a=[];a.push('\n\t\tif (typeof value !== "object" || value === null || Array.isArray(value)) {\n\t\t\t'+this.makeError({type:"object",actual:"value",messages:t})+"\n\t\t\treturn value;\n\t\t}\n\t");var i=r.properties||r.props;if(i){a.push("var parentObj = value;"),a.push("var parentField = field;");for(var s=Object.keys(i),u=0;u<s.length;u++){var l=s[u],o=E(l),f=A.test(o)?"."+o:"['"+o+"']",c="parentObj"+f,p=(e?e+".":"")+l;a.push("\n// Field: "+E(p)),a.push('field = parentField ? parentField + "'+f+'" : "'+o+'";'),a.push("value = "+c+";"),l=this.getRuleFromSchema(i[l]),a.push(this.compileRule(l,n,p,c+" = context.fn[%%INDEX%%](value, field, parentObj, errors, context);",c))}r.strict&&(e=Object.keys(i),a.push("\n\t\t\t\tfield = parentField;\n\t\t\t\tvar invalidProps = [];\n\t\t\t\tvar props = Object.keys(parentObj);\n\n\t\t\t\tfor (let i = 0; i < props.length; i++) {\n\t\t\t\t\tif ("+JSON.stringify(e)+".indexOf(props[i]) === -1) {\n\t\t\t\t\t\tinvalidProps.push(props[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (invalidProps.length) {\n\t\t\t"),"remove"==r.strict?a.push("\n\t\t\t\t\tinvalidProps.forEach(function(field) {\n\t\t\t\t\t\tdelete parentObj[field];\n\t\t\t\t\t});\n\t\t\t\t"):a.push("\n\t\t\t\t\t"+this.makeError({type:"objectStrict",expected:'"'+e.join(", ")+'"',actual:"invalidProps.join(', ')",messages:t})+"\n\t\t\t\t"),a.push("\n\t\t\t\t}\n\t\t\t")),a.push("\n\t\t\treturn parentObj;\n\t\t")}else a.push("\n\t\t\treturn value;\n\t\t");return{source:a.join("\n")}}function l(t){var e=t.schema;t=t.messages;var n=[];n.push("\n\t\tvar origValue = value;\n\t");var r=!1;return!0===e.convert&&(r=!0,n.push('\n\t\t\tif (typeof value !== "number") {\n\t\t\t\tvalue = Number(value);\n\t\t\t}\n\t\t')),n.push('\n\t\tif (typeof value !== "number" || isNaN(value) || !isFinite(value)) {\n\t\t\t'+this.makeError({type:"number",actual:"origValue",messages:t})+"\n\t\t\treturn value;\n\t\t}\n\t"),null!=e.min&&n.push("\n\t\t\tif (value < "+e.min+") {\n\t\t\t\t"+this.makeError({type:"numberMin",expected:e.min,actual:"origValue",messages:t})+"\n\t\t\t}\n\t\t"),null!=e.max&&n.push("\n\t\t\tif (value > "+e.max+") {\n\t\t\t\t"+this.makeError({type:"numberMax",expected:e.max,actual:"origValue",messages:t})+"\n\t\t\t}\n\t\t"),null!=e.equal&&n.push("\n\t\t\tif (value !== "+e.equal+") {\n\t\t\t\t"+this.makeError({type:"numberEqual",expected:e.equal,actual:"origValue",messages:t})+"\n\t\t\t}\n\t\t"),null!=e.notEqual&&n.push("\n\t\t\tif (value === "+e.notEqual+") {\n\t\t\t\t"+this.makeError({type:"numberNotEqual",expected:e.notEqual,actual:"origValue",messages:t})+"\n\t\t\t}\n\t\t"),!0===e.integer&&n.push("\n\t\t\tif (value % 1 !== 0) {\n\t\t\t\t"+this.makeError({type:"numberInteger",actual:"origValue",messages:t})+"\n\t\t\t}\n\t\t"),!0===e.positive&&n.push("\n\t\t\tif (value <= 0) {\n\t\t\t\t"+this.makeError({type:"numberPositive",actual:"origValue",messages:t})+"\n\t\t\t}\n\t\t"),!0===e.negative&&n.push("\n\t\t\tif (value >= 0) {\n\t\t\t\t"+this.makeError({type:"numberNegative",actual:"origValue",messages:t})+"\n\t\t\t}\n\t\t"),n.push("\n\t\treturn value;\n\t"),{sanitized:r,source:n.join("\n")}}function o(t,e,n){t=t.schema;var r=[];r.push("\n\t\tvar prevErrLen = errors.length;\n\t\tvar errBefore;\n\t\tvar hasValid = false;\n\t\tvar newVal = value;\n\t");for(var a=0;a<t.rules.length;a++){r.push("\n\t\t\tif (!hasValid) {\n\t\t\t\terrBefore = errors.length;\n\t\t");var i=this.getRuleFromSchema(t.rules[a]);r.push(this.compileRule(i,n,e,"var tmpVal = context.fn[%%INDEX%%](value, field, parent, errors, context);","tmpVal")),r.push("\n\t\t\t\tif (errors.length == errBefore) {\n\t\t\t\t\thasValid = true;\n\t\t\t\t\tnewVal = tmpVal;\n\t\t\t\t}\n\t\t\t}\n\t\t")}return r.push("\n\t\tif (hasValid) {\n\t\t\terrors.length = prevErrLen;\n\t\t}\n\n\t\treturn newVal;\n\t"),{source:r.join("\n")}}function f(t){return{source:'\n\t\t\tif (typeof value !== "function")\n\t\t\t\t'+this.makeError({type:"function",actual:"value",messages:t.messages})+"\n\n\t\t\treturn value;\n\t\t"}}function c(t){var e=t.schema;t=t.messages;var n=[];return n.push("\n\t\tif (value !== null && value !== undefined) {\n\t"),e.remove?n.push("\n\t\t\treturn undefined;\n\t\t"):n.push("\n\t\t\t"+this.makeError({type:"forbidden",actual:"value",messages:t})+"\n\t\t"),n.push("\n\t\t}\n\t\treturn value;\n\t"),{source:n.join("\n")}}function p(t){var e=t.schema;t=t.messages;var n=[];return e.field?(e.strict?n.push('\n\t\t\t\tif (value !== parent["'+e.field+'"])\n\t\t\t'):n.push('\n\t\t\t\tif (value != parent["'+e.field+'"])\n\t\t\t'),n.push("\n\t\t\t\t"+this.makeError({type:"equalField",actual:"value",expected:JSON.stringify(e.field),messages:t})+"\n\t\t")):(e.strict?n.push("\n\t\t\t\tif (value !== "+JSON.stringify(e.value)+")\n\t\t\t"):n.push("\n\t\t\t\tif (value != "+JSON.stringify(e.value)+")\n\t\t\t"),n.push("\n\t\t\t\t"+this.makeError({type:"equalValue",actual:"value",expected:JSON.stringify(e.value),messages:t})+"\n\t\t")),n.push("\n\t\treturn value;\n\t"),{source:n.join("\n")}}function h(t){var e=t.schema;return t=t.messages,{source:"\n\t\t\tif ("+JSON.stringify(e.values||[])+".indexOf(value) === -1)\n\t\t\t\t"+this.makeError({type:"enumValue",expected:'"'+e.values.join(", ")+'"',actual:"value",messages:t})+"\n\n\t\t\treturn value;\n\t\t"}}function m(t){var e=t.schema;t=t.messages;var n=[],r="precise"==e.mode?N:T,a=!1;return n.push('\n\t\tif (typeof value !== "string") {\n\t\t\t'+this.makeError({type:"string",actual:"value",messages:t})+"\n\t\t\treturn value;\n\t\t}\n\t"),e.normalize&&(a=!0,n.push("\n\t\t\tvalue = value.trim().toLowerCase();\n\t\t")),n.push("\n\t\tif (!"+r.toString()+".test(value))\n\t\t\t"+this.makeError({type:"email",actual:"value",messages:t})+"\n\n\t\treturn value;\n\t"),{sanitized:a,source:n.join("\n")}}function d(t){var e=t.schema;t=t.messages;var n=[],r=!1;return n.push("\n\t\tvar origValue = value;\n\t"),!0===e.convert&&(r=!0,n.push("\n\t\t\tif (!(value instanceof Date)) {\n\t\t\t\tvalue = new Date(value);\n\t\t\t}\n\t\t")),n.push("\n\t\tif (!(value instanceof Date) || isNaN(value.getTime()))\n\t\t\t"+this.makeError({type:"date",actual:"origValue",messages:t})+"\n\n\t\treturn value;\n\t"),{sanitized:r,source:n.join("\n")}}function v(t,e,n){var r=t.schema;t=t.messages;var a=[];return"function"==typeof r.check&&(n.customs[e]={schema:r,messages:t},a.push('\n\t\t\tconst rule = context.customs["'+e+'"];\n\t\t\tconst res = rule.schema.check.call(this, value, rule.schema, "'+e+'", parent, context);\n\t\t\tif (Array.isArray(res)) {\n\t\t\t\tres.forEach(err => errors.push(Object.assign({ message: rule.messages[err.type] }, err)));\n\t\t\t}\n\n\t\t\treturn value;\n\t\t')),{source:a.join("\n")}}function g(t){var e=t.schema;t=t.messages;var n=[],r=!1;return n.push("\n\t\tvar origValue = value;\n\t"),!0===e.convert&&(r=!0,n.push('\n\t\t\tif (typeof value !== "boolean") {\n\t\t\t\tif (\n\t\t\t\tvalue === 1\n\t\t\t\t|| value === "true"\n\t\t\t\t|| value === "1"\n\t\t\t\t|| value === "on"\n\t\t\t\t) {\n\t\t\t\t\tvalue = true;\n\t\t\t\t} else if (\n\t\t\t\tvalue === 0\n\t\t\t\t|| value === "false"\n\t\t\t\t|| value === "0"\n\t\t\t\t|| value === "off"\n\t\t\t\t) {\n\t\t\t\t\tvalue = false;\n\t\t\t\t}\n\t\t\t}\n\t\t')),n.push('\n\t\tif (typeof value !== "boolean")\n\t\t\t'+this.makeError({type:"boolean",actual:"origValue",messages:t})+"\n\n\t\treturn value;\n\t"),{sanitized:r,source:n.join("\n")}}function y(t,e,n){var r=t.schema,a=t.messages;if((t=[]).push("\n\t\tif (!Array.isArray(value)) {\n\t\t\t"+this.makeError({type:"array",actual:"value",messages:a})+"\n\t\t\treturn value;\n\t\t}\n\n\t\tvar len = value.length;\n\t"),!1===r.empty&&t.push("\n\t\t\tif (len === 0) {\n\t\t\t\t"+this.makeError({type:"arrayEmpty",actual:"value",messages:a})+"\n\t\t\t}\n\t\t"),null!=r.min&&t.push("\n\t\t\tif (len < "+r.min+") {\n\t\t\t\t"+this.makeError({type:"arrayMin",expected:r.min,actual:"len",messages:a})+"\n\t\t\t}\n\t\t"),null!=r.max&&t.push("\n\t\t\tif (len > "+r.max+") {\n\t\t\t\t"+this.makeError({type:"arrayMax",expected:r.max,actual:"len",messages:a})+"\n\t\t\t}\n\t\t"),null!=r.length&&t.push("\n\t\t\tif (len !== "+r.length+") {\n\t\t\t\t"+this.makeError({type:"arrayLength",expected:r.length,actual:"len",messages:a})+"\n\t\t\t}\n\t\t"),null!=r.contains&&t.push("\n\t\t\tif (value.indexOf("+JSON.stringify(r.contains)+") === -1) {\n\t\t\t\t"+this.makeError({type:"arrayContains",expected:JSON.stringify(r.contains),actual:"value",messages:a})+"\n\t\t\t}\n\t\t"),null!=r.enum){var i=JSON.stringify(r.enum);t.push("\n\t\t\tfor (var i = 0; i < value.length; i++) {\n\t\t\t\tif ("+i+".indexOf(value[i]) === -1) {\n\t\t\t\t\t"+this.makeError({type:"arrayEnum",expected:'"'+r.enum.join(", ")+'"',actual:"value[i]",messages:a})+"\n\t\t\t\t}\n\t\t\t}\n\t\t")}return null!=r.items&&(t.push("\n\t\t\tvar arr = value;\n\t\t\tvar parentField = field;\n\t\t\tfor (var i = 0; i < arr.length; i++) {\n\t\t"),r=this.getRuleFromSchema(r.items),t.push(this.compileRule(r,n,e,'arr[i] = context.fn[%%INDEX%%](arr[i], (parentField ? parentField : "") + "[" + i + "]", parent, errors, context);',"arr[i]")),t.push("\n\t\t\t}\n\t\t")),{source:t.join("\n")}}function b(){return{}}function x(t,e){for(var n in e)"object"==typeof e[n]&&null!==e[n]?(t[n]=t[n]||{},x(t[n],e[n])):t[n]=e[n];return t}function E(t){return t.replace(C,function(t){switch(t){case'"':case"'":case"\\":return"\\"+t;case"\n":return"\\n";case"\r":return"\\r";case"\u2028":return"\\u2028";case"\u2029":return"\\u2029"}})}function S(){throw Error("Dynamic requires are not currently supported by rollup-plugin-commonjs")}var k,O,j,_,w={required:"The '{field}' field is required.",string:"The '{field}' field must be a string.",stringEmpty:"The '{field}' field must not be empty.",stringMin:"The '{field}' field length must be greater than or equal to {expected} characters long.",stringMax:"The '{field}' field length must be less than or equal to {expected} characters long.",stringLength:"The '{field}' field length must be {expected} characters long.",stringPattern:"The '{field}' field fails to match the required pattern.",stringContains:"The '{field}' field must contain the '{expected}' text.",stringEnum:"The '{field}' field does not match any of the allowed values.",stringNumeric:"The '{field}' field must be a numeric string.",stringAlpha:"The '{field}' field must be an alphabetic string.",stringAlphanum:"The '{field}' field must be an alphanumeric string.",stringAlphadash:"The '{field}' field must be an alphadash string.",number:"The '{field}' field must be a number.",numberMin:"The '{field}' field must be greater than or equal to {expected}.",numberMax:"The '{field}' field must be less than or equal to {expected}.",numberEqual:"The '{field}' field must be equal to {expected}.",numberNotEqual:"The '{field}' field can't be equal to {expected}.",numberInteger:"The '{field}' field must be an integer.",numberPositive:"The '{field}' field must be a positive number.",numberNegative:"The '{field}' field must be a negative number.",array:"The '{field}' field must be an array.",arrayEmpty:"The '{field}' field must not be an empty array.",arrayMin:"The '{field}' field must contain at least {expected} items.",arrayMax:"The '{field}' field must contain less than or equal to {expected} items.",arrayLength:"The '{field}' field must contain {expected} items.",arrayContains:"The '{field}' field must contain the '{expected}' item.",arrayEnum:"The '{actual}' value in '{field}' field does not match any of the '{expected}' values.",boolean:"The '{field}' field must be a boolean.",date:"The '{field}' field must be a Date.",dateMin:"The '{field}' field must be greater than or equal to {expected}.",dateMax:"The '{field}' field must be less than or equal to {expected}.",enumValue:"The '{field}' field value '{expected}' does not match any of the allowed values.",equalValue:"The '{field}' field value must be equal to '{expected}'.",equalField:"The '{field}' field value must be equal to '{expected}' field value.",forbidden:"The '{field}' field is forbidden.",function:"The '{field}' field must be a function.",email:"The '{field}' field must be a valid e-mail.",luhn:"The '{field}' field must be a valid checksum luhn.",mac:"The '{field}' field must be a valid MAC address.",object:"The '{field}' must be an Object.",objectStrict:"The object '{field}' contains forbidden keys: '{actual}'.",url:"The '{field}' field must be a valid URL.",uuid:"The '{field}' field must be a valid UUID.",uuidVersion:"The '{field}' field must be a valid UUID version provided."},N=/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,T=/^\S+@\S+\.\S+$/,A=/^[_$a-zA-Z][_$a-zA-Z0-9]*$/,C=/["'\\\n\r\u2028\u2029]/g,V=/^-?[0-9]\d*(\.\d+)?$/,M=/^[a-zA-Z]+$/,F=/^[a-zA-Z0-9]+$/,q=/^[a-zA-Z0-9_-]+$/,R=/^https?:\/\/\S+/,I=/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[0-9a-f]{4}-[0-9a-f]{12}$/i,P=/^((([a-f0-9][a-f0-9]+[-]){5}|([a-f0-9][a-f0-9]+[:]){5})([a-f0-9][a-f0-9])$)|(^([a-f0-9][a-f0-9][a-f0-9][a-f0-9]+[.]){2}([a-f0-9][a-f0-9][a-f0-9][a-f0-9]))$/i;return t.prototype.validate=function(t,e){return this.compile(e)(t)},t.prototype.wrapRequiredCheckSourceCode=function(t,e,n){var r=[],a=null!=t.schema.default?JSON.stringify(t.schema.default):null;return r.push("\n\t\t\tif (value === undefined || value === null) {\n\t\t"),!0===t.schema.optional||"forbidden"==t.schema.type?null!=a&&n?r.push(n+" = "+a+";"):r.push("// Do nothing, it's an optional field"):null!=a&&n?r.push(n+" = "+a+";"):r.push(this.makeError({type:"required",actual:"value",messages:t.messages})),r.push("} else {"),e&&r.push(e),r.push("\t\t}"),r.join("\n")},t.prototype.compile=function(t){if(null===t||"object"!=typeof t)throw Error("Invalid schema.");var n=this,r={index:0,rules:[],fn:[],customs:{}};if(this.cache.clear(),!0!==t.$$root)if(Array.isArray(t))t=this.getRuleFromSchema(t).schema;else{var a=Object.assign({},t);t={type:"object",strict:a.$$strict,properties:a},delete a.$$strict}a=["var errors = [];","var field;"],t=this.getRuleFromSchema(t),a.push(this.compileRule(t,r,null,"context.fn[%%INDEX%%](value, field, null, errors, context);","value")),a.push("if (errors.length) {"),a.push('\n\t\t\treturn errors.map(err => {\n\t\t\t\tif (err.message)\n\t\t\t\t\terr.message = err.message\n\t\t\t\t\t\t.replace(/\\{field\\}/g, err.field || "")\n\t\t\t\t\t\t.replace(/\\{expected\\}/g, err.expected != null ? err.expected : "")\n\t\t\t\t\t\t.replace(/\\{actual\\}/g, err.actual != null ? err.actual : "");\n\n\t\t\t\treturn err;\n\t\t\t});\n\t\t'),a.push("}"),a.push("return true;"),t=a.join("\n");var i=new Function("value","context",t);if(this.opts.debug){var s=function(t){return t};"undefined"==typeof window&&(s=e),r.fn.forEach(function(t,e){return console.log(s("// Context.fn["+e+"]\n"+t.toString()))}),console.log(s("// Main check function\n"+i.toString()))}return this.cache.clear(),function(t){return r.data=t,i.call(n,t,r)}},t.prototype.compileRule=function(t,e,n,r,a){var i=[],s=this.cache.get(t.schema);return s?(t=s,t.cycle=!0,t.cycleStack=[],i.push(this.wrapRequiredCheckSourceCode(t,"\n\t\t\t\tvar rule = context.rules["+t.index+"];\n\t\t\t\tif (rule.cycleStack.indexOf(value) === -1) {\n\t\t\t\t\trule.cycleStack.push(value);\n\t\t\t\t\t"+r.replace("%%INDEX%%",t.index)+"\n\t\t\t\t\trule.cycleStack.pop(value);\n\t\t\t\t}\n\t\t\t",a))):(this.cache.set(t.schema,t),t.index=e.index,e.rules[e.index]=t,e.index++,n=t.ruleFunction.call(this,t,n,e),n.source?(n=new Function("value","field","parent","errors","context",n.source),e.fn[t.index]=n,i.push(this.wrapRequiredCheckSourceCode(t,r.replace("%%INDEX%%",t.index),a))):i.push(this.wrapRequiredCheckSourceCode(t))),i.join("\n")},t.prototype.getRuleFromSchema=function(t){if("string"==typeof t){var e=t.split("|").map(function(t){return t.trim()});t={type:e[0]},e.slice(1).map(function(e){var n=e.indexOf(":");if(-1!==n){var r=e.substr(0,n).trim();"true"===(e=e.substr(n+1).trim())||"false"===e?e="true"===e:Number.isNaN(Number(e))||(e=Number(e)),t[r]=e}else e.startsWith("no-")?t[e.slice(3)]=!1:t[e]=!0})}else if(Array.isArray(t)){if(0==t.length)throw Error("Invalid schema.");t={type:"multi",rules:t}}if(!(e=this.rules[t.type]))throw Error("Invalid '"+t.type+"' type in validator schema.");return{messages:Object.assign({},this.messages,t.messages),schema:t,ruleFunction:e}},t.prototype.makeError=function(t){var e=t.type,n=t.field,r=t.expected,a=t.actual,i={type:'"'+e+'"',message:'"'+t.messages[e]+'"'};return i.field=n?'"'+n+'"':"field",r&&(i.expected=r),a&&(i.actual=a),"errors.push({ "+Object.keys(i).map(function(t){return t+": "+i[t]}).join(", ")+" });"},t.prototype.add=function(t,e){this.rules[t]=e},t}var f=f||{};f.scope={},f.ASSUME_ES5=!1,f.ASSUME_NO_NATIVE_MAP=!1,f.ASSUME_NO_NATIVE_SET=!1,f.defineProperty=f.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(t,e,n){t!=Array.prototype&&t!=Object.prototype&&(t[e]=n.value)},f.getGlobal=function(t){return"undefined"!=typeof window&&window===t?t:"undefined"!=typeof global&&null!=global?global:t},f.global=f.getGlobal(this),f.SYMBOL_PREFIX="jscomp_symbol_",f.initSymbol=function(){f.initSymbol=function(){},f.global.Symbol||(f.global.Symbol=f.Symbol)},f.Symbol=function(){var t=0;return function(e){return f.SYMBOL_PREFIX+(e||"")+t++}}(),f.initSymbolIterator=function(){f.initSymbol();var t=f.global.Symbol.iterator;t||(t=f.global.Symbol.iterator=f.global.Symbol("iterator")),"function"!=typeof Array.prototype[t]&&f.defineProperty(Array.prototype,t,{configurable:!0,writable:!0,value:function(){return f.arrayIterator(this)}}),f.initSymbolIterator=function(){}},f.arrayIterator=function(t){var e=0;return f.iteratorPrototype(function(){return e<t.length?{done:!1,value:t[e++]}:{done:!0}})},f.iteratorPrototype=function(t){return f.initSymbolIterator(),t={next:t},t[f.global.Symbol.iterator]=function(){return this},t},f.iteratorFromArray=function(t,e){f.initSymbolIterator(),t instanceof String&&(t+="");var n=0,r={next:function(){if(n<t.length){var a=n++;return{value:e(a,t[a]),done:!1}}return r.next=function(){return{done:!0,value:void 0}},r.next()}};return r[Symbol.iterator]=function(){return r},r},f.polyfill=function(t,e){if(e){var n=f.global;t=t.split(".");for(var r=0;r<t.length-1;r++){var a=t[r];a in n||(n[a]={}),n=n[a]}(e=e(r=n[t=t[t.length-1]]))!=r&&null!=e&&f.defineProperty(n,t,{configurable:!0,writable:!0,value:e})}},f.polyfill("Array.prototype.values",function(t){return t||function(){return f.iteratorFromArray(this,function(t,e){return e})}},"es8","es3"),f.polyfill("Array.prototype.keys",function(t){return t||function(){return f.iteratorFromArray(this,function(t){return t})}},"es6","es3"),f.checkEs6ConformanceViaProxy=function(){try{var t={},e=Object.create(new f.global.Proxy(t,{get:function(n,r,a){return n==t&&"q"==r&&a==e}}));return!0===e.q}catch(t){return!1}},f.USE_PROXY_FOR_ES6_CONFORMANCE_CHECKS=!1,f.ES6_CONFORMANCE=f.USE_PROXY_FOR_ES6_CONFORMANCE_CHECKS&&f.checkEs6ConformanceViaProxy(),f.makeIterator=function(t){f.initSymbolIterator();var e=t[Symbol.iterator];return e?e.call(t):f.arrayIterator(t)},f.owns=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},f.polyfill("WeakMap",function(t){function e(t){if(this.id_=(i+=Math.random()+1).toString(),t){f.initSymbol(),f.initSymbolIterator(),t=f.makeIterator(t);for(var e;!(e=t.next()).done;)e=e.value,this.set(e[0],e[1])}}function n(t){f.owns(t,a)||f.defineProperty(t,a,{value:{}})}function r(t){var e=Object[t];e&&(Object[t]=function(t){return n(t),e(t)})}if(f.USE_PROXY_FOR_ES6_CONFORMANCE_CHECKS){if(t&&f.ES6_CONFORMANCE)return t}else if(function(){if(!t||!Object.seal)return!1;try{var e=Object.seal({}),n=Object.seal({}),r=new t([[e,2],[n,3]]);return 2==r.get(e)&&3==r.get(n)&&(r.delete(e),r.set(n,4),!r.has(e)&&4==r.get(n))}catch(t){return!1}}())return t;var a="$jscomp_hidden_"+Math.random();r("freeze"),r("preventExtensions"),r("seal");var i=0;return e.prototype.set=function(t,e){if(n(t),!f.owns(t,a))throw Error("WeakMap key fail: "+t);return t[a][this.id_]=e,this},e.prototype.get=function(t){return f.owns(t,a)?t[a][this.id_]:void 0},e.prototype.has=function(t){return f.owns(t,a)&&f.owns(t[a],this.id_)},e.prototype.delete=function(t){return!(!f.owns(t,a)||!f.owns(t[a],this.id_))&&delete t[a][this.id_]},e},"es6","es3"),f.MapEntry=function(){},f.polyfill("Map",function(t){function e(){var t={};return t.previous=t.next=t.head=t}function n(t,e){var n=t.head_;return f.iteratorPrototype(function(){if(n){for(;n.head!=t.head_;)n=n.previous;for(;n.next!=n.head;)return n=n.next,{done:!1,value:e(n)};n=null}return{done:!0,value:void 0}})}function r(t,e){var n=e&&typeof e;"object"==n||"function"==n?i.has(e)?n=i.get(e):(n=""+ ++s,i.set(e,n)):n="p_"+e;var r=t.data_[n];if(r&&f.owns(t.data_,n))for(t=0;t<r.length;t++){var a=r[t];if(e!==e&&a.key!==a.key||e===a.key)return{id:n,list:r,index:t,entry:a}}return{id:n,list:r,index:-1,entry:void 0}}function a(t){if(this.data_={},this.head_=e(),this.size=0,t){t=f.makeIterator(t);for(var n;!(n=t.next()).done;)n=n.value,this.set(n[0],n[1])}}if(f.USE_PROXY_FOR_ES6_CONFORMANCE_CHECKS){if(t&&f.ES6_CONFORMANCE)return t}else if(function(){if(f.ASSUME_NO_NATIVE_MAP||!t||"function"!=typeof t||!t.prototype.entries||"function"!=typeof Object.seal)return!1;try{var e=Object.seal({x:4}),n=new t(f.makeIterator([[e,"s"]]));if("s"!=n.get(e)||1!=n.size||n.get({x:4})||n.set({x:4},"t")!=n||2!=n.size)return!1;var r=n.entries(),a=r.next();return!a.done&&a.value[0]==e&&"s"==a.value[1]&&!((a=r.next()).done||4!=a.value[0].x||"t"!=a.value[1]||!r.next().done)}catch(t){return!1}}())return t;f.initSymbol(),f.initSymbolIterator();var i=new WeakMap;a.prototype.set=function(t,e){var n=r(this,t);return n.list||(n.list=this.data_[n.id]=[]),n.entry?n.entry.value=e:(n.entry={next:this.head_,previous:this.head_.previous,head:this.head_,key:t,value:e},n.list.push(n.entry),this.head_.previous.next=n.entry,this.head_.previous=n.entry,this.size++),this},a.prototype.delete=function(t){return!(!(t=r(this,t)).entry||!t.list)&&(t.list.splice(t.index,1),t.list.length||delete this.data_[t.id],t.entry.previous.next=t.entry.next,t.entry.next.previous=t.entry.previous,t.entry.head=null,this.size--,!0)},a.prototype.clear=function(){this.data_={},this.head_=this.head_.previous=e(),this.size=0},a.prototype.has=function(t){return!!r(this,t).entry},a.prototype.get=function(t){return(t=r(this,t).entry)&&t.value},a.prototype.entries=function(){return n(this,function(t){return[t.key,t.value]})},a.prototype.keys=function(){return n(this,function(t){return t.key})},a.prototype.values=function(){return n(this,function(t){return t.value})},a.prototype.forEach=function(t,e){for(var n,r=this.entries();!(n=r.next()).done;)n=n.value,t.call(e,n[1],n[0],this)},a.prototype[Symbol.iterator]=a.prototype.entries;var s=0;return a},"es6","es3"),f.assign="function"==typeof Object.assign?Object.assign:function(t,e){for(var n=1;n<arguments.length;n++){var r=arguments[n];if(r)for(var a in r)f.owns(r,a)&&(t[a]=r[a])}return t},f.polyfill("Object.assign",function(t){return t||f.assign},"es6","es3"),f.polyfill("Number.isNaN",function(t){return t||function(t){return"number"==typeof t&&isNaN(t)}},"es6","es3"),f.checkStringArgs=function(t,e,n){if(null==t)throw new TypeError("The 'this' value for String.prototype."+n+" must not be null or undefined");if(e instanceof RegExp)throw new TypeError("First argument to String.prototype."+n+" must not be a regular expression");return t+""},f.polyfill("String.prototype.startsWith",function(t){return t||function(t,e){var n=f.checkStringArgs(this,t,"startsWith");t+="";var r=n.length,a=t.length;e=Math.max(0,Math.min(0|e,n.length));for(var i=0;i<a&&e<r;)if(n[e++]!=t[i++])return!1;return i>=a}},"es6","es3");var t=this;"object"==typeof exports&&"undefined"!=typeof module?module.exports=u():"function"==typeof define&&define.amd?define(u):(t=t||self,t.FastestValidator=u()); |
322
index.d.ts
@@ -9,5 +9,7 @@ declare module 'fastest-validator' { | ||
| 'boolean' | ||
| 'custom' | ||
| 'date' | ||
| 'email' | ||
| 'enum' | ||
| 'equal' | ||
| 'forbidden' | ||
@@ -17,2 +19,3 @@ | 'function' | ||
| 'mac' | ||
| 'multi' | ||
| 'number' | ||
@@ -23,3 +26,3 @@ | 'object' | ||
| 'uuid' | ||
| 'custom'; | ||
| string; | ||
@@ -66,3 +69,3 @@ /** | ||
*/ | ||
contains?: T[]; | ||
contains?: T | T[]; | ||
/** | ||
@@ -75,3 +78,3 @@ * Every element must be an element of the enum array | ||
*/ | ||
items: ValidationRule; | ||
items?: ValidationRule; | ||
} | ||
@@ -124,2 +127,4 @@ | ||
mode?: 'quick' | 'precise'; | ||
normalize?: boolean; | ||
} | ||
@@ -143,2 +148,30 @@ | ||
/** | ||
* Validation schema definition for "equal" built-in validator | ||
* @see https://github.com/icebob/fastest-validator#equal | ||
*/ | ||
interface RuleEqual<T = any> extends RuleCustom { | ||
/** | ||
* Name of built-in validator | ||
*/ | ||
type: 'equal'; | ||
/** | ||
* The valid value | ||
*/ | ||
value?: T; | ||
/** | ||
* Another field name | ||
*/ | ||
field?: string; | ||
/** | ||
* Strict value checking. | ||
* | ||
* @type {'boolean'} | ||
* @memberof RuleEqual | ||
*/ | ||
strict?: boolean; | ||
} | ||
/** | ||
* Validation schema definition for "forbidden" built-in validator | ||
@@ -152,2 +185,10 @@ * @see https://github.com/icebob/fastest-validator#forbidden | ||
type: 'forbidden'; | ||
/** | ||
* Removes the forbidden value. | ||
* | ||
* @type {'boolean'} | ||
* @memberof RuleForbidden | ||
*/ | ||
remove?: boolean; | ||
} | ||
@@ -167,2 +208,37 @@ | ||
/** | ||
* Validation schema definition for "luhn" built-in validator | ||
* @see https://github.com/icebob/fastest-validator#luhn | ||
*/ | ||
interface RuleLuhn extends RuleCustom { | ||
/** | ||
* Name of built-in validator | ||
*/ | ||
type: 'luhn'; | ||
} | ||
/** | ||
* Validation schema definition for "mac" built-in validator | ||
* @see https://github.com/icebob/fastest-validator#mac | ||
*/ | ||
interface RuleMac extends RuleCustom { | ||
/** | ||
* Name of built-in validator | ||
*/ | ||
type: 'mac'; | ||
} | ||
/** | ||
* Validation schema definition for "multi" built-in validator | ||
* @see https://github.com/icebob/fastest-validator#multi | ||
*/ | ||
interface RuleMulti extends RuleCustom { | ||
/** | ||
* Name of built-in validator | ||
*/ | ||
type: 'multi'; | ||
rules: RuleCustom[] | string[]; | ||
} | ||
/** | ||
* Validation schema definition for "number" built-in validator | ||
@@ -208,3 +284,3 @@ * @see https://github.com/icebob/fastest-validator#number | ||
/** | ||
* if true and the type is not Number, tries to convert with parseFloat | ||
* if true and the type is not Number, converts with Number() | ||
* @default false | ||
@@ -232,2 +308,3 @@ */ | ||
*/ | ||
properties?: ValidationSchema; | ||
props?: ValidationSchema; | ||
@@ -290,2 +367,20 @@ } | ||
alphadash?: boolean; | ||
/** | ||
* if true and the type is not a String, converts with String() | ||
* @default false | ||
*/ | ||
convert?: boolean; | ||
trim?: boolean; | ||
trimLeft?: boolean; | ||
trimRight?: boolean; | ||
padStart?: number; | ||
padEnd?: number; | ||
padChar?: string; | ||
lowercase?: boolean; | ||
uppercase?: boolean; | ||
localeLowercase?: boolean; | ||
localeUppercase?: boolean; | ||
} | ||
@@ -320,28 +415,6 @@ | ||
/** | ||
* Validation schema definition for "mac" built-in validator | ||
* @see https://github.com/icebob/fastest-validator#mac | ||
*/ | ||
interface RuleMac extends RuleCustom { | ||
/** | ||
* Name of built-in validator | ||
*/ | ||
type: 'mac'; | ||
} | ||
/** | ||
* Validation schema definition for "luhn" built-in validator | ||
* @see https://github.com/icebob/fastest-validator#luhn | ||
*/ | ||
interface RuleLuhn extends RuleCustom { | ||
/** | ||
* Name of built-in validator | ||
*/ | ||
type: 'luhn'; | ||
} | ||
/** | ||
* Validation schema definition for custom inline validator | ||
* @see https://github.com/icebob/fastest-validator#custom-validator | ||
*/ | ||
interface RuleCustomInline extends RuleCustom { | ||
interface RuleCustomInline<T = any> extends RuleCustom { | ||
/** | ||
@@ -357,3 +430,3 @@ * Name of built-in validator | ||
*/ | ||
check: (value: any, schema: ValidationRuleObject) => true | ValidationError[]; | ||
check: (value: T, schema: ValidationRuleObject, path: string, parent?: object, context?: any) => true | ValidationError[]; | ||
} | ||
@@ -382,2 +455,7 @@ | ||
/** | ||
* Default value | ||
*/ | ||
default?: any; | ||
/** | ||
* You can define any additional options for custom validators | ||
@@ -393,125 +471,195 @@ */ | ||
/** | ||
* The '{field}' field is required! | ||
* The '{field}' field is required. | ||
*/ | ||
required?: string; | ||
/** | ||
* The '{field}' field must be a string! | ||
* The '{field}' field must be a string. | ||
*/ | ||
string?: string; | ||
/** | ||
* The '{field}' field must not be empty! | ||
* The '{field}' field must not be empty. | ||
*/ | ||
stringEmpty?: string; | ||
/** | ||
* The '{field}' field length must be greater than or equal to {expected} characters long! | ||
* The '{field}' field length must be greater than or equal to {expected} characters long. | ||
*/ | ||
stringMin?: string; | ||
/** | ||
* The '{field}' field length must be less than or equal to {expected} characters long! | ||
* The '{field}' field length must be less than or equal to {expected} characters long. | ||
*/ | ||
stringMax?: string; | ||
/** | ||
* The '{field}' field length must be {expected} characters long! | ||
* The '{field}' field length must be {expected} characters long. | ||
*/ | ||
stringLength?: string; | ||
/** | ||
* The '{field}' field fails to match the required pattern! | ||
* The '{field}' field fails to match the required pattern. | ||
*/ | ||
stringPattern?: string; | ||
/** | ||
* The '{field}' field must contain the '{expected}' text! | ||
* The '{field}' field must contain the '{expected}' text. | ||
*/ | ||
stringContains?: string; | ||
/** | ||
* The '{field}' field does not match any of the allowed values! | ||
* The '{field}' field does not match any of the allowed values. | ||
*/ | ||
stringEnum?: string; | ||
/** | ||
* The '{field}' field must be a number! | ||
* The '{field}' field must be a numeric string. | ||
*/ | ||
stringNumeric?: string; | ||
/** | ||
* The '{field}' field must be an alphabetic string. | ||
*/ | ||
stringAlpha?: string; | ||
/** | ||
* The '{field}' field must be an alphanumeric string. | ||
*/ | ||
stringAlphanum?: string; | ||
/** | ||
* The '{field}' field must be an alphadash string. | ||
*/ | ||
stringAlphadash?: string; | ||
/** | ||
* The '{field}' field must be a number. | ||
*/ | ||
number?: string; | ||
/** | ||
* The '{field}' field must be greater than or equal to {expected}! | ||
* The '{field}' field must be greater than or equal to {expected}. | ||
*/ | ||
numberMin?: string; | ||
/** | ||
* The '{field}' field must be less than or equal to {expected}! | ||
* The '{field}' field must be less than or equal to {expected}. | ||
*/ | ||
numberMax?: string; | ||
/** | ||
* The '{field}' field must be equal with {expected}! | ||
* The '{field}' field must be equal with {expected}. | ||
*/ | ||
numberEqual?: string; | ||
/** | ||
* The '{field}' field can't be equal with {expected}! | ||
* The '{field}' field can't be equal with {expected}. | ||
*/ | ||
numberNotEqual?: string; | ||
/** | ||
* The '{field}' field must be an integer! | ||
* The '{field}' field must be an integer. | ||
*/ | ||
numberInteger?: string; | ||
/** | ||
* The '{field}' field must be a positive number! | ||
* The '{field}' field must be a positive number. | ||
*/ | ||
numberPositive?: string; | ||
/** | ||
* The '{field}' field must be a negative number! | ||
* The '{field}' field must be a negative number. | ||
*/ | ||
numberNegative?: string; | ||
/** | ||
* The '{field}' field must be an array! | ||
* The '{field}' field must be an array. | ||
*/ | ||
array?: string; | ||
/** | ||
* The '{field}' field must not be an empty array! | ||
* The '{field}' field must not be an empty array. | ||
*/ | ||
arrayEmpty?: string; | ||
/** | ||
* The '{field}' field must contain at least {expected} items! | ||
* The '{field}' field must contain at least {expected} items. | ||
*/ | ||
arrayMin?: string; | ||
/** | ||
* The '{field}' field must contain less than or equal to {expected} items! | ||
* The '{field}' field must contain less than or equal to {expected} items. | ||
*/ | ||
arrayMax?: string; | ||
/** | ||
* The '{field}' field must contain {expected} items! | ||
* The '{field}' field must contain {expected} items. | ||
*/ | ||
arrayLength?: string; | ||
/** | ||
* The '{field}' field must contain the '{expected}' item! | ||
* The '{field}' field must contain the '{expected}' item. | ||
*/ | ||
arrayContains?: string; | ||
/** | ||
* The '{field} field value '{expected}' does not match any of the allowed values! | ||
* The '{field} field value '{expected}' does not match any of the allowed values. | ||
*/ | ||
arrayEnum?: string; | ||
/** | ||
* The '{field}' field must be a boolean! | ||
* The '{field}' field must be a boolean. | ||
*/ | ||
boolean?: string; | ||
/** | ||
* The '{field}' field must be a function! | ||
* The '{field}' field must be a Date. | ||
*/ | ||
function?: string; | ||
/** | ||
* The '{field}' field must be a Date! | ||
*/ | ||
date?: string; | ||
/** | ||
* The '{field}' field must be greater than or equal to {expected}! | ||
* The '{field}' field must be greater than or equal to {expected}. | ||
*/ | ||
dateMin?: string; | ||
/** | ||
* The '{field}' field must be less than or equal to {expected}! | ||
* The '{field}' field must be less than or equal to {expected}. | ||
*/ | ||
dateMax?: string; | ||
/** | ||
* The '{field}' field is forbidden! | ||
* The '{field}' field value '{expected}' does not match any of the allowed values. | ||
*/ | ||
enumValue?: string; | ||
/** | ||
* The '{field}' field value must be equal to '{expected}'. | ||
*/ | ||
equalValue?: string; | ||
/** | ||
* The '{field}' field value must be equal to '{expected}' field value. | ||
*/ | ||
equalField?: string; | ||
/** | ||
* The '{field}' field is forbidden. | ||
*/ | ||
forbidden?: string; | ||
/** | ||
* The '{field}' field must be a valid e-mail! | ||
* The '{field}' field must be a function. | ||
*/ | ||
function?: string; | ||
/** | ||
* The '{field}' field must be a valid e-mail. | ||
*/ | ||
email?: string; | ||
/** | ||
* The '{field}' field must be a valid checksum luhn. | ||
*/ | ||
luhn?: string; | ||
/** | ||
* The '{field}' field must be a valid MAC address. | ||
*/ | ||
mac?: string; | ||
/** | ||
* The '{field}' must be an Object. | ||
*/ | ||
object?: string; | ||
/** | ||
* The object '{field}' contains forbidden keys: '{actual}'. | ||
*/ | ||
objectStrict?: string; | ||
/** | ||
* The '{field}' field must be a valid URL. | ||
*/ | ||
url?: string; | ||
/** | ||
* The '{field}' field must be a valid UUID. | ||
*/ | ||
uuid?: string; | ||
/** | ||
* The '{field}' field must be a valid UUID version provided. | ||
*/ | ||
uuidVersion?: string; | ||
} | ||
@@ -533,2 +681,3 @@ | ||
| RuleEmail | ||
| RuleEqual | ||
| RuleEnum | ||
@@ -539,2 +688,3 @@ | RuleForbidden | ||
| RuleMac | ||
| RuleMulti | ||
| RuleNumber | ||
@@ -551,3 +701,3 @@ | RuleObject | ||
*/ | ||
type ValidationRule = ValidationRuleObject | ValidationRuleObject[] | ValidationRuleName | string; | ||
type ValidationRule = ValidationRuleObject | ValidationRuleObject[] | ValidationRuleName; | ||
@@ -559,6 +709,2 @@ /** | ||
/** | ||
* List of validation rules for each defined field | ||
*/ | ||
[key: string]: ValidationRule | boolean; | ||
/** | ||
* Object properties which are not specified on the schema are ignored by default. | ||
@@ -569,2 +715,9 @@ * If you set the $$strict option to true any aditional properties will result in an strictObject error. | ||
$$strict?: boolean; | ||
$$root?: boolean; | ||
/** | ||
* List of validation rules for each defined field | ||
*/ | ||
[key: string]: ValidationRule | boolean | undefined; | ||
} | ||
@@ -579,3 +732,3 @@ | ||
*/ | ||
type: ValidationRuleName | string; | ||
type: ValidationRuleName; | ||
/** | ||
@@ -603,2 +756,3 @@ * Field that catch validation error | ||
type ValidatorConstructorOptions = { | ||
debug?: boolean, | ||
/** | ||
@@ -612,2 +766,12 @@ * List of possible error messages | ||
/** | ||
* List of possible error messages | ||
*/ | ||
messages: MessagesType; | ||
/** | ||
* List of rules attached to current validator | ||
*/ | ||
rules: { [key: string]: ValidationRuleObject }; | ||
/** | ||
* Constructor of validation class | ||
@@ -627,8 +791,11 @@ * @param {ValidatorConstructorOptions} opts List of possible validator constructor options | ||
* Build error message | ||
* @param {string} type Name of validation rule (equal to "type" option) | ||
* @param {{any}} [expected] Expected value for validation rule | ||
* @param {{any}} [actual] Actual value received to validation | ||
* @return {ValidationError} | ||
* @param {Object} opts | ||
* @param {String} opts.type | ||
* @param {String} opts.field | ||
* @param {any=} opts.expected | ||
* @param {any=} opts.actual | ||
* @param {MessagesType} opts.messages | ||
*/ | ||
makeError(type: keyof BuiltInMessages | string, expected?: any, actual?: any): ValidationError; | ||
makeError(opts: { type: keyof MessagesType, field?: string, expected?: any, actual?: any, messages: MessagesType }): ValidationError; | ||
@@ -640,3 +807,3 @@ /** | ||
*/ | ||
compile(schema: ValidationSchema | ValidationSchema[]): (object: object) => true | ValidationError[]; | ||
compile(schema: ValidationSchema | ValidationSchema[]): (object: any) => true | ValidationError[]; | ||
@@ -650,2 +817,9 @@ /** | ||
validate(obj: object, schema: ValidationSchema): true | ValidationError[]; | ||
/** | ||
* Get defined in validator rule | ||
* @param {ValidationRuleName | ValidationRuleName[]} name List or name of defined rule | ||
* @return {ValidationRule} | ||
*/ | ||
getRuleFromSchema(name: ValidationRuleName | ValidationRuleName[]): { messages: MessagesType, schema: ValidationSchema, ruleFunction: Function } | ||
} | ||
@@ -665,2 +839,3 @@ | ||
RuleEnum, | ||
RuleEqual, | ||
RuleForbidden, | ||
@@ -670,2 +845,3 @@ RuleFunction, | ||
RuleMac, | ||
RuleMulti, | ||
RuleNumber, | ||
@@ -672,0 +848,0 @@ RuleObject, |
"use strict"; | ||
module.exports = { | ||
required: "The '{field}' field is required!", | ||
required: "The '{field}' field is required.", | ||
string: "The '{field}' field must be a string!", | ||
stringEmpty: "The '{field}' field must not be empty!", | ||
stringMin: "The '{field}' field length must be greater than or equal to {expected} characters long!", | ||
stringMax: "The '{field}' field length must be less than or equal to {expected} characters long!", | ||
stringLength: "The '{field}' field length must be {expected} characters long!", | ||
stringPattern: "The '{field}' field fails to match the required pattern!", | ||
stringContains: "The '{field}' field must contain the '{expected}' text!", | ||
stringEnum: "The '{field}' field does not match any of the allowed values!", | ||
stringNumeric: "The '{field}' field must be a numeric string", | ||
stringAlpha: "The '{field}' field must be an alphabetic string", | ||
stringAlphanum: "The '{field}' field must be an alphanumeric string", | ||
stringAlphadash: "The '{field}' field must be an alphadash string", | ||
string: "The '{field}' field must be a string.", | ||
stringEmpty: "The '{field}' field must not be empty.", | ||
stringMin: "The '{field}' field length must be greater than or equal to {expected} characters long.", | ||
stringMax: "The '{field}' field length must be less than or equal to {expected} characters long.", | ||
stringLength: "The '{field}' field length must be {expected} characters long.", | ||
stringPattern: "The '{field}' field fails to match the required pattern.", | ||
stringContains: "The '{field}' field must contain the '{expected}' text.", | ||
stringEnum: "The '{field}' field does not match any of the allowed values.", | ||
stringNumeric: "The '{field}' field must be a numeric string.", | ||
stringAlpha: "The '{field}' field must be an alphabetic string.", | ||
stringAlphanum: "The '{field}' field must be an alphanumeric string.", | ||
stringAlphadash: "The '{field}' field must be an alphadash string.", | ||
number: "The '{field}' field must be a number!", | ||
numberMin: "The '{field}' field must be greater than or equal to {expected}!", | ||
numberMax: "The '{field}' field must be less than or equal to {expected}!", | ||
numberEqual: "The '{field}' field must be equal with {expected}!", | ||
numberNotEqual: "The '{field}' field can't be equal with {expected}!", | ||
numberInteger: "The '{field}' field must be an integer!", | ||
numberPositive: "The '{field}' field must be a positive number!", | ||
numberNegative: "The '{field}' field must be a negative number!", | ||
number: "The '{field}' field must be a number.", | ||
numberMin: "The '{field}' field must be greater than or equal to {expected}.", | ||
numberMax: "The '{field}' field must be less than or equal to {expected}.", | ||
numberEqual: "The '{field}' field must be equal to {expected}.", | ||
numberNotEqual: "The '{field}' field can't be equal to {expected}.", | ||
numberInteger: "The '{field}' field must be an integer.", | ||
numberPositive: "The '{field}' field must be a positive number.", | ||
numberNegative: "The '{field}' field must be a negative number.", | ||
array: "The '{field}' field must be an array!", | ||
arrayEmpty: "The '{field}' field must not be an empty array!", | ||
arrayMin: "The '{field}' field must contain at least {expected} items!", | ||
arrayMax: "The '{field}' field must contain less than or equal to {expected} items!", | ||
arrayLength: "The '{field}' field must contain {expected} items!", | ||
arrayContains: "The '{field}' field must contain the '{expected}' item!", | ||
arrayEnum: "The '{field} field value '{expected}' does not match any of the allowed values!", | ||
array: "The '{field}' field must be an array.", | ||
arrayEmpty: "The '{field}' field must not be an empty array.", | ||
arrayMin: "The '{field}' field must contain at least {expected} items.", | ||
arrayMax: "The '{field}' field must contain less than or equal to {expected} items.", | ||
arrayLength: "The '{field}' field must contain {expected} items.", | ||
arrayContains: "The '{field}' field must contain the '{expected}' item.", | ||
arrayEnum: "The '{actual}' value in '{field}' field does not match any of the '{expected}' values.", | ||
boolean: "The '{field}' field must be a boolean!", | ||
boolean: "The '{field}' field must be a boolean.", | ||
function: "The '{field}' field must be a function!", | ||
date: "The '{field}' field must be a Date.", | ||
dateMin: "The '{field}' field must be greater than or equal to {expected}.", | ||
dateMax: "The '{field}' field must be less than or equal to {expected}.", | ||
date: "The '{field}' field must be a Date!", | ||
dateMin: "The '{field}' field must be greater than or equal to {expected}!", | ||
dateMax: "The '{field}' field must be less than or equal to {expected}!", | ||
enumValue: "The '{field}' field value '{expected}' does not match any of the allowed values.", | ||
forbidden: "The '{field}' field is forbidden!", | ||
equalValue: "The '{field}' field value must be equal to '{expected}'.", | ||
equalField: "The '{field}' field value must be equal to '{expected}' field value.", | ||
email: "The '{field}' field must be a valid e-mail!", | ||
forbidden: "The '{field}' field is forbidden.", | ||
url: "The '{field}' field must be a valid URL!", | ||
function: "The '{field}' field must be a function.", | ||
enumValue: "The '{field} field value '{expected}' does not match any of the allowed values!", | ||
email: "The '{field}' field must be a valid e-mail.", | ||
object: "The '{field}' must be an Object!", | ||
objectStrict: "The object '{field}' contains invalid keys: '{actual}'!", | ||
uuid: "The {field} field must be a valid UUID", | ||
uuidVersion: "The {field} field must be a valid version provided", | ||
mac: "The {field} field must be a valid MAC address", | ||
luhn: "The {field} field must be a valid checksum luhn", | ||
luhn: "The '{field}' field must be a valid checksum luhn.", | ||
mac: "The '{field}' field must be a valid MAC address.", | ||
object: "The '{field}' must be an Object.", | ||
objectStrict: "The object '{field}' contains forbidden keys: '{actual}'.", | ||
url: "The '{field}' field must be a valid URL.", | ||
uuid: "The '{field}' field must be a valid UUID.", | ||
uuidVersion: "The '{field}' field must be a valid UUID version provided.", | ||
}; |
"use strict"; | ||
module.exports = function checkAny() { | ||
return true; | ||
}; | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function(/*{ schema, messages }, path, context*/) { | ||
return {}; | ||
}; |
"use strict"; | ||
module.exports = function checkArray(value, schema) { | ||
if (!Array.isArray(value)) { | ||
return this.makeError("array"); | ||
} | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function({ schema, messages }, path, context) { | ||
const src = []; | ||
const arrLength = value.length; | ||
src.push(` | ||
if (!Array.isArray(value)) { | ||
${this.makeError({ type: "array", actual: "value", messages })} | ||
return value; | ||
} | ||
if (schema.empty === false && arrLength === 0) { | ||
return this.makeError("arrayEmpty"); | ||
var len = value.length; | ||
`); | ||
if (schema.empty === false) { | ||
src.push(` | ||
if (len === 0) { | ||
${this.makeError({ type: "arrayEmpty", actual: "value", messages })} | ||
} | ||
`); | ||
} | ||
if (schema.min != null && arrLength < schema.min) { | ||
return this.makeError("arrayMin", schema.min, arrLength); | ||
if (schema.min != null) { | ||
src.push(` | ||
if (len < ${schema.min}) { | ||
${this.makeError({ type: "arrayMin", expected: schema.min, actual: "len", messages })} | ||
} | ||
`); | ||
} | ||
if (schema.max != null && arrLength > schema.max) { | ||
return this.makeError("arrayMax", schema.max, arrLength); | ||
if (schema.max != null) { | ||
src.push(` | ||
if (len > ${schema.max}) { | ||
${this.makeError({ type: "arrayMax", expected: schema.max, actual: "len", messages })} | ||
} | ||
`); | ||
} | ||
// Check fix length | ||
if (schema.length != null && arrLength !== schema.length) { | ||
return this.makeError("arrayLength", schema.length, arrLength); | ||
} | ||
if (schema.length != null) { | ||
src.push(` | ||
if (len !== ${schema.length}) { | ||
${this.makeError({ type: "arrayLength", expected: schema.length, actual: "len", messages })} | ||
} | ||
`); | ||
} | ||
if (schema.contains != null && value.indexOf(schema.contains) === -1) { | ||
return this.makeError("arrayContains", schema.contains); | ||
} | ||
if (schema.contains != null) { | ||
src.push(` | ||
if (value.indexOf(${JSON.stringify(schema.contains)}) === -1) { | ||
${this.makeError({ type: "arrayContains", expected: JSON.stringify(schema.contains), actual: "value", messages })} | ||
} | ||
`); | ||
} | ||
if (schema.enum != null) { | ||
for (let i = 0; i < value.length; i++) { | ||
if (schema.enum.indexOf(value[i]) === -1) { | ||
return this.makeError("arrayEnum", value[i], schema.enum); | ||
const enumStr = JSON.stringify(schema.enum); | ||
src.push(` | ||
for (var i = 0; i < value.length; i++) { | ||
if (${enumStr}.indexOf(value[i]) === -1) { | ||
${this.makeError({ type: "arrayEnum", expected: "\"" + schema.enum.join(", ") + "\"", actual: "value[i]", messages })} | ||
} | ||
} | ||
`); | ||
} | ||
if (schema.items != null) { | ||
src.push(` | ||
var arr = value; | ||
var parentField = field; | ||
for (var i = 0; i < arr.length; i++) { | ||
`); | ||
const rule = this.getRuleFromSchema(schema.items); | ||
src.push(this.compileRule(rule, context, path, "arr[i] = context.fn[%%INDEX%%](arr[i], (parentField ? parentField : \"\") + \"[\" + i + \"]\", parent, errors, context);", "arr[i]")); | ||
/* | ||
const res = rule.ruleFunction.call(this, rule, path, context); | ||
context.rules[context.index] = rule; | ||
if (res.source) { | ||
const fn = new Function("value", "field", "parent", "errors", "context", res.source); | ||
context.fn[context.index] = fn; | ||
src.push(`arr[i] = context.fn[${context.index}](arr[i], (parentField ? parentField : "") + "[" + i + "]", parent, errors, context);`); | ||
} | ||
} | ||
context.index++; | ||
*/ | ||
src.push(` | ||
} | ||
`); | ||
} | ||
return true; | ||
}; | ||
return { | ||
source: src.join("\n") | ||
}; | ||
}; |
"use strict"; | ||
module.exports = function checkBoolean(value, schema) { | ||
if (schema.convert === true && typeof value !== "boolean") { | ||
if ( | ||
value === 1 | ||
|| value === 0 | ||
|| value === "true" | ||
|| value === "false" | ||
|| value === "1" | ||
|| value === "0" | ||
|| value === "on" | ||
|| value === "off" | ||
) | ||
return true; | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function({ schema, messages }, path) { | ||
const src = []; | ||
let sanitized = false; | ||
src.push(` | ||
var origValue = value; | ||
`); | ||
if (schema.convert === true) { | ||
sanitized = true; | ||
src.push(` | ||
if (typeof value !== "boolean") { | ||
if ( | ||
value === 1 | ||
|| value === "true" | ||
|| value === "1" | ||
|| value === "on" | ||
) { | ||
value = true; | ||
} else if ( | ||
value === 0 | ||
|| value === "false" | ||
|| value === "0" | ||
|| value === "off" | ||
) { | ||
value = false; | ||
} | ||
} | ||
`); | ||
} | ||
if (typeof value !== "boolean") { | ||
return this.makeError("boolean"); | ||
} | ||
return true; | ||
}; | ||
src.push(` | ||
if (typeof value !== "boolean") | ||
${this.makeError({ type: "boolean", actual: "origValue", messages })} | ||
return value; | ||
`); | ||
return { | ||
sanitized, | ||
source: src.join("\n") | ||
}; | ||
}; |
"use strict"; | ||
module.exports = function customCheck(value, schema) { | ||
return schema.check.call(this, value, schema); | ||
}; | ||
module.exports = function({ schema, messages }, path, context) { | ||
const src = []; | ||
if (typeof schema.check == "function") { | ||
context.customs[path] = { schema, messages }; | ||
src.push(` | ||
const rule = context.customs["${path}"]; | ||
const res = rule.schema.check.call(this, value, rule.schema, "${path}", parent, context); | ||
if (Array.isArray(res)) { | ||
res.forEach(err => errors.push(Object.assign({ message: rule.messages[err.type] }, err))); | ||
} | ||
return value; | ||
`); | ||
} | ||
return { | ||
source: src.join("\n") | ||
}; | ||
}; |
"use strict"; | ||
module.exports = function checkDate(value, schema) { | ||
if (schema.convert === true && !(value instanceof Date)) { | ||
value = new Date(value); | ||
} | ||
if (!(value instanceof Date)) { | ||
return this.makeError("date"); | ||
} | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function({ schema, messages }, path) { | ||
const src = []; | ||
let sanitized = false; | ||
if (isNaN(value.getTime())) { | ||
return this.makeError("date"); | ||
src.push(` | ||
var origValue = value; | ||
`); | ||
if (schema.convert === true) { | ||
sanitized = true; | ||
src.push(` | ||
if (!(value instanceof Date)) { | ||
value = new Date(value); | ||
} | ||
`); | ||
} | ||
return true; | ||
}; | ||
src.push(` | ||
if (!(value instanceof Date) || isNaN(value.getTime())) | ||
${this.makeError({ type: "date", actual: "origValue", messages })} | ||
return value; | ||
`); | ||
return { | ||
sanitized, | ||
source: src.join("\n") | ||
}; | ||
}; |
@@ -6,18 +6,35 @@ "use strict"; | ||
module.exports = function checkEmail(value, schema) { | ||
if (typeof value !== "string") { | ||
return this.makeError("string"); | ||
} | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function({ schema, messages }, path) { | ||
const src = []; | ||
let pattern; | ||
if (schema.mode == "precise") | ||
pattern = PRECISE_PATTERN; | ||
else | ||
pattern = BASIC_PATTERN; | ||
const pattern = schema.mode == "precise" ? PRECISE_PATTERN : BASIC_PATTERN; | ||
let sanitized = false; | ||
if (!pattern.test(value)) { | ||
return this.makeError("email"); | ||
src.push(` | ||
if (typeof value !== "string") { | ||
${this.makeError({ type: "string", actual: "value", messages })} | ||
return value; | ||
} | ||
`); | ||
if (schema.normalize) { | ||
sanitized = true; | ||
src.push(` | ||
value = value.trim().toLowerCase(); | ||
`); | ||
} | ||
return true; | ||
src.push(` | ||
if (!${pattern.toString()}.test(value)) | ||
${this.makeError({ type: "email", actual: "value", messages })} | ||
return value; | ||
`); | ||
return { | ||
sanitized, | ||
source: src.join("\n") | ||
}; | ||
}; |
"use strict"; | ||
module.exports = function checkEnum(value, schema) { | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function({ schema, messages }, path) { | ||
const enumStr = JSON.stringify(schema.values || []); | ||
return { | ||
source: ` | ||
if (${enumStr}.indexOf(value) === -1) | ||
${this.makeError({ type: "enumValue", expected: "\"" + schema.values.join(", ") + "\"", actual: "value", messages })} | ||
if (schema.values != null && schema.values.indexOf(value) === -1) { | ||
return this.makeError("enumValue", schema.values, value); | ||
} | ||
return true; | ||
return value; | ||
` | ||
}; | ||
}; |
"use strict"; | ||
module.exports = function checkForbidden(value) { | ||
if (value !== null && value !== undefined) { | ||
return this.makeError("forbidden"); | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function checkForbidden({ schema, messages }, path) { | ||
const src = []; | ||
src.push(` | ||
if (value !== null && value !== undefined) { | ||
`); | ||
if (schema.remove) { | ||
src.push(` | ||
return undefined; | ||
`); | ||
} else { | ||
src.push(` | ||
${this.makeError({ type: "forbidden", actual: "value", messages })} | ||
`); | ||
} | ||
return true; | ||
}; | ||
src.push(` | ||
} | ||
return value; | ||
`); | ||
return { | ||
source: src.join("\n") | ||
}; | ||
}; |
"use strict"; | ||
module.exports = function checkFunction(value) { | ||
if (typeof value !== "function") { | ||
return this.makeError("function"); | ||
} | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function({ schema, messages }, path) { | ||
return { | ||
source: ` | ||
if (typeof value !== "function") | ||
${this.makeError({ type: "function", actual: "value", messages })} | ||
return true; | ||
}; | ||
return value; | ||
` | ||
}; | ||
}; |
@@ -9,26 +9,33 @@ "use strict"; | ||
* @return {boolean|{actual, expected, type}|ValidationError} | ||
* | ||
* Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function checkLuhn(value, schema) { | ||
module.exports = function({ schema, messages }, path) { | ||
return { | ||
source: ` | ||
if (typeof value !== "string") { | ||
${this.makeError({ type: "string", actual: "value", messages })} | ||
return value; | ||
} | ||
if(typeof value !== "number" && typeof value !== "string") | ||
return this.makeError("string"); | ||
if (typeof value !== "string") | ||
value = String(value); | ||
if (typeof value !== "string") | ||
value = String(value); | ||
val = value.replace(/\\D+/g, ""); | ||
value = value.replace(/\D+/g, ""); | ||
const check = function (array) { | ||
return number => { | ||
let len = number ? number.length : 0, | ||
var array = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]; | ||
var len = val ? val.length : 0, | ||
bit = 1, | ||
sum = 0; | ||
while (len--) { | ||
sum += !(bit ^= 1) ? parseInt(number[len], 10) : array[number[len]]; | ||
sum += !(bit ^= 1) ? parseInt(val[len], 10) : array[val[len]]; | ||
} | ||
return sum % 10 === 0 && sum > 0; | ||
}; | ||
}([0, 2, 4, 6, 8, 1, 3, 5, 7, 9]); | ||
return check(value) || this.makeError("luhn"); | ||
if (!(sum % 10 === 0 && sum > 0)) { | ||
${this.makeError({ type: "luhn", actual: "value", messages })} | ||
} | ||
return value; | ||
` | ||
}; | ||
}; |
@@ -5,11 +5,20 @@ "use strict"; | ||
module.exports = function checkMAC(value, schema) { | ||
if (typeof value !== "string") | ||
return this.makeError("string"); | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function({ schema, messages }, path) { | ||
return { | ||
source: ` | ||
if (typeof value !== "string") { | ||
${this.makeError({ type: "string", actual: "value", messages })} | ||
return value; | ||
} | ||
value = value.toLowerCase(); | ||
if (!PATTERN.test(value)) | ||
return this.makeError("mac"); | ||
var v = value.toLowerCase(); | ||
if (!${PATTERN.toString()}.test(v)) { | ||
${this.makeError({ type: "mac", actual: "value", messages })} | ||
} | ||
return true; | ||
return value; | ||
` | ||
}; | ||
}; |
"use strict"; | ||
module.exports = function checkNumber(value, schema) { | ||
if (schema.convert === true && typeof value !== "number") { | ||
value = Number(value); | ||
} | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function({ schema, messages }, path) { | ||
const src = []; | ||
if (typeof value !== "number") { | ||
return this.makeError("number"); | ||
} | ||
src.push(` | ||
var origValue = value; | ||
`); | ||
if (isNaN(value) || !isFinite(value)) { | ||
return this.makeError("number"); | ||
let sanitized = false; | ||
if (schema.convert === true) { | ||
sanitized = true; | ||
src.push(` | ||
if (typeof value !== "number") { | ||
value = Number(value); | ||
} | ||
`); | ||
} | ||
if (schema.min != null && value < schema.min) { | ||
return this.makeError("numberMin", schema.min, value); | ||
src.push(` | ||
if (typeof value !== "number" || isNaN(value) || !isFinite(value)) { | ||
${this.makeError({ type: "number", actual: "origValue", messages })} | ||
return value; | ||
} | ||
`); | ||
if (schema.min != null) { | ||
src.push(` | ||
if (value < ${schema.min}) { | ||
${this.makeError({ type: "numberMin", expected: schema.min, actual: "origValue", messages })} | ||
} | ||
`); | ||
} | ||
if (schema.max != null && value > schema.max) { | ||
return this.makeError("numberMax", schema.max, value); | ||
if (schema.max != null) { | ||
src.push(` | ||
if (value > ${schema.max}) { | ||
${this.makeError({ type: "numberMax", expected: schema.max, actual: "origValue", messages })} | ||
} | ||
`); | ||
} | ||
// Check fix value | ||
if (schema.equal != null && value !== schema.equal) { | ||
return this.makeError("numberEqual", schema.equal, value); | ||
} | ||
if (schema.equal != null) { | ||
src.push(` | ||
if (value !== ${schema.equal}) { | ||
${this.makeError({ type: "numberEqual", expected: schema.equal, actual: "origValue", messages })} | ||
} | ||
`); | ||
} | ||
// Check not fix value | ||
if (schema.notEqual != null && value === schema.notEqual) { | ||
return this.makeError("numberNotEqual", schema.notEqual); | ||
} | ||
if (schema.notEqual != null) { | ||
src.push(` | ||
if (value === ${schema.notEqual}) { | ||
${this.makeError({ type: "numberNotEqual", expected: schema.notEqual, actual: "origValue", messages })} | ||
} | ||
`); | ||
} | ||
// Check integer | ||
if (schema.integer === true && value % 1 !== 0) { | ||
return this.makeError("numberInteger", value); | ||
} | ||
if (schema.integer === true) { | ||
src.push(` | ||
if (value % 1 !== 0) { | ||
${this.makeError({ type: "numberInteger", actual: "origValue", messages })} | ||
} | ||
`); | ||
} | ||
// Check positive | ||
if (schema.positive === true && value <= 0) { | ||
return this.makeError("numberPositive", value); | ||
} | ||
if (schema.positive === true) { | ||
src.push(` | ||
if (value <= 0) { | ||
${this.makeError({ type: "numberPositive", actual: "origValue", messages })} | ||
} | ||
`); | ||
} | ||
// Check negative | ||
if (schema.negative === true && value >= 0) { | ||
return this.makeError("numberNegative", value); | ||
if (schema.negative === true) { | ||
src.push(` | ||
if (value >= 0) { | ||
${this.makeError({ type: "numberNegative", actual: "origValue", messages })} | ||
} | ||
`); | ||
} | ||
return true; | ||
}; | ||
src.push(` | ||
return value; | ||
`); | ||
return { | ||
sanitized, | ||
source: src.join("\n") | ||
}; | ||
}; |
"use strict"; | ||
module.exports = function checkObject(value, schema) { | ||
if (typeof value !== "object" || value === null || Array.isArray(value)) { | ||
return this.makeError("object"); | ||
} | ||
// Quick regex to match most common unquoted JavaScript property names. Note the spec allows Unicode letters. | ||
// Unmatched property names will be quoted and validate slighly slower. https://www.ecma-international.org/ecma-262/5.1/#sec-7.6 | ||
const identifierRegex = /^[_$a-zA-Z][_$a-zA-Z0-9]*$/; | ||
if (schema.strict === true && schema.props) { | ||
const allowedProps = Object.keys(schema.props); | ||
const invalidProps = []; | ||
const props = Object.keys(value); | ||
// Regex to escape quoted property names for eval/new Function | ||
const escapeEvalRegex = /["'\\\n\r\u2028\u2029]/g; | ||
for (let i = 0; i < props.length; i++) { | ||
if (allowedProps.indexOf(props[i]) === -1) { | ||
invalidProps.push(props[i]); | ||
/* istanbul ignore next */ | ||
function escapeEvalString(str) { | ||
// Based on https://github.com/joliss/js-string-escape | ||
return str.replace(escapeEvalRegex, function(character) { | ||
switch (character) { | ||
case "\"": | ||
case "'": | ||
case "\\": | ||
return "\\" + character; | ||
// Four possible LineTerminator characters need to be escaped: | ||
case "\n": | ||
return "\\n"; | ||
case "\r": | ||
return "\\r"; | ||
case "\u2028": | ||
return "\\u2028"; | ||
case "\u2029": | ||
return "\\u2029"; | ||
} | ||
}); | ||
} | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function({ schema, messages }, path, context) { | ||
const sourceCode = []; | ||
sourceCode.push(` | ||
if (typeof value !== "object" || value === null || Array.isArray(value)) { | ||
${this.makeError({ type: "object", actual: "value", messages })} | ||
return value; | ||
} | ||
`); | ||
const subSchema = schema.properties || schema.props; | ||
if (subSchema) { | ||
sourceCode.push("var parentObj = value;"); | ||
sourceCode.push("var parentField = field;"); | ||
const keys = Object.keys(subSchema); | ||
for (let i = 0; i < keys.length; i++) { | ||
const property = keys[i]; | ||
const name = escapeEvalString(property); | ||
const safeSubName = identifierRegex.test(name) ? `.${name}` : `['${name}']`; | ||
const safePropName = `parentObj${safeSubName}`; | ||
const newPath = (path ? path + "." : "") + property; | ||
sourceCode.push(`\n// Field: ${escapeEvalString(newPath)}`); | ||
sourceCode.push(`field = parentField ? parentField + "${safeSubName}" : "${name}";`); | ||
sourceCode.push(`value = ${safePropName};`); | ||
const rule = this.getRuleFromSchema(subSchema[property]); | ||
sourceCode.push(this.compileRule(rule, context, newPath, `${safePropName} = context.fn[%%INDEX%%](value, field, parentObj, errors, context);`, safePropName)); | ||
} | ||
// Strict handler | ||
if (schema.strict) { | ||
const allowedProps = Object.keys(subSchema); | ||
sourceCode.push(` | ||
field = parentField; | ||
var invalidProps = []; | ||
var props = Object.keys(parentObj); | ||
for (let i = 0; i < props.length; i++) { | ||
if (${JSON.stringify(allowedProps)}.indexOf(props[i]) === -1) { | ||
invalidProps.push(props[i]); | ||
} | ||
} | ||
if (invalidProps.length) { | ||
`); | ||
if (schema.strict == "remove") { | ||
sourceCode.push(` | ||
invalidProps.forEach(function(field) { | ||
delete parentObj[field]; | ||
}); | ||
`); | ||
} else { | ||
sourceCode.push(` | ||
${this.makeError({ type: "objectStrict", expected: "\"" + allowedProps.join(", ") + "\"", actual: "invalidProps.join(', ')", messages })} | ||
`); | ||
} | ||
sourceCode.push(` | ||
} | ||
`); | ||
} | ||
if (invalidProps.length !== 0) { | ||
return this.makeError("objectStrict", undefined, invalidProps.join(", ")); | ||
} | ||
sourceCode.push(` | ||
return parentObj; | ||
`); | ||
} else { | ||
sourceCode.push(` | ||
return value; | ||
`); | ||
} | ||
return true; | ||
}; | ||
return { | ||
source: sourceCode.join("\n") | ||
}; | ||
}; |
@@ -8,56 +8,195 @@ "use strict"; | ||
module.exports = function checkString(value, schema) { | ||
if (typeof value !== "string") { | ||
return this.makeError("string"); | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function checkString({ schema, messages }, path, context) { | ||
const src = []; | ||
let sanitized = false; | ||
if (schema.convert === true) { | ||
sanitized = true; | ||
src.push(` | ||
if (typeof value !== "string") { | ||
value = String(value); | ||
} | ||
`); | ||
} | ||
const valueLength = value.length; | ||
src.push(` | ||
if (typeof value !== "string") { | ||
${this.makeError({ type: "string", actual: "value", messages })} | ||
return value; | ||
} | ||
if (schema.empty === false && valueLength === 0) { | ||
return this.makeError("stringEmpty"); | ||
var origValue = value; | ||
`); | ||
if (schema.trim) { | ||
sanitized = true; | ||
src.push(` | ||
value = value.trim(); | ||
`); | ||
} | ||
if (schema.min != null && valueLength < schema.min) { | ||
return this.makeError("stringMin", schema.min, valueLength); | ||
if (schema.trimLeft) { | ||
sanitized = true; | ||
src.push(` | ||
value = value.trimLeft(); | ||
`); | ||
} | ||
if (schema.max != null && valueLength > schema.max) { | ||
return this.makeError("stringMax", schema.max, valueLength); | ||
if (schema.trimRight) { | ||
sanitized = true; | ||
src.push(` | ||
value = value.trimRight(); | ||
`); | ||
} | ||
if (schema.length != null && valueLength !== schema.length) { | ||
return this.makeError("stringLength", schema.length, valueLength); | ||
if (schema.padStart) { | ||
sanitized = true; | ||
const padChar = schema.padChar != null ? schema.padChar : " "; | ||
src.push(` | ||
value = value.padStart(${schema.padStart}, ${JSON.stringify(padChar)}); | ||
`); | ||
} | ||
if (schema.padEnd) { | ||
sanitized = true; | ||
const padChar = schema.padChar != null ? schema.padChar : " "; | ||
src.push(` | ||
value = value.padEnd(${schema.padEnd}, ${JSON.stringify(padChar)}); | ||
`); | ||
} | ||
if (schema.lowercase) { | ||
sanitized = true; | ||
src.push(` | ||
value = value.toLowerCase(); | ||
`); | ||
} | ||
if (schema.uppercase) { | ||
sanitized = true; | ||
src.push(` | ||
value = value.toUpperCase(); | ||
`); | ||
} | ||
if (schema.localeLowercase) { | ||
sanitized = true; | ||
src.push(` | ||
value = value.toLocaleLowerCase(); | ||
`); | ||
} | ||
if (schema.localeUppercase) { | ||
sanitized = true; | ||
src.push(` | ||
value = value.toLocaleUpperCase(); | ||
`); | ||
} | ||
src.push(` | ||
var len = value.length; | ||
`); | ||
if (schema.empty === false) { | ||
src.push(` | ||
if (len === 0) { | ||
${this.makeError({ type: "stringEmpty", actual: "value", messages })} | ||
} | ||
`); | ||
} | ||
if (schema.min != null) { | ||
src.push(` | ||
if (len < ${schema.min}) { | ||
${this.makeError({ type: "stringMin", expected: schema.min, actual: "len", messages })} | ||
} | ||
`); | ||
} | ||
if (schema.max != null) { | ||
src.push(` | ||
if (len > ${schema.max}) { | ||
${this.makeError({ type: "stringMax", expected: schema.max, actual: "len", messages })} | ||
} | ||
`); | ||
} | ||
if (schema.length != null) { | ||
src.push(` | ||
if (len !== ${schema.length}) { | ||
${this.makeError({ type: "stringLength", expected: schema.length, actual: "len", messages })} | ||
} | ||
`); | ||
} | ||
if (schema.pattern != null) { | ||
const pattern = typeof schema.pattern == "string" ? new RegExp(schema.pattern, schema.patternFlags) : schema.pattern; | ||
if (!pattern.test(value)) | ||
return this.makeError("stringPattern", pattern, value); | ||
let pattern = schema.pattern; | ||
if (typeof schema.pattern == "string") | ||
pattern = new RegExp(schema.pattern, schema.patternFlags); | ||
src.push(` | ||
if (!${pattern.toString()}.test(value)) | ||
${this.makeError({ type: "stringPattern", expected: "\"" + pattern.toString() + "\"", actual: "origValue", messages })} | ||
`); | ||
} | ||
if (schema.contains != null && value.indexOf(schema.contains) === -1) { | ||
return this.makeError("stringContains", schema.contains, value); | ||
if (schema.contains != null) { | ||
src.push(` | ||
if (value.indexOf("${schema.contains}") === -1) { | ||
${this.makeError({ type: "stringContains", expected: "\"" + schema.contains + "\"", actual: "origValue", messages })} | ||
} | ||
`); | ||
} | ||
if (schema.enum != null && schema.enum.indexOf(value) === -1) { | ||
return this.makeError("stringEnum", schema.enum, value); | ||
if (schema.enum != null) { | ||
const enumStr = JSON.stringify(schema.enum); | ||
src.push(` | ||
if (${enumStr}.indexOf(value) === -1) { | ||
${this.makeError({ type: "stringEnum", expected: "\"" + schema.enum.join(", ") + "\"", actual: "origValue", messages })} | ||
} | ||
`); | ||
} | ||
if (schema.numeric === true && !NUMERIC_PATTERN.test(value) ) { | ||
return this.makeError("stringNumeric", "A numeric string", value); | ||
if (schema.numeric === true) { | ||
src.push(` | ||
if (!${NUMERIC_PATTERN.toString()}.test(value) ) { | ||
${this.makeError({ type: "stringNumeric", actual: "origValue", messages })} | ||
} | ||
`); | ||
} | ||
if(schema.alpha === true && !ALPHA_PATTERN.test(value)) { | ||
return this.makeError("stringAlpha", "An alphabetic string", value); | ||
if(schema.alpha === true) { | ||
src.push(` | ||
if(!${ALPHA_PATTERN.toString()}.test(value)) { | ||
${this.makeError({ type: "stringAlpha", actual: "origValue", messages })} | ||
} | ||
`); | ||
} | ||
if(schema.alphanum === true && !ALPHANUM_PATTERN.test(value)) { | ||
return this.makeError("stringAlphanum", "An alphanumeric string", value); | ||
if(schema.alphanum === true) { | ||
src.push(` | ||
if(!${ALPHANUM_PATTERN.toString()}.test(value)) { | ||
${this.makeError({ type: "stringAlphanum", actual: "origValue", messages })} | ||
} | ||
`); | ||
} | ||
if(schema.alphadash === true && !ALPHADASH_PATTERN.test(value)) { | ||
return this.makeError("stringAlphadash", "An alphadash string", value); | ||
if(schema.alphadash === true) { | ||
src.push(` | ||
if(!${ALPHADASH_PATTERN.toString()}.test(value)) { | ||
${this.makeError({ type: "stringAlphadash", actual: "origValue", messages })} | ||
} | ||
`); | ||
} | ||
return true; | ||
src.push(` | ||
return value; | ||
`); | ||
return { | ||
sanitized, | ||
source: src.join("\n") | ||
}; | ||
}; |
@@ -7,12 +7,22 @@ "use strict"; | ||
module.exports = function checkUrl(value) { | ||
if (typeof value !== "string") { | ||
return this.makeError("string"); | ||
} | ||
if (!PATTERN.test(value)) { | ||
return this.makeError("url"); | ||
} | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function({ schema, messages }, path) { | ||
const src = []; | ||
src.push(` | ||
if (typeof value !== "string") { | ||
${this.makeError({ type: "string", actual: "value", messages })} | ||
return value; | ||
} | ||
return true; | ||
}; | ||
if (!${PATTERN.toString()}.test(value)) { | ||
${this.makeError({ type: "url", actual: "value", messages })} | ||
} | ||
return value; | ||
`); | ||
return { | ||
source: src.join("\n") | ||
}; | ||
}; |
@@ -5,23 +5,49 @@ "use strict"; | ||
module.exports = function checkUUID(value, schema) { | ||
if (typeof value !== "string") | ||
return this.makeError("string"); | ||
/** Signature: function(value, field, parent, errors, context) | ||
*/ | ||
module.exports = function({ schema, messages }, path) { | ||
const src = []; | ||
src.push(` | ||
if (typeof value !== "string") { | ||
${this.makeError({ type: "string", actual: "value", messages })} | ||
return value; | ||
} | ||
value = value.toLowerCase(); | ||
if (!PATTERN.test(value)) | ||
return this.makeError("uuid"); | ||
var val = value.toLowerCase(); | ||
if (!${PATTERN.toString()}.test(val)) { | ||
${this.makeError({ type: "uuid", actual: "value", messages })} | ||
return value; | ||
} | ||
const version = value.charAt(14)|0; | ||
if(schema.version && schema.version !== version) | ||
return this.makeError("uuidVersion", schema.version, version); | ||
const version = val.charAt(14) | 0; | ||
`); | ||
switch (version) { | ||
case 1: | ||
case 2: | ||
return true; | ||
case 3: | ||
case 4: | ||
case 5: | ||
return ["8", "9", "a", "b"].indexOf(value.charAt(19)) !== -1 || this.makeError("uuid"); | ||
if(schema.version) { | ||
src.push(` | ||
if (${schema.version} !== version) { | ||
${this.makeError({ type: "uuidVersion", expected: schema.version, actual: "version", messages })} | ||
return value; | ||
} | ||
`); | ||
} | ||
}; | ||
src.push(` | ||
switch (version) { | ||
case 1: | ||
case 2: | ||
break; | ||
case 3: | ||
case 4: | ||
case 5: | ||
if (["8", "9", "a", "b"].indexOf(value.charAt(19)) === -1) { | ||
${this.makeError({ type: "uuid", actual: "value", messages })} | ||
} | ||
} | ||
return value; | ||
`); | ||
return { | ||
source: src.join("\n") | ||
}; | ||
}; |
"use strict"; | ||
const flatten = require("./helpers/flatten"); | ||
//const flatten = require("./helpers/flatten"); | ||
const deepExtend = require("./helpers/deep-extend"); | ||
@@ -16,4 +16,6 @@ const defaultMessages = require("./messages"); | ||
enum: require("./rules/enum"), | ||
equal: require("./rules/equal"), | ||
forbidden: require("./rules/forbidden"), | ||
function: require("./rules/function"), | ||
multi: require("./rules/multi"), | ||
number: require("./rules/number"), | ||
@@ -29,388 +31,299 @@ object: require("./rules/object"), | ||
// Quick regex to match most common unquoted JavaScript property names. Note the spec allows Unicode letters. | ||
// Unmatched property names will be quoted and validate slighly slower. https://www.ecma-international.org/ecma-262/5.1/#sec-7.6 | ||
const identifierRegex = /^[_$a-zA-Z][_$a-zA-Z0-9]*$/; | ||
// Regex to escape quoted property names for eval/new Function | ||
const escapeEvalRegex = /["'\\\n\r\u2028\u2029]/g; | ||
function escapeEvalString(str) { | ||
// Based on https://github.com/joliss/js-string-escape | ||
return str.replace(escapeEvalRegex, function(character) { | ||
switch (character) { | ||
case "\"": | ||
case "'": | ||
case "\\": | ||
return "\\" + character; | ||
// Four possible LineTerminator characters need to be escaped: | ||
case "\n": | ||
return "\\n"; | ||
case "\r": | ||
return "\\r"; | ||
case "\u2028": | ||
return "\\u2028"; | ||
case "\u2029": | ||
return "\\u2029"; | ||
} | ||
}); | ||
} | ||
/** | ||
* Validator class constructor | ||
* | ||
* @param {Object} opts | ||
* Fastest Validator | ||
*/ | ||
function Validator(opts) { | ||
this.opts = { | ||
messages: deepExtend({}, defaultMessages) | ||
}; | ||
class Validator { | ||
if (opts) | ||
deepExtend(this.opts, opts); | ||
this.messages = this.opts.messages; | ||
this.messageKeys = Object.keys(this.messages); | ||
// Load rules | ||
this.rules = loadRules(); | ||
this.cache = new Map(); | ||
} | ||
/** | ||
* Validate an object by schema | ||
* | ||
* @param {Object} obj | ||
* @param {Object} schema | ||
*/ | ||
Validator.prototype.validate = function(obj, schema) { | ||
const check = this.compile(schema); | ||
return check(obj); | ||
}; | ||
/** | ||
* Compile a schema | ||
* | ||
* @param {Object} schema | ||
* @throws {Error} Invalid schema | ||
*/ | ||
Validator.prototype.compile = function(schema) { | ||
const self = this; | ||
if (Array.isArray(schema)) { | ||
// Multiple schemas | ||
if (schema.length == 0) { | ||
throw new Error("If the schema is an Array, must contain at least one element!"); | ||
} | ||
const rules = this.compileSchemaType(schema); | ||
this.cache.clear(); | ||
return function(value, path, parent) { | ||
return self.checkSchemaType(value, rules, path, parent || null); | ||
/** | ||
* Validator class constructor | ||
* | ||
* @param {Object} opts | ||
*/ | ||
constructor(opts) { | ||
this.opts = { | ||
messages: deepExtend({}, defaultMessages) | ||
}; | ||
} | ||
const rule = this.compileSchemaObject(schema); | ||
this.cache.clear(); | ||
return function(value, path, parent) { | ||
return self.checkSchemaObject(value, rule, path, parent || null); | ||
}; | ||
}; | ||
if (opts) | ||
deepExtend(this.opts, opts); | ||
Validator.prototype.compileSchemaObject = function(schemaObject) { | ||
if (schemaObject === null || typeof schemaObject !== "object" || Array.isArray(schemaObject)) { | ||
throw new Error("Invalid schema!"); | ||
} | ||
this.messages = this.opts.messages; | ||
let compiledObject = this.cache.get(schemaObject); | ||
if (compiledObject) { | ||
compiledObject.cycle = true; | ||
return compiledObject; | ||
} else { | ||
compiledObject = { cycle: false, properties: null, compiledObjectFunction: null, objectStack: [] }; | ||
this.cache.set(schemaObject, compiledObject); | ||
// Load rules | ||
this.rules = loadRules(); | ||
this.cache = new Map(); | ||
} | ||
compiledObject.properties = Object.keys(schemaObject) | ||
.filter(name => { | ||
return name !== "$$strict"; | ||
}) | ||
.map(name => { | ||
const compiledType = this.compileSchemaType(schemaObject[name]); | ||
return { name: name, compiledType: compiledType }; | ||
}); | ||
const sourceCode = []; | ||
sourceCode.push("let res;"); | ||
sourceCode.push("let propertyPath;"); | ||
sourceCode.push("const errors = [];"); | ||
if (schemaObject.$$strict === true) { | ||
sourceCode.push("const givenProps = new Map(Object.keys(value).map(key => [key, true]));"); | ||
/** | ||
* Validate an object by schema | ||
* | ||
* @param {Object} obj | ||
* @param {Object} schema | ||
* @returns {Array<Object>|boolean} | ||
*/ | ||
validate(obj, schema) { | ||
const check = this.compile(schema); | ||
return check(obj); | ||
} | ||
for (let i = 0; i < compiledObject.properties.length; i++) { | ||
const property = compiledObject.properties[i]; | ||
const name = escapeEvalString(property.name); | ||
const propertyValueExpr = identifierRegex.test(name) ? `value.${name}` : `value["${name}"]`; | ||
/** | ||
* Wrap a source code with `required` & `optional` checker codes. | ||
* @param {Object} rule | ||
* @param {String} innerSrc | ||
* @param {String?} resVar | ||
* @returns {String} | ||
*/ | ||
wrapRequiredCheckSourceCode(rule, innerSrc, resVar) { | ||
const src = []; | ||
const defaultValue = rule.schema.default != null ? JSON.stringify(rule.schema.default) : null; | ||
sourceCode.push(`propertyPath = (path !== undefined ? path + ".${name}" : "${name}");`); | ||
if (Array.isArray(property.compiledType)) { | ||
sourceCode.push(`res = this.checkSchemaType(${propertyValueExpr}, properties[${i}].compiledType, propertyPath, value);`); | ||
// Required, optional, forbidden | ||
src.push(` | ||
if (value === undefined || value === null) { | ||
`); | ||
if (rule.schema.optional === true || rule.schema.type == "forbidden") { | ||
// Optional field | ||
if (defaultValue != null && resVar) { | ||
src.push(`${resVar} = ${defaultValue};`); | ||
} else { | ||
src.push("// Do nothing, it's an optional field"); | ||
} | ||
} else { | ||
sourceCode.push(`res = this.checkSchemaRule(${propertyValueExpr}, properties[${i}].compiledType, propertyPath, value);`); | ||
// Required field | ||
if (defaultValue != null && resVar) { | ||
src.push(`${resVar} = ${defaultValue};`); | ||
} else { | ||
src.push(this.makeError({ type: "required", actual: "value", messages: rule.messages })); | ||
} | ||
} | ||
sourceCode.push("if (res !== true) {"); | ||
sourceCode.push(`\tthis.handleResult(errors, propertyPath, res, properties[${i}].compiledType.messages);`); | ||
sourceCode.push("}"); | ||
src.push("} else {"); | ||
if (schemaObject.$$strict === true) { | ||
sourceCode.push(`givenProps.delete("${name}");`); | ||
} | ||
} | ||
if (innerSrc) | ||
src.push(innerSrc); | ||
if (schemaObject.$$strict === true) { | ||
sourceCode.push("if (givenProps.size !== 0) {"); | ||
sourceCode.push("\tthis.handleResult(errors, path || 'rootObject', this.makeError('objectStrict', undefined, [...givenProps.keys()].join(', ')), this.messages);"); | ||
sourceCode.push("}"); | ||
src.push("\t\t}"); // Required, optional | ||
return src.join("\n"); | ||
} | ||
sourceCode.push("return errors.length === 0 ? true : errors;"); | ||
/** | ||
* Compile a schema | ||
* | ||
* @param {Object} schema | ||
* @throws {Error} Invalid schema | ||
* @returns {Function} | ||
*/ | ||
compile(schema) { | ||
if (schema === null || typeof schema !== "object") { | ||
throw new Error("Invalid schema."); | ||
} | ||
compiledObject.compiledObjectFunction = new Function("value", "properties", "path", "parent", sourceCode.join("\n")); | ||
const self = this; | ||
const context = { | ||
index: 0, | ||
rules: [], | ||
fn: [], | ||
customs: {} | ||
}; | ||
this.cache.clear(); | ||
return compiledObject; | ||
}; | ||
if (schema.$$root !== true) { | ||
if (Array.isArray(schema)) { | ||
const rule = this.getRuleFromSchema(schema); | ||
schema = rule.schema; | ||
} else { | ||
const prevSchema = Object.assign({}, schema); | ||
schema = { | ||
type: "object", | ||
strict: prevSchema.$$strict, | ||
properties: prevSchema | ||
}; | ||
Validator.prototype.compileSchemaType = function(schemaType) { | ||
if (Array.isArray(schemaType)) { | ||
// Multiple rules, flatten to array of compiled SchemaRule | ||
const rules = flatten(schemaType.map(r => this.compileSchemaType(r))); | ||
if (rules.length == 1) { | ||
return rules[0]; | ||
delete prevSchema.$$strict; | ||
} | ||
} | ||
return rules; | ||
} | ||
const sourceCode = [ | ||
"var errors = [];", | ||
"var field;", | ||
]; | ||
return this.compileSchemaRule(schemaType); | ||
const rule = this.getRuleFromSchema(schema); | ||
sourceCode.push(this.compileRule(rule, context, null, "context.fn[%%INDEX%%](value, field, null, errors, context);", "value")); | ||
}; | ||
sourceCode.push("if (errors.length) {"); | ||
sourceCode.push(` | ||
return errors.map(err => { | ||
if (err.message) | ||
err.message = err.message | ||
.replace(/\\{field\\}/g, err.field || "") | ||
.replace(/\\{expected\\}/g, err.expected != null ? err.expected : "") | ||
.replace(/\\{actual\\}/g, err.actual != null ? err.actual : ""); | ||
Validator.prototype.compileMessages = function(schemaType) { | ||
if (schemaType.messages) | ||
return Object.assign({}, this.messages, schemaType.messages); | ||
return err; | ||
}); | ||
`); | ||
return this.messages; | ||
}; | ||
sourceCode.push("}"); | ||
sourceCode.push("return true;"); | ||
Validator.prototype.compileSchemaRule = function(schemaRule) { | ||
const src = sourceCode.join("\n"); | ||
if (typeof schemaRule === "string") { | ||
schemaRule = { | ||
type: schemaRule | ||
}; | ||
} | ||
const checkFn = new Function("value", "context", src); | ||
const ruleFunction = this.rules[schemaRule.type]; | ||
/* istanbul ignore next */ | ||
if (this.opts.debug) { | ||
let formatter = function(code) { return code; }; | ||
if (typeof window === "undefined") // eslint-disable-line no-undef | ||
formatter = require("./helpers/prettier"); | ||
if (!ruleFunction) { | ||
throw new Error("Invalid '" + schemaRule.type + "' type in validator schema!"); | ||
} | ||
context.fn.forEach((fn, i) => console.log(formatter(`// Context.fn[${i}]\n` + fn.toString()))); // eslint-disable-line no-console | ||
console.log(formatter("// Main check function\n" + checkFn.toString())); // eslint-disable-line no-console | ||
} | ||
const messages = this.compileMessages(schemaRule); | ||
this.cache.clear(); | ||
let dataParameter = null; | ||
let dataFunction = null; | ||
if (schemaRule.type === "object" && schemaRule.props) { | ||
dataParameter = this.compileSchemaObject(schemaRule.props); | ||
dataFunction = this.checkSchemaObject; | ||
} else if (schemaRule.type === "array" && schemaRule.items) { | ||
dataParameter = this.compileSchemaType(schemaRule.items); | ||
dataFunction = this.checkSchemaArray; | ||
return function(data) { | ||
context.data = data; | ||
return checkFn.call(self, data, context); | ||
}; | ||
} | ||
return { | ||
messages: messages, | ||
schemaRule: schemaRule, | ||
ruleFunction: ruleFunction, | ||
dataFunction: dataFunction, | ||
dataParameter: dataParameter | ||
}; | ||
}; | ||
/** | ||
* Compile a rule to source code. | ||
* @param {Object} rule | ||
* @param {Object} context | ||
* @param {String} path | ||
* @param {String} innerSrc | ||
* @param {String} resVar | ||
* @returns {String} | ||
*/ | ||
compileRule(rule, context, path, innerSrc, resVar) { | ||
const sourceCode = []; | ||
Validator.prototype.checkSchemaObject = function(value, compiledObject, path, parent) { | ||
if (compiledObject.cycle) { | ||
if (compiledObject.objectStack.indexOf(value) !== -1) { | ||
return true; | ||
} | ||
const item = this.cache.get(rule.schema); | ||
if (item) { | ||
// Handle cyclic schema | ||
rule = item; | ||
rule.cycle = true; | ||
rule.cycleStack = []; | ||
sourceCode.push(this.wrapRequiredCheckSourceCode(rule, ` | ||
var rule = context.rules[${rule.index}]; | ||
if (rule.cycleStack.indexOf(value) === -1) { | ||
rule.cycleStack.push(value); | ||
${innerSrc.replace("%%INDEX%%", rule.index)} | ||
rule.cycleStack.pop(value); | ||
} | ||
`, resVar)); | ||
compiledObject.objectStack.push(value); | ||
const result = this.checkSchemaObjectInner(value, compiledObject, path, parent); | ||
compiledObject.objectStack.pop(); | ||
return result; | ||
} else { | ||
return this.checkSchemaObjectInner(value, compiledObject, path, parent); | ||
} | ||
}; | ||
Validator.prototype.checkSchemaObjectInner = function(value, compiledObject, path, parent) { | ||
return compiledObject.compiledObjectFunction.call(this, value, compiledObject.properties, path, parent); | ||
/* | ||
// Reference implementation of the object checker | ||
const errors = []; | ||
const propertiesLength = compiledObject.properties.length; | ||
for (let i = 0; i < propertiesLength; i++) { | ||
const property = compiledObject.properties[i]; | ||
const propertyPath = (path !== undefined ? path + "." : "") + property.name; | ||
const res = this.checkSchemaType(value[property.name], property.compiledType, propertyPath, value); | ||
if (res !== true) { | ||
this.handleResult(errors, propertyPath, res); | ||
} | ||
} | ||
return errors.length === 0 ? true : errors; | ||
*/ | ||
}; | ||
Validator.prototype.checkSchemaType = function(value, compiledType, path, parent) { | ||
if (Array.isArray(compiledType)) { | ||
const errors = []; | ||
const checksLength = compiledType.length; | ||
for (let i = 0; i < checksLength; i++) { | ||
// Always compiled to list of rules | ||
const res = this.checkSchemaRule(value, compiledType[i], path, parent); | ||
if (res !== true) { | ||
this.handleResult(errors, path, res, compiledType.messages); | ||
} else { | ||
this.cache.set(rule.schema, rule); | ||
rule.index = context.index; | ||
context.rules[context.index] = rule; | ||
context.index++; | ||
const res = rule.ruleFunction.call(this, rule, path, context); | ||
if (res.source) { | ||
const fn = new Function("value", "field", "parent", "errors", "context", res.source); | ||
context.fn[rule.index] = fn; | ||
sourceCode.push(this.wrapRequiredCheckSourceCode(rule, innerSrc.replace("%%INDEX%%", rule.index), resVar)); | ||
} else { | ||
// Jump out after first success and clear previous errors | ||
return true; | ||
sourceCode.push(this.wrapRequiredCheckSourceCode(rule)); | ||
} | ||
} | ||
return errors; | ||
return sourceCode.join("\n"); | ||
} | ||
return this.checkSchemaRule(value, compiledType, path, parent); | ||
}; | ||
/** | ||
* Create a rule instance from schema definition. | ||
* @param {Object} schema | ||
* @returns {Object} rule | ||
*/ | ||
getRuleFromSchema(schema) { | ||
if (typeof schema === "string") { | ||
const str = schema; | ||
const p = str.split("|").map(s => s.trim()); | ||
schema = { | ||
type: p[0] | ||
}; | ||
p.slice(1).map(s => { | ||
const idx = s.indexOf(":"); | ||
if (idx !== -1) { | ||
const key = s.substr(0, idx).trim(); | ||
let value = s.substr(idx + 1).trim(); | ||
if (value === "true" || value === "false") | ||
value = value === "true"; | ||
else if (!Number.isNaN(Number(value))) { | ||
value = Number(value); | ||
} | ||
schema[key] = value; | ||
} else { | ||
// boolean value | ||
if (s.startsWith("no-")) | ||
schema[s.slice(3)] = false; | ||
else | ||
schema[s] = true; | ||
} | ||
}); | ||
Validator.prototype.checkSchemaArray = function(value, compiledArray, path, parent) { | ||
const errors = []; | ||
const valueLength = value.length; | ||
} else if (Array.isArray(schema)) { | ||
if (schema.length == 0) | ||
throw new Error("Invalid schema."); | ||
for (let i = 0; i < valueLength; i++) { | ||
const itemPath = (path !== undefined ? path : "") + "[" + i + "]"; | ||
const res = this.checkSchemaType(value[i], compiledArray, itemPath, value, parent); | ||
if (res !== true) { | ||
this.handleResult(errors, itemPath, res, compiledArray.messages); | ||
schema = { | ||
type: "multi", | ||
rules: schema | ||
}; | ||
} | ||
} | ||
return errors.length === 0 ? true : errors; | ||
}; | ||
const ruleFunction = this.rules[schema.type]; | ||
if (!ruleFunction) | ||
throw new Error("Invalid '" + schema.type + "' type in validator schema."); | ||
Validator.prototype.checkSchemaRule = function(value, compiledRule, path, parent) { | ||
const schemaRule = compiledRule.schemaRule; | ||
const rule = { | ||
messages: Object.assign({}, this.messages, schema.messages), | ||
schema: schema, | ||
ruleFunction: ruleFunction | ||
}; | ||
if (value === undefined || value === null) { | ||
if (schemaRule.type === "forbidden") | ||
return true; | ||
if (schemaRule.optional === true) | ||
return true; | ||
const errors = []; | ||
this.handleResult(errors, path, this.makeError("required"), compiledRule.messages); | ||
return errors; | ||
return rule; | ||
} | ||
const res = compiledRule.ruleFunction.call(this, value, schemaRule, path, parent); | ||
/** | ||
* Generate error source code. | ||
* @param {Object} opts | ||
* @param {String} opts.type | ||
* @param {String} opts.field | ||
* @param {any} opts.expected | ||
* @param {any} opts.actual | ||
* @param {Object} opts.messages | ||
*/ | ||
makeError({ type, field, expected, actual, messages }) { | ||
const o = { | ||
type: `"${type}"`, | ||
message: `"${messages[type]}"`, | ||
}; | ||
if (field) o.field = `"${field}"`; | ||
else o.field = "field"; | ||
if (expected) o.expected = expected; | ||
if (actual) o.actual = actual; | ||
if (res !== true) { | ||
const errors = []; | ||
this.handleResult(errors, path, res, compiledRule.messages); | ||
const s = Object.keys(o) | ||
.map(key => `${key}: ${o[key]}`) | ||
.join(", "); | ||
return errors; | ||
return `errors.push({ ${s} });`; | ||
} | ||
if (compiledRule.dataFunction !== null) { | ||
return compiledRule.dataFunction.call(this, value, compiledRule.dataParameter, path, parent); | ||
/** | ||
* Add a custom rule | ||
* | ||
* @param {String} type | ||
* @param {Function} fn | ||
*/ | ||
add(type, fn) { | ||
this.rules[type] = fn; | ||
} | ||
} | ||
return true; | ||
}; | ||
/** | ||
* Handle results from validator functions | ||
* | ||
* @param {Array} errors | ||
* @param {String} fieldPath | ||
* @param {Array|Object} res | ||
*/ | ||
Validator.prototype.handleResult = function(errors, fieldPath, res, messages) { | ||
let items; | ||
if (!Array.isArray(res)) | ||
items = [res]; | ||
else | ||
items = res; | ||
items.forEach(err => { | ||
if (!err.field) | ||
err.field = fieldPath; | ||
if (!err.message) | ||
err.message = this.resolveMessage(err, messages[err.type]); | ||
errors.push(err); | ||
}); | ||
}; | ||
/** | ||
* Create a validation error object | ||
* | ||
* @param {String} type | ||
* @param {Any} expected | ||
* @param {Any} actual | ||
*/ | ||
Validator.prototype.makeError = function(type, expected, actual) { | ||
return { | ||
type: type, | ||
expected: expected, | ||
actual: actual | ||
}; | ||
}; | ||
/** | ||
* Resolve message string from a validation error object | ||
* | ||
* @param {Object} err Validation error object | ||
*/ | ||
Validator.prototype.resolveMessage = function(err, msg = null) { | ||
if (msg != null) { | ||
const expected = err.expected != null ? err.expected : ""; | ||
const actual = err.actual != null ? err.actual : ""; | ||
return msg.replace(/\{field\}/g, err.field).replace(/\{expected\}/g, expected).replace(/\{actual\}/g, actual); | ||
} | ||
}; | ||
/** | ||
* Add a custom validator rule | ||
* | ||
* @param {String} type | ||
* @param {Function} fn | ||
*/ | ||
Validator.prototype.add = function(type, fn) { | ||
this.rules[type] = fn; | ||
}; | ||
module.exports = Validator; |
{ | ||
"name": "fastest-validator", | ||
"version": "0.6.19", | ||
"version": "1.0.0-beta1", | ||
"description": "The fastest JS validator library for NodeJS", | ||
"main": "dist/index.js", | ||
"main": "index.js", | ||
"browser": "dist/index.min.js", | ||
"types": "dist/index.d.ts", | ||
"scripts": { | ||
"bench": "node benchmark/index.js", | ||
"bench:watch": "nodemon benchmark/index.js", | ||
"build": "rollup -c", | ||
"prepublish": "npm run build", | ||
"prepublishOnly": "npm run build", | ||
"dev": "nodemon examples/index.js", | ||
"ci": "jest --watch", | ||
"test": "jest --coverage", | ||
"lint": "eslint --ext=.js lib test rollup.config.js", | ||
"lint:fix": "eslint --fix --ext=.js lib test rollup.config.js", | ||
"deps": "npm-check -u", | ||
"coverall": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js" | ||
"coverall": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js", | ||
"test": "jest --coverage", | ||
"test:travis": "npm test" | ||
}, | ||
@@ -31,3 +34,2 @@ "repository": { | ||
"dist", | ||
"examples", | ||
"lib", | ||
@@ -44,13 +46,21 @@ "index.js", | ||
"devDependencies": { | ||
"@types/jest": "^24.0.22", | ||
"benchmarkify": "^2.1.2", | ||
"cli-highlight": "^2.1.3", | ||
"coveralls": "^3.0.7", | ||
"eslint": "^6.5.1", | ||
"eslint": "^6.6.0", | ||
"jest": "^24.9.0", | ||
"jest-cli": "^24.9.0", | ||
"npm-check": "^5.9.0", | ||
"rollup": "^1.25.2", | ||
"prettier": "^1.19.1", | ||
"rollup": "^1.26.4", | ||
"rollup-plugin-buble": "^0.19.8", | ||
"rollup-plugin-closure-compiler-js": "^1.0.6", | ||
"rollup-plugin-commonjs": "^10.1.0", | ||
"rollup-plugin-uglify-es": "^0.0.1" | ||
"rollup-plugin-copy": "^3.1.0", | ||
"rollup-plugin-uglify-es": "^0.0.1", | ||
"ts-jest": "^24.1.0", | ||
"ts-node": "^8.4.1", | ||
"tsd": "^0.10.0", | ||
"typescript": "^3.7.2" | ||
}, | ||
@@ -63,4 +73,13 @@ "jest": { | ||
"../test" | ||
] | ||
], | ||
"transform": { | ||
"^.+\\.(ts|tsx)$": "ts-jest" | ||
}, | ||
"globals": { | ||
"ts-jest": { | ||
"tsConfig": "test/typescript/tsconfig.json", | ||
"diagnostics": true | ||
} | ||
} | ||
} | ||
} |
585
README.md
@@ -15,4 +15,5 @@ ![Photos from @ikukevk](https://user-images.githubusercontent.com/306521/30183963-9c722dca-941c-11e7-9e83-c78377ad7f9d.jpg) | ||
## Key features | ||
* fast! Really! | ||
* blazing fast! Really! | ||
* 15+ built-in validators | ||
* many sanitizations | ||
* custom validators | ||
@@ -28,5 +29,5 @@ * nested objects & array handling | ||
# How fast? | ||
Very fast! ~5 million validations/sec (on Intel i7-4770K, Node.JS: 8.11.0) | ||
Very fast! ~5 million validations/sec (on Intel i7-4770K, Node.JS: 10.16.0) | ||
``` | ||
√ validate with pre-compiled schema 5,460,129 rps | ||
√ validate 8,461,975 rps | ||
``` | ||
@@ -48,7 +49,45 @@ | ||
# Table of contents | ||
- [Installations](#installation) | ||
- [Usage](#usage) | ||
- [Optional & required fields](#optional--required-fields) | ||
- [Strict validation](#strict-validation) | ||
- [Multiple validators](#multiple-validators) | ||
- [Root element schema](#root-element-schema) | ||
- [Sanitizations](#sanitizations) | ||
- [Shorthand definitions](#shorthand-definitions) | ||
- [Built-in validators](#built-in-validators) | ||
- [any](#any) | ||
- [array](#array) | ||
- [boolean](#boolean) | ||
- [date](#date) | ||
- [email](#email) | ||
- [enum](#enum) | ||
- [equal](#equal) | ||
- [forbidden](#forbidden) | ||
- [function](#function) | ||
- [luhn](#luhn) | ||
- [mac](#mac) | ||
- [multi](#multi) | ||
- [number](#number) | ||
- [object](#object) | ||
- [string](#string) | ||
- [url](#url) | ||
- [uuid](#uuid) | ||
- [Custom validator](#custom-validator) | ||
- [Custom error messages (l10n)](#custom-error-messages-l10n) | ||
- [Personalised Messages](#personalised-messages) | ||
- [Message types](#message-types) | ||
- [Development](#development) | ||
- [Test](#test) | ||
- [Contribution](#contribution) | ||
- [License](#license) | ||
- [Contact](#contact) | ||
## Installation | ||
### NPM | ||
You can install it via [NPM](http://npmjs.org/). | ||
``` | ||
$ npm install fastest-validator --save | ||
$ npm i fastest-validator --save | ||
``` | ||
@@ -64,3 +103,3 @@ or | ||
Call the `validate` method with the `object` and the `schema`. | ||
> If performance is important, you won't use this method. | ||
> If performance is important, you won't use this method because it's slow. | ||
@@ -98,3 +137,3 @@ ```js | ||
In this case, the first step is to compile the schema to a compiled "checker" function. After that, to validate your object, just call this "checker" function. | ||
> This method is ~10x faster than the "simple method". | ||
> This method is the fastest. | ||
@@ -154,3 +193,3 @@ ```js | ||
```js | ||
let schema = { | ||
const schema = { | ||
name: { type: "string" }, // required | ||
@@ -162,3 +201,3 @@ age: { type: "number", optional: true } | ||
v.validate({ name: "John" }, schema); // Valid | ||
v.validate({ age: 42 }, schema); // Fail | ||
v.validate({ age: 42 }, schema); // Fail because name is required | ||
``` | ||
@@ -170,3 +209,3 @@ | ||
```js | ||
let schema = { | ||
const schema = { | ||
name: { type: "string" }, // required | ||
@@ -180,2 +219,6 @@ $$strict: true // no additional properties allowed | ||
## Remove additional fields | ||
To remove the additional fields in the object, set `$$strict: "remove"`. | ||
# Multiple validators | ||
@@ -185,3 +228,3 @@ It is possible to define more validators for a field. In this case, only one validator needs to succeed for the field to be valid. | ||
```js | ||
let schema = { | ||
const schema = { | ||
cache: [ | ||
@@ -198,2 +241,54 @@ { type: "string" }, | ||
# Root element schema | ||
Basically the validator expects that you want to validate a Javascript object. If you want others, you can define the root level schema, as well. In this case set the `$$root: true` property. | ||
**Example to validate a `string` variable instead of `object`** | ||
```js | ||
const schema = { | ||
$$root: true, | ||
type: "string", | ||
min: 3, | ||
max: 6 | ||
}; | ||
v.validate("John", schema); // Valid | ||
v.validate("Al", schema); // Fail, too short. | ||
``` | ||
# Sanitizations | ||
The library contains several sanitizaters. **Please note, the sanitizers change the original checked object.** | ||
## Default values | ||
The most common sanitizer is the `default` property. With it, you can define a default value for all properties. If the property value is `null` or `undefined`, the validator set the defined default value into the property. | ||
**Default value example**: | ||
```js | ||
const schema = { | ||
roles: { type: "array", items: "string", default: ["user"] }, | ||
status: { type: "boolean", default: true }, | ||
}; | ||
const obj = {} | ||
v.validate(obj, schema); // Valid | ||
console.log(obj); | ||
/* | ||
{ | ||
roles: ["user"], | ||
status: true | ||
} | ||
*/ | ||
``` | ||
# Shorthand definitions | ||
You can use string-based shorthand validation definitions in the schema. | ||
```js | ||
const schema = { | ||
password: "string|min:6", | ||
age: "number|optional|integer|positive|min:0|max:99", // additional properties | ||
state: ["boolean", "number|min:0|max:1"] // multiple types | ||
} | ||
``` | ||
# Built-in validators | ||
@@ -205,3 +300,3 @@ | ||
```js | ||
let schema = { | ||
const schema = { | ||
prop: { type: "any" } | ||
@@ -220,3 +315,3 @@ } | ||
```js | ||
let schema = { | ||
const schema = { | ||
roles: { type: "array", items: "string" } | ||
@@ -232,3 +327,3 @@ } | ||
```js | ||
let schema = { | ||
const schema = { | ||
list: { type: "array", min: 2, items: { | ||
@@ -247,3 +342,3 @@ type: "number", positive: true, integer: true | ||
```js | ||
let schema = { | ||
const schema = { | ||
users: { type: "array", items: { | ||
@@ -267,7 +362,17 @@ type: "object", props: { | ||
**Example for `enum`:** | ||
```js | ||
const schema = { | ||
roles: { type: "array", items: "string", enum: [ "user", "admin" ] } | ||
} | ||
v.validate({ roles: ["user"] }, schema); // Valid | ||
v.validate({ roles: ["user", "admin"] }, schema); // Valid | ||
v.validate({ roles: ["guest"] }, schema); // Fail | ||
``` | ||
### Properties | ||
Property | Default | Description | ||
-------- | -------- | ----------- | ||
`empty` | `true` | If true, the validator accepts an empty array `[]`. | ||
`empty` | `true` | If `true`, the validator accepts an empty array `[]`. | ||
`min` | `null` | Minimum count of elements. | ||
@@ -278,15 +383,5 @@ `max` | `null` | Maximum count of elements. | ||
`enum` | `null` | Every element must be an element of the `enum` array. | ||
`items` | `null` | Schema for array items. | ||
**Example for `enum`:** | ||
```js | ||
let schema = { | ||
roles: { type: "array", items: "string", enum: [ "user", "admin" ] } | ||
} | ||
v.validate({ roles: ["user"] }, schema); // Valid | ||
v.validate({ roles: ["user", "admin"] }, schema); // Valid | ||
v.validate({ roles: ["guest"] }, schema); // Fail | ||
``` | ||
## `boolean` | ||
@@ -296,3 +391,3 @@ This is a `Boolean` validator. | ||
```js | ||
let schema = { | ||
const schema = { | ||
status: { type: "boolean" } | ||
@@ -309,4 +404,10 @@ } | ||
-------- | -------- | ----------- | ||
`convert` | `false` | if `true` and the type is not `Boolean`, try to convert. `1`, `"true"`, `"1"`, `"on"` will be true. `0`, `"false"`, `"0"`, `"off"` will be false. | ||
`convert` | `false` | if `true` and the type is not `Boolean`, it will be converted. `1`, `"true"`, `"1"`, `"on"` will be true. `0`, `"false"`, `"0"`, `"off"` will be false. _It's a sanitizer, it will change the value in the original object._ | ||
**Example for `convert`:** | ||
```js | ||
v.validate({ status: "true" }, { | ||
status: { type: "boolean", convert: true} | ||
}); // Valid | ||
``` | ||
@@ -317,3 +418,3 @@ ## `date` | ||
```js | ||
let schema = { | ||
const schema = { | ||
dob: { type: "date" } | ||
@@ -326,7 +427,15 @@ } | ||
``` | ||
### Properties | ||
Property | Default | Description | ||
-------- | -------- | ----------- | ||
`convert` | `false`| if `true` and the type is not `Date`, try to convert with `new Date()`. | ||
`convert` | `false`| if `true` and the type is not `Date`, try to convert with `new Date()`. _It's a sanitizer, it will change the value in the original object._ | ||
**Example for `convert`:** | ||
```js | ||
v.validate({ dob: 1488876927958 }, { | ||
dob: { type: "date", convert: true} | ||
}); // Valid | ||
``` | ||
## `email` | ||
@@ -336,3 +445,3 @@ This is an e-mail address validator. | ||
```js | ||
let schema = { | ||
const schema = { | ||
email: { type: "email" } | ||
@@ -350,2 +459,3 @@ } | ||
`mode` | `quick` | Checker method. Can be `quick` or `precise`. | ||
`normalize` | `false` | Normalize the e-mail address (trim & lower-case). _It's a sanitizer, it will change the value in the original object._ | ||
@@ -356,3 +466,3 @@ ## `enum` | ||
```js | ||
let schema = { | ||
const schema = { | ||
sex: { type: "enum", values: ["male", "female"] } | ||
@@ -371,3 +481,32 @@ } | ||
## `equal` | ||
This is an equal value validator. It checks a value with a static value or with another property. | ||
**Example with static value**: | ||
```js | ||
const schema = { | ||
agreeTerms: { type: "equal", value: true, strict: true } // strict means `===` | ||
} | ||
v.validate({ agreeTerms: true }, schema); // Valid | ||
v.validate({ agreeTerms: false }, schema); // Fail | ||
``` | ||
**Example with other field**: | ||
```js | ||
const schema = { | ||
password: { type: "string", min: 6 }, | ||
confirmPassword: { type: "equal", field: "password" } | ||
} | ||
v.validate({ password: "123456", confirmPassword: "123456" }, schema); // Valid | ||
v.validate({ password: "123456", confirmPassword: "pass1234" }, schema); // Fail | ||
``` | ||
### Properties | ||
Property | Default | Description | ||
-------- | -------- | ----------- | ||
`value` | `undefined`| The expected value. It can be any primitive types. | ||
`strict` | `false`| if `true`, it uses strict equal `===` for checking. | ||
## `forbidden` | ||
@@ -377,3 +516,3 @@ This validator returns an error if the property exists in the object. | ||
```js | ||
let schema = { | ||
const schema = { | ||
password: { type: "forbidden" } | ||
@@ -386,7 +525,34 @@ } | ||
### Properties | ||
Property | Default | Description | ||
-------- | -------- | ----------- | ||
`remove` | `false` | If `true`, the value will be removed in the original object. _It's a sanitizer, it will change the value in the original object._ | ||
**Example for `remove`:** | ||
```js | ||
const schema = { | ||
user: { type: "string" }, | ||
token: { type: "forbidden", remove: true } | ||
}; | ||
const obj = { | ||
user: "John", | ||
token: "123456" | ||
} | ||
v.validate(obj, schema); // Valid | ||
console.log(obj); | ||
/* | ||
{ | ||
user: "John", | ||
token: undefined | ||
} | ||
*/ | ||
``` | ||
## `function` | ||
This a `Function`validator. | ||
This a `Function` type validator. | ||
```js | ||
let schema = { | ||
const schema = { | ||
show: { type: "function" } | ||
@@ -397,6 +563,72 @@ } | ||
v.validate({ show: Date.now }, schema); // Valid | ||
v.validate({ show: null }, schema); // Fail | ||
v.validate({ show: "function" }, schema); // Fail | ||
``` | ||
## `luhn` | ||
This is an Luhn validator. | ||
[Luhn algorithm](https://en.wikipedia.org/wiki/Luhn_algorithm) checksum | ||
Credit Card numbers, IMEI numbers, National Provider Identifier numbers and others | ||
```js | ||
const schema = { | ||
cc: { type: "luhn" } | ||
} | ||
v.validate({ cc: "452373989901198" }, schema); // Valid | ||
v.validate({ cc: 452373989901198 }, schema); // Valid | ||
v.validate({ cc: "4523-739-8990-1198" }, schema); // Valid | ||
v.validate({ cc: "452373989901199" }, schema); // Fail | ||
``` | ||
## `mac` | ||
This is an MAC addresses validator. | ||
```js | ||
const schema = { | ||
mac: { type: "mac" } | ||
} | ||
v.validate({ mac: "01:C8:95:4B:65:FE" }, schema); // Valid | ||
v.validate({ mac: "01:c8:95:4b:65:fe", schema); // Valid | ||
v.validate({ mac: "01C8.954B.65FE" }, schema); // Valid | ||
v.validate({ mac: "01c8.954b.65fe", schema); // Valid | ||
v.validate({ mac: "01-C8-95-4B-65-FE" }, schema); // Valid | ||
v.validate({ mac: "01-c8-95-4b-65-fe" }, schema); // Valid | ||
v.validate({ mac: "01C8954B65FE" }, schema); // Fail | ||
``` | ||
## `multi` | ||
This is a multiple definitions validator. | ||
```js | ||
const schema = { | ||
status: { type: "multi", rules: [ | ||
{ type: "boolean" }, | ||
{ type: "number" } | ||
], default: true } | ||
} | ||
v.validate({ status: true }, schema); // Valid | ||
v.validate({ status: false }, schema); // Valid | ||
v.validate({ status: 1 }, schema); // Valid | ||
v.validate({ status: 0 }, schema); // Valid | ||
v.validate({ status: "yes" }, schema); // Fail | ||
``` | ||
**Shorthand multiple definitions**: | ||
```js | ||
const schema = { | ||
status: [ | ||
"boolean", | ||
"number" | ||
] | ||
} | ||
v.validate({ status: true }, schema); // Valid | ||
v.validate({ status: false }, schema); // Valid | ||
v.validate({ status: 1 }, schema); // Valid | ||
v.validate({ status: 0 }, schema); // Valid | ||
v.validate({ status: "yes" }, schema); // Fail | ||
``` | ||
## `number` | ||
@@ -406,3 +638,3 @@ This is a `Number` validator. | ||
```js | ||
let schema = { | ||
const schema = { | ||
age: { type: "number" } | ||
@@ -426,9 +658,10 @@ } | ||
`negative` | `false`| The value must be less than zero. | ||
`convert` | `false`| if `true` and the type is not `Number`, tries to convert with `parseFloat`. | ||
`convert` | `false`| if `true` and the type is not `Number`, it's converted with `Number()`. _It's a sanitizer, it will change the value in the original object._ | ||
## `object` | ||
This is a nested object validator. | ||
```js | ||
let schema = { | ||
address: { type: "object", props: { | ||
const schema = { | ||
address: { type: "object", strict: true, props: { | ||
country: { type: "string" }, | ||
@@ -454,2 +687,11 @@ city: "string", // short-hand | ||
}, schema); // Fail ("The 'address.zip' field is required!") | ||
v.validate({ | ||
address: { | ||
country: "Italy", | ||
city: "Rome", | ||
zip: 12345, | ||
state: "IT" | ||
} | ||
}, schema); // Fail ("The 'address.state' is an additional field!") | ||
``` | ||
@@ -460,9 +702,40 @@ | ||
-------- | -------- | ----------- | ||
`strict` | `false`| if `true` any properties which are not defined on the schema will throw an error. | ||
`strict` | `false`| if `true` any properties which are not defined on the schema will throw an error. If `remove` all additional properties will be removed from the original object. _It's a sanitizer, it will change the original object._ | ||
```js | ||
const schema = { | ||
address: { type: "object", strict: "remove", props: { | ||
country: { type: "string" }, | ||
city: "string", // short-hand | ||
zip: "number" // short-hand | ||
} } | ||
} | ||
const obj = { | ||
address: { | ||
country: "Italy", | ||
city: "Rome", | ||
zip: 12345, | ||
state: "IT" | ||
} | ||
}; | ||
v.validate(obj, schema); // Valid | ||
console.log(obj); | ||
/* | ||
{ | ||
address: { | ||
country: "Italy", | ||
city: "Rome", | ||
zip: 12345 | ||
} | ||
} | ||
*/ | ||
``` | ||
## `string` | ||
This is a `String`. | ||
This is a `String` validator. | ||
```js | ||
let schema = { | ||
const schema = { | ||
name: { type: "string" } | ||
@@ -479,3 +752,3 @@ } | ||
-------- | -------- | ----------- | ||
`empty` | `true` | If true, the validator accepts an empty string `""`. | ||
`empty` | `true` | If `true`, the validator accepts an empty string `""`. | ||
`min` | `null` | Minimum value length. | ||
@@ -491,4 +764,33 @@ `max` | `null` | Maximum value length. | ||
`alphadash` | `null` | The value must be an alphabetic string that contains dashes. | ||
`trim` | `null` | If `true`, the value will be trimmed. _It's a sanitizer, it will change the value in the original object._ | ||
`trimLeft` | `null` | If `true`, the value will be left trimmed. _It's a sanitizer, it will change the value in the original object._ | ||
`trimRight` | `null` | If `true`, the value will be right trimmed. _It's a sanitizer, it will change the value in the original object._ | ||
`padStart` | `null` | If it's a number, the value will be left padded. _It's a sanitizer, it will change the value in the original object._ | ||
`padEnd` | `null` | If it's a number, the value will be right padded. _It's a sanitizer, it will change the value in the original object._ | ||
`padChar` | `" "` | The padding characther for the `padStart` and `padEnd`. | ||
`lowercase` | `null` | If `true`, the value will be lower-cased. _It's a sanitizer, it will change the value in the original object._ | ||
`uppercase` | `null` | If `true`, the value will be upper-cased. _It's a sanitizer, it will change the value in the original object._ | ||
`localeLowercase` | `null` | If `true`, the value will be locale lower-cased. _It's a sanitizer, it will change the value in the original object._ | ||
`localeUppercase` | `null` | If `true`, the value will be locale upper-cased. _It's a sanitizer, it will change the value in the original object._ | ||
`convert` | `false`| if `true` and the type is not a `String`, it's converted with `String()`. _It's a sanitizer, it will change the value in the original object._ | ||
**Sanitization example** | ||
```js | ||
const schema = { | ||
username: { type: "string", min: 3, trim: true, lowercase: true} | ||
} | ||
const obj = { | ||
username: " Icebob " | ||
}; | ||
v.validate(obj, schema); // Valid | ||
console.log(obj); | ||
/* | ||
{ | ||
username: "icebob" | ||
} | ||
*/ | ||
``` | ||
## `url` | ||
@@ -498,3 +800,3 @@ This is an URL validator. | ||
```js | ||
let schema = { | ||
const schema = { | ||
url: { type: "url" } | ||
@@ -512,3 +814,3 @@ } | ||
```js | ||
let schema = { | ||
const schema = { | ||
uuid: { type: "uuid" } | ||
@@ -526,35 +828,3 @@ } | ||
## `mac` | ||
This is an MAC addresses validator. | ||
```js | ||
let schema = { | ||
mac: { type: "mac" } | ||
} | ||
v.validate({ mac: "01:C8:95:4B:65:FE" }, schema); // Valid | ||
v.validate({ mac: "01:c8:95:4b:65:fe", schema); // Valid | ||
v.validate({ mac: "01C8.954B.65FE" }, schema); // Valid | ||
v.validate({ mac: "01c8.954b.65fe", schema); // Valid | ||
v.validate({ mac: "01-C8-95-4B-65-FE" }, schema); // Valid | ||
v.validate({ mac: "01-c8-95-4b-65-fe" }, schema); // Valid | ||
v.validate({ mac: "01C8954B65FE" }, schema); // Fail | ||
``` | ||
## `luhn` | ||
This is an Luhn validator. | ||
[Luhn algorithm](https://en.wikipedia.org/wiki/Luhn_algorithm) checksum | ||
Credit Card numbers, IMEI numbers, National Provider Identifier numbers and others | ||
```js | ||
let schema = { | ||
cc: { type: "luhn" } | ||
} | ||
v.validate({ cc: "452373989901198" }, schema); // Valid | ||
v.validate({ cc: 452373989901198 }, schema); // Valid | ||
v.validate({ cc: "4523-739-8990-1198" }, schema); // Valid | ||
v.validate({ cc: "452373989901199" }, schema); // Fail | ||
``` | ||
# Custom validator | ||
@@ -572,7 +842,11 @@ You can also create your custom validator. | ||
// Register a custom 'even' validator | ||
v.add("even", value => { | ||
if (value % 2 != 0) | ||
return v.makeError("evenNumber", null, value); | ||
v.add("even", function({ schema, messages }, path, context) { | ||
return { | ||
source: ` | ||
if (value % 2 != 0) | ||
${this.makeError({ type: "evenNumber", actual: "value", messages })} | ||
return true; | ||
return value; | ||
` | ||
}; | ||
}); | ||
@@ -603,19 +877,19 @@ | ||
let v = new Validator({ | ||
messages: { | ||
// Register our new error message text | ||
weightMin: "The weight must be greater than {expected}! Actual: {actual}" | ||
} | ||
messages: { | ||
// Register our new error message text | ||
weightMin: "The weight must be greater than {expected}! Actual: {actual}" | ||
} | ||
}); | ||
const schema = { | ||
name: { type: "string", min: 3, max: 255 }, | ||
weight: { | ||
type: "custom", | ||
minWeight: 10, | ||
check(value, schema) { | ||
return (value < schema.minWeight) | ||
? this.makeError("weightMin", schema.minWeight, value) | ||
: true; | ||
} | ||
} | ||
name: { type: "string", min: 3, max: 255 }, | ||
weight: { | ||
type: "custom", | ||
minWeight: 10, | ||
check(value, schema) { | ||
return (value < schema.minWeight) | ||
? this.makeError("weightMin", schema.minWeight, value) | ||
: true; | ||
} | ||
} | ||
}; | ||
@@ -628,9 +902,9 @@ | ||
/* Returns an array with errors: | ||
[{ | ||
type: 'weightMin', | ||
expected: 10, | ||
actual: 8, | ||
field: 'weight', | ||
message: 'The weight must be greater than 10! Actual: 8' | ||
}] | ||
[{ | ||
type: 'weightMin', | ||
expected: 10, | ||
actual: 8, | ||
field: 'weight', | ||
message: 'The weight must be greater than 10! Actual: 8' | ||
}] | ||
*/ | ||
@@ -708,36 +982,50 @@ ``` | ||
``` | ||
## Message types | ||
# Message types | ||
Name | Default text | ||
------------------- | ------------- | ||
`required` | The '{field}' field is required! | ||
`string` | The '{field}' field must be a string! | ||
`stringEmpty` | The '{field}' field must not be empty! | ||
`stringMin` | The '{field}' field length must be greater than or equal to {expected} characters long! | ||
`stringMax` | The '{field}' field length must be less than or equal to {expected} characters long! | ||
`stringLength` | The '{field}' field length must be {expected} characters long! | ||
`stringPattern` | The '{field}' field fails to match the required pattern! | ||
`stringContains` | The '{field}' field must contain the '{expected}' text! | ||
`stringEnum` | The '{field}' field does not match any of the allowed values! | ||
`number` | The '{field}' field must be a number! | ||
`numberMin` | The '{field}' field must be greater than or equal to {expected}! | ||
`numberMax` | The '{field}' field must be less than or equal to {expected}! | ||
`numberEqual` | The '{field}' field must be equal with {expected}! | ||
`numberNotEqual` | The '{field}' field can't be equal with {expected}! | ||
`numberInteger` | The '{field}' field must be an integer! | ||
`numberPositive` | The '{field}' field must be a positive number! | ||
`numberNegative` | The '{field}' field must be a negative number! | ||
`array` | The '{field}' field must be an array! | ||
`arrayEmpty` | The '{field}' field must not be an empty array! | ||
`arrayMin` | The '{field}' field must contain at least {expected} items! | ||
`arrayMax` | The '{field}' field must contain less than or equal to {expected} items! | ||
`arrayLength` | The '{field}' field must contain {expected} items! | ||
`arrayContains` | The '{field}' field must contain the '{expected}' item! | ||
`arrayEnum` | The '{field} field value '{expected}' does not match any of the allowed values! | ||
`boolean` | The '{field}' field must be a boolean! | ||
`function` | The '{field}' field must be a function! | ||
`date` | The '{field}' field must be a Date! | ||
`dateMin` | The '{field}' field must be greater than or equal to {expected}! | ||
`dateMax` | The '{field}' field must be less than or equal to {expected}! | ||
`forbidden` | The '{field}' field is forbidden! | ||
`email` | The '{field}' field must be a valid e-mail! | ||
`required` | The '{field}' field is required. | ||
`string` | The '{field}' field must be a string. | ||
`stringEmpty` | The '{field}' field must not be empty. | ||
`stringMin` | The '{field}' field length must be greater than or equal to {expected} characters long. | ||
`stringMax` | The '{field}' field length must be less than or equal to {expected} characters long. | ||
`stringLength` | The '{field}' field length must be {expected} characters long. | ||
`stringPattern` | The '{field}' field fails to match the required pattern. | ||
`stringContains` | The '{field}' field must contain the '{expected}' text. | ||
`stringEnum` | The '{field}' field does not match any of the allowed values. | ||
`stringNumeric` | The '{field}' field must be a numeric string. | ||
`stringAlpha` | The '{field}' field must be an alphabetic string. | ||
`stringAlphanum` | The '{field}' field must be an alphanumeric string. | ||
`stringAlphadash` | The '{field}' field must be an alphadash string. | ||
`number` | The '{field}' field must be a number. | ||
`numberMin` | The '{field}' field must be greater than or equal to {expected}. | ||
`numberMax` | The '{field}' field must be less than or equal to {expected}. | ||
`numberEqual` | The '{field}' field must be equal to {expected}. | ||
`numberNotEqual` | The '{field}' field can't be equal to {expected}. | ||
`numberInteger` | The '{field}' field must be an integer. | ||
`numberPositive` | The '{field}' field must be a positive number. | ||
`numberNegative` | The '{field}' field must be a negative number. | ||
`array` | The '{field}' field must be an array. | ||
`arrayEmpty` | The '{field}' field must not be an empty array. | ||
`arrayMin` | The '{field}' field must contain at least {expected} items. | ||
`arrayMax` | The '{field}' field must contain less than or equal to {expected} items. | ||
`arrayLength` | The '{field}' field must contain {expected} items. | ||
`arrayContains` | The '{field}' field must contain the '{expected}' item. | ||
`arrayEnum` | The '{actual}' value in '{field}' field does not match any of the '{expected}' values. | ||
`boolean` | The '{field}' field must be a boolean. | ||
`function` | The '{field}' field must be a function. | ||
`date` | The '{field}' field must be a Date. | ||
`dateMin` | The '{field}' field must be greater than or equal to {expected}. | ||
`dateMax` | The '{field}' field must be less than or equal to {expected}. | ||
`forbidden` | The '{field}' field is forbidden. | ||
`email` | The '{field}' field must be a valid e-mail. | ||
`url` | The '{field}' field must be a valid URL. | ||
`enumValue` | The '{field}' field value '{expected}' does not match any of the allowed values. | ||
`equalValue` | The '{field}' field value must be equal to '{expected}'. | ||
`equalField` | The '{field}' field value must be equal to '{expected}' field value. | ||
`object` | The '{field}' must be an Object. | ||
`objectStrict` | The object '{field}' contains forbidden keys: '{actual}'. | ||
`uuid` | The '{field}' field must be a valid UUID. | ||
`uuidVersion` | The '{field}' field must be a valid UUID version provided. | ||
`mac` | The '{field}' field must be a valid MAC address. | ||
`luhn` | The '{field}' field must be a valid checksum luhn. | ||
@@ -750,5 +1038,4 @@ ## Message fields | ||
`actual` | The actual value | ||
`type` | The field type | ||
## Development | ||
# Development | ||
``` | ||
@@ -758,3 +1045,3 @@ npm run dev | ||
## Test | ||
# Test | ||
``` | ||
@@ -764,3 +1051,3 @@ npm test | ||
### Coverage report | ||
## Coverage report | ||
``` | ||
@@ -770,3 +1057,3 @@ -----------------|----------|----------|----------|----------|-------------------| | ||
-----------------|----------|----------|----------|----------|-------------------| | ||
All files | 100 | 100 | 100 | 100 | | | ||
All files | 100 | 97.73 | 100 | 100 | | | ||
lib | 100 | 100 | 100 | 100 | | | ||
@@ -778,10 +1065,11 @@ messages.js | 100 | 100 | 100 | 100 | | | ||
flatten.js | 100 | 100 | 100 | 100 | | | ||
lib/rules | 100 | 100 | 100 | 100 | | | ||
lib/rules | 100 | 96.43 | 100 | 100 | | | ||
any.js | 100 | 100 | 100 | 100 | | | ||
array.js | 100 | 100 | 100 | 100 | | | ||
boolean.js | 100 | 100 | 100 | 100 | | | ||
custom.js | 100 | 100 | 100 | 100 | | | ||
custom.js | 100 | 50 | 100 | 100 | 6 | | ||
date.js | 100 | 100 | 100 | 100 | | | ||
email.js | 100 | 100 | 100 | 100 | | | ||
enum.js | 100 | 100 | 100 | 100 | | | ||
enum.js | 100 | 50 | 100 | 100 | 6 | | ||
equal.js | 100 | 100 | 100 | 100 | | | ||
forbidden.js | 100 | 100 | 100 | 100 | | | ||
@@ -791,5 +1079,6 @@ function.js | 100 | 100 | 100 | 100 | | | ||
mac.js | 100 | 100 | 100 | 100 | | | ||
multi.js | 100 | 100 | 100 | 100 | | | ||
number.js | 100 | 100 | 100 | 100 | | | ||
object.js | 100 | 100 | 100 | 100 | | | ||
string.js | 100 | 100 | 100 | 100 | | | ||
string.js | 100 | 95.83 | 100 | 100 | 55,63 | | ||
url.js | 100 | 100 | 100 | 100 | | | ||
@@ -800,12 +1089,12 @@ uuid.js | 100 | 100 | 100 | 100 | | | ||
## Contribution | ||
# Contribution | ||
Please send pull requests improving the usage and fixing bugs, improving documentation and providing better examples, or providing some tests, because these things are important. | ||
## License | ||
# License | ||
fastest-validator is available under the [MIT license](https://tldrlegal.com/license/mit-license). | ||
## Contact | ||
# Contact | ||
Copyright (C) 2017 Icebob | ||
Copyright (C) 2019 Icebob | ||
[![@icebob](https://img.shields.io/badge/github-icebob-green.svg)](https://github.com/icebob) [![@icebob](https://img.shields.io/badge/twitter-Icebobcsi-blue.svg)](https://twitter.com/Icebobcsi) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
307298
4258
1053
19
36
2
3