@yolain/validation
Version:
Validation library inspired by Laravel's Validator
1,963 lines (1,666 loc) • 64.3 kB
JavaScript
/*! @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