diff --git a/README.md b/README.md
index 1a7ba45..31c6ea1 100755
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-
+
diff --git a/dist/iodine.min.js b/dist/iodine.min.js
index f552b5e..a99af4a 100644
--- a/dist/iodine.min.js
+++ b/dist/iodine.min.js
@@ -1,2 +1,2 @@
-var t=function(){this.messages=this._defaultMessages()};t.prototype._dateCompare=function(t,e,r,i){return void 0===i&&(i=!1),!!this.isDate(t)&&!(!this.isDate(e)&&!this.isInteger(e))&&(e="number"==typeof e?e:e.getTime(),"less"===r&&i?t.getTime()<=e:"less"!==r||i?"more"===r&&i?t.getTime()>=e:"more"!==r||i?void 0:t.getTime()>e:t.getTime()=e},t.prototype.isNotIn=function(t,e){return!this.isIn(t,e)},t.prototype.isNumeric=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},t.prototype.isOptional=function(t){return[null,void 0,""].includes(t)},t.prototype.isRegexMatch=function(t,e){return new RegExp(e).test(String(t).toLowerCase())},t.prototype.isRequired=function(t){return!this.isOptional(t)},t.prototype.isSame=function(t,e){return t==e},t.prototype.isStartingWith=function(t,e){return this.isString(t)&&t.startsWith(e)},t.prototype.isString=function(t){return"string"==typeof t},t.prototype.isTruthy=function(t){return[1,"1",!0,"true"].includes(t)},t.prototype.isUrl=function(t){return new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$").test(String(t).toLowerCase())},t.prototype.isUuid=function(t){return new RegExp("^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$").test(String(t).toLowerCase())},t.prototype.is=function(t,e){if(void 0===e&&(e=[]),0===e.length)return!0;if("optional"===e[0]&&this.isOptional(t))return!0;for(var r=0;r=e:"more"!==r||i?void 0:t.getTime()>e:t.getTime()=e},t.prototype.isNotIn=function(t,e){return!this.isIn(t,e)},t.prototype.isNumeric=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},t.prototype.isOptional=function(t){return[null,void 0,""].includes(t)},t.prototype.isRegexMatch=function(t,e){return new RegExp(e).test(String(t).toLowerCase())},t.prototype.isRequired=function(t){return!this.isOptional(t)},t.prototype.isSame=function(t,e){return t==e},t.prototype.isStartingWith=function(t,e){return this.isString(t)&&t.startsWith(e)},t.prototype.isString=function(t){return"string"==typeof t},t.prototype.isTruthy=function(t){return[1,"1",!0,"true"].includes(t)},t.prototype.isUrl=function(t){return new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$").test(String(t).toLowerCase())},t.prototype.isUuid=function(t){return new RegExp("^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$").test(String(t).toLowerCase())},t.prototype.is=function(t,e){if(void 0===e&&(e=[]),!e.length)return!0;if("optional"===e[0]&&this.isOptional(t))return!0;for(var r in e)if("optional"!==e[r]&&!this["is"+(e[r].split(":")[0][0].toUpperCase()+e[r].split(":")[0].slice(1))].apply(this,[t,e[r].split(":")[1]]))return e[r];return!0},t.prototype.setErrorMessages=function(t){this.messages=t},window.Iodine=new t;
//# sourceMappingURL=iodine.min.js.map
diff --git a/dist/iodine.min.js.map b/dist/iodine.min.js.map
index 41ab8ff..132917b 100644
--- a/dist/iodine.min.js.map
+++ b/dist/iodine.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"iodine.min.js","sources":["../src/iodine.js"],"sourcesContent":["/*\n|--------------------------------------------------------------------------\n| Iodine - JavaScript Library\n|--------------------------------------------------------------------------\n|\n| This library contains a collection of useful validation rules that can\n| be used to quickly verify whether items meet certain conditions.\n|\n*/\nexport default class Iodine\n{\n\n\t/**\n\t * Constructor.\n\t *\n\t **/\n\tconstructor()\n\t{\n\t\tthis.messages = this._defaultMessages();\n\t}\n\n\n\n\t/**\n\t * @internal.\n\t *\n\t **/\n\t_dateCompare(first, second, type, equals = false)\n\t{\n\t\tif (! this.isDate(first)) return false;\n\n\t\tif (! this.isDate(second) && ! this.isInteger(second)) return false;\n\n\t\tsecond = typeof second === 'number' ? second : second.getTime();\n\n\t\tif (type === 'less' && equals) return first.getTime() <= second;\n\t\tif (type === 'less' && ! equals) return first.getTime() < second;\n\t\tif (type === 'more' && equals) return first.getTime() >= second;\n\t\tif (type === 'more' && ! equals) return first.getTime() > second;\n\t}\n\n\n\n\t/**\n\t * @internal.\n\t *\n\t **/\n\t_defaultMessages()\n\t{\n\t\treturn {\n\t\t\tafter : `The date must be after: '[PARAM]'`,\n\t\t\tafterOrEqual : `The date must be after or equal to: '[PARAM]'`,\n\t\t\tarray : `Value must be an array`,\n\t\t\tbefore : `The date must be before: '[PARAM]'`,\n\t\t\tbeforeOrEqual : `The date must be before or equal to: '[PARAM]'`,\n\t\t\tboolean : `Value must be true or false`,\n\t\t\tdate : `Value must be a date`,\n\t\t\tdifferent : `Value must be different to '[PARAM]'`,\n\t\t\tendingWith : `Value must end with '[PARAM]'`,\n\t\t\temail : `Value must be a valid email address`,\n\t\t\tfalsy : `Value must be a falsy value (false, 'false', 0 or '0')`,\n\t\t\tin \t\t : `Value must be one of the following options: [PARAM]`,\n\t\t\tinteger : `Value must be an integer`,\n\t\t\tjson : `Value must be a parsable JSON object string`,\n\t\t\tmaximum : `Value must not be greater than '[PARAM]' in size or character length`,\n\t\t\tminimum : `Value must not be less than '[PARAM]' in size or character length`,\n\t\t\tnotIn : `Value must not be one of the following options: [PARAM]`,\n\t\t\tnumeric : `Value must be numeric`,\n\t\t\toptional : `Value is optional`,\n\t\t\tregexMatch : `Value must satisify the regular expression: [PARAM]`,\n\t\t\trequired : `Value must be present`,\n\t\t\tsame : `Value must be '[PARAM]'`,\n\t\t\tstartingWith : `Value must start with '[PARAM]'`,\n\t\t\tstring : `Value must be a string`,\n\t\t\ttruthy : `Value must be a truthy value (true, 'true', 1 or '1')`,\n\t\t\turl : `Value must be a valid url`,\n\t\t\tuuid : `Value must be a valid UUID`,\n\t\t};\n\t}\n\n\n\n\t/**\n\t * Attach a custom validation rule to the library.\n\t *\n\t **/\n\taddRule(name, closure)\n\t{\n\t\tIodine.prototype[`is${name[0].toUpperCase()}${name.slice(1)}`] = closure;\n\t}\n\n\n\n\t/**\n\t * Retrieve an error message for the given rule.\n\t *\n\t **/\n\tgetErrorMessage(rule, arg = undefined)\n\t{\n\t\tlet key = rule.split(':')[0];\n\t\tlet param = arg || rule.split(':')[1];\n\n\t\tif (['after', 'afterOrEqual', 'before', 'beforeOrEqual'].includes(key)) {\n\t\t\tparam = new Date(parseInt(param)).toLocaleTimeString(undefined, {\n\t\t\t\tyear: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: 'numeric'\n\t\t\t});\n\t\t}\n\n\t\treturn [null, undefined].includes(param)\n\t\t\t ? this.messages[key]\n\t\t\t : this.messages[key].replace(\"[PARAM]\", param);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is after another given date.\n\t *\n\t **/\n\tisAfter(value, after)\n\t{\n\t\treturn this._dateCompare(value, after, 'more', false);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is after or equal to another given date.\n\t *\n\t **/\n\tisAfterOrEqual(value, after)\n\t{\n\t\treturn this._dateCompare(value, after, 'more', true);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is an array.\n\t *\n\t **/\n\tisArray(value)\n\t{\n\t\treturn Array.isArray(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is before another given date.\n\t *\n\t **/\n\tisBefore(value, before)\n\t{\n\t\treturn this._dateCompare(value, before, 'less', false);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is before or equal to another given date.\n\t *\n\t **/\n\tisBeforeOrEqual(value, before)\n\t{\n\t\treturn this._dateCompare(value, before, 'less', true);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a boolean.\n\t *\n\t **/\n\tisBoolean(value)\n\t{\n\t\treturn [true, false].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a date object.\n\t *\n\t **/\n\tisDate(value)\n\t{\n\t\treturn value && Object.prototype.toString.call(value) === '[object Date]' && ! isNaN(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is different to another given value.\n\t *\n\t **/\n\tisDifferent(value, different)\n\t{\n\t\treturn value != different;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value ends with another given value.\n\t *\n\t **/\n\tisEndingWith(value, sub)\n\t{\n\t\treturn this.isString(value) && value.endsWith(sub);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid email address.\n\t *\n\t **/\n\tisEmail(value)\n\t{\n\t\treturn new RegExp('^\\\\S+@\\\\S+[\\\\.][0-9a-z]+$').test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is falsy.\n\t *\n\t **/\n\tisFalsy(value)\n\t{\n\t\treturn [0, '0', false, 'false'].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is within the given array of options.\n\t *\n\t **/\n\tisIn(value, options)\n\t{\n\t\toptions = typeof options === 'string'\n\t\t\t\t? options.split(\",\")\n\t\t\t\t: options;\n\n\t\treturn options.includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is an integer.\n\t *\n\t **/\n\tisInteger(value)\n\t{\n\t\treturn Number.isInteger(value) && parseInt(value).toString() === value.toString();\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a JSON string.\n\t *\n\t **/\n\tisJson(value)\n\t{\n\t\ttry {\n \treturn typeof JSON.parse(value) === 'object';\n\t\t} catch (e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\n\n\t/**\n\t * Determine if the given value meets the given maximum limit.\n\t *\n\t **/\n\tisMaximum(value, limit)\n\t{\n\t\tvalue = typeof value === 'string' ? value.length : value;\n\n\t\treturn parseFloat(value) <= limit;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value meets the given minimum limit.\n\t *\n\t **/\n\tisMinimum(value, limit)\n\t{\n\t\tvalue = typeof value === 'string' ? value.length : value;\n\n\t\treturn parseFloat(value) >= limit;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is not within the given array of options.\n\t *\n\t **/\n\tisNotIn(value, options)\n\t{\n\t\treturn ! this.isIn(value, options);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is numeric (an integer or a float).\n\t *\n\t **/\n\tisNumeric(value)\n\t{\n\t\treturn ! isNaN(parseFloat(value)) && isFinite(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is optional.\n\t *\n\t **/\n\tisOptional(value)\n\t{\n\t\treturn [null, undefined, ''].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value satisifies the given regular expression.\n\t *\n\t **/\n\tisRegexMatch(value, expression)\n\t{\n\t\treturn new RegExp(expression).test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is present.\n\t *\n\t **/\n\tisRequired(value)\n\t{\n\t\treturn ! this.isOptional(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is the same as another given value.\n\t *\n\t **/\n\tisSame(value, same)\n\t{\n\t\treturn value == same;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value starts with another given value.\n\t *\n\t **/\n\tisStartingWith(value, sub)\n\t{\n\t\treturn this.isString(value) && value.startsWith(sub);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a string.\n\t *\n\t **/\n\tisString(value)\n\t{\n\t\treturn typeof value === 'string';\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is truthy.\n\t *\n\t **/\n\tisTruthy(value)\n\t{\n\t\treturn [1, '1', true, 'true'].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid URL.\n\t *\n\t **/\n\tisUrl(value)\n\t{\n\t\treturn new RegExp('^(https?:\\\\/\\\\/)?((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.)+[a-z]{2,}|((\\\\d{1,3}\\\\.){3}\\\\d{1,3}))(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*(\\\\?[;&a-z\\\\d%_.~+=-]*)?(\\\\#[-a-z\\\\d_]*)?$')\n\t\t\t .test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid UUID.\n\t *\n\t **/\n\tisUuid(value)\n\t{\n\t\treturn new RegExp('^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$')\n\t\t\t .test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine whether the given value meets the given rules.\n\t *\n\t **/\n\tis(value, rules = [])\n\t{\n\t\t// Check if no rules were specified\n\t\tif (rules.length === 0) return true;\n\n\t\t// Check for an optional value\n\t\tif (rules[0] === 'optional' && this.isOptional(value)) return true;\n\n\t\t// Iterate through the rules\n\t\tfor (let index = 0; index < rules.length; index++) {\n\n\t\t\t// Ignore optional rules\n\t\t\tif (rules[index] === 'optional') continue;\n\n\t\t\t// Determine the method to use\n\t\t\tlet rule = rules[index].split(':')[0][0].toUpperCase()\n\t\t\t\t\t + rules[index].split(':')[0].slice(1);\n\n\t\t\t// Validate the value against the method\n\t\t\tlet result = this[`is${rule}`].apply(this, [value, rules[index].split(':')[1]]);\n\n\t\t\t// Check if the value failed validation\n\t\t\tif (! result) return rules[index];\n\n\t\t}\n\n\t\t// Otherwise, the value is valid\n\t\treturn true;\n\t}\n\n\n\n\t/**\n\t * Replace the default error messages with a new set.\n\t *\n\t **/\n\tsetErrorMessages(messages)\n\t{\n\t\tthis.messages = messages;\n\t}\n\n}\n\n\n\n/**\n * Create an instance of the library.\n *\n **/\nwindow.Iodine = new Iodine();"],"names":["Iodine","constructor","messages","this","_defaultMessages","_dateCompare","first","second","type","equals","isDate","isInteger","getTime","after","afterOrEqual","array","before","beforeOrEqual","boolean","date","different","endingWith","email","falsy","in","integer","json","maximum","minimum","notIn","numeric","optional","regexMatch","required","same","startingWith","string","truthy","url","uuid","addRule","name","closure","prototype","toUpperCase","slice","getErrorMessage","rule","arg","undefined","key","split","param","includes","Date","parseInt","toLocaleTimeString","year","month","day","hour","minute","replace","isAfter","value","isAfterOrEqual","isArray","Array","isBefore","isBeforeOrEqual","isBoolean","Object","toString","call","isNaN","isDifferent","isEndingWith","sub","isString","endsWith","isEmail","RegExp","test","String","toLowerCase","isFalsy","isIn","options","Number","isJson","JSON","parse","e","isMaximum","limit","length","parseFloat","isMinimum","isNotIn","isNumeric","isFinite","isOptional","isRegexMatch","expression","isRequired","isSame","isStartingWith","startsWith","isTruthy","isUrl","isUuid","is","rules","let","index","apply","setErrorMessages","window"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"iodine.min.js","sources":["../src/iodine.js"],"sourcesContent":["/*\n|--------------------------------------------------------------------------\n| Iodine - JavaScript Library\n|--------------------------------------------------------------------------\n|\n| This library contains a collection of useful validation rules that can\n| be used to quickly verify whether items meet certain conditions.\n|\n*/\nclass Iodine\n{\n\n\t/**\n\t * Constructor.\n\t *\n\t **/\n\tconstructor()\n\t{\n\t\tthis.messages = this._defaultMessages();\n\t}\n\n\n\n\t/**\n\t * @internal.\n\t *\n\t **/\n\t_dateCompare(first, second, type, equals = false)\n\t{\n\t\tif (! this.isDate(first)) return false;\n\n\t\tif (! this.isDate(second) && ! this.isInteger(second)) return false;\n\n\t\tsecond = typeof second === 'number' ? second : second.getTime();\n\n\t\tif (type === 'less' && equals) return first.getTime() <= second;\n\t\tif (type === 'less' && ! equals) return first.getTime() < second;\n\t\tif (type === 'more' && equals) return first.getTime() >= second;\n\t\tif (type === 'more' && ! equals) return first.getTime() > second;\n\t}\n\n\n\n\t/**\n\t * @internal.\n\t *\n\t **/\n\t_defaultMessages()\n\t{\n\t\treturn {\n\t\t\tafter : `The date must be after: '[PARAM]'`,\n\t\t\tafterOrEqual : `The date must be after or equal to: '[PARAM]'`,\n\t\t\tarray : `Value must be an array`,\n\t\t\tbefore : `The date must be before: '[PARAM]'`,\n\t\t\tbeforeOrEqual : `The date must be before or equal to: '[PARAM]'`,\n\t\t\tboolean : `Value must be true or false`,\n\t\t\tdate : `Value must be a date`,\n\t\t\tdifferent : `Value must be different to '[PARAM]'`,\n\t\t\tendingWith : `Value must end with '[PARAM]'`,\n\t\t\temail : `Value must be a valid email address`,\n\t\t\tfalsy : `Value must be a falsy value (false, 'false', 0 or '0')`,\n\t\t\tin \t\t : `Value must be one of the following options: [PARAM]`,\n\t\t\tinteger : `Value must be an integer`,\n\t\t\tjson : `Value must be a parsable JSON object string`,\n\t\t\tmaximum : `Value must not be greater than '[PARAM]' in size or character length`,\n\t\t\tminimum : `Value must not be less than '[PARAM]' in size or character length`,\n\t\t\tnotIn : `Value must not be one of the following options: [PARAM]`,\n\t\t\tnumeric : `Value must be numeric`,\n\t\t\toptional : `Value is optional`,\n\t\t\tregexMatch : `Value must satisify the regular expression: [PARAM]`,\n\t\t\trequired : `Value must be present`,\n\t\t\tsame : `Value must be '[PARAM]'`,\n\t\t\tstartingWith : `Value must start with '[PARAM]'`,\n\t\t\tstring : `Value must be a string`,\n\t\t\ttruthy : `Value must be a truthy value (true, 'true', 1 or '1')`,\n\t\t\turl : `Value must be a valid url`,\n\t\t\tuuid : `Value must be a valid UUID`,\n\t\t};\n\t}\n\n\n\n\t/**\n\t * Attach a custom validation rule to the library.\n\t *\n\t **/\n\taddRule(name, closure)\n\t{\n\t\tIodine.prototype[`is${name[0].toUpperCase()}${name.slice(1)}`] = closure;\n\t}\n\n\n\n\t/**\n\t * Retrieve an error message for the given rule.\n\t *\n\t **/\n\tgetErrorMessage(rule, arg = undefined)\n\t{\n\t\tlet key = rule.split(':')[0];\n\t\tlet param = arg || rule.split(':')[1];\n\n\t\tif (['after', 'afterOrEqual', 'before', 'beforeOrEqual'].includes(key)) {\n\t\t\tparam = new Date(parseInt(param)).toLocaleTimeString(undefined, {\n\t\t\t\tyear: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: 'numeric'\n\t\t\t});\n\t\t}\n\n\t\treturn [null, undefined].includes(param)\n\t\t\t ? this.messages[key]\n\t\t\t : this.messages[key].replace(\"[PARAM]\", param);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is after another given date.\n\t *\n\t **/\n\tisAfter(value, after)\n\t{\n\t\treturn this._dateCompare(value, after, 'more', false);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is after or equal to another given date.\n\t *\n\t **/\n\tisAfterOrEqual(value, after)\n\t{\n\t\treturn this._dateCompare(value, after, 'more', true);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is an array.\n\t *\n\t **/\n\tisArray(value)\n\t{\n\t\treturn Array.isArray(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is before another given date.\n\t *\n\t **/\n\tisBefore(value, before)\n\t{\n\t\treturn this._dateCompare(value, before, 'less', false);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is before or equal to another given date.\n\t *\n\t **/\n\tisBeforeOrEqual(value, before)\n\t{\n\t\treturn this._dateCompare(value, before, 'less', true);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a boolean.\n\t *\n\t **/\n\tisBoolean(value)\n\t{\n\t\treturn [true, false].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a date object.\n\t *\n\t **/\n\tisDate(value)\n\t{\n\t\treturn value && Object.prototype.toString.call(value) === '[object Date]' && ! isNaN(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is different to another given value.\n\t *\n\t **/\n\tisDifferent(value, different)\n\t{\n\t\treturn value != different;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value ends with another given value.\n\t *\n\t **/\n\tisEndingWith(value, sub)\n\t{\n\t\treturn this.isString(value) && value.endsWith(sub);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid email address.\n\t *\n\t **/\n\tisEmail(value)\n\t{\n\t\treturn new RegExp('^\\\\S+@\\\\S+[\\\\.][0-9a-z]+$').test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is falsy.\n\t *\n\t **/\n\tisFalsy(value)\n\t{\n\t\treturn [0, '0', false, 'false'].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is within the given array of options.\n\t *\n\t **/\n\tisIn(value, options)\n\t{\n\t\toptions = typeof options === 'string'\n\t\t\t\t? options.split(\",\")\n\t\t\t\t: options;\n\n\t\treturn options.includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is an integer.\n\t *\n\t **/\n\tisInteger(value)\n\t{\n\t\treturn Number.isInteger(value) && parseInt(value).toString() === value.toString();\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a JSON string.\n\t *\n\t **/\n\tisJson(value)\n\t{\n\t\ttry {\n \treturn typeof JSON.parse(value) === 'object';\n\t\t} catch (e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\n\n\t/**\n\t * Determine if the given value meets the given maximum limit.\n\t *\n\t **/\n\tisMaximum(value, limit)\n\t{\n\t\tvalue = typeof value === 'string' ? value.length : value;\n\n\t\treturn parseFloat(value) <= limit;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value meets the given minimum limit.\n\t *\n\t **/\n\tisMinimum(value, limit)\n\t{\n\t\tvalue = typeof value === 'string' ? value.length : value;\n\n\t\treturn parseFloat(value) >= limit;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is not within the given array of options.\n\t *\n\t **/\n\tisNotIn(value, options)\n\t{\n\t\treturn ! this.isIn(value, options);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is numeric (an integer or a float).\n\t *\n\t **/\n\tisNumeric(value)\n\t{\n\t\treturn ! isNaN(parseFloat(value)) && isFinite(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is optional.\n\t *\n\t **/\n\tisOptional(value)\n\t{\n\t\treturn [null, undefined, ''].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value satisifies the given regular expression.\n\t *\n\t **/\n\tisRegexMatch(value, expression)\n\t{\n\t\treturn new RegExp(expression).test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is present.\n\t *\n\t **/\n\tisRequired(value)\n\t{\n\t\treturn ! this.isOptional(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is the same as another given value.\n\t *\n\t **/\n\tisSame(value, same)\n\t{\n\t\treturn value == same;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value starts with another given value.\n\t *\n\t **/\n\tisStartingWith(value, sub)\n\t{\n\t\treturn this.isString(value) && value.startsWith(sub);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a string.\n\t *\n\t **/\n\tisString(value)\n\t{\n\t\treturn typeof value === 'string';\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is truthy.\n\t *\n\t **/\n\tisTruthy(value)\n\t{\n\t\treturn [1, '1', true, 'true'].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid URL.\n\t *\n\t **/\n\tisUrl(value)\n\t{\n\t\treturn new RegExp('^(https?:\\\\/\\\\/)?((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.)+[a-z]{2,}|((\\\\d{1,3}\\\\.){3}\\\\d{1,3}))(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*(\\\\?[;&a-z\\\\d%_.~+=-]*)?(\\\\#[-a-z\\\\d_]*)?$')\n\t\t\t .test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid UUID.\n\t *\n\t **/\n\tisUuid(value)\n\t{\n\t\treturn new RegExp('^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$')\n\t\t\t .test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine whether the given value meets the given rules.\n\t *\n\t **/\n\tis(value, rules = [])\n\t{\n\t\t// Check if no rules were specified\n\t\tif (! rules.length) return true;\n\n\t\t// Check for an optional value\n\t\tif (rules[0] === 'optional' && this.isOptional(value)) return true;\n\n\t\t// Iterate through the rules\n\t\tfor (let index in rules) {\n\n\t\t\t// Ignore optional rules\n\t\t\tif (rules[index] === 'optional') continue;\n\n\t\t\t// Determine the method to use\n\t\t\tlet rule = rules[index].split(':')[0][0].toUpperCase()\n\t\t\t\t\t + rules[index].split(':')[0].slice(1);\n\n\t\t\t// Validate the value against the method\n\t\t\tlet result = this[`is${rule}`].apply(this, [value, rules[index].split(':')[1]]);\n\n\t\t\t// Check if the value failed validation\n\t\t\tif (! result) return rules[index];\n\n\t\t}\n\n\t\t// Otherwise, the value is valid\n\t\treturn true;\n\t}\n\n\n\n\t/**\n\t * Replace the default error messages with a new set.\n\t *\n\t **/\n\tsetErrorMessages(messages)\n\t{\n\t\tthis.messages = messages;\n\t}\n\n}\n\n\n\n/**\n * Create an instance of the library.\n *\n **/\nwindow.Iodine = new Iodine();\n"],"names":["Iodine","constructor","messages","this","_defaultMessages","_dateCompare","first","second","type","equals","isDate","isInteger","getTime","after","afterOrEqual","array","before","beforeOrEqual","boolean","date","different","endingWith","email","falsy","in","integer","json","maximum","minimum","notIn","numeric","optional","regexMatch","required","same","startingWith","string","truthy","url","uuid","addRule","name","closure","prototype","toUpperCase","slice","getErrorMessage","rule","arg","undefined","key","split","param","includes","Date","parseInt","toLocaleTimeString","year","month","day","hour","minute","replace","isAfter","value","isAfterOrEqual","isArray","Array","isBefore","isBeforeOrEqual","isBoolean","Object","toString","call","isNaN","isDifferent","isEndingWith","sub","isString","endsWith","isEmail","RegExp","test","String","toLowerCase","isFalsy","isIn","options","Number","isJson","JSON","parse","e","isMaximum","limit","length","parseFloat","isMinimum","isNotIn","isNumeric","isFinite","isOptional","isRegexMatch","expression","isRequired","isSame","isStartingWith","startsWith","isTruthy","isUrl","isUuid","is","rules","let","index","apply","setErrorMessages","window"],"mappings":"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"}
\ No newline at end of file
diff --git a/dist/iodine.min.mjs b/dist/iodine.min.mjs
index e38dc8c..64bdc4a 100644
--- a/dist/iodine.min.mjs
+++ b/dist/iodine.min.mjs
@@ -1,2 +1,2 @@
-var t=function(){this.messages=this._defaultMessages()};t.prototype._dateCompare=function(t,e,r,i){return void 0===i&&(i=!1),!!this.isDate(t)&&!(!this.isDate(e)&&!this.isInteger(e))&&(e="number"==typeof e?e:e.getTime(),"less"===r&&i?t.getTime()<=e:"less"!==r||i?"more"===r&&i?t.getTime()>=e:"more"!==r||i?void 0:t.getTime()>e:t.getTime()=e},t.prototype.isNotIn=function(t,e){return!this.isIn(t,e)},t.prototype.isNumeric=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},t.prototype.isOptional=function(t){return[null,void 0,""].includes(t)},t.prototype.isRegexMatch=function(t,e){return new RegExp(e).test(String(t).toLowerCase())},t.prototype.isRequired=function(t){return!this.isOptional(t)},t.prototype.isSame=function(t,e){return t==e},t.prototype.isStartingWith=function(t,e){return this.isString(t)&&t.startsWith(e)},t.prototype.isString=function(t){return"string"==typeof t},t.prototype.isTruthy=function(t){return[1,"1",!0,"true"].includes(t)},t.prototype.isUrl=function(t){return new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$").test(String(t).toLowerCase())},t.prototype.isUuid=function(t){return new RegExp("^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$").test(String(t).toLowerCase())},t.prototype.is=function(t,e){if(void 0===e&&(e=[]),0===e.length)return!0;if("optional"===e[0]&&this.isOptional(t))return!0;for(var r=0;r=e:"more"!==r||i?void 0:t.getTime()>e:t.getTime()=e},t.prototype.isNotIn=function(t,e){return!this.isIn(t,e)},t.prototype.isNumeric=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},t.prototype.isOptional=function(t){return[null,void 0,""].includes(t)},t.prototype.isRegexMatch=function(t,e){return new RegExp(e).test(String(t).toLowerCase())},t.prototype.isRequired=function(t){return!this.isOptional(t)},t.prototype.isSame=function(t,e){return t==e},t.prototype.isStartingWith=function(t,e){return this.isString(t)&&t.startsWith(e)},t.prototype.isString=function(t){return"string"==typeof t},t.prototype.isTruthy=function(t){return[1,"1",!0,"true"].includes(t)},t.prototype.isUrl=function(t){return new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$").test(String(t).toLowerCase())},t.prototype.isUuid=function(t){return new RegExp("^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$").test(String(t).toLowerCase())},t.prototype.is=function(t,e){if(void 0===e&&(e=[]),!e.length)return!0;if("optional"===e[0]&&this.isOptional(t))return!0;for(var r in e)if("optional"!==e[r]&&!this["is"+(e[r].split(":")[0][0].toUpperCase()+e[r].split(":")[0].slice(1))].apply(this,[t,e[r].split(":")[1]]))return e[r];return!0},t.prototype.setErrorMessages=function(t){this.messages=t},window.Iodine=new t;
//# sourceMappingURL=iodine.min.mjs.map
diff --git a/dist/iodine.min.mjs.map b/dist/iodine.min.mjs.map
index 9c84797..6adcd78 100644
--- a/dist/iodine.min.mjs.map
+++ b/dist/iodine.min.mjs.map
@@ -1 +1 @@
-{"version":3,"file":"iodine.min.mjs","sources":["../src/iodine.js"],"sourcesContent":["/*\n|--------------------------------------------------------------------------\n| Iodine - JavaScript Library\n|--------------------------------------------------------------------------\n|\n| This library contains a collection of useful validation rules that can\n| be used to quickly verify whether items meet certain conditions.\n|\n*/\nexport default class Iodine\n{\n\n\t/**\n\t * Constructor.\n\t *\n\t **/\n\tconstructor()\n\t{\n\t\tthis.messages = this._defaultMessages();\n\t}\n\n\n\n\t/**\n\t * @internal.\n\t *\n\t **/\n\t_dateCompare(first, second, type, equals = false)\n\t{\n\t\tif (! this.isDate(first)) return false;\n\n\t\tif (! this.isDate(second) && ! this.isInteger(second)) return false;\n\n\t\tsecond = typeof second === 'number' ? second : second.getTime();\n\n\t\tif (type === 'less' && equals) return first.getTime() <= second;\n\t\tif (type === 'less' && ! equals) return first.getTime() < second;\n\t\tif (type === 'more' && equals) return first.getTime() >= second;\n\t\tif (type === 'more' && ! equals) return first.getTime() > second;\n\t}\n\n\n\n\t/**\n\t * @internal.\n\t *\n\t **/\n\t_defaultMessages()\n\t{\n\t\treturn {\n\t\t\tafter : `The date must be after: '[PARAM]'`,\n\t\t\tafterOrEqual : `The date must be after or equal to: '[PARAM]'`,\n\t\t\tarray : `Value must be an array`,\n\t\t\tbefore : `The date must be before: '[PARAM]'`,\n\t\t\tbeforeOrEqual : `The date must be before or equal to: '[PARAM]'`,\n\t\t\tboolean : `Value must be true or false`,\n\t\t\tdate : `Value must be a date`,\n\t\t\tdifferent : `Value must be different to '[PARAM]'`,\n\t\t\tendingWith : `Value must end with '[PARAM]'`,\n\t\t\temail : `Value must be a valid email address`,\n\t\t\tfalsy : `Value must be a falsy value (false, 'false', 0 or '0')`,\n\t\t\tin \t\t : `Value must be one of the following options: [PARAM]`,\n\t\t\tinteger : `Value must be an integer`,\n\t\t\tjson : `Value must be a parsable JSON object string`,\n\t\t\tmaximum : `Value must not be greater than '[PARAM]' in size or character length`,\n\t\t\tminimum : `Value must not be less than '[PARAM]' in size or character length`,\n\t\t\tnotIn : `Value must not be one of the following options: [PARAM]`,\n\t\t\tnumeric : `Value must be numeric`,\n\t\t\toptional : `Value is optional`,\n\t\t\tregexMatch : `Value must satisify the regular expression: [PARAM]`,\n\t\t\trequired : `Value must be present`,\n\t\t\tsame : `Value must be '[PARAM]'`,\n\t\t\tstartingWith : `Value must start with '[PARAM]'`,\n\t\t\tstring : `Value must be a string`,\n\t\t\ttruthy : `Value must be a truthy value (true, 'true', 1 or '1')`,\n\t\t\turl : `Value must be a valid url`,\n\t\t\tuuid : `Value must be a valid UUID`,\n\t\t};\n\t}\n\n\n\n\t/**\n\t * Attach a custom validation rule to the library.\n\t *\n\t **/\n\taddRule(name, closure)\n\t{\n\t\tIodine.prototype[`is${name[0].toUpperCase()}${name.slice(1)}`] = closure;\n\t}\n\n\n\n\t/**\n\t * Retrieve an error message for the given rule.\n\t *\n\t **/\n\tgetErrorMessage(rule, arg = undefined)\n\t{\n\t\tlet key = rule.split(':')[0];\n\t\tlet param = arg || rule.split(':')[1];\n\n\t\tif (['after', 'afterOrEqual', 'before', 'beforeOrEqual'].includes(key)) {\n\t\t\tparam = new Date(parseInt(param)).toLocaleTimeString(undefined, {\n\t\t\t\tyear: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: 'numeric'\n\t\t\t});\n\t\t}\n\n\t\treturn [null, undefined].includes(param)\n\t\t\t ? this.messages[key]\n\t\t\t : this.messages[key].replace(\"[PARAM]\", param);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is after another given date.\n\t *\n\t **/\n\tisAfter(value, after)\n\t{\n\t\treturn this._dateCompare(value, after, 'more', false);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is after or equal to another given date.\n\t *\n\t **/\n\tisAfterOrEqual(value, after)\n\t{\n\t\treturn this._dateCompare(value, after, 'more', true);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is an array.\n\t *\n\t **/\n\tisArray(value)\n\t{\n\t\treturn Array.isArray(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is before another given date.\n\t *\n\t **/\n\tisBefore(value, before)\n\t{\n\t\treturn this._dateCompare(value, before, 'less', false);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is before or equal to another given date.\n\t *\n\t **/\n\tisBeforeOrEqual(value, before)\n\t{\n\t\treturn this._dateCompare(value, before, 'less', true);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a boolean.\n\t *\n\t **/\n\tisBoolean(value)\n\t{\n\t\treturn [true, false].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a date object.\n\t *\n\t **/\n\tisDate(value)\n\t{\n\t\treturn value && Object.prototype.toString.call(value) === '[object Date]' && ! isNaN(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is different to another given value.\n\t *\n\t **/\n\tisDifferent(value, different)\n\t{\n\t\treturn value != different;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value ends with another given value.\n\t *\n\t **/\n\tisEndingWith(value, sub)\n\t{\n\t\treturn this.isString(value) && value.endsWith(sub);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid email address.\n\t *\n\t **/\n\tisEmail(value)\n\t{\n\t\treturn new RegExp('^\\\\S+@\\\\S+[\\\\.][0-9a-z]+$').test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is falsy.\n\t *\n\t **/\n\tisFalsy(value)\n\t{\n\t\treturn [0, '0', false, 'false'].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is within the given array of options.\n\t *\n\t **/\n\tisIn(value, options)\n\t{\n\t\toptions = typeof options === 'string'\n\t\t\t\t? options.split(\",\")\n\t\t\t\t: options;\n\n\t\treturn options.includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is an integer.\n\t *\n\t **/\n\tisInteger(value)\n\t{\n\t\treturn Number.isInteger(value) && parseInt(value).toString() === value.toString();\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a JSON string.\n\t *\n\t **/\n\tisJson(value)\n\t{\n\t\ttry {\n \treturn typeof JSON.parse(value) === 'object';\n\t\t} catch (e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\n\n\t/**\n\t * Determine if the given value meets the given maximum limit.\n\t *\n\t **/\n\tisMaximum(value, limit)\n\t{\n\t\tvalue = typeof value === 'string' ? value.length : value;\n\n\t\treturn parseFloat(value) <= limit;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value meets the given minimum limit.\n\t *\n\t **/\n\tisMinimum(value, limit)\n\t{\n\t\tvalue = typeof value === 'string' ? value.length : value;\n\n\t\treturn parseFloat(value) >= limit;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is not within the given array of options.\n\t *\n\t **/\n\tisNotIn(value, options)\n\t{\n\t\treturn ! this.isIn(value, options);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is numeric (an integer or a float).\n\t *\n\t **/\n\tisNumeric(value)\n\t{\n\t\treturn ! isNaN(parseFloat(value)) && isFinite(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is optional.\n\t *\n\t **/\n\tisOptional(value)\n\t{\n\t\treturn [null, undefined, ''].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value satisifies the given regular expression.\n\t *\n\t **/\n\tisRegexMatch(value, expression)\n\t{\n\t\treturn new RegExp(expression).test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is present.\n\t *\n\t **/\n\tisRequired(value)\n\t{\n\t\treturn ! this.isOptional(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is the same as another given value.\n\t *\n\t **/\n\tisSame(value, same)\n\t{\n\t\treturn value == same;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value starts with another given value.\n\t *\n\t **/\n\tisStartingWith(value, sub)\n\t{\n\t\treturn this.isString(value) && value.startsWith(sub);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a string.\n\t *\n\t **/\n\tisString(value)\n\t{\n\t\treturn typeof value === 'string';\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is truthy.\n\t *\n\t **/\n\tisTruthy(value)\n\t{\n\t\treturn [1, '1', true, 'true'].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid URL.\n\t *\n\t **/\n\tisUrl(value)\n\t{\n\t\treturn new RegExp('^(https?:\\\\/\\\\/)?((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.)+[a-z]{2,}|((\\\\d{1,3}\\\\.){3}\\\\d{1,3}))(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*(\\\\?[;&a-z\\\\d%_.~+=-]*)?(\\\\#[-a-z\\\\d_]*)?$')\n\t\t\t .test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid UUID.\n\t *\n\t **/\n\tisUuid(value)\n\t{\n\t\treturn new RegExp('^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$')\n\t\t\t .test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine whether the given value meets the given rules.\n\t *\n\t **/\n\tis(value, rules = [])\n\t{\n\t\t// Check if no rules were specified\n\t\tif (rules.length === 0) return true;\n\n\t\t// Check for an optional value\n\t\tif (rules[0] === 'optional' && this.isOptional(value)) return true;\n\n\t\t// Iterate through the rules\n\t\tfor (let index = 0; index < rules.length; index++) {\n\n\t\t\t// Ignore optional rules\n\t\t\tif (rules[index] === 'optional') continue;\n\n\t\t\t// Determine the method to use\n\t\t\tlet rule = rules[index].split(':')[0][0].toUpperCase()\n\t\t\t\t\t + rules[index].split(':')[0].slice(1);\n\n\t\t\t// Validate the value against the method\n\t\t\tlet result = this[`is${rule}`].apply(this, [value, rules[index].split(':')[1]]);\n\n\t\t\t// Check if the value failed validation\n\t\t\tif (! result) return rules[index];\n\n\t\t}\n\n\t\t// Otherwise, the value is valid\n\t\treturn true;\n\t}\n\n\n\n\t/**\n\t * Replace the default error messages with a new set.\n\t *\n\t **/\n\tsetErrorMessages(messages)\n\t{\n\t\tthis.messages = messages;\n\t}\n\n}\n\n\n\n/**\n * Create an instance of the library.\n *\n **/\nwindow.Iodine = new Iodine();"],"names":["Iodine","constructor","messages","this","_defaultMessages","_dateCompare","first","second","type","equals","isDate","isInteger","getTime","after","afterOrEqual","array","before","beforeOrEqual","boolean","date","different","endingWith","email","falsy","in","integer","json","maximum","minimum","notIn","numeric","optional","regexMatch","required","same","startingWith","string","truthy","url","uuid","addRule","name","closure","prototype","toUpperCase","slice","getErrorMessage","rule","arg","undefined","key","split","param","includes","Date","parseInt","toLocaleTimeString","year","month","day","hour","minute","replace","isAfter","value","isAfterOrEqual","isArray","Array","isBefore","isBeforeOrEqual","isBoolean","Object","toString","call","isNaN","isDifferent","isEndingWith","sub","isString","endsWith","isEmail","RegExp","test","String","toLowerCase","isFalsy","isIn","options","Number","isJson","JSON","parse","e","isMaximum","limit","length","parseFloat","isMinimum","isNotIn","isNumeric","isFinite","isOptional","isRegexMatch","expression","isRequired","isSame","isStartingWith","startsWith","isTruthy","isUrl","isUuid","is","rules","let","index","apply","setErrorMessages","window"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"iodine.min.mjs","sources":["../src/iodine.js"],"sourcesContent":["/*\n|--------------------------------------------------------------------------\n| Iodine - JavaScript Library\n|--------------------------------------------------------------------------\n|\n| This library contains a collection of useful validation rules that can\n| be used to quickly verify whether items meet certain conditions.\n|\n*/\nclass Iodine\n{\n\n\t/**\n\t * Constructor.\n\t *\n\t **/\n\tconstructor()\n\t{\n\t\tthis.messages = this._defaultMessages();\n\t}\n\n\n\n\t/**\n\t * @internal.\n\t *\n\t **/\n\t_dateCompare(first, second, type, equals = false)\n\t{\n\t\tif (! this.isDate(first)) return false;\n\n\t\tif (! this.isDate(second) && ! this.isInteger(second)) return false;\n\n\t\tsecond = typeof second === 'number' ? second : second.getTime();\n\n\t\tif (type === 'less' && equals) return first.getTime() <= second;\n\t\tif (type === 'less' && ! equals) return first.getTime() < second;\n\t\tif (type === 'more' && equals) return first.getTime() >= second;\n\t\tif (type === 'more' && ! equals) return first.getTime() > second;\n\t}\n\n\n\n\t/**\n\t * @internal.\n\t *\n\t **/\n\t_defaultMessages()\n\t{\n\t\treturn {\n\t\t\tafter : `The date must be after: '[PARAM]'`,\n\t\t\tafterOrEqual : `The date must be after or equal to: '[PARAM]'`,\n\t\t\tarray : `Value must be an array`,\n\t\t\tbefore : `The date must be before: '[PARAM]'`,\n\t\t\tbeforeOrEqual : `The date must be before or equal to: '[PARAM]'`,\n\t\t\tboolean : `Value must be true or false`,\n\t\t\tdate : `Value must be a date`,\n\t\t\tdifferent : `Value must be different to '[PARAM]'`,\n\t\t\tendingWith : `Value must end with '[PARAM]'`,\n\t\t\temail : `Value must be a valid email address`,\n\t\t\tfalsy : `Value must be a falsy value (false, 'false', 0 or '0')`,\n\t\t\tin \t\t : `Value must be one of the following options: [PARAM]`,\n\t\t\tinteger : `Value must be an integer`,\n\t\t\tjson : `Value must be a parsable JSON object string`,\n\t\t\tmaximum : `Value must not be greater than '[PARAM]' in size or character length`,\n\t\t\tminimum : `Value must not be less than '[PARAM]' in size or character length`,\n\t\t\tnotIn : `Value must not be one of the following options: [PARAM]`,\n\t\t\tnumeric : `Value must be numeric`,\n\t\t\toptional : `Value is optional`,\n\t\t\tregexMatch : `Value must satisify the regular expression: [PARAM]`,\n\t\t\trequired : `Value must be present`,\n\t\t\tsame : `Value must be '[PARAM]'`,\n\t\t\tstartingWith : `Value must start with '[PARAM]'`,\n\t\t\tstring : `Value must be a string`,\n\t\t\ttruthy : `Value must be a truthy value (true, 'true', 1 or '1')`,\n\t\t\turl : `Value must be a valid url`,\n\t\t\tuuid : `Value must be a valid UUID`,\n\t\t};\n\t}\n\n\n\n\t/**\n\t * Attach a custom validation rule to the library.\n\t *\n\t **/\n\taddRule(name, closure)\n\t{\n\t\tIodine.prototype[`is${name[0].toUpperCase()}${name.slice(1)}`] = closure;\n\t}\n\n\n\n\t/**\n\t * Retrieve an error message for the given rule.\n\t *\n\t **/\n\tgetErrorMessage(rule, arg = undefined)\n\t{\n\t\tlet key = rule.split(':')[0];\n\t\tlet param = arg || rule.split(':')[1];\n\n\t\tif (['after', 'afterOrEqual', 'before', 'beforeOrEqual'].includes(key)) {\n\t\t\tparam = new Date(parseInt(param)).toLocaleTimeString(undefined, {\n\t\t\t\tyear: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: 'numeric'\n\t\t\t});\n\t\t}\n\n\t\treturn [null, undefined].includes(param)\n\t\t\t ? this.messages[key]\n\t\t\t : this.messages[key].replace(\"[PARAM]\", param);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is after another given date.\n\t *\n\t **/\n\tisAfter(value, after)\n\t{\n\t\treturn this._dateCompare(value, after, 'more', false);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is after or equal to another given date.\n\t *\n\t **/\n\tisAfterOrEqual(value, after)\n\t{\n\t\treturn this._dateCompare(value, after, 'more', true);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is an array.\n\t *\n\t **/\n\tisArray(value)\n\t{\n\t\treturn Array.isArray(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is before another given date.\n\t *\n\t **/\n\tisBefore(value, before)\n\t{\n\t\treturn this._dateCompare(value, before, 'less', false);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is before or equal to another given date.\n\t *\n\t **/\n\tisBeforeOrEqual(value, before)\n\t{\n\t\treturn this._dateCompare(value, before, 'less', true);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a boolean.\n\t *\n\t **/\n\tisBoolean(value)\n\t{\n\t\treturn [true, false].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a date object.\n\t *\n\t **/\n\tisDate(value)\n\t{\n\t\treturn value && Object.prototype.toString.call(value) === '[object Date]' && ! isNaN(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is different to another given value.\n\t *\n\t **/\n\tisDifferent(value, different)\n\t{\n\t\treturn value != different;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value ends with another given value.\n\t *\n\t **/\n\tisEndingWith(value, sub)\n\t{\n\t\treturn this.isString(value) && value.endsWith(sub);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid email address.\n\t *\n\t **/\n\tisEmail(value)\n\t{\n\t\treturn new RegExp('^\\\\S+@\\\\S+[\\\\.][0-9a-z]+$').test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is falsy.\n\t *\n\t **/\n\tisFalsy(value)\n\t{\n\t\treturn [0, '0', false, 'false'].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is within the given array of options.\n\t *\n\t **/\n\tisIn(value, options)\n\t{\n\t\toptions = typeof options === 'string'\n\t\t\t\t? options.split(\",\")\n\t\t\t\t: options;\n\n\t\treturn options.includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is an integer.\n\t *\n\t **/\n\tisInteger(value)\n\t{\n\t\treturn Number.isInteger(value) && parseInt(value).toString() === value.toString();\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a JSON string.\n\t *\n\t **/\n\tisJson(value)\n\t{\n\t\ttry {\n \treturn typeof JSON.parse(value) === 'object';\n\t\t} catch (e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\n\n\t/**\n\t * Determine if the given value meets the given maximum limit.\n\t *\n\t **/\n\tisMaximum(value, limit)\n\t{\n\t\tvalue = typeof value === 'string' ? value.length : value;\n\n\t\treturn parseFloat(value) <= limit;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value meets the given minimum limit.\n\t *\n\t **/\n\tisMinimum(value, limit)\n\t{\n\t\tvalue = typeof value === 'string' ? value.length : value;\n\n\t\treturn parseFloat(value) >= limit;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is not within the given array of options.\n\t *\n\t **/\n\tisNotIn(value, options)\n\t{\n\t\treturn ! this.isIn(value, options);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is numeric (an integer or a float).\n\t *\n\t **/\n\tisNumeric(value)\n\t{\n\t\treturn ! isNaN(parseFloat(value)) && isFinite(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is optional.\n\t *\n\t **/\n\tisOptional(value)\n\t{\n\t\treturn [null, undefined, ''].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value satisifies the given regular expression.\n\t *\n\t **/\n\tisRegexMatch(value, expression)\n\t{\n\t\treturn new RegExp(expression).test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is present.\n\t *\n\t **/\n\tisRequired(value)\n\t{\n\t\treturn ! this.isOptional(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is the same as another given value.\n\t *\n\t **/\n\tisSame(value, same)\n\t{\n\t\treturn value == same;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value starts with another given value.\n\t *\n\t **/\n\tisStartingWith(value, sub)\n\t{\n\t\treturn this.isString(value) && value.startsWith(sub);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a string.\n\t *\n\t **/\n\tisString(value)\n\t{\n\t\treturn typeof value === 'string';\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is truthy.\n\t *\n\t **/\n\tisTruthy(value)\n\t{\n\t\treturn [1, '1', true, 'true'].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid URL.\n\t *\n\t **/\n\tisUrl(value)\n\t{\n\t\treturn new RegExp('^(https?:\\\\/\\\\/)?((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.)+[a-z]{2,}|((\\\\d{1,3}\\\\.){3}\\\\d{1,3}))(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*(\\\\?[;&a-z\\\\d%_.~+=-]*)?(\\\\#[-a-z\\\\d_]*)?$')\n\t\t\t .test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid UUID.\n\t *\n\t **/\n\tisUuid(value)\n\t{\n\t\treturn new RegExp('^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$')\n\t\t\t .test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine whether the given value meets the given rules.\n\t *\n\t **/\n\tis(value, rules = [])\n\t{\n\t\t// Check if no rules were specified\n\t\tif (! rules.length) return true;\n\n\t\t// Check for an optional value\n\t\tif (rules[0] === 'optional' && this.isOptional(value)) return true;\n\n\t\t// Iterate through the rules\n\t\tfor (let index in rules) {\n\n\t\t\t// Ignore optional rules\n\t\t\tif (rules[index] === 'optional') continue;\n\n\t\t\t// Determine the method to use\n\t\t\tlet rule = rules[index].split(':')[0][0].toUpperCase()\n\t\t\t\t\t + rules[index].split(':')[0].slice(1);\n\n\t\t\t// Validate the value against the method\n\t\t\tlet result = this[`is${rule}`].apply(this, [value, rules[index].split(':')[1]]);\n\n\t\t\t// Check if the value failed validation\n\t\t\tif (! result) return rules[index];\n\n\t\t}\n\n\t\t// Otherwise, the value is valid\n\t\treturn true;\n\t}\n\n\n\n\t/**\n\t * Replace the default error messages with a new set.\n\t *\n\t **/\n\tsetErrorMessages(messages)\n\t{\n\t\tthis.messages = messages;\n\t}\n\n}\n\n\n\n/**\n * Create an instance of the library.\n *\n **/\nwindow.Iodine = new Iodine();\n"],"names":["Iodine","constructor","messages","this","_defaultMessages","_dateCompare","first","second","type","equals","isDate","isInteger","getTime","after","afterOrEqual","array","before","beforeOrEqual","boolean","date","different","endingWith","email","falsy","in","integer","json","maximum","minimum","notIn","numeric","optional","regexMatch","required","same","startingWith","string","truthy","url","uuid","addRule","name","closure","prototype","toUpperCase","slice","getErrorMessage","rule","arg","undefined","key","split","param","includes","Date","parseInt","toLocaleTimeString","year","month","day","hour","minute","replace","isAfter","value","isAfterOrEqual","isArray","Array","isBefore","isBeforeOrEqual","isBoolean","Object","toString","call","isNaN","isDifferent","isEndingWith","sub","isString","endsWith","isEmail","RegExp","test","String","toLowerCase","isFalsy","isIn","options","Number","isJson","JSON","parse","e","isMaximum","limit","length","parseFloat","isMinimum","isNotIn","isNumeric","isFinite","isOptional","isRegexMatch","expression","isRequired","isSame","isStartingWith","startsWith","isTruthy","isUrl","isUuid","is","rules","let","index","apply","setErrorMessages","window"],"mappings":"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"}
\ No newline at end of file
diff --git a/dist/iodine.min.umd.js b/dist/iodine.min.umd.js
index 43c9326..0b9973b 100644
--- a/dist/iodine.min.umd.js
+++ b/dist/iodine.min.umd.js
@@ -1,2 +1,2 @@
-!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.iodine=e()}(this,function(){var t=function(){this.messages=this._defaultMessages()};return t.prototype._dateCompare=function(t,e,r,i){return void 0===i&&(i=!1),!!this.isDate(t)&&!(!this.isDate(e)&&!this.isInteger(e))&&(e="number"==typeof e?e:e.getTime(),"less"===r&&i?t.getTime()<=e:"less"!==r||i?"more"===r&&i?t.getTime()>=e:"more"!==r||i?void 0:t.getTime()>e:t.getTime()=e},t.prototype.isNotIn=function(t,e){return!this.isIn(t,e)},t.prototype.isNumeric=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},t.prototype.isOptional=function(t){return[null,void 0,""].includes(t)},t.prototype.isRegexMatch=function(t,e){return new RegExp(e).test(String(t).toLowerCase())},t.prototype.isRequired=function(t){return!this.isOptional(t)},t.prototype.isSame=function(t,e){return t==e},t.prototype.isStartingWith=function(t,e){return this.isString(t)&&t.startsWith(e)},t.prototype.isString=function(t){return"string"==typeof t},t.prototype.isTruthy=function(t){return[1,"1",!0,"true"].includes(t)},t.prototype.isUrl=function(t){return new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$").test(String(t).toLowerCase())},t.prototype.isUuid=function(t){return new RegExp("^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$").test(String(t).toLowerCase())},t.prototype.is=function(t,e){if(void 0===e&&(e=[]),0===e.length)return!0;if("optional"===e[0]&&this.isOptional(t))return!0;for(var r=0;r=e:"more"!==r||i?void 0:t.getTime()>e:t.getTime()=e},t.prototype.isNotIn=function(t,e){return!this.isIn(t,e)},t.prototype.isNumeric=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},t.prototype.isOptional=function(t){return[null,void 0,""].includes(t)},t.prototype.isRegexMatch=function(t,e){return new RegExp(e).test(String(t).toLowerCase())},t.prototype.isRequired=function(t){return!this.isOptional(t)},t.prototype.isSame=function(t,e){return t==e},t.prototype.isStartingWith=function(t,e){return this.isString(t)&&t.startsWith(e)},t.prototype.isString=function(t){return"string"==typeof t},t.prototype.isTruthy=function(t){return[1,"1",!0,"true"].includes(t)},t.prototype.isUrl=function(t){return new RegExp("^(https?:\\/\\/)?((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|((\\d{1,3}\\.){3}\\d{1,3}))(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*(\\?[;&a-z\\d%_.~+=-]*)?(\\#[-a-z\\d_]*)?$").test(String(t).toLowerCase())},t.prototype.isUuid=function(t){return new RegExp("^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$").test(String(t).toLowerCase())},t.prototype.is=function(t,e){if(void 0===e&&(e=[]),!e.length)return!0;if("optional"===e[0]&&this.isOptional(t))return!0;for(var r in e)if("optional"!==e[r]&&!this["is"+(e[r].split(":")[0][0].toUpperCase()+e[r].split(":")[0].slice(1))].apply(this,[t,e[r].split(":")[1]]))return e[r];return!0},t.prototype.setErrorMessages=function(t){this.messages=t},window.Iodine=new t});
//# sourceMappingURL=iodine.min.umd.js.map
diff --git a/dist/iodine.min.umd.js.map b/dist/iodine.min.umd.js.map
index 083999b..0a85149 100644
--- a/dist/iodine.min.umd.js.map
+++ b/dist/iodine.min.umd.js.map
@@ -1 +1 @@
-{"version":3,"file":"iodine.min.umd.js","sources":["../src/iodine.js"],"sourcesContent":["/*\n|--------------------------------------------------------------------------\n| Iodine - JavaScript Library\n|--------------------------------------------------------------------------\n|\n| This library contains a collection of useful validation rules that can\n| be used to quickly verify whether items meet certain conditions.\n|\n*/\nexport default class Iodine\n{\n\n\t/**\n\t * Constructor.\n\t *\n\t **/\n\tconstructor()\n\t{\n\t\tthis.messages = this._defaultMessages();\n\t}\n\n\n\n\t/**\n\t * @internal.\n\t *\n\t **/\n\t_dateCompare(first, second, type, equals = false)\n\t{\n\t\tif (! this.isDate(first)) return false;\n\n\t\tif (! this.isDate(second) && ! this.isInteger(second)) return false;\n\n\t\tsecond = typeof second === 'number' ? second : second.getTime();\n\n\t\tif (type === 'less' && equals) return first.getTime() <= second;\n\t\tif (type === 'less' && ! equals) return first.getTime() < second;\n\t\tif (type === 'more' && equals) return first.getTime() >= second;\n\t\tif (type === 'more' && ! equals) return first.getTime() > second;\n\t}\n\n\n\n\t/**\n\t * @internal.\n\t *\n\t **/\n\t_defaultMessages()\n\t{\n\t\treturn {\n\t\t\tafter : `The date must be after: '[PARAM]'`,\n\t\t\tafterOrEqual : `The date must be after or equal to: '[PARAM]'`,\n\t\t\tarray : `Value must be an array`,\n\t\t\tbefore : `The date must be before: '[PARAM]'`,\n\t\t\tbeforeOrEqual : `The date must be before or equal to: '[PARAM]'`,\n\t\t\tboolean : `Value must be true or false`,\n\t\t\tdate : `Value must be a date`,\n\t\t\tdifferent : `Value must be different to '[PARAM]'`,\n\t\t\tendingWith : `Value must end with '[PARAM]'`,\n\t\t\temail : `Value must be a valid email address`,\n\t\t\tfalsy : `Value must be a falsy value (false, 'false', 0 or '0')`,\n\t\t\tin \t\t : `Value must be one of the following options: [PARAM]`,\n\t\t\tinteger : `Value must be an integer`,\n\t\t\tjson : `Value must be a parsable JSON object string`,\n\t\t\tmaximum : `Value must not be greater than '[PARAM]' in size or character length`,\n\t\t\tminimum : `Value must not be less than '[PARAM]' in size or character length`,\n\t\t\tnotIn : `Value must not be one of the following options: [PARAM]`,\n\t\t\tnumeric : `Value must be numeric`,\n\t\t\toptional : `Value is optional`,\n\t\t\tregexMatch : `Value must satisify the regular expression: [PARAM]`,\n\t\t\trequired : `Value must be present`,\n\t\t\tsame : `Value must be '[PARAM]'`,\n\t\t\tstartingWith : `Value must start with '[PARAM]'`,\n\t\t\tstring : `Value must be a string`,\n\t\t\ttruthy : `Value must be a truthy value (true, 'true', 1 or '1')`,\n\t\t\turl : `Value must be a valid url`,\n\t\t\tuuid : `Value must be a valid UUID`,\n\t\t};\n\t}\n\n\n\n\t/**\n\t * Attach a custom validation rule to the library.\n\t *\n\t **/\n\taddRule(name, closure)\n\t{\n\t\tIodine.prototype[`is${name[0].toUpperCase()}${name.slice(1)}`] = closure;\n\t}\n\n\n\n\t/**\n\t * Retrieve an error message for the given rule.\n\t *\n\t **/\n\tgetErrorMessage(rule, arg = undefined)\n\t{\n\t\tlet key = rule.split(':')[0];\n\t\tlet param = arg || rule.split(':')[1];\n\n\t\tif (['after', 'afterOrEqual', 'before', 'beforeOrEqual'].includes(key)) {\n\t\t\tparam = new Date(parseInt(param)).toLocaleTimeString(undefined, {\n\t\t\t\tyear: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: 'numeric'\n\t\t\t});\n\t\t}\n\n\t\treturn [null, undefined].includes(param)\n\t\t\t ? this.messages[key]\n\t\t\t : this.messages[key].replace(\"[PARAM]\", param);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is after another given date.\n\t *\n\t **/\n\tisAfter(value, after)\n\t{\n\t\treturn this._dateCompare(value, after, 'more', false);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is after or equal to another given date.\n\t *\n\t **/\n\tisAfterOrEqual(value, after)\n\t{\n\t\treturn this._dateCompare(value, after, 'more', true);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is an array.\n\t *\n\t **/\n\tisArray(value)\n\t{\n\t\treturn Array.isArray(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is before another given date.\n\t *\n\t **/\n\tisBefore(value, before)\n\t{\n\t\treturn this._dateCompare(value, before, 'less', false);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is before or equal to another given date.\n\t *\n\t **/\n\tisBeforeOrEqual(value, before)\n\t{\n\t\treturn this._dateCompare(value, before, 'less', true);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a boolean.\n\t *\n\t **/\n\tisBoolean(value)\n\t{\n\t\treturn [true, false].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a date object.\n\t *\n\t **/\n\tisDate(value)\n\t{\n\t\treturn value && Object.prototype.toString.call(value) === '[object Date]' && ! isNaN(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is different to another given value.\n\t *\n\t **/\n\tisDifferent(value, different)\n\t{\n\t\treturn value != different;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value ends with another given value.\n\t *\n\t **/\n\tisEndingWith(value, sub)\n\t{\n\t\treturn this.isString(value) && value.endsWith(sub);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid email address.\n\t *\n\t **/\n\tisEmail(value)\n\t{\n\t\treturn new RegExp('^\\\\S+@\\\\S+[\\\\.][0-9a-z]+$').test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is falsy.\n\t *\n\t **/\n\tisFalsy(value)\n\t{\n\t\treturn [0, '0', false, 'false'].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is within the given array of options.\n\t *\n\t **/\n\tisIn(value, options)\n\t{\n\t\toptions = typeof options === 'string'\n\t\t\t\t? options.split(\",\")\n\t\t\t\t: options;\n\n\t\treturn options.includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is an integer.\n\t *\n\t **/\n\tisInteger(value)\n\t{\n\t\treturn Number.isInteger(value) && parseInt(value).toString() === value.toString();\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a JSON string.\n\t *\n\t **/\n\tisJson(value)\n\t{\n\t\ttry {\n \treturn typeof JSON.parse(value) === 'object';\n\t\t} catch (e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\n\n\t/**\n\t * Determine if the given value meets the given maximum limit.\n\t *\n\t **/\n\tisMaximum(value, limit)\n\t{\n\t\tvalue = typeof value === 'string' ? value.length : value;\n\n\t\treturn parseFloat(value) <= limit;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value meets the given minimum limit.\n\t *\n\t **/\n\tisMinimum(value, limit)\n\t{\n\t\tvalue = typeof value === 'string' ? value.length : value;\n\n\t\treturn parseFloat(value) >= limit;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is not within the given array of options.\n\t *\n\t **/\n\tisNotIn(value, options)\n\t{\n\t\treturn ! this.isIn(value, options);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is numeric (an integer or a float).\n\t *\n\t **/\n\tisNumeric(value)\n\t{\n\t\treturn ! isNaN(parseFloat(value)) && isFinite(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is optional.\n\t *\n\t **/\n\tisOptional(value)\n\t{\n\t\treturn [null, undefined, ''].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value satisifies the given regular expression.\n\t *\n\t **/\n\tisRegexMatch(value, expression)\n\t{\n\t\treturn new RegExp(expression).test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is present.\n\t *\n\t **/\n\tisRequired(value)\n\t{\n\t\treturn ! this.isOptional(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is the same as another given value.\n\t *\n\t **/\n\tisSame(value, same)\n\t{\n\t\treturn value == same;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value starts with another given value.\n\t *\n\t **/\n\tisStartingWith(value, sub)\n\t{\n\t\treturn this.isString(value) && value.startsWith(sub);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a string.\n\t *\n\t **/\n\tisString(value)\n\t{\n\t\treturn typeof value === 'string';\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is truthy.\n\t *\n\t **/\n\tisTruthy(value)\n\t{\n\t\treturn [1, '1', true, 'true'].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid URL.\n\t *\n\t **/\n\tisUrl(value)\n\t{\n\t\treturn new RegExp('^(https?:\\\\/\\\\/)?((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.)+[a-z]{2,}|((\\\\d{1,3}\\\\.){3}\\\\d{1,3}))(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*(\\\\?[;&a-z\\\\d%_.~+=-]*)?(\\\\#[-a-z\\\\d_]*)?$')\n\t\t\t .test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid UUID.\n\t *\n\t **/\n\tisUuid(value)\n\t{\n\t\treturn new RegExp('^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$')\n\t\t\t .test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine whether the given value meets the given rules.\n\t *\n\t **/\n\tis(value, rules = [])\n\t{\n\t\t// Check if no rules were specified\n\t\tif (rules.length === 0) return true;\n\n\t\t// Check for an optional value\n\t\tif (rules[0] === 'optional' && this.isOptional(value)) return true;\n\n\t\t// Iterate through the rules\n\t\tfor (let index = 0; index < rules.length; index++) {\n\n\t\t\t// Ignore optional rules\n\t\t\tif (rules[index] === 'optional') continue;\n\n\t\t\t// Determine the method to use\n\t\t\tlet rule = rules[index].split(':')[0][0].toUpperCase()\n\t\t\t\t\t + rules[index].split(':')[0].slice(1);\n\n\t\t\t// Validate the value against the method\n\t\t\tlet result = this[`is${rule}`].apply(this, [value, rules[index].split(':')[1]]);\n\n\t\t\t// Check if the value failed validation\n\t\t\tif (! result) return rules[index];\n\n\t\t}\n\n\t\t// Otherwise, the value is valid\n\t\treturn true;\n\t}\n\n\n\n\t/**\n\t * Replace the default error messages with a new set.\n\t *\n\t **/\n\tsetErrorMessages(messages)\n\t{\n\t\tthis.messages = messages;\n\t}\n\n}\n\n\n\n/**\n * Create an instance of the library.\n *\n **/\nwindow.Iodine = new Iodine();"],"names":["Iodine","constructor","messages","this","_defaultMessages","_dateCompare","first","second","type","equals","isDate","isInteger","getTime","after","afterOrEqual","array","before","beforeOrEqual","boolean","date","different","endingWith","email","falsy","in","integer","json","maximum","minimum","notIn","numeric","optional","regexMatch","required","same","startingWith","string","truthy","url","uuid","addRule","name","closure","prototype","toUpperCase","slice","getErrorMessage","rule","arg","undefined","key","split","param","includes","Date","parseInt","toLocaleTimeString","year","month","day","hour","minute","replace","isAfter","value","isAfterOrEqual","isArray","Array","isBefore","isBeforeOrEqual","isBoolean","Object","toString","call","isNaN","isDifferent","isEndingWith","sub","isString","endsWith","isEmail","RegExp","test","String","toLowerCase","isFalsy","isIn","options","Number","isJson","JSON","parse","e","isMaximum","limit","length","parseFloat","isMinimum","isNotIn","isNumeric","isFinite","isOptional","isRegexMatch","expression","isRequired","isSame","isStartingWith","startsWith","isTruthy","isUrl","isUuid","is","rules","let","index","apply","setErrorMessages","window"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"iodine.min.umd.js","sources":["../src/iodine.js"],"sourcesContent":["/*\n|--------------------------------------------------------------------------\n| Iodine - JavaScript Library\n|--------------------------------------------------------------------------\n|\n| This library contains a collection of useful validation rules that can\n| be used to quickly verify whether items meet certain conditions.\n|\n*/\nclass Iodine\n{\n\n\t/**\n\t * Constructor.\n\t *\n\t **/\n\tconstructor()\n\t{\n\t\tthis.messages = this._defaultMessages();\n\t}\n\n\n\n\t/**\n\t * @internal.\n\t *\n\t **/\n\t_dateCompare(first, second, type, equals = false)\n\t{\n\t\tif (! this.isDate(first)) return false;\n\n\t\tif (! this.isDate(second) && ! this.isInteger(second)) return false;\n\n\t\tsecond = typeof second === 'number' ? second : second.getTime();\n\n\t\tif (type === 'less' && equals) return first.getTime() <= second;\n\t\tif (type === 'less' && ! equals) return first.getTime() < second;\n\t\tif (type === 'more' && equals) return first.getTime() >= second;\n\t\tif (type === 'more' && ! equals) return first.getTime() > second;\n\t}\n\n\n\n\t/**\n\t * @internal.\n\t *\n\t **/\n\t_defaultMessages()\n\t{\n\t\treturn {\n\t\t\tafter : `The date must be after: '[PARAM]'`,\n\t\t\tafterOrEqual : `The date must be after or equal to: '[PARAM]'`,\n\t\t\tarray : `Value must be an array`,\n\t\t\tbefore : `The date must be before: '[PARAM]'`,\n\t\t\tbeforeOrEqual : `The date must be before or equal to: '[PARAM]'`,\n\t\t\tboolean : `Value must be true or false`,\n\t\t\tdate : `Value must be a date`,\n\t\t\tdifferent : `Value must be different to '[PARAM]'`,\n\t\t\tendingWith : `Value must end with '[PARAM]'`,\n\t\t\temail : `Value must be a valid email address`,\n\t\t\tfalsy : `Value must be a falsy value (false, 'false', 0 or '0')`,\n\t\t\tin \t\t : `Value must be one of the following options: [PARAM]`,\n\t\t\tinteger : `Value must be an integer`,\n\t\t\tjson : `Value must be a parsable JSON object string`,\n\t\t\tmaximum : `Value must not be greater than '[PARAM]' in size or character length`,\n\t\t\tminimum : `Value must not be less than '[PARAM]' in size or character length`,\n\t\t\tnotIn : `Value must not be one of the following options: [PARAM]`,\n\t\t\tnumeric : `Value must be numeric`,\n\t\t\toptional : `Value is optional`,\n\t\t\tregexMatch : `Value must satisify the regular expression: [PARAM]`,\n\t\t\trequired : `Value must be present`,\n\t\t\tsame : `Value must be '[PARAM]'`,\n\t\t\tstartingWith : `Value must start with '[PARAM]'`,\n\t\t\tstring : `Value must be a string`,\n\t\t\ttruthy : `Value must be a truthy value (true, 'true', 1 or '1')`,\n\t\t\turl : `Value must be a valid url`,\n\t\t\tuuid : `Value must be a valid UUID`,\n\t\t};\n\t}\n\n\n\n\t/**\n\t * Attach a custom validation rule to the library.\n\t *\n\t **/\n\taddRule(name, closure)\n\t{\n\t\tIodine.prototype[`is${name[0].toUpperCase()}${name.slice(1)}`] = closure;\n\t}\n\n\n\n\t/**\n\t * Retrieve an error message for the given rule.\n\t *\n\t **/\n\tgetErrorMessage(rule, arg = undefined)\n\t{\n\t\tlet key = rule.split(':')[0];\n\t\tlet param = arg || rule.split(':')[1];\n\n\t\tif (['after', 'afterOrEqual', 'before', 'beforeOrEqual'].includes(key)) {\n\t\t\tparam = new Date(parseInt(param)).toLocaleTimeString(undefined, {\n\t\t\t\tyear: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: 'numeric'\n\t\t\t});\n\t\t}\n\n\t\treturn [null, undefined].includes(param)\n\t\t\t ? this.messages[key]\n\t\t\t : this.messages[key].replace(\"[PARAM]\", param);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is after another given date.\n\t *\n\t **/\n\tisAfter(value, after)\n\t{\n\t\treturn this._dateCompare(value, after, 'more', false);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is after or equal to another given date.\n\t *\n\t **/\n\tisAfterOrEqual(value, after)\n\t{\n\t\treturn this._dateCompare(value, after, 'more', true);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is an array.\n\t *\n\t **/\n\tisArray(value)\n\t{\n\t\treturn Array.isArray(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is before another given date.\n\t *\n\t **/\n\tisBefore(value, before)\n\t{\n\t\treturn this._dateCompare(value, before, 'less', false);\n\t}\n\n\n\n\t/**\n\t * Determine if the given date is before or equal to another given date.\n\t *\n\t **/\n\tisBeforeOrEqual(value, before)\n\t{\n\t\treturn this._dateCompare(value, before, 'less', true);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a boolean.\n\t *\n\t **/\n\tisBoolean(value)\n\t{\n\t\treturn [true, false].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a date object.\n\t *\n\t **/\n\tisDate(value)\n\t{\n\t\treturn value && Object.prototype.toString.call(value) === '[object Date]' && ! isNaN(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is different to another given value.\n\t *\n\t **/\n\tisDifferent(value, different)\n\t{\n\t\treturn value != different;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value ends with another given value.\n\t *\n\t **/\n\tisEndingWith(value, sub)\n\t{\n\t\treturn this.isString(value) && value.endsWith(sub);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid email address.\n\t *\n\t **/\n\tisEmail(value)\n\t{\n\t\treturn new RegExp('^\\\\S+@\\\\S+[\\\\.][0-9a-z]+$').test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is falsy.\n\t *\n\t **/\n\tisFalsy(value)\n\t{\n\t\treturn [0, '0', false, 'false'].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is within the given array of options.\n\t *\n\t **/\n\tisIn(value, options)\n\t{\n\t\toptions = typeof options === 'string'\n\t\t\t\t? options.split(\",\")\n\t\t\t\t: options;\n\n\t\treturn options.includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is an integer.\n\t *\n\t **/\n\tisInteger(value)\n\t{\n\t\treturn Number.isInteger(value) && parseInt(value).toString() === value.toString();\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a JSON string.\n\t *\n\t **/\n\tisJson(value)\n\t{\n\t\ttry {\n \treturn typeof JSON.parse(value) === 'object';\n\t\t} catch (e) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\n\n\t/**\n\t * Determine if the given value meets the given maximum limit.\n\t *\n\t **/\n\tisMaximum(value, limit)\n\t{\n\t\tvalue = typeof value === 'string' ? value.length : value;\n\n\t\treturn parseFloat(value) <= limit;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value meets the given minimum limit.\n\t *\n\t **/\n\tisMinimum(value, limit)\n\t{\n\t\tvalue = typeof value === 'string' ? value.length : value;\n\n\t\treturn parseFloat(value) >= limit;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is not within the given array of options.\n\t *\n\t **/\n\tisNotIn(value, options)\n\t{\n\t\treturn ! this.isIn(value, options);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is numeric (an integer or a float).\n\t *\n\t **/\n\tisNumeric(value)\n\t{\n\t\treturn ! isNaN(parseFloat(value)) && isFinite(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is optional.\n\t *\n\t **/\n\tisOptional(value)\n\t{\n\t\treturn [null, undefined, ''].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value satisifies the given regular expression.\n\t *\n\t **/\n\tisRegexMatch(value, expression)\n\t{\n\t\treturn new RegExp(expression).test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is present.\n\t *\n\t **/\n\tisRequired(value)\n\t{\n\t\treturn ! this.isOptional(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is the same as another given value.\n\t *\n\t **/\n\tisSame(value, same)\n\t{\n\t\treturn value == same;\n\t}\n\n\n\n\t/**\n\t * Determine if the given value starts with another given value.\n\t *\n\t **/\n\tisStartingWith(value, sub)\n\t{\n\t\treturn this.isString(value) && value.startsWith(sub);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a string.\n\t *\n\t **/\n\tisString(value)\n\t{\n\t\treturn typeof value === 'string';\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is truthy.\n\t *\n\t **/\n\tisTruthy(value)\n\t{\n\t\treturn [1, '1', true, 'true'].includes(value);\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid URL.\n\t *\n\t **/\n\tisUrl(value)\n\t{\n\t\treturn new RegExp('^(https?:\\\\/\\\\/)?((([a-z\\\\d]([a-z\\\\d-]*[a-z\\\\d])*)\\\\.)+[a-z]{2,}|((\\\\d{1,3}\\\\.){3}\\\\d{1,3}))(\\\\:\\\\d+)?(\\\\/[-a-z\\\\d%_.~+]*)*(\\\\?[;&a-z\\\\d%_.~+=-]*)?(\\\\#[-a-z\\\\d_]*)?$')\n\t\t\t .test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine if the given value is a valid UUID.\n\t *\n\t **/\n\tisUuid(value)\n\t{\n\t\treturn new RegExp('^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$')\n\t\t\t .test(String(value).toLowerCase());\n\t}\n\n\n\n\t/**\n\t * Determine whether the given value meets the given rules.\n\t *\n\t **/\n\tis(value, rules = [])\n\t{\n\t\t// Check if no rules were specified\n\t\tif (! rules.length) return true;\n\n\t\t// Check for an optional value\n\t\tif (rules[0] === 'optional' && this.isOptional(value)) return true;\n\n\t\t// Iterate through the rules\n\t\tfor (let index in rules) {\n\n\t\t\t// Ignore optional rules\n\t\t\tif (rules[index] === 'optional') continue;\n\n\t\t\t// Determine the method to use\n\t\t\tlet rule = rules[index].split(':')[0][0].toUpperCase()\n\t\t\t\t\t + rules[index].split(':')[0].slice(1);\n\n\t\t\t// Validate the value against the method\n\t\t\tlet result = this[`is${rule}`].apply(this, [value, rules[index].split(':')[1]]);\n\n\t\t\t// Check if the value failed validation\n\t\t\tif (! result) return rules[index];\n\n\t\t}\n\n\t\t// Otherwise, the value is valid\n\t\treturn true;\n\t}\n\n\n\n\t/**\n\t * Replace the default error messages with a new set.\n\t *\n\t **/\n\tsetErrorMessages(messages)\n\t{\n\t\tthis.messages = messages;\n\t}\n\n}\n\n\n\n/**\n * Create an instance of the library.\n *\n **/\nwindow.Iodine = new Iodine();\n"],"names":["Iodine","constructor","messages","this","_defaultMessages","_dateCompare","first","second","type","equals","isDate","isInteger","getTime","after","afterOrEqual","array","before","beforeOrEqual","boolean","date","different","endingWith","email","falsy","in","integer","json","maximum","minimum","notIn","numeric","optional","regexMatch","required","same","startingWith","string","truthy","url","uuid","addRule","name","closure","prototype","toUpperCase","slice","getErrorMessage","rule","arg","undefined","key","split","param","includes","Date","parseInt","toLocaleTimeString","year","month","day","hour","minute","replace","isAfter","value","isAfterOrEqual","isArray","Array","isBefore","isBeforeOrEqual","isBoolean","Object","toString","call","isNaN","isDifferent","isEndingWith","sub","isString","endsWith","isEmail","RegExp","test","String","toLowerCase","isFalsy","isIn","options","Number","isJson","JSON","parse","e","isMaximum","limit","length","parseFloat","isMinimum","isNotIn","isNumeric","isFinite","isOptional","isRegexMatch","expression","isRequired","isSame","isStartingWith","startsWith","isTruthy","isUrl","isUuid","is","rules","let","index","apply","setErrorMessages","window"],"mappings":"0IASA,IAAMA,EAOLC,gBAEMC,SAAWC,KAAKC,gCAStBC,sBAAaC,EAAOC,EAAQC,EAAMC,0BAAS,KAEpCN,KAAKO,OAAOJ,OAEZH,KAAKO,OAAOH,KAAaJ,KAAKQ,UAAUJ,MAE9CA,EAA2B,iBAAXA,EAAsBA,EAASA,EAAOK,UAEzC,SAATJ,GAAmBC,EAAeH,EAAMM,WAAaL,EAC5C,SAATC,GAAqBC,EACZ,SAATD,GAAmBC,EAAeH,EAAMM,WAAaL,EAC5C,SAATC,GAAqBC,SAAeH,EAAMM,UAAYL,EAFlBD,EAAMM,UAAYL,gBAW3DH,kCAEQ,CACNS,MAAiB,oCACjBC,aAAiB,gDACjBC,MAAiB,yBACjBC,OAAiB,qCACjBC,cAAiB,iDACjBC,QAAiB,8BACjBC,KAAiB,uBACjBC,UAAiB,uCACjBC,WAAiB,gCACjBC,MAAiB,sCACjBC,MAAiB,yDACjBC,GAAc,sDACdC,QAAiB,2BACjBC,KAAiB,8CACjBC,QAAiB,uEACjBC,QAAiB,oEACjBC,MAAiB,0DACjBC,QAAiB,wBACjBC,SAAiB,oBACjBC,WAAiB,sDACjBC,SAAiB,wBACjBC,KAAiB,0BACjBC,aAAiB,kCACjBC,OAAiB,yBACjBC,OAAiB,wDACjBC,IAAiB,4BACjBC,KAAiB,2CAUnBC,iBAAQC,EAAMC,GAEb1C,EAAO2C,eAAeF,EAAK,GAAGG,cAAgBH,EAAKI,MAAM,IAAQH,eASlEI,yBAAgBC,EAAMC,uBAAMC,OAEvBC,EAAQH,EAAKI,MAAM,KAAK,GACxBC,EAAQJ,GAAOD,EAAKI,MAAM,KAAK,SAE/B,CAAC,QAAS,eAAgB,SAAU,iBAAiBE,SAASH,KACjEE,EAAQ,IAAIE,KAAKC,SAASH,IAAQI,wBAAmBP,EAAW,CAC/DQ,KAAM,UAAWC,MAAO,QAASC,IAAK,UAAWC,KAAM,UAAWC,OAAQ,aAIrE,CAAC,UAAMZ,GAAWI,SAASD,GAC9BjD,KAAKD,SAASgD,GACd/C,KAAKD,SAASgD,GAAKY,QAAQ,UAAWV,gBAS3CW,iBAAQC,EAAOnD,UAEPV,KAAKE,aAAa2D,EAAOnD,EAAO,QAAQ,gBAShDoD,wBAAeD,EAAOnD,UAEdV,KAAKE,aAAa2D,EAAOnD,EAAO,QAAQ,gBAShDqD,iBAAQF,UAEAG,MAAMD,QAAQF,gBAStBI,kBAASJ,EAAOhD,UAERb,KAAKE,aAAa2D,EAAOhD,EAAQ,QAAQ,gBASjDqD,yBAAgBL,EAAOhD,UAEfb,KAAKE,aAAa2D,EAAOhD,EAAQ,QAAQ,gBASjDsD,mBAAUN,SAEF,EAAC,GAAM,GAAOX,SAASW,gBAS/BtD,gBAAOsD,UAECA,GAAmD,kBAA1CO,OAAO5B,UAAU6B,SAASC,KAAKT,KAAgCU,MAAMV,gBAStFW,qBAAYX,EAAO5C,UAEX4C,GAAS5C,eASjBwD,sBAAaZ,EAAOa,UAEZ1E,KAAK2E,SAASd,IAAUA,EAAMe,SAASF,gBAS/CG,iBAAQhB,UAEA,IAAIiB,OAAO,6BAA6BC,KAAKC,OAAOnB,GAAOoB,4BASnEC,iBAAQrB,SAEA,CAAC,EAAG,KAAK,EAAO,SAASX,SAASW,gBAS1CsB,cAAKtB,EAAOuB,UAEXA,EAA6B,iBAAZA,EACbA,EAAQpC,MAAM,KACdoC,GAEWlC,SAASW,gBASzBrD,mBAAUqD,UAEFwB,OAAO7E,UAAUqD,IAAUT,SAASS,GAAOQ,aAAeR,EAAMQ,wBASxEiB,gBAAOzB,aAGqC,iBAAtB0B,KAAKC,MAAM3B,GAC9B,MAAO4B,UACD,gBAUTC,mBAAU7B,EAAO8B,UAEhB9B,EAAyB,iBAAVA,EAAqBA,EAAM+B,OAAS/B,EAE5CgC,WAAWhC,IAAU8B,eAS7BG,mBAAUjC,EAAO8B,UAEhB9B,EAAyB,iBAAVA,EAAqBA,EAAM+B,OAAS/B,EAE5CgC,WAAWhC,IAAU8B,eAS7BI,iBAAQlC,EAAOuB,UAELpF,KAAKmF,KAAKtB,EAAOuB,gBAS3BY,mBAAUnC,UAEAU,MAAMsB,WAAWhC,KAAWoC,SAASpC,gBAS/CqC,oBAAWrC,SAEH,CAAC,UAAMf,EAAW,IAAII,SAASW,gBASvCsC,sBAAatC,EAAOuC,UAEZ,IAAItB,OAAOsB,GAAYrB,KAAKC,OAAOnB,GAAOoB,4BASlDoB,oBAAWxC,UAED7D,KAAKkG,WAAWrC,gBAS1ByC,gBAAOzC,EAAO9B,UAEN8B,GAAS9B,eASjBwE,wBAAe1C,EAAOa,UAEd1E,KAAK2E,SAASd,IAAUA,EAAM2C,WAAW9B,gBASjDC,kBAASd,SAEgB,iBAAVA,eASf4C,kBAAS5C,SAED,CAAC,EAAG,KAAK,EAAM,QAAQX,SAASW,gBASxC6C,eAAM7C,UAEE,IAAIiB,OAAO,yKACfC,KAAKC,OAAOnB,GAAOoB,4BASvB0B,gBAAO9C,UAEC,IAAIiB,OAAO,6EACfC,KAAKC,OAAOnB,GAAOoB,4BASvB2B,YAAG/C,EAAOgD,qBAAQ,KAGXA,EAAMjB,OAAQ,OAAO,KAGV,aAAbiB,EAAM,IAAqB7G,KAAKkG,WAAWrC,GAAQ,OAAO,MAGzDiD,IAAIC,KAASF,KAGI,aAAjBA,EAAME,KAOG/G,WAJF6G,EAAME,GAAO/D,MAAM,KAAK,GAAG,GAAGP,cACpCoE,EAAME,GAAO/D,MAAM,KAAK,GAAGN,MAAM,KAGPsE,MAAMhH,KAAM,CAAC6D,EAAOgD,EAAME,GAAO/D,MAAM,KAAK,KAG7D,OAAO6D,EAAME,UAKrB,eASRE,0BAAiBlH,QAEXA,SAAWA,GAWlBmH,OAAOrH,OAAS,IAAIA"}
\ No newline at end of file
diff --git a/package.json b/package.json
index 594b7f6..b8d9fb2 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@kingshott/iodine",
- "version": "3.0.0",
+ "version": "3.0.1",
"description": "A micro client-side validation library",
"repository": {
"type": "git",
@@ -8,6 +8,7 @@
},
"scripts": {
"build": "microbundle",
+ "watch": "microbundle watch",
"test": "jest"
},
"main": "dist/iodine.min.js",
diff --git a/resources/version.svg b/resources/version.svg
index f473e34..18a572a 100644
--- a/resources/version.svg
+++ b/resources/version.svg
@@ -14,7 +14,7 @@
stable
stable
- v3.0.0
- v3.0.0
+ v3.0.1
+ v3.0.1
\ No newline at end of file
diff --git a/src/iodine.js b/src/iodine.js
index 12c45e0..d8aa4c4 100644
--- a/src/iodine.js
+++ b/src/iodine.js
@@ -7,7 +7,7 @@
| be used to quickly verify whether items meet certain conditions.
|
*/
-export default class Iodine
+class Iodine
{
/**
@@ -431,13 +431,13 @@ export default class Iodine
is(value, rules = [])
{
// Check if no rules were specified
- if (rules.length === 0) return true;
+ if (! rules.length) return true;
// Check for an optional value
if (rules[0] === 'optional' && this.isOptional(value)) return true;
// Iterate through the rules
- for (let index = 0; index < rules.length; index++) {
+ for (let index in rules) {
// Ignore optional rules
if (rules[index] === 'optional') continue;
@@ -477,4 +477,4 @@ export default class Iodine
* Create an instance of the library.
*
**/
-window.Iodine = new Iodine();
\ No newline at end of file
+window.Iodine = new Iodine();
diff --git a/tests/test.js b/tests/test.js
index 4fba8ef..6832ee8 100644
--- a/tests/test.js
+++ b/tests/test.js
@@ -1,5 +1,5 @@
// Import Iodine
-import '../src/iodine.js';
+import '../dist/iodine.min.js';