UNPKG

@yolain/validation

Version:

Validation library inspired by Laravel's Validator

1,963 lines (1,666 loc) 64.3 kB
/*! @yolain/validation - v1.0.0 - https://github.com/yolain/validation#readme - 2020-11-06 */ (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){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = getTimezoneOffsetInMilliseconds; var MILLISECONDS_IN_MINUTE = 60000; /** * Google Chrome as of 67.0.3396.87 introduced timezones with offset that includes seconds. * They usually appear for dates that denote time before the timezones were introduced * (e.g. for 'Europe/Prague' timezone the offset is GMT+00:57:44 before 1 October 1891 * and GMT+01:00:00 after that date) * * Date#getTimezoneOffset returns the offset in minutes and would return 57 for the example above, * which would lead to incorrect calculations. * * This function returns the timezone offset in milliseconds that takes seconds in account. */ function getTimezoneOffsetInMilliseconds(dirtyDate) { var date = new Date(dirtyDate.getTime()); var baseTimezoneOffset = date.getTimezoneOffset(); date.setSeconds(0, 0); var millisecondsPartOfTimezoneOffset = date.getTime() % MILLISECONDS_IN_MINUTE; return baseTimezoneOffset * MILLISECONDS_IN_MINUTE + millisecondsPartOfTimezoneOffset; } module.exports = exports.default; },{}],2:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = toInteger; function toInteger(dirtyNumber) { if (dirtyNumber === null || dirtyNumber === true || dirtyNumber === false) { return NaN; } var number = Number(dirtyNumber); if (isNaN(number)) { return number; } return number < 0 ? Math.ceil(number) : Math.floor(number); } module.exports = exports.default; },{}],3:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = isValid; var _index = _interopRequireDefault(require("../toDate/index.js")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * @name isValid * @category Common Helpers * @summary Is the given date valid? * * @description * Returns false if argument is Invalid Date and true otherwise. * Argument is converted to Date using `toDate`. See [toDate]{@link https://date-fns.org/docs/toDate} * Invalid Date is a Date, whose time value is NaN. * * Time value of Date: http://es5.github.io/#x15.9.1.1 * * ### v2.0.0 breaking changes: * * - [Changes that are common for the whole library](https://github.com/date-fns/date-fns/blob/master/docs/upgradeGuide.md#Common-Changes). * * - Now `isValid` doesn't throw an exception * if the first argument is not an instance of Date. * Instead, argument is converted beforehand using `toDate`. * * Examples: * * | `isValid` argument | Before v2.0.0 | v2.0.0 onward | * |---------------------------|---------------|---------------| * | `new Date()` | `true` | `true` | * | `new Date('2016-01-01')` | `true` | `true` | * | `new Date('')` | `false` | `false` | * | `new Date(1488370835081)` | `true` | `true` | * | `new Date(NaN)` | `false` | `false` | * | `'2016-01-01'` | `TypeError` | `true` | * | `''` | `TypeError` | `false` | * | `1488370835081` | `TypeError` | `true` | * | `NaN` | `TypeError` | `false` | * * We introduce this change to make *date-fns* consistent with ECMAScript behavior * that try to coerce arguments to the expected type * (which is also the case with other *date-fns* functions). * * @param {*} date - the date to check * @returns {Boolean} the date is valid * @throws {TypeError} 1 argument required * * @example * // For the valid date: * var result = isValid(new Date(2014, 1, 31)) * //=> true * * @example * // For the value, convertable into a date: * var result = isValid(1393804800000) * //=> true * * @example * // For the invalid date: * var result = isValid(new Date('')) * //=> false */ function isValid(dirtyDate) { if (arguments.length < 1) { throw new TypeError('1 argument required, but only ' + arguments.length + ' present'); } var date = (0, _index.default)(dirtyDate); return !isNaN(date); } module.exports = exports.default; },{"../toDate/index.js":5}],4:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = parseISO; var _index = _interopRequireDefault(require("../_lib/toInteger/index.js")); var _index2 = _interopRequireDefault(require("../_lib/getTimezoneOffsetInMilliseconds/index.js")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var MILLISECONDS_IN_HOUR = 3600000; var MILLISECONDS_IN_MINUTE = 60000; var DEFAULT_ADDITIONAL_DIGITS = 2; var patterns = { dateTimeDelimiter: /[T ]/, timeZoneDelimiter: /[Z ]/i, timezone: /([Z+-].*)$/ }; var dateRegex = /^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/; var timeRegex = /^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/; var timezoneRegex = /^([+-])(\d{2})(?::?(\d{2}))?$/; /** * @name parseISO * @category Common Helpers * @summary Parse ISO string * * @description * Parse the given string in ISO 8601 format and return an instance of Date. * * Function accepts complete ISO 8601 formats as well as partial implementations. * ISO 8601: http://en.wikipedia.org/wiki/ISO_8601 * * If the argument isn't a string, the function cannot parse the string or * the values are invalid, it returns Invalid Date. * * ### v2.0.0 breaking changes: * * - [Changes that are common for the whole library](https://github.com/date-fns/date-fns/blob/master/docs/upgradeGuide.md#Common-Changes). * * - The previous `parse` implementation was renamed to `parseISO`. * * ```javascript * // Before v2.0.0 * parse('2016-01-01') * * // v2.0.0 onward * parseISO('2016-01-01') * ``` * * - `parseISO` now validates separate date and time values in ISO-8601 strings * and returns `Invalid Date` if the date is invalid. * * ```javascript * parseISO('2018-13-32') * //=> Invalid Date * ``` * * - `parseISO` now doesn't fall back to `new Date` constructor * if it fails to parse a string argument. Instead, it returns `Invalid Date`. * * @param {String} argument - the value to convert * @param {Object} [options] - an object with options. * @param {0|1|2} [options.additionalDigits=2] - the additional number of digits in the extended year format * @returns {Date} the parsed date in the local time zone * @throws {TypeError} 1 argument required * @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2 * * @example * // Convert string '2014-02-11T11:30:30' to date: * var result = parseISO('2014-02-11T11:30:30') * //=> Tue Feb 11 2014 11:30:30 * * @example * // Convert string '+02014101' to date, * // if the additional number of digits in the extended year format is 1: * var result = parseISO('+02014101', { additionalDigits: 1 }) * //=> Fri Apr 11 2014 00:00:00 */ function parseISO(argument, dirtyOptions) { if (arguments.length < 1) { throw new TypeError('1 argument required, but only ' + arguments.length + ' present'); } var options = dirtyOptions || {}; var additionalDigits = options.additionalDigits == null ? DEFAULT_ADDITIONAL_DIGITS : (0, _index.default)(options.additionalDigits); if (additionalDigits !== 2 && additionalDigits !== 1 && additionalDigits !== 0) { throw new RangeError('additionalDigits must be 0, 1 or 2'); } if (!(typeof argument === 'string' || Object.prototype.toString.call(argument) === '[object String]')) { return new Date(NaN); } var dateStrings = splitDateString(argument); var date; if (dateStrings.date) { var parseYearResult = parseYear(dateStrings.date, additionalDigits); date = parseDate(parseYearResult.restDateString, parseYearResult.year); } if (isNaN(date) || !date) { return new Date(NaN); } var timestamp = date.getTime(); var time = 0; var offset; if (dateStrings.time) { time = parseTime(dateStrings.time); if (isNaN(time) || time === null) { return new Date(NaN); } } if (dateStrings.timezone) { offset = parseTimezone(dateStrings.timezone); if (isNaN(offset)) { return new Date(NaN); } } else { var fullTime = timestamp + time; var fullTimeDate = new Date(fullTime); offset = (0, _index2.default)(fullTimeDate); // Adjust time when it's coming from DST var fullTimeDateNextDay = new Date(fullTime); fullTimeDateNextDay.setDate(fullTimeDate.getDate() + 1); var offsetDiff = (0, _index2.default)(fullTimeDateNextDay) - offset; if (offsetDiff > 0) { offset += offsetDiff; } } return new Date(timestamp + time + offset); } function splitDateString(dateString) { var dateStrings = {}; var array = dateString.split(patterns.dateTimeDelimiter); var timeString; if (/:/.test(array[0])) { dateStrings.date = null; timeString = array[0]; } else { dateStrings.date = array[0]; timeString = array[1]; if (patterns.timeZoneDelimiter.test(dateStrings.date)) { dateStrings.date = dateString.split(patterns.timeZoneDelimiter)[0]; timeString = dateString.substr(dateStrings.date.length, dateString.length); } } if (timeString) { var token = patterns.timezone.exec(timeString); if (token) { dateStrings.time = timeString.replace(token[1], ''); dateStrings.timezone = token[1]; } else { dateStrings.time = timeString; } } return dateStrings; } function parseYear(dateString, additionalDigits) { var regex = new RegExp('^(?:(\\d{4}|[+-]\\d{' + (4 + additionalDigits) + '})|(\\d{2}|[+-]\\d{' + (2 + additionalDigits) + '})$)'); var captures = dateString.match(regex); // Invalid ISO-formatted year if (!captures) return { year: null }; var year = captures[1] && parseInt(captures[1]); var century = captures[2] && parseInt(captures[2]); return { year: century == null ? year : century * 100, restDateString: dateString.slice((captures[1] || captures[2]).length) }; } function parseDate(dateString, year) { // Invalid ISO-formatted year if (year === null) return null; var captures = dateString.match(dateRegex); // Invalid ISO-formatted string if (!captures) return null; var isWeekDate = !!captures[4]; var dayOfYear = parseDateUnit(captures[1]); var month = parseDateUnit(captures[2]) - 1; var day = parseDateUnit(captures[3]); var week = parseDateUnit(captures[4]); var dayOfWeek = parseDateUnit(captures[5]) - 1; if (isWeekDate) { if (!validateWeekDate(year, week, dayOfWeek)) { return new Date(NaN); } return dayOfISOWeekYear(year, week, dayOfWeek); } else { var date = new Date(0); if (!validateDate(year, month, day) || !validateDayOfYearDate(year, dayOfYear)) { return new Date(NaN); } date.setUTCFullYear(year, month, Math.max(dayOfYear, day)); return date; } } function parseDateUnit(value) { return value ? parseInt(value) : 1; } function parseTime(timeString) { var captures = timeString.match(timeRegex); if (!captures) return null; // Invalid ISO-formatted time var hours = parseTimeUnit(captures[1]); var minutes = parseTimeUnit(captures[2]); var seconds = parseTimeUnit(captures[3]); if (!validateTime(hours, minutes, seconds)) { return NaN; } return hours * MILLISECONDS_IN_HOUR + minutes * MILLISECONDS_IN_MINUTE + seconds * 1000; } function parseTimeUnit(value) { return value && parseFloat(value.replace(',', '.')) || 0; } function parseTimezone(timezoneString) { if (timezoneString === 'Z') return 0; var captures = timezoneString.match(timezoneRegex); if (!captures) return 0; var sign = captures[1] === '+' ? -1 : 1; var hours = parseInt(captures[2]); var minutes = captures[3] && parseInt(captures[3]) || 0; if (!validateTimezone(hours, minutes)) { return NaN; } return sign * (hours * MILLISECONDS_IN_HOUR + minutes * MILLISECONDS_IN_MINUTE); } function dayOfISOWeekYear(isoWeekYear, week, day) { var date = new Date(0); date.setUTCFullYear(isoWeekYear, 0, 4); var fourthOfJanuaryDay = date.getUTCDay() || 7; var diff = (week - 1) * 7 + day + 1 - fourthOfJanuaryDay; date.setUTCDate(date.getUTCDate() + diff); return date; } // Validation functions // February is null to handle the leap year (using ||) var daysInMonths = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; function isLeapYearIndex(year) { return year % 400 === 0 || year % 4 === 0 && year % 100; } function validateDate(year, month, date) { return month >= 0 && month <= 11 && date >= 1 && date <= (daysInMonths[month] || (isLeapYearIndex(year) ? 29 : 28)); } function validateDayOfYearDate(year, dayOfYear) { return dayOfYear >= 1 && dayOfYear <= (isLeapYearIndex(year) ? 366 : 365); } function validateWeekDate(_year, week, day) { return week >= 1 && week <= 53 && day >= 0 && day <= 6; } function validateTime(hours, minutes, seconds) { if (hours === 24) { return minutes === 0 && seconds === 0; } return seconds >= 0 && seconds < 60 && minutes >= 0 && minutes < 60 && hours >= 0 && hours < 25; } function validateTimezone(_hours, minutes) { return minutes >= 0 && minutes <= 59; } module.exports = exports.default; },{"../_lib/getTimezoneOffsetInMilliseconds/index.js":1,"../_lib/toInteger/index.js":2}],5:[function(require,module,exports){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = toDate; /** * @name toDate * @category Common Helpers * @summary Convert the given argument to an instance of Date. * * @description * Convert the given argument to an instance of Date. * * If the argument is an instance of Date, the function returns its clone. * * If the argument is a number, it is treated as a timestamp. * * If the argument is none of the above, the function returns Invalid Date. * * **Note**: *all* Date arguments passed to any *date-fns* function is processed by `toDate`. * * @param {Date|Number} argument - the value to convert * @returns {Date} the parsed date in the local time zone * @throws {TypeError} 1 argument required * * @example * // Clone the date: * const result = toDate(new Date(2014, 1, 11, 11, 30, 30)) * //=> Tue Feb 11 2014 11:30:30 * * @example * // Convert the timestamp to date: * const result = toDate(1392098430000) * //=> Tue Feb 11 2014 11:30:30 */ function toDate(argument) { if (arguments.length < 1) { throw new TypeError('1 argument required, but only ' + arguments.length + ' present'); } var argStr = Object.prototype.toString.call(argument); // Clone the date if (argument instanceof Date || typeof argument === 'object' && argStr === '[object Date]') { // Prevent the date to lose the milliseconds when passed to new Date() in IE10 return new Date(argument.getTime()); } else if (typeof argument === 'number' || argStr === '[object Number]') { return new Date(argument); } else { if ((typeof argument === 'string' || argStr === '[object String]') && typeof console !== 'undefined') { // eslint-disable-next-line no-console console.warn("Starting with v2.0.0-beta.1 date-fns doesn't accept strings as arguments. Please use `parseISO` to parse strings. See: https://git.io/fjule"); // eslint-disable-next-line no-console console.warn(new Error().stack); } return new Date(NaN); } } module.exports = exports.default; },{}],6:[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; },{}],7:[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 }; },{}],8:[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]; } // New Add+ else if(!this.isEmpty()){ let key = Object.keys(this.errors)[0]; return this.errors[key][0]; }else{ return false; } // return false; }, /** * Get all error messages from all failing attributes * * @param {Boolean} full * @return {Object} Failed attribute names for keys and an array of messages for values */ all: function(full=false) { // New Add+ if(full && !this.isEmpty()){ let values = Object.values(this.errors); return values.flat(); }else{ 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; }, /** * isEmpty * @return {Boolean} */ isEmpty(){ return Object.keys(this.errors).length==0; } }; module.exports = Errors; },{}],9:[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":10,"./messages":11}],10:[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: 'The :attribute field must be between :min and :max.', 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: {} }; },{}],11:[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]; // New Add+ for (var i = 0, format; i < formats.length; i++) { format = formats[i]; if (customMessages && customMessages[rule.attribute]) { var attribute = customMessages[rule.attribute]; if (typeof attribute == 'string') { rule.attribute = attribute; template = messages[format]; } else if (typeof attribute == 'object' && attribute.hasOwnProperty(rule.name)) { template = attribute[rule.name]; } else if (typeof attribute == 'object' && attribute.hasOwnProperty('text')) { rule.attribute = attribute['text']; template = messages[format]; } } else 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":7}],12:[function(require,module,exports){ var isDateValid = require('date-fns/isValid'); var parseISO = require('date-fns/parseISO'); function leapYear(year) { return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; } function isValidDate(inDate) { if (inDate instanceof Date) { return !isNaN(inDate); } // reformat if supplied as mm.dd.yyyy (period delimiter) if (typeof inDate === 'string') { var pos = inDate.indexOf('.'); if (pos > 0 && pos <= 6) { inDate = inDate.replace(/\./g, '-'); } if (inDate.length === 10) { return isDateValid(parseISO(inDate)); } } var testDate = new Date(inDate); var yr = testDate.getFullYear(); var mo = testDate.getMonth(); var day = testDate.getDate(); var daysInMonth = [31, leapYear(yr) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; if (yr < 1000) { return false; } if (isNaN(mo)) { return false; } if (mo + 1 > 12) { return false; } if (isNaN(day)) { return false; } if (day > daysInMonth[mo]) { return false; } return true; } 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) { 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,}))$/; 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).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) { 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); } }; 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; },{"date-fns/isValid":3,"date-fns/parseISO":4}],13:[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._isValid