diff --git a/README.md b/README.md index 31c6ea1..cd545ce 100755 --- a/README.md +++ b/README.md @@ -136,35 +136,35 @@ Iodine.setErrorMessages({ same: `Champ doit ĂȘtre '[PARAM]'` }); // French The following validation rules are available: -| Rule | Description | +| Rule | Description | | ----------------------------- | ------------------------------------------------------------------------------- | -| isAfter(date/integer) | Verify that the item is a `Date` after a given `Date` or timestamp -| isAfterOrEqual(date/integer) | Verify that the item is a `Date` after or equal to a given `Date` or timestamp -| isArray | Verify that the item is an `array` -| isBefore(date/integer) | Verify that the item is a `Date` before a given `Date` or timestamp +| isAfter(date/integer) | Verify that the item is a `Date` after a given `Date` or timestamp +| isAfterOrEqual(date/integer) | Verify that the item is a `Date` after or equal to a given `Date` or timestamp +| isArray | Verify that the item is an `array` +| isBefore(date/integer) | Verify that the item is a `Date` before a given `Date` or timestamp | isBeforeOrEqual(date/integer) | Verify that the item is a `Date` before or equal to a given `Date` or timestamp -| isBoolean | Verify that the item is either `true` or `false` -| isDate | Verify that the item is a `Date` object -| isDifferent(value) | Verify that the item is different to the supplied value (uses loose compare) -| isEndingWith(value) | Verify that the item ends with the given value -| isEmail | Verify that the item is a valid email address -| isFalsy | Verify that the item is either `false`, `'false'`, `0` or `'0'` -| isIn(array) | Verify that the item is within the given `array` -| isInteger | Verify that the item is an `integer` -| isJson | Verify that the item is a parsable JSON object `string` -| isMaximum(limit) | Verify that the item does not exceed the given limit (number or char length) -| isMinimum(limit) | Verify that the item is not under the given limit (number or char length) -| isNotIn(array) | Verify that the item is not within the given `array` -| isNumeric | Verify that the item is `number` or a numeric `string` -| isOptional | Allow for optional values (only for use with multiple checks) -| isRegexMatch(exp) | Verify that the item satisifies the given regular expression -| isRequired | Verify that the item is not `null`, `undefined` or an empty `string` -| isSame(value) | Verify that the item is the same as the supplied value (uses loose compare) -| isStartingWith(value) | Verify that the item starts with the given value -| isString | Verify that the item is a `string` -| isTruthy | Verify that the item is either `true`, `'true'`, `1` or `'1'` -| isUrl | Verify that the item is a valid URL -| isUuid | Verify that the item is a `UUID` +| isBoolean | Verify that the item is either `true` or `false` +| isDate | Verify that the item is a `Date` object +| isDifferent(value) | Verify that the item is different to the supplied value (uses loose compare) +| isEndingWith(value) | Verify that the item ends with the given value +| isEmail | Verify that the item is a valid email address +| isFalsy | Verify that the item is either `false`, `'false'`, `0` or `'0'` +| isIn(array) | Verify that the item is within the given `array` +| isInteger | Verify that the item is an `integer` +| isJson | Verify that the item is a parsable JSON object `string` +| isMaximum(limit) | Verify that the item does not exceed the given limit (number or char length) +| isMinimum(limit) | Verify that the item is not under the given limit (number or char length) +| isNotIn(array) | Verify that the item is not within the given `array` +| isNumeric | Verify that the item is `number` or a numeric `string` +| isOptional | Allow for optional values (only for use with multiple checks) +| isRegexMatch(exp) | Verify that the item satisifies the given regular expression +| isRequired | Verify that the item is not `null`, `undefined` or an empty `string` +| isSame(value) | Verify that the item is the same as the supplied value (uses loose compare) +| isStartingWith(value) | Verify that the item starts with the given value +| isString | Verify that the item is a `string` +| isTruthy | Verify that the item is either `true`, `'true'`, `1` or `'1'` +| isUrl | Verify that the item is a valid URL +| isUuid | Verify that the item is a `UUID` Examine the tests for examples of how to use each rule. diff --git a/dist/iodine.min.js.map b/dist/iodine.min.js.map index 132917b..05fb6f2 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*/\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 +{"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 /**\n * Constructor.\n *\n **/\n constructor()\n {\n this.messages = this._defaultMessages();\n }\n\n\n\n /**\n * @internal.\n *\n **/\n _dateCompare(first, second, type, equals = false)\n {\n if (! this.isDate(first)) return false;\n\n if (! this.isDate(second) && ! this.isInteger(second)) return false;\n\n second = typeof second === 'number' ? second : second.getTime();\n\n if (type === 'less' && equals) return first.getTime() <= second;\n if (type === 'less' && ! equals) return first.getTime() < second;\n if (type === 'more' && equals) return first.getTime() >= second;\n if (type === 'more' && ! equals) return first.getTime() > second;\n }\n\n\n\n /**\n * @internal.\n *\n **/\n _defaultMessages()\n {\n return {\n after : `The date must be after: '[PARAM]'`,\n afterOrEqual : `The date must be after or equal to: '[PARAM]'`,\n array : `Value must be an array`,\n before : `The date must be before: '[PARAM]'`,\n beforeOrEqual : `The date must be before or equal to: '[PARAM]'`,\n boolean : `Value must be true or false`,\n date : `Value must be a date`,\n different : `Value must be different to '[PARAM]'`,\n endingWith : `Value must end with '[PARAM]'`,\n email : `Value must be a valid email address`,\n falsy : `Value must be a falsy value (false, 'false', 0 or '0')`,\n in : `Value must be one of the following options: [PARAM]`,\n integer : `Value must be an integer`,\n json : `Value must be a parsable JSON object string`,\n maximum : `Value must not be greater than '[PARAM]' in size or character length`,\n minimum : `Value must not be less than '[PARAM]' in size or character length`,\n notIn : `Value must not be one of the following options: [PARAM]`,\n numeric : `Value must be numeric`,\n optional : `Value is optional`,\n regexMatch : `Value must satisify the regular expression: [PARAM]`,\n required : `Value must be present`,\n same : `Value must be '[PARAM]'`,\n startingWith : `Value must start with '[PARAM]'`,\n string : `Value must be a string`,\n truthy : `Value must be a truthy value (true, 'true', 1 or '1')`,\n url : `Value must be a valid url`,\n uuid : `Value must be a valid UUID`,\n };\n }\n\n\n\n /**\n * Attach a custom validation rule to the library.\n *\n **/\n addRule(name, closure)\n {\n Iodine.prototype[`is${name[0].toUpperCase()}${name.slice(1)}`] = closure;\n }\n\n\n\n /**\n * Retrieve an error message for the given rule.\n *\n **/\n getErrorMessage(rule, arg = undefined)\n {\n let key = rule.split(':')[0];\n let param = arg || rule.split(':')[1];\n\n if (['after', 'afterOrEqual', 'before', 'beforeOrEqual'].includes(key)) {\n param = new Date(parseInt(param)).toLocaleTimeString(undefined, {\n year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: 'numeric'\n });\n }\n\n return [null, undefined].includes(param)\n ? this.messages[key]\n : this.messages[key].replace('[PARAM]', param);\n }\n\n\n\n /**\n * Determine if the given date is after another given date.\n *\n **/\n isAfter(value, after)\n {\n return this._dateCompare(value, after, 'more', false);\n }\n\n\n\n /**\n * Determine if the given date is after or equal to another given date.\n *\n **/\n isAfterOrEqual(value, after)\n {\n return this._dateCompare(value, after, 'more', true);\n }\n\n\n\n /**\n * Determine if the given value is an array.\n *\n **/\n isArray(value)\n {\n return Array.isArray(value);\n }\n\n\n\n /**\n * Determine if the given date is before another given date.\n *\n **/\n isBefore(value, before)\n {\n return this._dateCompare(value, before, 'less', false);\n }\n\n\n\n /**\n * Determine if the given date is before or equal to another given date.\n *\n **/\n isBeforeOrEqual(value, before)\n {\n return this._dateCompare(value, before, 'less', true);\n }\n\n\n\n /**\n * Determine if the given value is a boolean.\n *\n **/\n isBoolean(value)\n {\n return [true, false].includes(value);\n }\n\n\n\n /**\n * Determine if the given value is a date object.\n *\n **/\n isDate(value)\n {\n return value && Object.prototype.toString.call(value) === '[object Date]' && ! isNaN(value);\n }\n\n\n\n /**\n * Determine if the given value is different to another given value.\n *\n **/\n isDifferent(value, different)\n {\n return value != different;\n }\n\n\n\n /**\n * Determine if the given value ends with another given value.\n *\n **/\n isEndingWith(value, sub)\n {\n return this.isString(value) && value.endsWith(sub);\n }\n\n\n\n /**\n * Determine if the given value is a valid email address.\n *\n **/\n isEmail(value)\n {\n return new RegExp('^\\\\S+@\\\\S+[\\\\.][0-9a-z]+$').test(String(value).toLowerCase());\n }\n\n\n\n /**\n * Determine if the given value is falsy.\n *\n **/\n isFalsy(value)\n {\n return [0, '0', false, 'false'].includes(value);\n }\n\n\n\n /**\n * Determine if the given value is within the given array of options.\n *\n **/\n isIn(value, options)\n {\n options = typeof options === 'string'\n ? options.split(',')\n : options;\n\n return options.includes(value);\n }\n\n\n\n /**\n * Determine if the given value is an integer.\n *\n **/\n isInteger(value)\n {\n return Number.isInteger(value) && parseInt(value).toString() === value.toString();\n }\n\n\n\n /**\n * Determine if the given value is a JSON string.\n *\n **/\n isJson(value)\n {\n try {\n return typeof JSON.parse(value) === 'object';\n } catch (e) {\n return false;\n }\n }\n\n\n\n /**\n * Determine if the given value meets the given maximum limit.\n *\n **/\n isMaximum(value, limit)\n {\n value = typeof value === 'string' ? value.length : value;\n\n return parseFloat(value) <= limit;\n }\n\n\n\n /**\n * Determine if the given value meets the given minimum limit.\n *\n **/\n isMinimum(value, limit)\n {\n value = typeof value === 'string' ? value.length : value;\n\n return parseFloat(value) >= limit;\n }\n\n\n\n /**\n * Determine if the given value is not within the given array of options.\n *\n **/\n isNotIn(value, options)\n {\n return ! this.isIn(value, options);\n }\n\n\n\n /**\n * Determine if the given value is numeric (an integer or a float).\n *\n **/\n isNumeric(value)\n {\n return ! isNaN(parseFloat(value)) && isFinite(value);\n }\n\n\n\n /**\n * Determine if the given value is optional.\n *\n **/\n isOptional(value)\n {\n return [null, undefined, ''].includes(value);\n }\n\n\n\n /**\n * Determine if the given value satisifies the given regular expression.\n *\n **/\n isRegexMatch(value, expression)\n {\n return new RegExp(expression).test(String(value).toLowerCase());\n }\n\n\n\n /**\n * Determine if the given value is present.\n *\n **/\n isRequired(value)\n {\n return ! this.isOptional(value);\n }\n\n\n\n /**\n * Determine if the given value is the same as another given value.\n *\n **/\n isSame(value, same)\n {\n return value == same;\n }\n\n\n\n /**\n * Determine if the given value starts with another given value.\n *\n **/\n isStartingWith(value, sub)\n {\n return this.isString(value) && value.startsWith(sub);\n }\n\n\n\n /**\n * Determine if the given value is a string.\n *\n **/\n isString(value)\n {\n return typeof value === 'string';\n }\n\n\n\n /**\n * Determine if the given value is truthy.\n *\n **/\n isTruthy(value)\n {\n return [1, '1', true, 'true'].includes(value);\n }\n\n\n\n /**\n * Determine if the given value is a valid URL.\n *\n **/\n isUrl(value)\n {\n 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_]*)?$')\n .test(String(value).toLowerCase());\n }\n\n\n\n /**\n * Determine if the given value is a valid UUID.\n *\n **/\n isUuid(value)\n {\n 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}$')\n .test(String(value).toLowerCase());\n }\n\n\n\n /**\n * Determine whether the given value meets the given rules.\n *\n **/\n is(value, rules = [])\n {\n if (! rules.length) return true;\n\n if (rules[0] === 'optional' && this.isOptional(value)) return true;\n\n for (let index in rules) {\n\n if (rules[index] === 'optional') continue;\n\n let rule = rules[index].split(':')[0][0].toUpperCase()\n + rules[index].split(':')[0].slice(1);\n\n let result = this[`is${rule}`].apply(this, [value, rules[index].split(':')[1]]);\n\n if (! result) return rules[index];\n\n }\n\n return true;\n }\n\n\n\n /**\n * Replace the default error messages with a new set.\n *\n **/\n setErrorMessages(messages)\n {\n this.messages = messages;\n }\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.map b/dist/iodine.min.mjs.map index 6adcd78..1eaa715 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*/\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 +{"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 /**\n * Constructor.\n *\n **/\n constructor()\n {\n this.messages = this._defaultMessages();\n }\n\n\n\n /**\n * @internal.\n *\n **/\n _dateCompare(first, second, type, equals = false)\n {\n if (! this.isDate(first)) return false;\n\n if (! this.isDate(second) && ! this.isInteger(second)) return false;\n\n second = typeof second === 'number' ? second : second.getTime();\n\n if (type === 'less' && equals) return first.getTime() <= second;\n if (type === 'less' && ! equals) return first.getTime() < second;\n if (type === 'more' && equals) return first.getTime() >= second;\n if (type === 'more' && ! equals) return first.getTime() > second;\n }\n\n\n\n /**\n * @internal.\n *\n **/\n _defaultMessages()\n {\n return {\n after : `The date must be after: '[PARAM]'`,\n afterOrEqual : `The date must be after or equal to: '[PARAM]'`,\n array : `Value must be an array`,\n before : `The date must be before: '[PARAM]'`,\n beforeOrEqual : `The date must be before or equal to: '[PARAM]'`,\n boolean : `Value must be true or false`,\n date : `Value must be a date`,\n different : `Value must be different to '[PARAM]'`,\n endingWith : `Value must end with '[PARAM]'`,\n email : `Value must be a valid email address`,\n falsy : `Value must be a falsy value (false, 'false', 0 or '0')`,\n in : `Value must be one of the following options: [PARAM]`,\n integer : `Value must be an integer`,\n json : `Value must be a parsable JSON object string`,\n maximum : `Value must not be greater than '[PARAM]' in size or character length`,\n minimum : `Value must not be less than '[PARAM]' in size or character length`,\n notIn : `Value must not be one of the following options: [PARAM]`,\n numeric : `Value must be numeric`,\n optional : `Value is optional`,\n regexMatch : `Value must satisify the regular expression: [PARAM]`,\n required : `Value must be present`,\n same : `Value must be '[PARAM]'`,\n startingWith : `Value must start with '[PARAM]'`,\n string : `Value must be a string`,\n truthy : `Value must be a truthy value (true, 'true', 1 or '1')`,\n url : `Value must be a valid url`,\n uuid : `Value must be a valid UUID`,\n };\n }\n\n\n\n /**\n * Attach a custom validation rule to the library.\n *\n **/\n addRule(name, closure)\n {\n Iodine.prototype[`is${name[0].toUpperCase()}${name.slice(1)}`] = closure;\n }\n\n\n\n /**\n * Retrieve an error message for the given rule.\n *\n **/\n getErrorMessage(rule, arg = undefined)\n {\n let key = rule.split(':')[0];\n let param = arg || rule.split(':')[1];\n\n if (['after', 'afterOrEqual', 'before', 'beforeOrEqual'].includes(key)) {\n param = new Date(parseInt(param)).toLocaleTimeString(undefined, {\n year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: 'numeric'\n });\n }\n\n return [null, undefined].includes(param)\n ? this.messages[key]\n : this.messages[key].replace('[PARAM]', param);\n }\n\n\n\n /**\n * Determine if the given date is after another given date.\n *\n **/\n isAfter(value, after)\n {\n return this._dateCompare(value, after, 'more', false);\n }\n\n\n\n /**\n * Determine if the given date is after or equal to another given date.\n *\n **/\n isAfterOrEqual(value, after)\n {\n return this._dateCompare(value, after, 'more', true);\n }\n\n\n\n /**\n * Determine if the given value is an array.\n *\n **/\n isArray(value)\n {\n return Array.isArray(value);\n }\n\n\n\n /**\n * Determine if the given date is before another given date.\n *\n **/\n isBefore(value, before)\n {\n return this._dateCompare(value, before, 'less', false);\n }\n\n\n\n /**\n * Determine if the given date is before or equal to another given date.\n *\n **/\n isBeforeOrEqual(value, before)\n {\n return this._dateCompare(value, before, 'less', true);\n }\n\n\n\n /**\n * Determine if the given value is a boolean.\n *\n **/\n isBoolean(value)\n {\n return [true, false].includes(value);\n }\n\n\n\n /**\n * Determine if the given value is a date object.\n *\n **/\n isDate(value)\n {\n return value && Object.prototype.toString.call(value) === '[object Date]' && ! isNaN(value);\n }\n\n\n\n /**\n * Determine if the given value is different to another given value.\n *\n **/\n isDifferent(value, different)\n {\n return value != different;\n }\n\n\n\n /**\n * Determine if the given value ends with another given value.\n *\n **/\n isEndingWith(value, sub)\n {\n return this.isString(value) && value.endsWith(sub);\n }\n\n\n\n /**\n * Determine if the given value is a valid email address.\n *\n **/\n isEmail(value)\n {\n return new RegExp('^\\\\S+@\\\\S+[\\\\.][0-9a-z]+$').test(String(value).toLowerCase());\n }\n\n\n\n /**\n * Determine if the given value is falsy.\n *\n **/\n isFalsy(value)\n {\n return [0, '0', false, 'false'].includes(value);\n }\n\n\n\n /**\n * Determine if the given value is within the given array of options.\n *\n **/\n isIn(value, options)\n {\n options = typeof options === 'string'\n ? options.split(',')\n : options;\n\n return options.includes(value);\n }\n\n\n\n /**\n * Determine if the given value is an integer.\n *\n **/\n isInteger(value)\n {\n return Number.isInteger(value) && parseInt(value).toString() === value.toString();\n }\n\n\n\n /**\n * Determine if the given value is a JSON string.\n *\n **/\n isJson(value)\n {\n try {\n return typeof JSON.parse(value) === 'object';\n } catch (e) {\n return false;\n }\n }\n\n\n\n /**\n * Determine if the given value meets the given maximum limit.\n *\n **/\n isMaximum(value, limit)\n {\n value = typeof value === 'string' ? value.length : value;\n\n return parseFloat(value) <= limit;\n }\n\n\n\n /**\n * Determine if the given value meets the given minimum limit.\n *\n **/\n isMinimum(value, limit)\n {\n value = typeof value === 'string' ? value.length : value;\n\n return parseFloat(value) >= limit;\n }\n\n\n\n /**\n * Determine if the given value is not within the given array of options.\n *\n **/\n isNotIn(value, options)\n {\n return ! this.isIn(value, options);\n }\n\n\n\n /**\n * Determine if the given value is numeric (an integer or a float).\n *\n **/\n isNumeric(value)\n {\n return ! isNaN(parseFloat(value)) && isFinite(value);\n }\n\n\n\n /**\n * Determine if the given value is optional.\n *\n **/\n isOptional(value)\n {\n return [null, undefined, ''].includes(value);\n }\n\n\n\n /**\n * Determine if the given value satisifies the given regular expression.\n *\n **/\n isRegexMatch(value, expression)\n {\n return new RegExp(expression).test(String(value).toLowerCase());\n }\n\n\n\n /**\n * Determine if the given value is present.\n *\n **/\n isRequired(value)\n {\n return ! this.isOptional(value);\n }\n\n\n\n /**\n * Determine if the given value is the same as another given value.\n *\n **/\n isSame(value, same)\n {\n return value == same;\n }\n\n\n\n /**\n * Determine if the given value starts with another given value.\n *\n **/\n isStartingWith(value, sub)\n {\n return this.isString(value) && value.startsWith(sub);\n }\n\n\n\n /**\n * Determine if the given value is a string.\n *\n **/\n isString(value)\n {\n return typeof value === 'string';\n }\n\n\n\n /**\n * Determine if the given value is truthy.\n *\n **/\n isTruthy(value)\n {\n return [1, '1', true, 'true'].includes(value);\n }\n\n\n\n /**\n * Determine if the given value is a valid URL.\n *\n **/\n isUrl(value)\n {\n 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_]*)?$')\n .test(String(value).toLowerCase());\n }\n\n\n\n /**\n * Determine if the given value is a valid UUID.\n *\n **/\n isUuid(value)\n {\n 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}$')\n .test(String(value).toLowerCase());\n }\n\n\n\n /**\n * Determine whether the given value meets the given rules.\n *\n **/\n is(value, rules = [])\n {\n if (! rules.length) return true;\n\n if (rules[0] === 'optional' && this.isOptional(value)) return true;\n\n for (let index in rules) {\n\n if (rules[index] === 'optional') continue;\n\n let rule = rules[index].split(':')[0][0].toUpperCase()\n + rules[index].split(':')[0].slice(1);\n\n let result = this[`is${rule}`].apply(this, [value, rules[index].split(':')[1]]);\n\n if (! result) return rules[index];\n\n }\n\n return true;\n }\n\n\n\n /**\n * Replace the default error messages with a new set.\n *\n **/\n setErrorMessages(messages)\n {\n this.messages = messages;\n }\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":"AASA,IAAMA,EAOFC,gBAESC,SAAWC,KAAKC,gCASzBC,sBAAaC,EAAOC,EAAQC,EAAMC,0BAAS,KAEjCN,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,gBAW9DH,kCAEW,CACHS,MAAiB,oCACjBC,aAAiB,gDACjBC,MAAiB,yBACjBC,OAAiB,qCACjBC,cAAiB,iDACjBC,QAAiB,8BACjBC,KAAiB,uBACjBC,UAAiB,uCACjBC,WAAiB,gCACjBC,MAAiB,sCACjBC,MAAiB,yDACjBC,GAAoB,sDACpBC,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,2CAUzBC,iBAAQC,EAAMC,GAEV1C,EAAO2C,eAAeF,EAAK,GAAGG,cAAgBH,EAAKI,MAAM,IAAQH,eASrEI,yBAAgBC,EAAMC,uBAAMC,OAEpBC,EAAQH,EAAKI,MAAM,KAAK,GACxBC,EAAQJ,GAAOD,EAAKI,MAAM,KAAK,SAE/B,CAAC,QAAS,eAAgB,SAAU,iBAAiBE,SAASH,KAC9DE,EAAQ,IAAIE,KAAKC,SAASH,IAAQI,wBAAmBP,EAAW,CAC5DQ,KAAM,UAAWC,MAAO,QAASC,IAAK,UAAWC,KAAM,UAAWC,OAAQ,aAI3E,CAAC,UAAMZ,GAAWI,SAASD,GAC3BjD,KAAKD,SAASgD,GACd/C,KAAKD,SAASgD,GAAKY,QAAQ,UAAWV,gBASjDW,iBAAQC,EAAOnD,UAEJV,KAAKE,aAAa2D,EAAOnD,EAAO,QAAQ,gBASnDoD,wBAAeD,EAAOnD,UAEXV,KAAKE,aAAa2D,EAAOnD,EAAO,QAAQ,gBASnDqD,iBAAQF,UAEGG,MAAMD,QAAQF,gBASzBI,kBAASJ,EAAOhD,UAELb,KAAKE,aAAa2D,EAAOhD,EAAQ,QAAQ,gBASpDqD,yBAAgBL,EAAOhD,UAEZb,KAAKE,aAAa2D,EAAOhD,EAAQ,QAAQ,gBASpDsD,mBAAUN,SAEC,EAAC,GAAM,GAAOX,SAASW,gBASlCtD,gBAAOsD,UAEIA,GAAmD,kBAA1CO,OAAO5B,UAAU6B,SAASC,KAAKT,KAAgCU,MAAMV,gBASzFW,qBAAYX,EAAO5C,UAER4C,GAAS5C,eASpBwD,sBAAaZ,EAAOa,UAET1E,KAAK2E,SAASd,IAAUA,EAAMe,SAASF,gBASlDG,iBAAQhB,UAEG,IAAIiB,OAAO,6BAA6BC,KAAKC,OAAOnB,GAAOoB,4BAStEC,iBAAQrB,SAEG,CAAC,EAAG,KAAK,EAAO,SAASX,SAASW,gBAS7CsB,cAAKtB,EAAOuB,UAERA,EAA6B,iBAAZA,EACPA,EAAQpC,MAAM,KACdoC,GAEKlC,SAASW,gBAS5BrD,mBAAUqD,UAECwB,OAAO7E,UAAUqD,IAAUT,SAASS,GAAOQ,aAAeR,EAAMQ,wBAS3EiB,gBAAOzB,aAGqC,iBAAtB0B,KAAKC,MAAM3B,GAC3B,MAAO4B,UACE,gBAUfC,mBAAU7B,EAAO8B,UAEb9B,EAAyB,iBAAVA,EAAqBA,EAAM+B,OAAS/B,EAE5CgC,WAAWhC,IAAU8B,eAShCG,mBAAUjC,EAAO8B,UAEb9B,EAAyB,iBAAVA,EAAqBA,EAAM+B,OAAS/B,EAE5CgC,WAAWhC,IAAU8B,eAShCI,iBAAQlC,EAAOuB,UAEFpF,KAAKmF,KAAKtB,EAAOuB,gBAS9BY,mBAAUnC,UAEGU,MAAMsB,WAAWhC,KAAWoC,SAASpC,gBASlDqC,oBAAWrC,SAEA,CAAC,UAAMf,EAAW,IAAII,SAASW,gBAS1CsC,sBAAatC,EAAOuC,UAET,IAAItB,OAAOsB,GAAYrB,KAAKC,OAAOnB,GAAOoB,4BASrDoB,oBAAWxC,UAEE7D,KAAKkG,WAAWrC,gBAS7ByC,gBAAOzC,EAAO9B,UAEH8B,GAAS9B,eASpBwE,wBAAe1C,EAAOa,UAEX1E,KAAK2E,SAASd,IAAUA,EAAM2C,WAAW9B,gBASpDC,kBAASd,SAEmB,iBAAVA,eASlB4C,kBAAS5C,SAEE,CAAC,EAAG,KAAK,EAAM,QAAQX,SAASW,gBAS3C6C,eAAM7C,UAEK,IAAIiB,OAAO,yKACZC,KAAKC,OAAOnB,GAAOoB,4BAS7B0B,gBAAO9C,UAEI,IAAIiB,OAAO,6EACZC,KAAKC,OAAOnB,GAAOoB,4BAS7B2B,YAAG/C,EAAOgD,qBAAQ,KAERA,EAAMjB,OAAQ,OAAO,KAEV,aAAbiB,EAAM,IAAqB7G,KAAKkG,WAAWrC,GAAQ,OAAO,MAEzDiD,IAAIC,KAASF,KAEO,aAAjBA,EAAME,KAKG/G,WAHF6G,EAAME,GAAO/D,MAAM,KAAK,GAAG,GAAGP,cAC9BoE,EAAME,GAAO/D,MAAM,KAAK,GAAGN,MAAM,KAEbsE,MAAMhH,KAAM,CAAC6D,EAAOgD,EAAME,GAAO/D,MAAM,KAAK,KAE7D,OAAO6D,EAAME,UAIxB,eASXE,0BAAiBlH,QAERA,SAAWA,GAWxBmH,OAAOrH,OAAS,IAAIA"} \ No newline at end of file diff --git a/dist/iodine.min.umd.js.map b/dist/iodine.min.umd.js.map index 0a85149..18707ce 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*/\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 +{"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 /**\n * Constructor.\n *\n **/\n constructor()\n {\n this.messages = this._defaultMessages();\n }\n\n\n\n /**\n * @internal.\n *\n **/\n _dateCompare(first, second, type, equals = false)\n {\n if (! this.isDate(first)) return false;\n\n if (! this.isDate(second) && ! this.isInteger(second)) return false;\n\n second = typeof second === 'number' ? second : second.getTime();\n\n if (type === 'less' && equals) return first.getTime() <= second;\n if (type === 'less' && ! equals) return first.getTime() < second;\n if (type === 'more' && equals) return first.getTime() >= second;\n if (type === 'more' && ! equals) return first.getTime() > second;\n }\n\n\n\n /**\n * @internal.\n *\n **/\n _defaultMessages()\n {\n return {\n after : `The date must be after: '[PARAM]'`,\n afterOrEqual : `The date must be after or equal to: '[PARAM]'`,\n array : `Value must be an array`,\n before : `The date must be before: '[PARAM]'`,\n beforeOrEqual : `The date must be before or equal to: '[PARAM]'`,\n boolean : `Value must be true or false`,\n date : `Value must be a date`,\n different : `Value must be different to '[PARAM]'`,\n endingWith : `Value must end with '[PARAM]'`,\n email : `Value must be a valid email address`,\n falsy : `Value must be a falsy value (false, 'false', 0 or '0')`,\n in : `Value must be one of the following options: [PARAM]`,\n integer : `Value must be an integer`,\n json : `Value must be a parsable JSON object string`,\n maximum : `Value must not be greater than '[PARAM]' in size or character length`,\n minimum : `Value must not be less than '[PARAM]' in size or character length`,\n notIn : `Value must not be one of the following options: [PARAM]`,\n numeric : `Value must be numeric`,\n optional : `Value is optional`,\n regexMatch : `Value must satisify the regular expression: [PARAM]`,\n required : `Value must be present`,\n same : `Value must be '[PARAM]'`,\n startingWith : `Value must start with '[PARAM]'`,\n string : `Value must be a string`,\n truthy : `Value must be a truthy value (true, 'true', 1 or '1')`,\n url : `Value must be a valid url`,\n uuid : `Value must be a valid UUID`,\n };\n }\n\n\n\n /**\n * Attach a custom validation rule to the library.\n *\n **/\n addRule(name, closure)\n {\n Iodine.prototype[`is${name[0].toUpperCase()}${name.slice(1)}`] = closure;\n }\n\n\n\n /**\n * Retrieve an error message for the given rule.\n *\n **/\n getErrorMessage(rule, arg = undefined)\n {\n let key = rule.split(':')[0];\n let param = arg || rule.split(':')[1];\n\n if (['after', 'afterOrEqual', 'before', 'beforeOrEqual'].includes(key)) {\n param = new Date(parseInt(param)).toLocaleTimeString(undefined, {\n year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: 'numeric'\n });\n }\n\n return [null, undefined].includes(param)\n ? this.messages[key]\n : this.messages[key].replace('[PARAM]', param);\n }\n\n\n\n /**\n * Determine if the given date is after another given date.\n *\n **/\n isAfter(value, after)\n {\n return this._dateCompare(value, after, 'more', false);\n }\n\n\n\n /**\n * Determine if the given date is after or equal to another given date.\n *\n **/\n isAfterOrEqual(value, after)\n {\n return this._dateCompare(value, after, 'more', true);\n }\n\n\n\n /**\n * Determine if the given value is an array.\n *\n **/\n isArray(value)\n {\n return Array.isArray(value);\n }\n\n\n\n /**\n * Determine if the given date is before another given date.\n *\n **/\n isBefore(value, before)\n {\n return this._dateCompare(value, before, 'less', false);\n }\n\n\n\n /**\n * Determine if the given date is before or equal to another given date.\n *\n **/\n isBeforeOrEqual(value, before)\n {\n return this._dateCompare(value, before, 'less', true);\n }\n\n\n\n /**\n * Determine if the given value is a boolean.\n *\n **/\n isBoolean(value)\n {\n return [true, false].includes(value);\n }\n\n\n\n /**\n * Determine if the given value is a date object.\n *\n **/\n isDate(value)\n {\n return value && Object.prototype.toString.call(value) === '[object Date]' && ! isNaN(value);\n }\n\n\n\n /**\n * Determine if the given value is different to another given value.\n *\n **/\n isDifferent(value, different)\n {\n return value != different;\n }\n\n\n\n /**\n * Determine if the given value ends with another given value.\n *\n **/\n isEndingWith(value, sub)\n {\n return this.isString(value) && value.endsWith(sub);\n }\n\n\n\n /**\n * Determine if the given value is a valid email address.\n *\n **/\n isEmail(value)\n {\n return new RegExp('^\\\\S+@\\\\S+[\\\\.][0-9a-z]+$').test(String(value).toLowerCase());\n }\n\n\n\n /**\n * Determine if the given value is falsy.\n *\n **/\n isFalsy(value)\n {\n return [0, '0', false, 'false'].includes(value);\n }\n\n\n\n /**\n * Determine if the given value is within the given array of options.\n *\n **/\n isIn(value, options)\n {\n options = typeof options === 'string'\n ? options.split(',')\n : options;\n\n return options.includes(value);\n }\n\n\n\n /**\n * Determine if the given value is an integer.\n *\n **/\n isInteger(value)\n {\n return Number.isInteger(value) && parseInt(value).toString() === value.toString();\n }\n\n\n\n /**\n * Determine if the given value is a JSON string.\n *\n **/\n isJson(value)\n {\n try {\n return typeof JSON.parse(value) === 'object';\n } catch (e) {\n return false;\n }\n }\n\n\n\n /**\n * Determine if the given value meets the given maximum limit.\n *\n **/\n isMaximum(value, limit)\n {\n value = typeof value === 'string' ? value.length : value;\n\n return parseFloat(value) <= limit;\n }\n\n\n\n /**\n * Determine if the given value meets the given minimum limit.\n *\n **/\n isMinimum(value, limit)\n {\n value = typeof value === 'string' ? value.length : value;\n\n return parseFloat(value) >= limit;\n }\n\n\n\n /**\n * Determine if the given value is not within the given array of options.\n *\n **/\n isNotIn(value, options)\n {\n return ! this.isIn(value, options);\n }\n\n\n\n /**\n * Determine if the given value is numeric (an integer or a float).\n *\n **/\n isNumeric(value)\n {\n return ! isNaN(parseFloat(value)) && isFinite(value);\n }\n\n\n\n /**\n * Determine if the given value is optional.\n *\n **/\n isOptional(value)\n {\n return [null, undefined, ''].includes(value);\n }\n\n\n\n /**\n * Determine if the given value satisifies the given regular expression.\n *\n **/\n isRegexMatch(value, expression)\n {\n return new RegExp(expression).test(String(value).toLowerCase());\n }\n\n\n\n /**\n * Determine if the given value is present.\n *\n **/\n isRequired(value)\n {\n return ! this.isOptional(value);\n }\n\n\n\n /**\n * Determine if the given value is the same as another given value.\n *\n **/\n isSame(value, same)\n {\n return value == same;\n }\n\n\n\n /**\n * Determine if the given value starts with another given value.\n *\n **/\n isStartingWith(value, sub)\n {\n return this.isString(value) && value.startsWith(sub);\n }\n\n\n\n /**\n * Determine if the given value is a string.\n *\n **/\n isString(value)\n {\n return typeof value === 'string';\n }\n\n\n\n /**\n * Determine if the given value is truthy.\n *\n **/\n isTruthy(value)\n {\n return [1, '1', true, 'true'].includes(value);\n }\n\n\n\n /**\n * Determine if the given value is a valid URL.\n *\n **/\n isUrl(value)\n {\n 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_]*)?$')\n .test(String(value).toLowerCase());\n }\n\n\n\n /**\n * Determine if the given value is a valid UUID.\n *\n **/\n isUuid(value)\n {\n 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}$')\n .test(String(value).toLowerCase());\n }\n\n\n\n /**\n * Determine whether the given value meets the given rules.\n *\n **/\n is(value, rules = [])\n {\n if (! rules.length) return true;\n\n if (rules[0] === 'optional' && this.isOptional(value)) return true;\n\n for (let index in rules) {\n\n if (rules[index] === 'optional') continue;\n\n let rule = rules[index].split(':')[0][0].toUpperCase()\n + rules[index].split(':')[0].slice(1);\n\n let result = this[`is${rule}`].apply(this, [value, rules[index].split(':')[1]]);\n\n if (! result) return rules[index];\n\n }\n\n return true;\n }\n\n\n\n /**\n * Replace the default error messages with a new set.\n *\n **/\n setErrorMessages(messages)\n {\n this.messages = messages;\n }\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/package.json b/package.json index b00fb48..1ba9ab5 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "@kingshott/iodine", - "version": "3.0.2", + "version": "3.0.3", "description": "A micro client-side validation library", "repository": { "type": "git", "url": "https://github.com/mattkingshott/iodine.git" }, - "keywords": [ + "keywords": [ "iodine", "validation", "data", @@ -14,7 +14,7 @@ ], "scripts": { "build": "microbundle", - "watch": "microbundle watch", + "watch": "microbundle watch", "test": "jest" }, "main": "dist/iodine.min.js", diff --git a/resources/version.svg b/resources/version.svg index e7dd202..3b7f1c3 100644 --- a/resources/version.svg +++ b/resources/version.svg @@ -14,7 +14,7 @@ stable stable - v3.0.2 - v3.0.2 + v3.0.3 + v3.0.3 \ No newline at end of file diff --git a/src/iodine.js b/src/iodine.js index d8aa4c4..c8c616e 100644 --- a/src/iodine.js +++ b/src/iodine.js @@ -10,464 +10,456 @@ class Iodine { - /** - * Constructor. - * - **/ - constructor() - { - this.messages = this._defaultMessages(); - } - - - - /** - * @internal. - * - **/ - _dateCompare(first, second, type, equals = false) - { - if (! this.isDate(first)) return false; - - if (! this.isDate(second) && ! this.isInteger(second)) return false; - - second = typeof second === 'number' ? second : second.getTime(); - - if (type === 'less' && equals) return first.getTime() <= second; - if (type === 'less' && ! equals) return first.getTime() < second; - if (type === 'more' && equals) return first.getTime() >= second; - if (type === 'more' && ! equals) return first.getTime() > second; - } - - - - /** - * @internal. - * - **/ - _defaultMessages() - { - return { - after : `The date must be after: '[PARAM]'`, - afterOrEqual : `The date must be after or equal to: '[PARAM]'`, - array : `Value must be an array`, - before : `The date must be before: '[PARAM]'`, - beforeOrEqual : `The date must be before or equal to: '[PARAM]'`, - boolean : `Value must be true or false`, - date : `Value must be a date`, - different : `Value must be different to '[PARAM]'`, - endingWith : `Value must end with '[PARAM]'`, - email : `Value must be a valid email address`, - falsy : `Value must be a falsy value (false, 'false', 0 or '0')`, - in : `Value must be one of the following options: [PARAM]`, - integer : `Value must be an integer`, - json : `Value must be a parsable JSON object string`, - maximum : `Value must not be greater than '[PARAM]' in size or character length`, - minimum : `Value must not be less than '[PARAM]' in size or character length`, - notIn : `Value must not be one of the following options: [PARAM]`, - numeric : `Value must be numeric`, - optional : `Value is optional`, - regexMatch : `Value must satisify the regular expression: [PARAM]`, - required : `Value must be present`, - same : `Value must be '[PARAM]'`, - startingWith : `Value must start with '[PARAM]'`, - string : `Value must be a string`, - truthy : `Value must be a truthy value (true, 'true', 1 or '1')`, - url : `Value must be a valid url`, - uuid : `Value must be a valid UUID`, - }; - } - - - - /** - * Attach a custom validation rule to the library. - * - **/ - addRule(name, closure) - { - Iodine.prototype[`is${name[0].toUpperCase()}${name.slice(1)}`] = closure; - } - - - - /** - * Retrieve an error message for the given rule. - * - **/ - getErrorMessage(rule, arg = undefined) - { - let key = rule.split(':')[0]; - let param = arg || rule.split(':')[1]; - - if (['after', 'afterOrEqual', 'before', 'beforeOrEqual'].includes(key)) { - param = new Date(parseInt(param)).toLocaleTimeString(undefined, { - year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: 'numeric' - }); - } - - return [null, undefined].includes(param) - ? this.messages[key] - : this.messages[key].replace("[PARAM]", param); - } - - - - /** - * Determine if the given date is after another given date. - * - **/ - isAfter(value, after) - { - return this._dateCompare(value, after, 'more', false); - } - - - - /** - * Determine if the given date is after or equal to another given date. - * - **/ - isAfterOrEqual(value, after) - { - return this._dateCompare(value, after, 'more', true); - } - - - - /** - * Determine if the given value is an array. - * - **/ - isArray(value) - { - return Array.isArray(value); - } - - - - /** - * Determine if the given date is before another given date. - * - **/ - isBefore(value, before) - { - return this._dateCompare(value, before, 'less', false); - } - - - - /** - * Determine if the given date is before or equal to another given date. - * - **/ - isBeforeOrEqual(value, before) - { - return this._dateCompare(value, before, 'less', true); - } + /** + * Constructor. + * + **/ + constructor() + { + this.messages = this._defaultMessages(); + } + + + + /** + * @internal. + * + **/ + _dateCompare(first, second, type, equals = false) + { + if (! this.isDate(first)) return false; + + if (! this.isDate(second) && ! this.isInteger(second)) return false; + + second = typeof second === 'number' ? second : second.getTime(); + + if (type === 'less' && equals) return first.getTime() <= second; + if (type === 'less' && ! equals) return first.getTime() < second; + if (type === 'more' && equals) return first.getTime() >= second; + if (type === 'more' && ! equals) return first.getTime() > second; + } + + + + /** + * @internal. + * + **/ + _defaultMessages() + { + return { + after : `The date must be after: '[PARAM]'`, + afterOrEqual : `The date must be after or equal to: '[PARAM]'`, + array : `Value must be an array`, + before : `The date must be before: '[PARAM]'`, + beforeOrEqual : `The date must be before or equal to: '[PARAM]'`, + boolean : `Value must be true or false`, + date : `Value must be a date`, + different : `Value must be different to '[PARAM]'`, + endingWith : `Value must end with '[PARAM]'`, + email : `Value must be a valid email address`, + falsy : `Value must be a falsy value (false, 'false', 0 or '0')`, + in : `Value must be one of the following options: [PARAM]`, + integer : `Value must be an integer`, + json : `Value must be a parsable JSON object string`, + maximum : `Value must not be greater than '[PARAM]' in size or character length`, + minimum : `Value must not be less than '[PARAM]' in size or character length`, + notIn : `Value must not be one of the following options: [PARAM]`, + numeric : `Value must be numeric`, + optional : `Value is optional`, + regexMatch : `Value must satisify the regular expression: [PARAM]`, + required : `Value must be present`, + same : `Value must be '[PARAM]'`, + startingWith : `Value must start with '[PARAM]'`, + string : `Value must be a string`, + truthy : `Value must be a truthy value (true, 'true', 1 or '1')`, + url : `Value must be a valid url`, + uuid : `Value must be a valid UUID`, + }; + } + + + + /** + * Attach a custom validation rule to the library. + * + **/ + addRule(name, closure) + { + Iodine.prototype[`is${name[0].toUpperCase()}${name.slice(1)}`] = closure; + } + + + + /** + * Retrieve an error message for the given rule. + * + **/ + getErrorMessage(rule, arg = undefined) + { + let key = rule.split(':')[0]; + let param = arg || rule.split(':')[1]; + + if (['after', 'afterOrEqual', 'before', 'beforeOrEqual'].includes(key)) { + param = new Date(parseInt(param)).toLocaleTimeString(undefined, { + year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: 'numeric' + }); + } + + return [null, undefined].includes(param) + ? this.messages[key] + : this.messages[key].replace('[PARAM]', param); + } + + + + /** + * Determine if the given date is after another given date. + * + **/ + isAfter(value, after) + { + return this._dateCompare(value, after, 'more', false); + } + + + + /** + * Determine if the given date is after or equal to another given date. + * + **/ + isAfterOrEqual(value, after) + { + return this._dateCompare(value, after, 'more', true); + } + + + + /** + * Determine if the given value is an array. + * + **/ + isArray(value) + { + return Array.isArray(value); + } + + + + /** + * Determine if the given date is before another given date. + * + **/ + isBefore(value, before) + { + return this._dateCompare(value, before, 'less', false); + } + + + + /** + * Determine if the given date is before or equal to another given date. + * + **/ + isBeforeOrEqual(value, before) + { + return this._dateCompare(value, before, 'less', true); + } - /** - * Determine if the given value is a boolean. - * - **/ - isBoolean(value) - { - return [true, false].includes(value); - } + /** + * Determine if the given value is a boolean. + * + **/ + isBoolean(value) + { + return [true, false].includes(value); + } - /** - * Determine if the given value is a date object. - * - **/ - isDate(value) - { - return value && Object.prototype.toString.call(value) === '[object Date]' && ! isNaN(value); - } + /** + * Determine if the given value is a date object. + * + **/ + isDate(value) + { + return value && Object.prototype.toString.call(value) === '[object Date]' && ! isNaN(value); + } - /** - * Determine if the given value is different to another given value. - * - **/ - isDifferent(value, different) - { - return value != different; - } + /** + * Determine if the given value is different to another given value. + * + **/ + isDifferent(value, different) + { + return value != different; + } - /** - * Determine if the given value ends with another given value. - * - **/ - isEndingWith(value, sub) - { - return this.isString(value) && value.endsWith(sub); - } + /** + * Determine if the given value ends with another given value. + * + **/ + isEndingWith(value, sub) + { + return this.isString(value) && value.endsWith(sub); + } - /** - * Determine if the given value is a valid email address. - * - **/ - isEmail(value) - { - return new RegExp('^\\S+@\\S+[\\.][0-9a-z]+$').test(String(value).toLowerCase()); - } + /** + * Determine if the given value is a valid email address. + * + **/ + isEmail(value) + { + return new RegExp('^\\S+@\\S+[\\.][0-9a-z]+$').test(String(value).toLowerCase()); + } - /** - * Determine if the given value is falsy. - * - **/ - isFalsy(value) - { - return [0, '0', false, 'false'].includes(value); - } + /** + * Determine if the given value is falsy. + * + **/ + isFalsy(value) + { + return [0, '0', false, 'false'].includes(value); + } - /** - * Determine if the given value is within the given array of options. - * - **/ - isIn(value, options) - { - options = typeof options === 'string' - ? options.split(",") - : options; + /** + * Determine if the given value is within the given array of options. + * + **/ + isIn(value, options) + { + options = typeof options === 'string' + ? options.split(',') + : options; - return options.includes(value); - } + return options.includes(value); + } - /** - * Determine if the given value is an integer. - * - **/ - isInteger(value) - { - return Number.isInteger(value) && parseInt(value).toString() === value.toString(); - } + /** + * Determine if the given value is an integer. + * + **/ + isInteger(value) + { + return Number.isInteger(value) && parseInt(value).toString() === value.toString(); + } - /** - * Determine if the given value is a JSON string. - * - **/ - isJson(value) - { - try { - return typeof JSON.parse(value) === 'object'; - } catch (e) { - return false; - } - } + /** + * Determine if the given value is a JSON string. + * + **/ + isJson(value) + { + try { + return typeof JSON.parse(value) === 'object'; + } catch (e) { + return false; + } + } - /** - * Determine if the given value meets the given maximum limit. - * - **/ - isMaximum(value, limit) - { - value = typeof value === 'string' ? value.length : value; + /** + * Determine if the given value meets the given maximum limit. + * + **/ + isMaximum(value, limit) + { + value = typeof value === 'string' ? value.length : value; - return parseFloat(value) <= limit; - } + return parseFloat(value) <= limit; + } - /** - * Determine if the given value meets the given minimum limit. - * - **/ - isMinimum(value, limit) - { - value = typeof value === 'string' ? value.length : value; + /** + * Determine if the given value meets the given minimum limit. + * + **/ + isMinimum(value, limit) + { + value = typeof value === 'string' ? value.length : value; - return parseFloat(value) >= limit; - } + return parseFloat(value) >= limit; + } - /** - * Determine if the given value is not within the given array of options. - * - **/ - isNotIn(value, options) - { - return ! this.isIn(value, options); - } + /** + * Determine if the given value is not within the given array of options. + * + **/ + isNotIn(value, options) + { + return ! this.isIn(value, options); + } - /** - * Determine if the given value is numeric (an integer or a float). - * - **/ - isNumeric(value) - { - return ! isNaN(parseFloat(value)) && isFinite(value); - } + /** + * Determine if the given value is numeric (an integer or a float). + * + **/ + isNumeric(value) + { + return ! isNaN(parseFloat(value)) && isFinite(value); + } - /** - * Determine if the given value is optional. - * - **/ - isOptional(value) - { - return [null, undefined, ''].includes(value); - } + /** + * Determine if the given value is optional. + * + **/ + isOptional(value) + { + return [null, undefined, ''].includes(value); + } - /** - * Determine if the given value satisifies the given regular expression. - * - **/ - isRegexMatch(value, expression) - { - return new RegExp(expression).test(String(value).toLowerCase()); - } + /** + * Determine if the given value satisifies the given regular expression. + * + **/ + isRegexMatch(value, expression) + { + return new RegExp(expression).test(String(value).toLowerCase()); + } - /** - * Determine if the given value is present. - * - **/ - isRequired(value) - { - return ! this.isOptional(value); - } + /** + * Determine if the given value is present. + * + **/ + isRequired(value) + { + return ! this.isOptional(value); + } - /** - * Determine if the given value is the same as another given value. - * - **/ - isSame(value, same) - { - return value == same; - } + /** + * Determine if the given value is the same as another given value. + * + **/ + isSame(value, same) + { + return value == same; + } - /** - * Determine if the given value starts with another given value. - * - **/ - isStartingWith(value, sub) - { - return this.isString(value) && value.startsWith(sub); - } + /** + * Determine if the given value starts with another given value. + * + **/ + isStartingWith(value, sub) + { + return this.isString(value) && value.startsWith(sub); + } - /** - * Determine if the given value is a string. - * - **/ - isString(value) - { - return typeof value === 'string'; - } + /** + * Determine if the given value is a string. + * + **/ + isString(value) + { + return typeof value === 'string'; + } - /** - * Determine if the given value is truthy. - * - **/ - isTruthy(value) - { - return [1, '1', true, 'true'].includes(value); - } + /** + * Determine if the given value is truthy. + * + **/ + isTruthy(value) + { + return [1, '1', true, 'true'].includes(value); + } - /** - * Determine if the given value is a valid URL. - * - **/ - isUrl(value) - { - 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(value).toLowerCase()); - } + /** + * Determine if the given value is a valid URL. + * + **/ + isUrl(value) + { + 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(value).toLowerCase()); + } - /** - * Determine if the given value is a valid UUID. - * - **/ - isUuid(value) - { - 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(value).toLowerCase()); - } + /** + * Determine if the given value is a valid UUID. + * + **/ + isUuid(value) + { + 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(value).toLowerCase()); + } - /** - * Determine whether the given value meets the given rules. - * - **/ - is(value, rules = []) - { - // Check if no rules were specified - if (! rules.length) return true; + /** + * Determine whether the given value meets the given rules. + * + **/ + is(value, rules = []) + { + if (! rules.length) return true; - // Check for an optional value - if (rules[0] === 'optional' && this.isOptional(value)) return true; + if (rules[0] === 'optional' && this.isOptional(value)) return true; - // Iterate through the rules - for (let index in rules) { + for (let index in rules) { - // Ignore optional rules - if (rules[index] === 'optional') continue; + if (rules[index] === 'optional') continue; - // Determine the method to use - let rule = rules[index].split(':')[0][0].toUpperCase() - + rules[index].split(':')[0].slice(1); + let rule = rules[index].split(':')[0][0].toUpperCase() + + rules[index].split(':')[0].slice(1); - // Validate the value against the method - let result = this[`is${rule}`].apply(this, [value, rules[index].split(':')[1]]); + let result = this[`is${rule}`].apply(this, [value, rules[index].split(':')[1]]); - // Check if the value failed validation - if (! result) return rules[index]; + if (! result) return rules[index]; - } + } - // Otherwise, the value is valid - return true; - } + return true; + } - /** - * Replace the default error messages with a new set. - * - **/ - setErrorMessages(messages) - { - this.messages = messages; - } + /** + * Replace the default error messages with a new set. + * + **/ + setErrorMessages(messages) + { + this.messages = messages; + } } diff --git a/tests/test.js b/tests/test.js index 6832ee8..43dedc1 100644 --- a/tests/test.js +++ b/tests/test.js @@ -1,4 +1,3 @@ -// Import Iodine import '../dist/iodine.min.js'; @@ -8,7 +7,7 @@ import '../dist/iodine.min.js'; * **/ test('it validates after date values', () => { - let year = new Date().getFullYear(); + let year = new Date().getFullYear(); expect(Iodine.isAfter(new Date(year + 1, 12, 18), new Date(year, 12, 18))).toBe(true); expect(Iodine.isAfter(new Date(year + 1, 12, 17), Date.now())).toBe(true); expect(Iodine.isAfter(new Date(`December 18, ${year + 1} 03:24:00`), new Date(year, 12, 18))).toBe(true); @@ -25,7 +24,7 @@ test('it validates after date values', () => { * **/ test('it validates after or equal date values', () => { - let year = new Date().getFullYear(); + let year = new Date().getFullYear(); expect(Iodine.isAfterOrEqual(new Date(year + 1, 12, 18), new Date(year, 12, 18))).toBe(true); expect(Iodine.isAfterOrEqual(new Date(year + 1, 12, 17), Date.now())).toBe(true); expect(Iodine.isAfterOrEqual(new Date(`December 18, ${year + 1} 03:24:00`), new Date(year, 12, 18))).toBe(true); @@ -43,7 +42,7 @@ test('it validates after or equal date values', () => { * **/ test('it validates before date values', () => { - let year = new Date().getFullYear(); + let year = new Date().getFullYear(); expect(Iodine.isBefore(new Date(year - 1, 12, 18), new Date(year, 12, 18))).toBe(true); expect(Iodine.isBefore(new Date(year - 1, 12, 17), Date.now())).toBe(true); expect(Iodine.isBefore(new Date(`December 18, ${year - 1} 03:24:00`), new Date(year, 12, 18))).toBe(true); @@ -60,7 +59,7 @@ test('it validates before date values', () => { * **/ test('it validates before or equal date values', () => { - let year = new Date().getFullYear(); + let year = new Date().getFullYear(); expect(Iodine.isBeforeOrEqual(new Date(year - 1, 12, 18), new Date(year, 12, 18))).toBe(true); expect(Iodine.isBeforeOrEqual(new Date(year - 1, 12, 17), Date.now())).toBe(true); expect(Iodine.isBeforeOrEqual(new Date(`December 18, ${year - 1} 03:24:00`), new Date(year, 12, 18))).toBe(true); @@ -398,7 +397,7 @@ test('it validates values against multiple rules', () => { * **/ test('it retrieves formatted error messages for rules', () => { - let time = Date.UTC(2020, 4, 2, 3, 17, 0); + let time = Date.UTC(2020, 4, 2, 3, 17, 0); expect(Iodine.getErrorMessage('array')).toBe('Value must be an array'); expect(Iodine.getErrorMessage('endingWith')).toBe(`Value must end with '[PARAM]'`); expect(Iodine.getErrorMessage('endingWith:world')).toBe(`Value must end with 'world'`); @@ -414,10 +413,10 @@ test('it retrieves formatted error messages for rules', () => { * **/ test('it can replace the default error messages', () => { - Iodine.setErrorMessages({ array : 'Hello world', endingWith : 'Hello, [PARAM]' }); + Iodine.setErrorMessages({ array : 'Hello world', endingWith : 'Hello, [PARAM]' }); expect(Iodine.getErrorMessage('array')).toBe('Hello world'); expect(Iodine.getErrorMessage('endingWith:John')).toBe('Hello, John'); - expect(Iodine.getErrorMessage('endingWith', "John")).toBe('Hello, John'); + expect(Iodine.getErrorMessage('endingWith', 'John')).toBe('Hello, John'); }); @@ -427,14 +426,14 @@ test('it can replace the default error messages', () => { * **/ test('it can add simple custom rules', () => { - Iodine.addRule('lowerCase', (value) => value === value.toLowerCase()); - Iodine.setErrorMessages({ lowerCase : 'Value must be in lower case' }); + Iodine.addRule('lowerCase', (value) => value === value.toLowerCase()); + Iodine.setErrorMessages({ lowerCase : 'Value must be in lower case' }); expect(Iodine.isLowerCase('hello')).toBe(true); expect(Iodine.isLowerCase('Hello')).toBe(false); expect(Iodine.isLowerCase('HELLO')).toBe(false); - expect(Iodine.is('hello', ['required', 'lowerCase'])).toBe(true); - expect(Iodine.is('Hello', ['required', 'lowerCase'])).toBe('lowerCase'); - expect(Iodine.is('HELLO', ['required', 'lowerCase'])).toBe('lowerCase'); + expect(Iodine.is('hello', ['required', 'lowerCase'])).toBe(true); + expect(Iodine.is('Hello', ['required', 'lowerCase'])).toBe('lowerCase'); + expect(Iodine.is('HELLO', ['required', 'lowerCase'])).toBe('lowerCase'); expect(Iodine.getErrorMessage('lowerCase')).toBe('Value must be in lower case'); }); @@ -445,14 +444,14 @@ test('it can add simple custom rules', () => { * **/ test('it can add advanced custom rules', () => { - Iodine.addRule('equals', (value, param) => value == param); - Iodine.setErrorMessages({ equals : `Value must be equal to '[PARAM]'` }); + Iodine.addRule('equals', (value, param) => value == param); + Iodine.setErrorMessages({ equals : `Value must be equal to '[PARAM]'` }); expect(Iodine.isEquals(1, 1)).toBe(true); expect(Iodine.isEquals(1, 2)).toBe(false); expect(Iodine.isEquals(1, 3)).toBe(false); - expect(Iodine.is(1, ['required', 'equals:1'])).toBe(true); - expect(Iodine.is(1, ['required', 'equals:2'])).toBe('equals:2'); - expect(Iodine.is(1, ['required', 'equals:3'])).toBe('equals:3'); + expect(Iodine.is(1, ['required', 'equals:1'])).toBe(true); + expect(Iodine.is(1, ['required', 'equals:2'])).toBe('equals:2'); + expect(Iodine.is(1, ['required', 'equals:3'])).toBe('equals:3'); expect(Iodine.getErrorMessage('equals:2')).toBe(`Value must be equal to '2'`); expect(Iodine.getErrorMessage('equals', 2)).toBe(`Value must be equal to '2'`); }); \ No newline at end of file