UNPKG

validatorjs2

Version:

Validation library inspired by Laravel's Validator

2,041 lines (1,729 loc) 53 kB
/*! validatorjs - 2020-12-03 */ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Validator = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ function AsyncResolvers(onFailedOne, onResolvedAll) { this.onResolvedAll = onResolvedAll; this.onFailedOne = onFailedOne; this.resolvers = {}; this.resolversCount = 0; this.passed = []; this.failed = []; this.firing = false; } AsyncResolvers.prototype = { /** * Add resolver * * @param {Rule} rule * @return {integer} */ add: function(rule) { var index = this.resolversCount; this.resolvers[index] = rule; this.resolversCount++; return index; }, /** * Resolve given index * * @param {integer} index * @return {void} */ resolve: function(index) { var rule = this.resolvers[index]; if (rule.passes === true) { this.passed.push(rule); } else if (rule.passes === false) { this.failed.push(rule); this.onFailedOne(rule); } this.fire(); }, /** * Determine if all have been resolved * * @return {boolean} */ isAllResolved: function() { return (this.passed.length + this.failed.length) === this.resolversCount; }, /** * Attempt to fire final all resolved callback if completed * * @return {void} */ fire: function() { if (!this.firing) { return; } if (this.isAllResolved()) { this.onResolvedAll(this.failed.length === 0); } }, /** * Enable firing * * @return {void} */ enableFiring: function() { this.firing = true; } }; module.exports = AsyncResolvers; },{}],2:[function(require,module,exports){ var replacements = { /** * Between replacement (replaces :min and :max) * * @param {string} template * @param {Rule} rule * @return {string} */ between: function(template, rule) { var parameters = rule.getParameters(); return this._replacePlaceholders(rule, template, { min: parameters[0], max: parameters[1] }); }, /** * Digits-Between replacement (replaces :min and :max) * * @param {string} template * @param {Rule} rule * @return {string} */ digits_between: function(template, rule) { var parameters = rule.getParameters(); return this._replacePlaceholders(rule, template, { min: parameters[0], max: parameters[1] }); }, /** * Required_if replacement. * * @param {string} template * @param {Rule} rule * @return {string} */ required_if: function(template, rule) { var parameters = rule.getParameters(); return this._replacePlaceholders(rule, template, { other: this._getAttributeName(parameters[0]), value: parameters[1] }); }, /** * Required_unless replacement. * * @param {string} template * @param {Rule} rule * @return {string} */ required_unless: function(template, rule) { var parameters = rule.getParameters(); return this._replacePlaceholders(rule, template, { other: this._getAttributeName(parameters[0]), value: parameters[1] }); }, /** * Required_with replacement. * * @param {string} template * @param {Rule} rule * @return {string} */ required_with: function(template, rule) { var parameters = rule.getParameters(); return this._replacePlaceholders(rule, template, { field: this._getAttributeName(parameters[0]) }); }, /** * Required_with_all replacement. * * @param {string} template * @param {Rule} rule * @return {string} */ required_with_all: function(template, rule) { var parameters = rule.getParameters(); var getAttributeName = this._getAttributeName.bind(this); return this._replacePlaceholders(rule, template, { fields: parameters.map(getAttributeName).join(', ') }); }, /** * Required_without replacement. * * @param {string} template * @param {Rule} rule * @return {string} */ required_without: function(template, rule) { var parameters = rule.getParameters(); return this._replacePlaceholders(rule, template, { field: this._getAttributeName(parameters[0]) }); }, /** * Required_without_all replacement. * * @param {string} template * @param {Rule} rule * @return {string} */ required_without_all: function(template, rule) { var parameters = rule.getParameters(); var getAttributeName = this._getAttributeName.bind(this); return this._replacePlaceholders(rule, template, { fields: parameters.map(getAttributeName).join(', ') }); }, /** * After replacement. * * @param {string} template * @param {Rule} rule * @return {string} */ after: function(template, rule) { var parameters = rule.getParameters(); return this._replacePlaceholders(rule, template, { after: this._getAttributeName(parameters[0]) }); }, /** * Before replacement. * * @param {string} template * @param {Rule} rule * @return {string} */ before: function(template, rule) { var parameters = rule.getParameters(); return this._replacePlaceholders(rule, template, { before: this._getAttributeName(parameters[0]) }); }, /** * After_or_equal replacement. * * @param {string} template * @param {Rule} rule * @return {string} */ after_or_equal: function(template, rule) { var parameters = rule.getParameters(); return this._replacePlaceholders(rule, template, { after_or_equal: this._getAttributeName(parameters[0]) }); }, /** * Before_or_equal replacement. * * @param {string} template * @param {Rule} rule * @return {string} */ before_or_equal: function(template, rule) { var parameters = rule.getParameters(); return this._replacePlaceholders(rule, template, { before_or_equal: this._getAttributeName(parameters[0]) }); }, /** * Same replacement. * * @param {string} template * @param {Rule} rule * @return {string} */ same: function(template, rule) { var parameters = rule.getParameters(); return this._replacePlaceholders(rule, template, { same: this._getAttributeName(parameters[0]) }); }, }; function formatter(attribute) { return attribute.replace(/[_\[]/g, ' ').replace(/]/g, ''); } module.exports = { replacements: replacements, formatter: formatter }; },{}],3:[function(require,module,exports){ var Errors = function() { this.errors = {}; }; Errors.prototype = { constructor: Errors, /** * Add new error message for given attribute * * @param {string} attribute * @param {string} message * @return {void} */ add: function(attribute, message) { if (!this.has(attribute)) { this.errors[attribute] = []; } if (this.errors[attribute].indexOf(message) === -1) { this.errors[attribute].push(message); } }, /** * Returns an array of error messages for an attribute, or an empty array * * @param {string} attribute A key in the data object being validated * @return {array} An array of error messages */ get: function(attribute) { if (this.has(attribute)) { return this.errors[attribute]; } return []; }, /** * Returns the first error message for an attribute, false otherwise * * @param {string} attribute A key in the data object being validated * @return {string|false} First error message or false */ first: function(attribute) { if (this.has(attribute)) { return this.errors[attribute][0]; } return false; }, /** * Get all error messages from all failing attributes * * @return {Object} Failed attribute names for keys and an array of messages for values */ all: function() { return this.errors; }, /** * Determine if there are any error messages for an attribute * * @param {string} attribute A key in the data object being validated * @return {boolean} */ has: function(attribute) { if (this.errors.hasOwnProperty(attribute)) { return true; } return false; } }; module.exports = Errors; },{}],4:[function(require,module,exports){ var Messages = require('./messages'); require('./lang/en'); var require_method = require; var container = { messages: {}, /** * Set messages for language * * @param {string} lang * @param {object} rawMessages * @return {void} */ _set: function(lang, rawMessages) { this.messages[lang] = rawMessages; }, /** * Set message for given language's rule. * * @param {string} lang * @param {string} attribute * @param {string|object} message * @return {void} */ _setRuleMessage: function(lang, attribute, message) { this._load(lang); if (message === undefined) { message = this.messages[lang].def; } this.messages[lang][attribute] = message; }, /** * Load messages (if not already loaded) * * @param {string} lang * @return {void} */ _load: function(lang) { if (!this.messages[lang]) { try { var rawMessages = require_method('./lang/' + lang); this._set(lang, rawMessages); } catch (e) {} } }, /** * Get raw messages for language * * @param {string} lang * @return {object} */ _get: function(lang) { this._load(lang); return this.messages[lang]; }, /** * Make messages for given language * * @param {string} lang * @return {Messages} */ _make: function(lang) { this._load(lang); return new Messages(lang, this.messages[lang]); } }; module.exports = container; },{"./lang/en":5,"./messages":6}],5:[function(require,module,exports){ module.exports = { accepted: 'The :attribute must be accepted.', after: 'The :attribute must be after :after.', after_or_equal: 'The :attribute must be equal or after :after_or_equal.', alpha: 'The :attribute field must contain only alphabetic characters.', alpha_dash: 'The :attribute field may only contain alpha-numeric characters, as well as dashes and underscores.', alpha_num: 'The :attribute field must be alphanumeric.', before: 'The :attribute must be before :before.', before_or_equal: 'The :attribute must be equal or before :before_or_equal.', between: { numeric: 'The :attribute field must be between :min and :max.', string: 'The :attribute field must be between :min and :max characters.', }, confirmed: 'The :attribute confirmation does not match.', email: 'The :attribute format is invalid.', date: 'The :attribute is not a valid date format.', def: 'The :attribute attribute has errors.', digits: 'The :attribute must be :digits digits.', digits_between: 'The :attribute field must be between :min and :max digits.', different: 'The :attribute and :different must be different.', in: 'The selected :attribute is invalid.', integer: 'The :attribute must be an integer.', hex: 'The :attribute field should have hexadecimal format', min: { numeric: 'The :attribute must be at least :min.', string: 'The :attribute must be at least :min characters.' }, max: { numeric: 'The :attribute may not be greater than :max.', string: 'The :attribute may not be greater than :max characters.' }, not_in: 'The selected :attribute is invalid.', numeric: 'The :attribute must be a number.', present: 'The :attribute field must be present (but can be empty).', required: 'The :attribute field is required.', required_if: 'The :attribute field is required when :other is :value.', required_unless: 'The :attribute field is required when :other is not :value.', required_with: 'The :attribute field is required when :field is not empty.', required_with_all: 'The :attribute field is required when :fields are not empty.', required_without: 'The :attribute field is required when :field is empty.', required_without_all: 'The :attribute field is required when :fields are empty.', same: 'The :attribute and :same fields must match.', size: { numeric: 'The :attribute must be :size.', string: 'The :attribute must be :size characters.' }, string: 'The :attribute must be a string.', url: 'The :attribute format is invalid.', regex: 'The :attribute format is invalid.', attributes: {} }; },{}],6:[function(require,module,exports){ var Attributes = require('./attributes'); var Messages = function(lang, messages) { this.lang = lang; this.messages = messages; this.customMessages = {}; this.attributeNames = {}; }; Messages.prototype = { constructor: Messages, /** * Set custom messages * * @param {object} customMessages * @return {void} */ _setCustom: function(customMessages) { this.customMessages = customMessages || {}; }, /** * Set custom attribute names. * * @param {object} attributes */ _setAttributeNames: function(attributes) { this.attributeNames = attributes; }, /** * Set the attribute formatter. * * @param {fuction} func * @return {void} */ _setAttributeFormatter: function(func) { this.attributeFormatter = func; }, /** * Get attribute name to display. * * @param {string} attribute * @return {string} */ _getAttributeName: function(attribute) { var name = attribute; if (this.attributeNames.hasOwnProperty(attribute)) { return this.attributeNames[attribute]; } else if (this.messages.attributes.hasOwnProperty(attribute)) { name = this.messages.attributes[attribute]; } if (this.attributeFormatter) { name = this.attributeFormatter(name); } return name; }, /** * Get all messages * * @return {object} */ all: function() { return this.messages; }, /** * Render message * * @param {Rule} rule * @return {string} */ render: function(rule) { if (rule.customMessage) { return rule.customMessage; } var template = this._getTemplate(rule); var message; if (Attributes.replacements[rule.name]) { message = Attributes.replacements[rule.name].apply(this, [template, rule]); } else { message = this._replacePlaceholders(rule, template, {}); } return message; }, /** * Get the template to use for given rule * * @param {Rule} rule * @return {string} */ _getTemplate: function(rule) { var messages = this.messages; var template = messages.def; var customMessages = this.customMessages; var formats = [rule.name + '.' + rule.attribute, rule.name]; for (var i = 0, format; i < formats.length; i++) { format = formats[i]; if (customMessages.hasOwnProperty(format)) { template = customMessages[format]; break; } else if (messages.hasOwnProperty(format)) { template = messages[format]; break; } } if (typeof template === 'object') { template = template[rule._getValueType()]; } return template; }, /** * Replace placeholders in the template using the data object * * @param {Rule} rule * @param {string} template * @param {object} data * @return {string} */ _replacePlaceholders: function(rule, template, data) { var message, attribute; data.attribute = this._getAttributeName(rule.attribute); data[rule.name] = data[rule.name] || rule.getParameters().join(','); if (typeof template === 'string' && typeof data === 'object') { message = template; for (attribute in data) { message = message.replace(new RegExp(':' + attribute, 'g'), data[attribute]); } } return message; } }; module.exports = Messages; },{"./attributes":2}],7:[function(require,module,exports){ // https://docs.microsoft.com/en-us/office/troubleshoot/excel/determine-a-leap-year function leapYear(year) { return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; } function checkFalsePositiveDates(dateString = '') { if (dateString.length === 10) { // massage input to use yyyy-mm-dd format // we support yyyy/mm/dd or yyyy.mm.dd let normalizedDate = dateString.replace('.', '-').replace('/', '-'); let parts = normalizedDate.split('-'); if (parts.length === 3) { if (parts[0].length === 4) { // yyyy-mm-dd format let y = parseInt(parts[0]); let m = parseInt(parts[1]); let d = parseInt(parts[2]); if (m === 2) { // return leapYear(y) ? d <= 29 : d <= 28; if (leapYear(y)) { if (d > 29) { return false; } } else { if (d > 28) { return false; } } } if (m === 4 || m === 6 || m === 9 || m === 11) { if (d > 30) { return false; } } } } return true; // we are not in feburary, proceed } return true; // we are not testing formatted date, proceed to rest of validation } function isValidDate(dateString) { let testDate; if (typeof dateString === 'number') { testDate = new Date(dateString); if (typeof testDate === 'object') { return true; } } // first convert incoming string to date object and see if it correct date and format testDate = new Date(dateString); if (typeof testDate === 'object') { if (testDate.toString() === 'Invalid Date') { return false; } /** * Check for false positive dates * perform special check on february as JS `new Date` incorrectly returns valid date * Eg. let newDate = new Date('2020-02-29') // returns as March 02 2020 * Eg. let newDate = new Date('2019-02-29') // returns as March 01 2020 * Eg. let newDate = new Date('2019-04-31') // returns as April 30 2020 */ if (!checkFalsePositiveDates(dateString)) { return false; } // valid date object and not a february date return true; } // First check for the pattern var regex_date = /^\d{4}\-\d{1,2}\-\d{1,2}$/; if (!regex_date.test(dateString)) { return false; } // Parse the date parts to integers var parts = dateString.split("-"); var day = parseInt(parts[2], 10); var month = parseInt(parts[1], 10); var year = parseInt(parts[0], 10); // Check the ranges of month and year if (year < 1000 || year > 3000 || month == 0 || month > 12) { return false; } var monthLength = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; // Adjust for leap years if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) { monthLength[1] = 29; } // Check the range of the day return day > 0 && day <= monthLength[month - 1]; } var rules = { required: function (val) { var str; if (val === undefined || val === null) { return false; } str = String(val).replace(/\s/g, ""); return str.length > 0 ? true : false; }, required_if: function (val, req, attribute) { req = this.getParameters(); if (this.validator._objectPath(this.validator.input, req[0]) === req[1]) { return this.validator.getRule("required").validate(val); } return true; }, required_unless: function (val, req, attribute) { req = this.getParameters(); if (this.validator._objectPath(this.validator.input, req[0]) !== req[1]) { return this.validator.getRule("required").validate(val); } return true; }, required_with: function (val, req, attribute) { if (this.validator._objectPath(this.validator.input, req)) { return this.validator.getRule("required").validate(val); } return true; }, required_with_all: function (val, req, attribute) { req = this.getParameters(); for (var i = 0; i < req.length; i++) { if (!this.validator._objectPath(this.validator.input, req[i])) { return true; } } return this.validator.getRule("required").validate(val); }, required_without: function (val, req, attribute) { if (this.validator._objectPath(this.validator.input, req)) { return true; } return this.validator.getRule("required").validate(val); }, required_without_all: function (val, req, attribute) { req = this.getParameters(); for (var i = 0; i < req.length; i++) { if (this.validator._objectPath(this.validator.input, req[i])) { return true; } } return this.validator.getRule("required").validate(val); }, boolean: function (val) { return ( val === true || val === false || val === 0 || val === 1 || val === "0" || val === "1" || val === "true" || val === "false" ); }, // compares the size of strings // with numbers, compares the value size: function (val, req, attribute) { if (val) { req = parseFloat(req); var size = this.getSize(); return size === req; } return true; }, string: function (val, req, attribute) { return typeof val === "string"; }, sometimes: function (val) { return true; }, /** * Compares the size of strings or the value of numbers if there is a truthy value */ min: function (val, req, attribute) { var size = this.getSize(); return size >= req; }, /** * Compares the size of strings or the value of numbers if there is a truthy value */ max: function (val, req, attribute) { var size = this.getSize(); return size <= req; }, between: function (val, req, attribute) { req = this.getParameters(); var size = this.getSize(); var min = parseFloat(req[0], 10); var max = parseFloat(req[1], 10); return size >= min && size <= max; }, email: function (val) { // Added umlaut support https://github.com/skaterdav85/validatorjs/issues/308 var re = /^(([^<>()[\]\\.,;:\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,}))$/; if (!re.test(val)) { // added support domain 3-n level https://github.com/skaterdav85/validatorjs/issues/384 re = /^((?:[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]|[^\u0000-\u007F])+@(?:[a-zA-Z0-9]|[^\u0000-\u007F])(?:(?:[a-zA-Z0-9-]|[^\u0000-\u007F]){0,61}(?:[a-zA-Z0-9]|[^\u0000-\u007F]))?(?:\.(?:[a-zA-Z0-9]|[^\u0000-\u007F])(?:(?:[a-zA-Z0-9-]|[^\u0000-\u007F]){0,61}(?:[a-zA-Z0-9]|[^\u0000-\u007F]))?)+)*$/; } return re.test(val); }, numeric: function (val) { var num; num = Number(val); // tries to convert value to a number. useful if value is coming from form element if (typeof num === "number" && !isNaN(num) && typeof val !== "boolean") { return true; } else { return false; } }, array: function (val) { return val instanceof Array; }, url: function (url) { return /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-z]{2,63}\b([-a-zA-Z0-9@:%_\+.~#?&/=]*)/i.test(url); }, alpha: function (val) { return /^[a-zA-Z]+$/.test(val); }, alpha_dash: function (val) { return /^[a-zA-Z0-9_\-]+$/.test(val); }, alpha_num: function (val) { return /^[a-zA-Z0-9]+$/.test(val); }, same: function (val, req) { var val1 = this.validator._flattenObject(this.validator.input)[req]; var val2 = val; if (val1 === val2) { return true; } return false; }, different: function (val, req) { var val1 = this.validator._flattenObject(this.validator.input)[req]; var val2 = val; if (val1 !== val2) { return true; } return false; }, in: function (val, req) { var list, i; if (val) { list = this.getParameters(); } if (val && !(val instanceof Array)) { var localValue = val; for (i = 0; i < list.length; i++) { if (typeof list[i] === "string") { localValue = String(val); } if (localValue === list[i]) { return true; } } return false; } if (val && val instanceof Array) { for (i = 0; i < val.length; i++) { if (list.indexOf(val[i]) < 0) { return false; } } } return true; }, not_in: function (val, req) { var list = this.getParameters(); var len = list.length; var returnVal = true; for (var i = 0; i < len; i++) { var localValue = val; if (typeof list[i] === "string") { localValue = String(val); } if (localValue === list[i]) { returnVal = false; break; } } return returnVal; }, accepted: function (val) { if (val === "on" || val === "yes" || val === 1 || val === "1" || val === true) { return true; } return false; }, confirmed: function (val, req, key) { var confirmedKey = key + "_confirmation"; if (this.validator.input[confirmedKey] === val) { return true; } return false; }, integer: function (val) { return String(parseInt(val, 10)) === String(val); }, digits: function (val, req) { var numericRule = this.validator.getRule('numeric'); if (numericRule.validate(val) && String(val.trim()).length === parseInt(req)) { return true; } return false; }, digits_between: function (val) { var numericRule = this.validator.getRule("numeric"); var req = this.getParameters(); var valueDigitsCount = String(val).length; var min = parseFloat(req[0], 10); var max = parseFloat(req[1], 10); if (numericRule.validate(val) && valueDigitsCount >= min && valueDigitsCount <= max) { return true; } return false; }, regex: function (val, req) { let reqPattern = req; var mod = /[g|i|m]{1,3}$/; var flag = req.match(mod); flag = flag ? flag[0] : ""; req = req.replace(mod, "").slice(1, -1); req = new RegExp(req, flag); return !!req.test(val); }, date: function (val, format) { return isValidDate(val); }, present: function (val) { return typeof val !== "undefined"; }, after: function (val, req) { var val1 = this.validator.input[req]; var val2 = val; if (!isValidDate(val1)) { return false; } if (!isValidDate(val2)) { return false; } if (new Date(val1).getTime() < new Date(val2).getTime()) { return true; } return false; }, after_or_equal: function (val, req) { var val1 = this.validator.input[req]; var val2 = val; if (!isValidDate(val1)) { return false; } if (!isValidDate(val2)) { return false; } if (new Date(val1).getTime() <= new Date(val2).getTime()) { return true; } return false; }, before: function (val, req) { var val1 = this.validator.input[req]; var val2 = val; if (!isValidDate(val1)) { return false; } if (!isValidDate(val2)) { return false; } if (new Date(val1).getTime() > new Date(val2).getTime()) { return true; } return false; }, before_or_equal: function (val, req) { var val1 = this.validator.input[req]; var val2 = val; if (!isValidDate(val1)) { return false; } if (!isValidDate(val2)) { return false; } if (new Date(val1).getTime() >= new Date(val2).getTime()) { return true; } return false; }, hex: function (val) { return /^[0-9a-f]+$/i.test(val); }, ipv4: function (val, req, attribute) { if (typeof val != 'string') return false; // regex to check that each octet is valid var er = /^[0-9]+$/; // ipv4 octets are delimited by dot octets = val.split('.'); // check 1: ipv4 address should contains 4 octets if (octets.length != 4) return false; for (let i = 0; i < octets.length; i++) { const element = octets[i]; // check 2: each octet should be integer bigger than 0 if (!er.test(element)) return false; // check 3: each octet value should be less than 256 var octetValue = parseInt(element); if (octetValue >= 256) return false; } // if all checks passed, we know it's valid IPv4 address! return true; }, ipv6: function (val, req, attribute) { if (typeof val != 'string') return false; // regex to check that each hextet is valid var er = /^[0-9a-f]+$/; // ipv6 hextets are delimited by colon hextets = val.split(':'); // check 1: ipv6 should contain only one consecutive colons colons = val.match(/::/); if (colons != null && val.match(/::/g).length > 1) return false; // check 2: ipv6 should not be ending or starting with colon // edge case: not with consecutive colons if (val[0] == ':' && (colons == null || (colons != null && colons.index != 0))) return false; if (val[val.length - 1] == ':' && (colons == null || (colons != null && colons.index != val.length - 2))) return false; // check 3: ipv6 should contain no less than 3 sector // minimum ipv6 addres - ::1 if (3 > hextets.length) return false; // check 4: ipv6 should contain no more than 8 sectors // only 1 edge case: when first or last sector is ommited var isEdgeCase = (hextets.length == 9 && colons != null && (colons.index == 0 || colons.index == val.length - 2)); if (hextets.length > 8 && !isEdgeCase) return false; // check 5: ipv6 should contain exactly one consecutive colons if it has less than 8 sectors if (hextets.length != 8 && colons == null) return false; for (let i = 0; i < hextets.length; i++) { const element = hextets[i]; if (element.length == 0) continue; // check 6: all of hextets should contain numbers from 0 to f (in hexadecimal) if (!er.test(element)) return false; // check 7: all of hextet values should be less then ffff (in hexadeimal) // checking using length of hextet. lowest invalid value's length is 5. // so all valid hextets are length of 4 or less if (element.length > 4) return false; } return true; }, ip: function (val, req, attribute) { return rules['ipv4'](val, req, attribute) || rules['ipv6'](val, req, attribute); } }; var missedRuleValidator = function () { throw new Error("Validator `" + this.name + "` is not defined!"); }; var missedRuleMessage; function Rule(name, fn, async) { this.name = name; this.fn = fn; this.passes = null; this._customMessage = undefined; this.async = async; } Rule.prototype = { /** * Validate rule * * @param {mixed} inputValue * @param {mixed} ruleValue * @param {string} attribute * @param {function} callback * @return {boolean|undefined} */ validate: function (inputValue, ruleValue, attribute, callback) { var _this = this; this._setValidatingData(attribute, inputValue, ruleValue); if (typeof callback === "function") { this.callback = callback; var handleResponse = function (passes, message) { _this.response(passes, message); }; if (this.async) { return this._apply(inputValue, ruleValue, attribute, handleResponse); } else { return handleResponse(this._apply(inputValue, ruleValue, attribute)); } } return this._apply(inputValue, ruleValue, attribute); }, /** * Apply validation function * * @param {mixed} inputValue * @param {mixed} ruleValue * @param {string} attribute * @param {function} callback * @return {boolean|undefined} */ _apply: function (inputValue, ruleValue, attribute, callback) { var fn = this.isMissed() ? missedRuleValidator : this.fn; return fn.apply(this, [inputValue, ruleValue, attribute, callback]); }, /** * Set validating data * * @param {string} attribute * @param {mixed} inputValue * @param {mixed} ruleValue * @return {void} */ _setValidatingData: function (attribute, inputValue, ruleValue) { this.attribute = attribute; this.inputValue = inputValue; this.ruleValue = ruleValue; }, /** * Get parameters * * @return {array} */ getParameters: function () { var value = []; if (typeof this.ruleValue === "string") { value = this.ruleValue.split(","); } if (typeof this.ruleValue === "number") { value.push(this.ruleValue); } if (this.ruleValue instanceof Array) { value = this.ruleValue; } return value; }, /** * Get true size of value * * @return {integer|float} */ getSize: function () { var value = this.inputValue; if (value instanceof Array) { return value.length; } if (typeof value === "number") { return value; } if (this.validator._hasNumericRule(this.attribute)) { return parseFloat(value, 10); } return value.length; }, /** * Get the type of value being checked; numeric or string. * * @return {string} */ _getValueType: function () { if (typeof this.inputValue === "number" || this.validator._hasNumericRule(this.attribute)) { return "numeric"; } return "string"; }, /** * Set the async callback response * * @param {boolean|undefined} passes Whether validation passed * @param {string|undefined} message Custom error message * @return {void} */ response: function (passes, message) { this.passes = passes === undefined || passes === true; this._customMessage = message; this.callback(this.passes, message); }, /** * Set validator instance * * @param {Validator} validator * @return {void} */ setValidator: function (validator) { this.validator = validator; }, /** * Check if rule is missed * * @return {boolean} */ isMissed: function () { return typeof this.fn !== "function"; }, get customMessage() { return this.isMissed() ? missedRuleMessage : this._customMessage; } }; var manager = { /** * List of async rule names * * @type {Array} */ asyncRules: [], /** * Implicit rules (rules to always validate) * * @type {Array} */ implicitRules: [ "required", "required_if", "required_unless", "required_with", "required_with_all", "required_without", "required_without_all", "accepted", "present" ], /** * Get rule by name * * @param {string} name * @param {Validator} * @return {Rule} */ make: function (name, validator) { var async = this.isAsync(name); var rule = new Rule(name, rules[name], async); rule.setValidator(validator); return rule; }, /** * Determine if given rule is async * * @param {string} name * @return {boolean} */ isAsync: function (name) { for (var i = 0, len = this.asyncRules.length; i < len; i++) { if (this.asyncRules[i] === name) { return true; } } return false; }, /** * Determine if rule is implicit (should always validate) * * @param {string} name * @return {boolean} */ isImplicit: function (name) { return this.implicitRules.indexOf(name) > -1; }, /** * Register new rule * * @param {string} name * @param {function} fn * @return {void} */ register: function (name, fn) { rules[name] = fn; }, /** * Register new implicit rule * * @param {string} name * @param {function} fn * @return {void} */ registerImplicit: function (name, fn) { this.register(name, fn); this.implicitRules.push(name); }, /** * Register async rule * * @param {string} name * @param {function} fn * @return {void} */ registerAsync: function (name, fn) { this.register(name, fn); this.asyncRules.push(name); }, /** * Register implicit async rule * * @param {string} name * @param {function} fn * @return {void} */ registerAsyncImplicit: function (name, fn) { this.registerImplicit(name, fn); this.asyncRules.push(name); }, registerMissedRuleValidator: function (fn, message) { missedRuleValidator = fn; missedRuleMessage = message; } }; module.exports = manager; },{}],8:[function(require,module,exports){ var Rules = require('./rules'); var Lang = require('./lang'); var Errors = require('./errors'); var Attributes = require('./attributes'); var AsyncResolvers = require('./async'); var Validator = function (input, rules, customMessages) { var lang = Validator.getDefaultLang(); this.input = input || {}; this.messages = Lang._make(lang); this.messages._setCustom(customMessages); this.setAttributeFormatter(Validator.prototype.attributeFormatter); this.errors = new Errors(); this.errorCount = 0; this.hasAsync = false; this.rules = this._parseRules(rules); }; Validator.prototype = { constructor: Validator, /** * Default language * * @type {string} */ lang: 'en', /** * Numeric based rules * * @type {array} */ numericRules: ['integer', 'numeric'], /** * Attribute formatter. * * @type {function} */ attributeFormatter: Attributes.formatter, /** * Run validator * * @return {boolean} Whether it passes; true = passes, false = fails */ check: function () { var self = this; for (var attribute in this.rules) { var attributeRules = this.rules[attribute]; var inputValue = this._objectPath(this.input, attribute); if (this._hasRule(attribute, ['sometimes']) && !this._suppliedWithData(attribute)) { continue; } for (var i = 0, len = attributeRules.length, rule, ruleOptions, rulePassed; i < len; i++) { ruleOptions = attributeRules[i]; rule = this.getRule(ruleOptions.name); if (!this._isValidatable(rule, inputValue)) { continue; } rulePassed = rule.validate(inputValue, ruleOptions.value, attribute); if (!rulePassed) { this._addFailure(rule); } if (this._shouldStopValidating(attribute, rulePassed)) { break; } } } return this.errorCount === 0; }, /** * Run async validator * * @param {function} passes * @param {function} fails * @return {void} */ checkAsync: function (passes, fails) { var _this = this; passes = passes || function () {}; fails = fails || function () {}; var failsOne = function (rule, message) { _this._addFailure(rule, message); }; var resolvedAll = function (allPassed) { if (allPassed) { passes(); } else { fails(); } }; var asyncResolvers = new AsyncResolvers(failsOne, resolvedAll); var validateRule = function (inputValue, ruleOptions, attribute, rule) { return function () { var resolverIndex = asyncResolvers.add(rule); rule.validate(inputValue, ruleOptions.value, attribute, function () { asyncResolvers.resolve(resolverIndex); }); }; }; for (var attribute in this.rules) { var attributeRules = this.rules[attribute]; var inputValue = this._objectPath(this.input, attribute); if (this._hasRule(attribute, ['sometimes']) && !this._suppliedWithData(attribute)) { continue; } for (var i = 0, len = attributeRules.length, rule, ruleOptions; i < len; i++) { ruleOptions = attributeRules[i]; rule = this.getRule(ruleOptions.name); if (!this._isValidatable(rule, inputValue)) { continue; } validateRule(inputValue, ruleOptions, attribute, rule)(); } } asyncResolvers.enableFiring(); asyncResolvers.fire(); }, /** * Add failure and error message for given rule * * @param {Rule} rule */ _addFailure: function (rule) { var msg = this.messages.render(rule); this.errors.add(rule.attribute, msg); this.errorCount++; }, /** * Flatten nested object, normalizing { foo: { bar: 1 } } into: { 'foo.bar': 1 } * * @param {object} nested object * @return {object} flattened object */ _flattenObject: function (obj) { var flattened = {}; function recurse(current, property) { if (!property && Object.getOwnPropertyNames(current).length === 0) { return; } if (Object(current) !== current || Array.isArray(current)) { flattened[property] = current; } else { var isEmpty = true; for (var p in current) { isEmpty = false; recurse(current[p], property ? property + '.' + p : p); } if (isEmpty) { flattened[property] = {}; } } } if (obj) { recurse(obj); } return flattened; }, /** * Extract value from nested object using string path with dot notation * * @param {object} object to search in * @param {string} path inside object * @return {any|void} value under the path */ _objectPath: function (obj, path) { if (Object.prototype.hasOwnProperty.call(obj, path)) { return obj[path]; } var keys = path.replace(/\[(\w+)\]/g, '.$1').replace(/^\./, '').split('.'); var copy = {}; for (var attr in obj) { if (Object.prototype.hasOwnProperty.call(obj, attr)) { copy[attr] = obj[attr]; } } for (var i = 0, l = keys.length; i < l; i++) { if (typeof copy === 'object' && copy !== null && Object.hasOwnProperty.call(copy, keys[i])) { copy = copy[keys[i]]; } else { return; } } return copy; }, /** * Parse rules, normalizing format into: { attribute: [{ name: 'age', value: 3 }] } * * @param {object} rules * @return {object} */ _parseRules: function (rules) { var parsedRules = {}; rules = this._flattenObject(rules); for (var attribute in rules) { var rulesArray = rules[attribute]; this._parseRulesCheck(attribute, rulesArray, parsedRules); } return parsedRules; }, _parseRulesCheck: function (attribute, rulesArray, parsedRules, wildCardValues) { if (attribute.indexOf('*') > -1) { this._parsedRulesRecurse(attribute, rulesArray, parsedRules, wildCardValues); } else { this._parseRulesDefault(attribute, rulesArray, parsedRules, wildCardValues); } }, _parsedRulesRecurse: function (attribute, rulesArray, parsedRules, wildCardValues) { var parentPath = attribute.substr(0, attribute.indexOf('*') - 1); var propertyValue = this._objectPath(this.input, parentPath); if (propertyValue) { for (var propertyNumber = 0; propertyNumber < propertyValue.length; propertyNumber++) { var workingValues = wildCardValues ? wildCardValues.slice() : []; workingValues.push(propertyNumber); this._parseRulesCheck(attribute.replace('*', propertyNumber), rulesArray, parsedRules, workingValues); } } }, _parseRulesDefault: function (attribute, rulesArray, parsedRules, wildCardValues) { var attributeRules = []; if (rulesArray instanceof Array) { rulesArray = this._prepareRulesArray(rulesArray); } if (typeof rulesArray === 'string') { rulesArray = rulesArray.split('|'); } for (var i = 0, len = rulesArray.length, rule; i < len; i++) { rule = typeof rulesArray[i] === 'string' ? this._extractRuleAndRuleValue(rulesArray[i]) : rulesArray[i]; if (rule.value) { rule.value = this._replaceWildCards(rule.value, wildCardValues); this._replaceWildCardsMessages(wildCardValues); } if (Rules.isAsync(rule.name)) { this.hasAsync = true; } attributeRules.push(rule); } parsedRules[attribute] = attributeRules; }, _replaceWildCards: function (path, nums) { if (!nums) { return path; } var path2 = path; nums.forEach(function (value) { if(Array.isArray(path2)){ path2 = path2[0]; } const pos = path2.indexOf('*'); if (pos === -1) { return path2; } path2 = path2.substr(0, pos) + value + path2.substr(pos + 1); }); if(Array.isArray(path)){ path[0] = path2; path2 = path; } return path2; }, _replaceWildCardsMessages: function (nums) { var customMessages = this.messages.customMessages; var self = this; Object.keys(customMessages).forEach(function (key) { if (nums) { var newKey = self._replaceWildCards(key, nums); customMessages[newKey] = customMessages[key]; } }); this.messages._setCustom(customMessages); }, /** * Prepare rules if it comes in Array. Check for objects. Need for type validation. * * @param {array} rulesArray * @return {array} */ _prepareRulesArray: function (rulesArray) { var rules = []; for (var i = 0, len = rulesArray.length; i < len; i++) { if (typeof rulesArray[i] === 'object') { for (var rule in rulesArray[i]) { rules.push({ name: rule, value: rulesArray[i][rule] }); } } else { rules.push(rulesArray[i]); } } return rules; }, /** * Determines if the attribute is supplied with the original data object. * * @param {array} attribute * @return {boolean} */ _suppliedWithData: function (attribute) { return this.input.hasOwnProperty(attribute); }, /** * Extract a rule and a value from a ruleString (i.e. min:3), rule = min, value = 3 * * @param {string} ruleString min:3 * @return {object} object containing the name of the rule and value */ _extractRuleAndRuleValue: function (ruleString) { var rule = {}, ruleArray; rule.name = ruleString; if (ruleString.indexOf(':') >= 0) { ruleArray = ruleString.split(':'); rule.name = ruleArray[0]; rule.value = ruleArray.slice(1).join(':'); } return rule; }, /** * Determine if attribute has any of the given rules * * @param {string} attribute * @param {array} findRules * @return {boolean} */ _hasRule: function (attribute, findRules) { var rules = this.rules[attribute] || []; for (var i = 0, len = rules.length; i < len; i++) { if (findRules.indexOf(rules[i].name) > -1) { return true; } } return false; }, /** * Determine if attribute has any numeric-based rules. * * @param {string} attribute * @return {Boolean} */ _hasNumericRule: function (attribute) { return this._hasRule(attribute, this.numericRules); }, /** * Determine if rule is validatable * * @param {Rule} rule * @param {mixed} value * @return {boolean} */ _isValidatable: function (rule, value) { if (Array.isArray(value)) { return true; } if (Rules.isImplicit(rule.name)) { return true; } return this.getRule('required').validate(value); }, /** * Determine if we should stop validating. * * @param {string} attribute * @param {boolean} rulePassed * @return {boolean} */ _shouldStopValidating: function (attribute, rulePassed) { var stopOnAttributes = this.stopOnAttributes; if (typeof stopOnAttributes === 'undefined' || stopOnAttributes === false || rulePassed === true) { return false; } if (stopOnAttributes instanceof Array) { return stopOnAttributes.indexOf(attribute) > -1; } return true; }, /** * Set custom attribute names. * * @param {object} attributes * @return {void} */ setAttributeNames: function (attributes) { this.messages._setAttributeNames(attributes); }, /** * Set the attribute formatter. * * @param {fuction} func * @return {void} */ setAttributeFormatter: function (func) { this.messages._setAttributeFormatter(func); }, /** * Get validation rule * * @param {string} name * @return {Rule} */ getRule: function (name) { return Rules.make(name, this); }, /** * Stop on first error. * * @param {boolean|array} An array of attributes or boolean true/false for all attributes. * @return {void} */ stopOnError: function (attributes) { this.stopOnAttributes = attributes; }, /** * Determine if validation passes * * @param {function} passes * @return {boolean|undefined} */ passes: function (passes) { var async = this._checkAsync('passes', passes); if (async) { return this.checkAsync(passes); } return this.check(); }, /** * Determine if validation fails * * @param {function} fails * @return {boolean|undefined} */ fails: function (fails) { var async = this._checkAsync('fails', fails); if (async) { return this.checkAsync(function () {}, fails); } return !this.check(); }, /** * Check if validation should be called asynchronously * * @param {string} funcName Name of the caller * @param {function} callback * @return {boolean} */ _checkAsync: function (funcName, callback) { var hasCallback = typeof callback === 'function'; if (this.hasAsync && !