diff --git a/README.md b/README.md index cc9a97882..5fec17cf7 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ Validator | Description **isDate(str [, options])** | check if the string is a valid date. e.g. [`2002-07-15`, new Date()].

`options` is an object which can contain the keys `format`, `strictMode` and/or `delimiters`.

`format` is a string and defaults to `YYYY/MM/DD`.

`strictMode` is a boolean and defaults to `false`. If `strictMode` is set to true, the validator will reject strings different from `format`.

`delimiters` is an array of allowed date delimiters and defaults to `['/', '-']`. **isDecimal(str [, options])** | check if the string represents a decimal number, such as 0.1, .3, 1.1, 1.00003, 4.0, etc.

`options` is an object which defaults to `{force_decimal: false, decimal_digits: '1,', locale: 'en-US'}`.

`locale` determines the decimal separator and is one of `['ar', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-LB', 'ar-LY', 'ar-MA', 'ar-QA', 'ar-QM', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'el-GR', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'eo', 'es-ES', 'fa', 'fa-AF', 'fa-IR', 'fr-FR', 'fr-CA', 'hu-HU', 'id-ID', 'it-IT', 'ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pl-Pl', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA', 'vi-VN']`.
**Note:** `decimal_digits` is given as a range like '1,3', a specific value like '3' or min like '1,'. **isDivisibleBy(str, number)** | check if the string is a number that is divisible by another. +**isDuration(str)** | check if the string is a valid duration. e.g. [`1 week`, `2 days`, `1h`, `30m`, `15 s`].

It is designed to match the format used by the [ms](https://github.com/vercel/ms) package. **isEAN(str)** | check if the string is an [EAN (European Article Number)][European Article Number]. **isEmail(str [, options])** | check if the string is an email.

`options` is an object which defaults to `{ allow_display_name: false, require_display_name: false, allow_utf8_local_part: true, require_tld: true, allow_ip_domain: false, allow_underscores: false, domain_specific_validation: false, blacklisted_chars: '', host_blacklist: [] }`. If `allow_display_name` is set to true, the validator will also match `Display Name `. If `require_display_name` is set to true, the validator will reject strings without the format `Display Name `. If `allow_utf8_local_part` is set to false, the validator will not allow any non-English UTF8 character in email address' local part. If `require_tld` is set to false, email addresses without a TLD in their domain will also be matched. If `ignore_max_length` is set to true, the validator will not check for the standard max length of an email. If `allow_ip_domain` is set to true, the validator will allow IP addresses in the host part. If `domain_specific_validation` is true, some additional validation will be enabled, e.g. disallowing certain syntactically valid email addresses that are rejected by Gmail. If `blacklisted_chars` receives a string, then the validator will reject emails that include any of the characters in the string, in the name part. If `host_blacklist` is set to an array of strings or regexp, and the part of the email after the `@` symbol matches one of the strings defined in it, the validation fails. If `host_whitelist` is set to an array of strings or regexp, and the part of the email after the `@` symbol matches none of the strings defined in it, the validation fails. **isEmpty(str [, options])** | check if the string has a length of zero.

`options` is an object which defaults to `{ ignore_whitespace: false }`. diff --git a/src/index.js b/src/index.js index b813c6078..5cd26ba05 100644 --- a/src/index.js +++ b/src/index.js @@ -14,6 +14,7 @@ import isIPRange from './lib/isIPRange'; import isFQDN from './lib/isFQDN'; import isDate from './lib/isDate'; import isTime from './lib/isTime'; +import isDuration from './lib/isDuration'; import isBoolean from './lib/isBoolean'; import isLocale from './lib/isLocale'; @@ -245,6 +246,7 @@ const validator = { isLicensePlate, isVAT, ibanLocales, + isDuration, }; export default validator; diff --git a/src/lib/isDuration.js b/src/lib/isDuration.js new file mode 100644 index 000000000..d85fcf0d0 --- /dev/null +++ b/src/lib/isDuration.js @@ -0,0 +1,60 @@ +import assertString from './util/assertString'; + +const BaseDurationUnits = [ + 'Years', + 'Year', + 'Yrs', + 'Yr', + 'Y', + 'Weeks', + 'Week', + 'W', + 'Days', + 'Day', + 'D', + 'Hours', + 'Hour', + 'Hrs', + 'Hr', + 'H', + 'Minutes', + 'Minute', + 'Mins', + 'Min', + 'M', + 'Seconds', + 'Second', + 'Secs', + 'Sec', + 's', + 'Milliseconds', + 'Millisecond', + 'Msecs', + 'Msec', + 'Ms', +]; + +const AllDurationUnits = new Set(BaseDurationUnits.reduce((acc, unit) => acc.concat([ + unit, unit.toUpperCase(), unit.toLowerCase()]), [])); + +/** + * Checks if the string is a valid duration. + * It is designed to match the format used by the [ms](https://github.com/vercel/ms) package. + * The duration can be "1 week","2 days","1h", "30m", "15 s", etc. + */ +export default function isDuration(value) { + assertString(value); + + // Match number (integer or decimal) optionally followed by a unit + // Supports: "1", "1.5", ".5", "-1", "-1.5", "-.5", "1h", "1.5 hours", etc. + // Using indexed capture groups for Node.js <10 compatibility + const match = value.match(/^(-?(?:\d+(?:\.\d+)?|\.\d+))(?:\s?([a-zA-Z]+))?$/); + + if (!match) { + return false; + } + + const unit = match[2]; + + return unit === undefined || AllDurationUnits.has(unit); +} diff --git a/test/validators/isDuration.test.js b/test/validators/isDuration.test.js new file mode 100644 index 000000000..b3074c904 --- /dev/null +++ b/test/validators/isDuration.test.js @@ -0,0 +1,44 @@ +import { describe } from 'mocha'; +import test from '../testFunctions'; + +describe('isDuration', () => { + it('should validate duration strings', () => { + test({ + validator: 'isDuration', + valid: [ + '1 week', + '2 days', + '1h', + '30m', + '15 s', + '100ms', + '1.5h', + '2.5 weeks', + '-1d', + '-200', + ], + invalid: [ + '', + 'abc', + '1 invalid', + 'week 1', + '1.2.3h', + '+1h', // plus sign is not allowed as in `ms` package + '+200', // plus sign is not allowed as in `ms` package + ], + }); + }); + + it('should accept various unit formats', () => { + test({ + validator: 'isDuration', + valid: [ + '1 Year', + '2 WEEKS', + '3 days', + '4H', + '5m', + ], + }); + }); +});