diff --git a/CHANGELOG.md b/CHANGELOG.md index aec8e38fb..6b063ff2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,92 @@ +## 13.7.0 + +### New Features + +- [#1706](https://github.com/validatorjs/validator.js/pull/1706) `isISO4217`, currency code validator @jpaya17 + +### New Features + +- [#1706](https://github.com/validatorjs/validator.js/pull/1706) `isISO4217`, currency code validator @jpaya17 + +### Fixes and Enhancements + +- [#1647](https://github.com/validatorjs/validator.js/pull/1647) `isFQDN`: add `allow_wildcard` option @fasenderos +- [#1654](https://github.com/validatorjs/validator.js/pull/1654) `isRFC3339`: Disallow prepended and appended strings to RFC 3339 date-time @jmacmahon +- [#1658](https://github.com/validatorjs/validator.js/pull/1658) maintenance: increase code coverage @tux-tn +- [#1669](https://github.com/validatorjs/validator.js/pull/1669) `IBAN` export list of country codes that implement IBAN @dror-heller @fedeci +- [#1676](https://github.com/validatorjs/validator.js/pull/1676) `isBoolean`: add `loose` option @brybrophy +- [#1697](https://github.com/validatorjs/validator.js/pull/1697) maintenance: fix npm installation error @rubiin +- [#1708](https://github.com/validatorjs/validator.js/pull/1708) `isISO31661Alpha3`: perf @jpaya17 +- [#1711](https://github.com/validatorjs/validator.js/pull/1711) `isDate`: allow users to strictly validate dates with `.` as delimiter @flymans +- [#1715](https://github.com/validatorjs/validator.js/pull/1715) `isCreditCard`: fix for Union Pay cards @shreyassai123 +- [#1718](https://github.com/validatorjs/validator.js/pull/1718) `isEmail`: replace all dots in GMail length validation @DasDingGehtNicht +- [#1721](https://github.com/validatorjs/validator.js/pull/1721) `isURL`: add `allow_fragments` and `allow_query_components` @cowboy-bebug +- [#1724](https://github.com/validatorjs/validator.js/pull/1724) `isISO31661Alpha2`: perf @jpaya17 +- [#1730](https://github.com/validatorjs/validator.js/pull/1730) `isMagnetURI` @tux-tn +- [#1738](https://github.com/validatorjs/validator.js/pull/1738) `rtrim`: remove regex to prevent ReDOS attack @tux-tn +- [#1747](https://github.com/validatorjs/validator.js/pull/1747) maintenance: run scripts in parallel for build and clean @sachinraja +- [#1748](https://github.com/validatorjs/validator.js/pull/1748) `isURL`: higher priority to `whitelist` @deepanshu2506 +- [#1751](https://github.com/validatorjs/validator.js/pull/1751) `isURL`: allow url with colon and no port @MatteoPierro +- [#1777](https://github.com/validatorjs/validator.js/pull/1777) `isUUID`: fix for `null` version argument @theteladras +- [#1799](https://github.com/validatorjs/validator.js/pull/1799) `isFQDN`: check more special chars @MatteoPierro +- [#1833](https://github.com/validatorjs/validator.js/pull/1833) `isURL`: allow URL with an empty user @MiguelSavignano +- [#1835](https://github.com/validatorjs/validator.js/pull/1835) `unescape`: fixed bug where intermediate string contains escaped @Marcholio +- [#1836](https://github.com/validatorjs/validator.js/pull/1836) `contains`: can check that string contains seed multiple times @Marcholio +- [#1844](https://github.com/validatorjs/validator.js/pull/1844) docs: add CDN instructions @luiscobits +- [#1848](https://github.com/validatorjs/validator.js/pull/1848) `isUUID`: add support for validation of `v1` and `v2` @theteladras +- [#1941](https://github.com/validatorjs/validator.js/pull/1641) `isEmail`: add `host_blacklist` option @fedeci + +### New and Improved Locales + +- `isAlpha`, `isAlphanumeric`: + - [#1716](https://github.com/validatorjs/validator.js/pull/1716) `hi-IN` @MiKr13 + - [#1837](https://github.com/validatorjs/validator.js/pull/1837) `fi-FI` @Marcholio + +- `isPassportNumber`: + - [#1656](https://github.com/validatorjs/validator.js/pull/1656) `ID` @rubiin + - [#1714](https://github.com/validatorjs/validator.js/pull/1714) `CN` @anirudhgiri + - [#1809](https://github.com/validatorjs/validator.js/pull/1809) `PL` @Ronqn + - [#1810](https://github.com/validatorjs/validator.js/pull/1810) `RU` @Theta-Dev + +- `isPostalCode`: + - [#1788](https://github.com/validatorjs/validator.js/pull/1788) `LK` @nimanthadilz + +- `isIdentityCard`: + - [#1657](https://github.com/validatorjs/validator.js/pull/1657) `TH` @tithanayut + - [#1745](https://github.com/validatorjs/validator.js/pull/1745) `PL` @wiktorwojcik112 @fedeci @tux-tn + - [#1786](https://github.com/validatorjs/validator.js/pull/1786) `LK` @nimanthadilz @tux-tn + - [#1838](https://github.com/validatorjs/validator.js/pull/1838) `FI` @Marcholio + +- `isMobilePhone`: + - [#1679](https://github.com/validatorjs/validator.js/pull/1679) `de-DE` @AnnaMariaJansen + - [#1689](https://github.com/validatorjs/validator.js/pull/1689) `vi-VN` @luisrivas + - [#1695](https://github.com/validatorjs/validator.js/pull/1695) [#1682](https://github.com/validatorjs/validator.js/pull/1682) `zh-CN` @laulujan @yisibl + - [#1734](https://github.com/validatorjs/validator.js/pull/1734) `es-VE` @islasjuanp + - [#1746](https://github.com/validatorjs/validator.js/pull/1746) `nl-BE` @divikshrivastava + - [#1765](https://github.com/validatorjs/validator.js/pull/1765) `es-CU` @pasagedev + - [#1766](https://github.com/validatorjs/validator.js/pull/1766) `es-SV`, @hereje + - [#1767](https://github.com/validatorjs/validator.js/pull/1767) `ar-PS`, @brendan-c + - [#1769](https://github.com/validatorjs/validator.js/pull/1769) `en-BM` @HackProAIT + - [#1770](https://github.com/validatorjs/validator.js/pull/1770) `dz-BT` @lakshayr003 + - [#1771](https://github.com/validatorjs/validator.js/pull/1771) `en-BW`, @mgndolan + - [#1772](https://github.com/validatorjs/validator.js/pull/1772) `fr-CM` @beckettnormington + - [#1778](https://github.com/validatorjs/validator.js/pull/1778) `en-PK` @ammad20120 @tux-tn + - [#1780](https://github.com/validatorjs/validator.js/pull/1780) `tk-TM`, @Husan-Eshonqulov + - [#1784](https://github.com/validatorjs/validator.js/pull/1784) `en-GY`, @mfkrause + - [#1785](https://github.com/validatorjs/validator.js/pull/1785) `si-LK` @Madhavi96 + - [#1797](https://github.com/validatorjs/validator.js/pull/1797) `fr-PF`, @hereje + - [#1820](https://github.com/validatorjs/validator.js/pull/1820) `en-KI`, @c-tanner + - [#1826](https://github.com/validatorjs/validator.js/pull/1826) `hu-HU` @danielTiringer + - [#1834](https://github.com/validatorjs/validator.js/pull/1834) `fr-BF`, `en-NA` @lakshayr003 + - [#1846](https://github.com/validatorjs/validator.js/pull/1846) `tg-TJ` @mgnss + +- `isLicensePlate`: + - [#1565](https://github.com/validatorjs/validator.js/pull/1565) `cs-CZ` @filiptronicek + - [#1790](https://github.com/validatorjs/validator.js/pull/1790) `fi-FI` @Marcholio + +- `isVAT`: + - [#1825](https://github.com/validatorjs/validator.js/pull/1825) `NL` @zeno4ever + #### 13.6.1 - **New features**: diff --git a/README.md b/README.md index 07e88b173..74174d0a1 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,12 @@ The library can also be installed through [bower][bower] $ bower install validator-js ``` +CDN + +```html + +``` + ## Contributors [Become a backer](https://opencollective.com/validatorjs#backer) @@ -82,11 +88,11 @@ Here is a list of the validators currently available. Validator | Description --------------------------------------- | -------------------------------------- -**contains(str, seed [, options ])** | check if the string contains the seed.

`options` is an object that defaults to `{ ignoreCase: false}`.
`ignoreCase` specified whether the case of the substring be same or not. +**contains(str, seed [, options ])** | check if the string contains the seed.

`options` is an object that defaults to `{ ignoreCase: false, minOccurrences: 1 }`.
Options:
`ignoreCase`: Ignore case when doing comparison, default false
`minOccurences`: Minimum number of occurrences for the seed in the string. Defaults to 1. **equals(str, comparison)** | check if the string matches the comparison. **isAfter(str [, date])** | check if the string is a date that's after the specified date (defaults to now). -**isAlpha(str [, locale, options])** | check if the string contains only letters (a-zA-Z).

Locale 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', 'es-ES', 'fa-IR', 'fr-CA', 'fr-FR', 'he', 'hi-IN', 'hu-HU', 'it-IT', 'ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sk-SK', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`) and defaults to `en-US`. Locale list is `validator.isAlphaLocales`. options is an optional object that can be supplied with the following key(s): ignore which can either be a String or RegExp of characters to be ignored e.g. " -" will ignore spaces and -'s. -**isAlphanumeric(str [, locale, options])** | check if the string contains only letters and numbers (a-zA-Z0-9).

Locale 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', 'es-ES', 'fa-IR', 'fr-CA', 'fr-FR', 'he', 'hi-IN', 'hu-HU', 'it-IT', 'ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sk-SK', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`) and defaults to `en-US`. Locale list is `validator.isAlphanumericLocales`. options is an optional object that can be supplied with the following key(s): ignore which can either be a String or RegExp of characters to be ignored e.g. " -" will ignore spaces and -'s. +**isAlpha(str [, locale, options])** | check if the string contains only letters (a-zA-Z).

Locale 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', 'es-ES', 'fa-IR', 'fi-FI', 'fr-CA', 'fr-FR', 'he', 'hi-IN', 'hu-HU', 'it-IT', 'ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sk-SK', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`) and defaults to `en-US`. Locale list is `validator.isAlphaLocales`. options is an optional object that can be supplied with the following key(s): ignore which can either be a String or RegExp of characters to be ignored e.g. " -" will ignore spaces and -'s. +**isAlphanumeric(str [, locale, options])** | check if the string contains only letters and numbers (a-zA-Z0-9).

Locale 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', 'es-ES', 'fa-IR', 'fi-FI', 'fr-CA', 'fr-FR', 'he', 'hi-IN', 'hu-HU', 'it-IT', 'ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sk-SK', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`) and defaults to `en-US`. Locale list is `validator.isAlphanumericLocales`. options is an optional object that can be supplied with the following key(s): ignore which can either be a String or RegExp of characters to be ignored e.g. " -" will ignore spaces and -'s. **isAscii(str)** | check if the string contains ASCII chars only. **isBase32(str)** | check if a string is base32 encoded. **isBase58(str)** | check if a string is base58 encoded. @@ -107,7 +113,7 @@ Validator | Description **isEmpty(str [, options])** | check if the string has a length of zero.

`options` is an object which defaults to `{ ignore_whitespace:false }`. **isEthereumAddress(str)** | check if the string is an [Ethereum](https://ethereum.org/) address using basic regex. Does not validate address checksums. **isFloat(str [, options])** | check if the string is a float.

`options` is an object which can contain the keys `min`, `max`, `gt`, and/or `lt` to validate the float is within boundaries (e.g. `{ min: 7.22, max: 9.55 }`) it also has `locale` as an option.

`min` and `max` are equivalent to 'greater or equal' and 'less or equal', respectively while `gt` and `lt` are their strict counterparts.

`locale` determine 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', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'es-ES', 'fr-CA', 'fr-FR', 'hu-HU', 'it-IT', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`. Locale list is `validator.isFloatLocales`. -**isFQDN(str [, options])** | check if the string is a fully qualified domain name (e.g. domain.com).

`options` is an object which defaults to `{ require_tld: true, allow_underscores: false, allow_trailing_dot: false , allow_numeric_tld: false }`. +**isFQDN(str [, options])** | check if the string is a fully qualified domain name (e.g. domain.com).

`options` is an object which defaults to `{ require_tld: true, allow_underscores: false, allow_trailing_dot: false, allow_numeric_tld: false, allow_wildcard: false }`. If `allow_wildcard` is set to true, the validator will allow domain starting with `*.` (e.g. `*.example.com` or `*.shop.example.com`). **isFullWidth(str)** | check if the string contains any full-width chars. **isHalfWidth(str)** | check if the string contains any half-width chars. **isHash(str, algorithm)** | check if the string is a hash of type algorithm.

Algorithm is one of `['md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'ripemd128', 'ripemd160', 'tiger128', 'tiger160', 'tiger192', 'crc32', 'crc32b']` @@ -115,7 +121,7 @@ Validator | Description **isHexColor(str)** | check if the string is a hexadecimal color. **isHSL(str)** | check if the string is an HSL (hue, saturation, lightness, optional alpha) color based on [CSS Colors Level 4 specification](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).

Comma-separated format supported. Space-separated format supported with the exception of a few edge cases (ex: `hsl(200grad+.1%62%/1)`). **isIBAN(str)** | check if a string is a IBAN (International Bank Account Number). -**isIdentityCard(str [, locale])** | check if the string is a valid identity card code.

`locale` is one of `['PL', 'ES', 'IN', 'IT', 'IR', 'MZ', 'NO', 'TH', 'zh-TW', 'he-IL', 'ar-LY', 'ar-TN', 'zh-CN']` OR `'any'`. If 'any' is used, function will check if any of the locals match.

Defaults to 'any'. +**isIdentityCard(str [, locale])** | check if the string is a valid identity card code.

`locale` is one of `['LK', 'PL', 'ES', 'FI', 'IN', 'IT', 'IR', 'MZ', 'NO', 'TH', 'zh-TW', 'he-IL', 'ar-LY', 'ar-TN', 'zh-CN']` OR `'any'`. If 'any' is used, function will check if any of the locals match.

Defaults to 'any'. **isIMEI(str [, options]))** | check if the string is a valid IMEI number. Imei should be of format `###############` or `##-######-######-#`.

`options` is an object which can contain the keys `allow_hyphens`. Defaults to first format . If allow_hyphens is set to true, the validator will validate the second format. **isIn(str, values)** | check if the string is in a array of allowed values. **isInt(str [, options])** | check if the string is an integer.

`options` is an object which can contain the keys `min` and/or `max` to check the integer is within boundaries (e.g. `{ min: 10, max: 99 }`). `options` can also contain the key `allow_leading_zeroes`, which when set to false will disallow integer values with leading zeroes (e.g. `{ allow_leading_zeroes: false }`). Finally, `options` can contain the keys `gt` and/or `lt` which will enforce integers being greater than or less than, respectively, the value provided (e.g. `{gt: 1, lt: 4}` for a number between 1 and 4). @@ -133,21 +139,21 @@ Validator | Description **isJWT(str)** | check if the string is valid JWT token. **isLatLong(str [, options])** | check if the string is a valid latitude-longitude coordinate in the format `lat,long` or `lat, long`.

`options` is an object that defaults to `{ checkDMS: false }`. Pass `checkDMS` as `true` to validate DMS(degrees, minutes, and seconds) latitude-longitude format. **isLength(str [, options])** | check if the string's length falls in a range.

`options` is an object which defaults to `{min:0, max: undefined}`. Note: this function takes into account surrogate pairs. -**isLicensePlate(str [, locale])** | check if string matches the format of a country's license plate.

(locale is one of `['cs-CZ', 'de-DE', 'de-LI', 'pt-PT', 'sq-AL', 'pt-BR']` or `any`) +**isLicensePlate(str [, locale])** | check if string matches the format of a country's license plate.

(locale is one of `['cs-CZ', 'de-DE', 'de-LI', 'fi-FI', pt-PT', 'sq-AL', 'pt-BR']` or `any`) **isLocale(str)** | check if the string is a locale **isLowercase(str)** | check if the string is lowercase. **isMACAddress(str)** | check if the string is a MAC address.

`options` is an object which defaults to `{no_separators: false}`. If `no_separators` is true, the validator will allow MAC addresses without separators. Also, it allows the use of hyphens, spaces or dots e.g '01 02 03 04 05 ab', '01-02-03-04-05-ab' or '0102.0304.05ab'. **isMagnetURI(str)** | check if the string is a [magnet uri format](https://en.wikipedia.org/wiki/Magnet_URI_scheme). **isMD5(str)** | check if the string is a MD5 hash.

Please note that you can also use the `isHash(str, 'md5')` function. Keep in mind that MD5 has some collision weaknesses compared to other algorithms (e.g., SHA). **isMimeType(str)** | check if the string matches to a valid [MIME type](https://en.wikipedia.org/wiki/Media_type) format -**isMobilePhone(str [, locale [, options]])** | check if the string is a mobile phone number,

(locale is either an array of locales (e.g `['sk-SK', 'sr-RS']`) OR one of `['am-Am', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', ar-JO', 'ar-KW', 'ar-SA', 'ar-SY', 'ar-TN', 'az-AZ', 'az-LY', 'az-LB', 'bs-BA', 'be-BY', 'bg-BG', 'bn-BD', 'ca-AD', 'cs-CZ', 'da-DK', 'de-DE', 'de-AT', 'de-CH', 'de-LU', 'el-GR', 'en-AU', 'en-CA', 'en-GB', 'en-GG', 'en-GH', 'en-HK', 'en-MO', 'en-IE', 'en-IN', 'en-KE', 'en-MT', 'en-MU', 'en-NG', 'en-NZ', 'en-PK', 'en-PH', 'en-RW', 'en-SG', 'en-SL', 'en-UG', 'en-US', 'en-TZ', 'en-ZA', 'en-ZM', 'en-ZW', 'es-AR', 'es-BO', 'es-CL', 'es-CO', 'es-CR', 'es-DO', 'es-HN', 'es-PE', 'es-EC', 'es-ES', 'es-MX', 'es-PA', 'es-PY', 'es-UY', 'es-VE', 'et-EE', 'fa-IR', 'fi-FI', 'fj-FJ', 'fo-FO', 'fr-BE', 'fr-FR', 'fr-GF', 'fr-GP', 'fr-MQ', 'fr-RE', 'ga-IE', 'he-IL', 'hu-HU', 'id-ID', 'it-IT', 'it-SM', 'ja-JP', 'ka-GE', 'kk-KZ', 'kl-GL', 'ko-KR', 'lt-LT', 'ms-MY', 'my-MM', ''mz-MZ', nb-NO', 'ne-NP', 'nl-BE', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'pt-AO', 'ro-RO', 'ru-RU', 'si-LK' 'sl-SI', 'sk-SK', 'sq-AL', 'sr-RS', 'sv-SE', 'th-TH', 'tr-TR', 'uk-UA', 'uz-UZ', 'vi-VN', 'zh-CN', 'zh-HK', 'zh-MO', 'zh-TW']` OR defaults to 'any'. If 'any' or a falsey value is used, function will check if any of the locales match).

`options` is an optional object that can be supplied with the following keys: `strictMode`, if this is set to `true`, the mobile phone number must be supplied with the country code and therefore must start with `+`. Locale list is `validator.isMobilePhoneLocales`. +**isMobilePhone(str [, locale [, options]])** | check if the string is a mobile phone number,

(locale is either an array of locales (e.g `['sk-SK', 'sr-RS']`) OR one of `['am-Am', 'ar-AE', 'ar-BH', 'ar-DZ', 'ar-EG', 'ar-IQ', ar-JO', 'ar-KW', 'ar-PS', 'ar-SA', 'ar-SY', 'ar-TN', 'az-AZ', 'az-LY', 'az-LB', 'bs-BA', 'be-BY', 'bg-BG', 'bn-BD', 'ca-AD', 'cs-CZ', 'da-DK', 'de-DE', 'de-AT', 'de-CH', 'de-LU', 'dv-MV', 'el-GR', 'en-AU', 'en-BM', 'en-BW', 'en-CA', 'en-GB', 'en-GG', 'en-GH', 'en-GY', 'en-HK', 'en-MO', 'en-IE', 'en-IN', 'en-KE', 'en-KI', 'en-MT', 'en-MU', 'en-NG', 'en-NZ', 'en-PK', 'en-PH', 'en-RW', 'en-SG', 'en-SL', 'en-UG', 'en-US', 'en-TZ', 'en-ZA', 'en-ZM', 'en-ZW', 'es-AR', 'es-BO', 'es-CL', 'es-CO', 'es-CR', 'es-CU', 'es-DO', 'es-HN', 'es-PE', 'es-EC', 'es-ES', 'es-MX', 'es-PA', 'es-PY', 'es-SV', 'es-UY', 'es-VE', 'et-EE', 'fa-IR', 'fi-FI', 'fj-FJ', 'fo-FO', 'fr-BE', 'fr-BF', 'fr-FR', 'fr-GF', 'fr-GP', 'fr-MQ', 'fr-PF', 'fr-RE', 'ga-IE', 'he-IL', 'hu-HU', 'id-ID', 'it-IT', 'it-SM', 'ja-JP', 'ka-GE', 'kk-KZ', 'kl-GL', 'ko-KR', 'lt-LT', 'ms-MY', 'my-MM', 'mz-MZ', nb-NO', 'ne-NP', 'nl-BE', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'pt-AO', 'ro-RO', 'ru-RU', 'si-LK' 'sl-SI', 'sk-SK', 'sq-AL', 'sr-RS', 'sv-SE', 'tg-TJ', 'th-TH', 'tk-TM', 'tr-TR', 'uk-UA', 'uz-UZ', 'vi-VN', 'zh-CN', 'zh-HK', 'zh-MO', 'zh-TW', 'dz-BT']` OR defaults to 'any'. If 'any' or a falsey value is used, function will check if any of the locales match).

`options` is an optional object that can be supplied with the following keys: `strictMode`, if this is set to `true`, the mobile phone number must be supplied with the country code and therefore must start with `+`. Locale list is `validator.isMobilePhoneLocales`. **isMongoId(str)** | check if the string is a valid hex-encoded representation of a [MongoDB ObjectId][mongoid]. **isMultibyte(str)** | check if the string contains one or more multibyte chars. **isNumeric(str [, options])** | check if the string contains only numbers.

`options` is an object which defaults to `{no_symbols: false}` it also has locale as an option. If `no_symbols` is true, the validator will reject numeric strings that feature a symbol (e.g. `+`, `-`, or `.`).

`locale` determine 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', 'en-AU', 'en-GB', 'en-HK', 'en-IN', 'en-NZ', 'en-US', 'en-ZA', 'en-ZM', 'es-ES', 'fr-FR', 'fr-CA', 'hu-HU', 'it-IT', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'sl-SI', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'tr-TR', 'uk-UA']`. **isOctal(str)** | check if the string is a valid octal number. -**isPassportNumber(str, countryCode)** | check if the string is a valid passport number.

(countryCode is one of `[ 'AM', 'AR', 'AT', 'AU', 'BE', 'BG', 'BY', 'BR', 'CA', 'CH', 'CN', 'CY', 'CZ', 'DE', 'DK', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'IE' 'IN', 'IR', 'ID', 'IS', 'IT', 'JP', 'KR', 'LT', 'LU', 'LV', 'LY', 'MT', 'MY', 'MZ', 'NL', 'PO', 'PT', 'RO', 'RU', 'SE', 'SL', 'SK', 'TR', 'UA', 'US' ]`. +**isPassportNumber(str, countryCode)** | check if the string is a valid passport number.

(countryCode is one of `[ 'AM', 'AR', 'AT', 'AU', 'BE', 'BG', 'BY', 'BR', 'CA', 'CH', 'CN', 'CY', 'CZ', 'DE', 'DK', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'IE' 'IN', 'IR', 'ID', 'IS', 'IT', 'JP', 'KR', 'LT', 'LU', 'LV', 'LY', 'MT', 'MY', 'MZ', 'NL', 'PL', 'PT', 'RO', 'RU', 'SE', 'SL', 'SK', 'TR', 'UA', 'US' ]`. **isPort(str)** | check if the string is a valid port number. -**isPostalCode(str, locale)** | check if the string is a postal code,

(locale is one of `[ 'AD', 'AT', 'AU', 'AZ', 'BE', 'BG', 'BR', 'BY', 'CA', 'CH', 'CN', 'CZ', 'DE', 'DK', 'DO', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HT', 'HU', 'ID', 'IE' 'IL', 'IN', 'IR', 'IS', 'IT', 'JP', 'KE', 'KR', 'LI', 'LT', 'LU', 'LV', 'MT', 'MX', 'MY', 'NL', 'NO', 'NP', 'NZ', 'PL', 'PR', 'PT', 'RO', 'RU', 'SA', 'SE', 'SG', 'SI', 'TH', 'TN', 'TW', 'UA', 'US', 'ZA', 'ZM' ]` OR 'any'. If 'any' is used, function will check if any of the locals match. Locale list is `validator.isPostalCodeLocales`.). +**isPostalCode(str, locale)** | check if the string is a postal code,

(locale is one of `[ 'AD', 'AT', 'AU', 'AZ', 'BE', 'BG', 'BR', 'BY', 'CA', 'CH', 'CN', 'CZ', 'DE', 'DK', 'DO', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HT', 'HU', 'ID', 'IE' 'IL', 'IN', 'IR', 'IS', 'IT', 'JP', 'KE', 'KR', 'LI', 'LK', 'LT', 'LU', 'LV', 'MT', 'MX', 'MY', 'NL', 'NO', 'NP', 'NZ', 'PL', 'PR', 'PT', 'RO', 'RU', 'SA', 'SE', 'SG', 'SI', 'TH', 'TN', 'TW', 'UA', 'US', 'ZA', 'ZM' ]` OR 'any'. If 'any' is used, function will check if any of the locals match. Locale list is `validator.isPostalCodeLocales`.). **isRFC3339(str)** | check if the string is a valid [RFC 3339](https://tools.ietf.org/html/rfc3339) date. **isRgbColor(str [, includePercentValues])** | check if the string is a rgb or rgba color.

`includePercentValues` defaults to `true`. If you don't want to allow to set `rgb` or `rgba` values with percents, like `rgb(5%,5%,5%)`, or `rgba(90%,90%,90%,.3)`, then set it to false. **isSemVer(str)** | check if the string is a Semantic Versioning Specification (SemVer). @@ -157,9 +163,9 @@ Validator | Description **isStrongPassword(str [, options])** | Check if a password is strong or not. Allows for custom requirements or scoring rules. If `returnScore` is true, then the function returns an integer score for the password rather than a boolean.
Default options:
`{ minLength: 8, minLowercase: 1, minUppercase: 1, minNumbers: 1, minSymbols: 1, returnScore: false, pointsPerUnique: 1, pointsPerRepeat: 0.5, pointsForContainingLower: 10, pointsForContainingUpper: 10, pointsForContainingNumber: 10, pointsForContainingSymbol: 10 }` **isTaxID(str, locale)** | Check if the given value is a valid Tax Identification Number. Default locale is `en-US`.

More info about exact TIN support can be found in `src/lib/isTaxID.js`

Supported locales: `[ 'bg-BG', 'cs-CZ', 'de-AT', 'de-DE', 'dk-DK', 'el-CY', 'el-GR', 'en-GB', 'en-IE', 'en-US', 'es-ES', 'et-EE', 'fi-FI', 'fr-BE', 'fr-FR', 'fr-LU', 'hr-HR', 'hu-HU', 'it-IT', 'lb-LU', 'lt-LT', 'lv-LV' 'mt-MT', 'nl-BE', 'nl-NL', 'pl-PL', 'pt-BR', 'pt-PT', 'ro-RO', 'sk-SK', 'sl-SI', 'sv-SE' ]` **isURL(str [, options])** | check if the string is an URL.

`options` is an object which defaults to `{ protocols: ['http','https','ftp'], require_tld: true, require_protocol: false, require_host: true, require_port: false, require_valid_protocol: true, allow_underscores: false, host_whitelist: false, host_blacklist: false, allow_trailing_dot: false, allow_protocol_relative_urls: false, allow_fragments: true, allow_query_components: true, disallow_auth: false, validate_length: true }`.

require_protocol - if set as true isURL will return false if protocol is not present in the URL.
require_valid_protocol - isURL will check if the URL's protocol is present in the protocols option.
protocols - valid protocols can be modified with this option.
require_host - if set as false isURL will not check if host is present in the URL.
require_port - if set as true isURL will check if port is present in the URL.
allow_protocol_relative_urls - if set as true protocol relative URLs will be allowed.
allow_fragments - if set as false isURL will return false if fragments are present.
allow_query_components - if set as false isURL will return false if query components are present.
validate_length - if set as false isURL will skip string length validation (2083 characters is IE max URL length). -**isUUID(str [, version])** | check if the string is a UUID (version 3, 4 or 5). +**isUUID(str [, version])** | check if the string is a UUID (version 1, 2, 3, 4 or 5). **isVariableWidth(str)** | check if the string contains a mixture of full and half-width chars. -**isVAT(str, countryCode)** | checks that the string is a [valid VAT number](https://en.wikipedia.org/wiki/VAT_identification_number) if validation is available for the given country code matching [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2).

Available country codes: `[ 'GB', 'IT' ]`. +**isVAT(str, countryCode)** | checks that the string is a [valid VAT number](https://en.wikipedia.org/wiki/VAT_identification_number) if validation is available for the given country code matching [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2).

Available country codes: `[ 'GB', 'IT','NL' ]`. **isWhitelisted(str, chars)** | checks characters if they appear in the whitelist. **matches(str, pattern [, modifiers])** | check if string matches the pattern.

Either `matches('foo', /foo/i)` or `matches('foo', 'foo', 'i')`. diff --git a/package.json b/package.json index a912c032a..7d505205e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "validator", "description": "String validation and sanitization", - "version": "13.6.0", + "version": "13.7.0", "sideEffects": false, "homepage": "https://github.com/validatorjs/validator.js", "files": [ diff --git a/src/index.js b/src/index.js index a0e8aa63c..b8ad651ee 100644 --- a/src/index.js +++ b/src/index.js @@ -121,7 +121,7 @@ import isStrongPassword from './lib/isStrongPassword'; import isVAT from './lib/isVAT'; -const version = '13.6.0'; +const version = '13.7.0'; const validator = { version, diff --git a/src/lib/alpha.js b/src/lib/alpha.js index 27d3fbc6c..d663eded0 100644 --- a/src/lib/alpha.js +++ b/src/lib/alpha.js @@ -8,6 +8,7 @@ export const alpha = { 'el-GR': /^[Α-ώ]+$/i, 'es-ES': /^[A-ZÁÉÍÑÓÚÜ]+$/i, 'fa-IR': /^[ابپتثجچحخدذرزژسشصضطظعغفقکگلمنوهی]+$/i, + 'fi-FI': /^[A-ZÅÄÖ]+$/i, 'fr-FR': /^[A-ZÀÂÆÇÉÈÊËÏÎÔŒÙÛÜŸ]+$/i, 'it-IT': /^[A-ZÀÉÈÌÎÓÒÙ]+$/i, 'nb-NO': /^[A-ZÆØÅ]+$/i, @@ -42,6 +43,7 @@ export const alphanumeric = { 'de-DE': /^[0-9A-ZÄÖÜß]+$/i, 'el-GR': /^[0-9Α-ω]+$/i, 'es-ES': /^[0-9A-ZÁÉÍÑÓÚÜ]+$/i, + 'fi-FI': /^[0-9A-ZÅÄÖ]+$/i, 'fr-FR': /^[0-9A-ZÀÂÆÇÉÈÊËÏÎÔŒÙÛÜŸ]+$/i, 'it-IT': /^[0-9A-ZÀÉÈÌÎÓÒÙ]+$/i, 'hu-HU': /^[0-9A-ZÁÉÍÓÖŐÚÜŰ]+$/i, diff --git a/src/lib/contains.js b/src/lib/contains.js index ec083fa18..7be314b04 100644 --- a/src/lib/contains.js +++ b/src/lib/contains.js @@ -4,12 +4,16 @@ import merge from './util/merge'; const defaulContainsOptions = { ignoreCase: false, + minOccurrences: 1, }; export default function contains(str, elem, options) { assertString(str); options = merge(options, defaulContainsOptions); - return options.ignoreCase ? - str.toLowerCase().indexOf(toString(elem).toLowerCase()) >= 0 : - str.indexOf(toString(elem)) >= 0; + + if (options.ignoreCase) { + return str.toLowerCase().split(toString(elem).toLowerCase()).length > options.minOccurrences; + } + + return str.split(toString(elem)).length > options.minOccurrences; } diff --git a/src/lib/isFQDN.js b/src/lib/isFQDN.js index 3dff7d2fd..4a04cf34e 100644 --- a/src/lib/isFQDN.js +++ b/src/lib/isFQDN.js @@ -6,6 +6,7 @@ const default_fqdn_options = { allow_underscores: false, allow_trailing_dot: false, allow_numeric_tld: false, + allow_wildcard: false, }; export default function isFQDN(str, options) { @@ -16,6 +17,12 @@ export default function isFQDN(str, options) { if (options.allow_trailing_dot && str[str.length - 1] === '.') { str = str.substring(0, str.length - 1); } + + /* Remove the optional wildcard before checking validity */ + if (options.allow_wildcard === true && str.indexOf('*.') === 0) { + str = str.substring(2); + } + const parts = str.split('.'); const tld = parts[parts.length - 1]; @@ -25,12 +32,12 @@ export default function isFQDN(str, options) { return false; } - if (!/^([a-z\u00a1-\uffff]{2,}|xn[a-z0-9-]{2,})$/i.test(tld)) { + if (!/^([a-z\u00A1-\u00A8\u00AA-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]{2,}|xn[a-z0-9-]{2,})$/i.test(tld)) { return false; } - // disallow spaces && special characers - if (/[\s\u2002-\u200B\u202F\u205F\u3000\uFEFF\uDB40\uDC20\u00A9\uFFFD]/.test(tld)) { + // disallow spaces + if (/\s/.test(tld)) { return false; } } diff --git a/src/lib/isIdentityCard.js b/src/lib/isIdentityCard.js index 8ea15e262..9dc1302ad 100644 --- a/src/lib/isIdentityCard.js +++ b/src/lib/isIdentityCard.js @@ -63,6 +63,26 @@ const validators = { return sanitized.endsWith(controlDigits[number % 23]); }, + FI: (str) => { + // https://dvv.fi/en/personal-identity-code#:~:text=control%20character%20for%20a-,personal,-identity%20code%20calculated + assertString(str); + + if (str.length !== 11) { + return false; + } + + if (!str.match(/^\d{6}[\-A\+]\d{3}[0-9ABCDEFHJKLMNPRSTUVWXY]{1}$/)) { + return false; + } + + const checkDigits = '0123456789ABCDEFHJKLMNPRSTUVWXY'; + + const idAsNumber = (parseInt(str.slice(0, 6), 10) * 1000) + parseInt(str.slice(7, 10), 10); + const remainder = idAsNumber % 31; + const checkDigit = checkDigits[remainder]; + + return checkDigit === str.slice(10, 11); + }, IN: (str) => { const DNI = /^[1-9]\d{3}\s?\d{4}\s?\d{4}$/; @@ -160,6 +180,14 @@ const validators = { } return str[12] === ((11 - (sum % 11)) % 10).toString(); }, + LK: (str) => { + const old_nic = /^[1-9]\d{8}[vx]$/i; + const new_nic = /^[1-9]\d{11}$/i; + + if (str.length === 10 && old_nic.test(str)) return true; + else if (str.length === 12 && new_nic.test(str)) return true; + return false; + }, 'he-IL': (str) => { const DNI = /^\d{9}$/; diff --git a/src/lib/isLicensePlate.js b/src/lib/isLicensePlate.js index d81995bff..d6b27a5ad 100644 --- a/src/lib/isLicensePlate.js +++ b/src/lib/isLicensePlate.js @@ -6,6 +6,7 @@ const validators = { 'de-DE': str => /^((AW|UL|AK|GA|AÖ|LF|AZ|AM|AS|ZE|AN|AB|A|KG|KH|BA|EW|BZ|HY|KM|BT|HP|B|BC|BI|BO|FN|TT|ÜB|BN|AH|BS|FR|HB|ZZ|BB|BK|BÖ|OC|OK|CW|CE|C|CO|LH|CB|KW|LC|LN|DA|DI|DE|DH|SY|NÖ|DO|DD|DU|DN|D|EI|EA|EE|FI|EM|EL|EN|PF|ED|EF|ER|AU|ZP|E|ES|NT|EU|FL|FO|FT|FF|F|FS|FD|FÜ|GE|G|GI|GF|GS|ZR|GG|GP|GR|NY|ZI|GÖ|GZ|GT|HA|HH|HM|HU|WL|HZ|WR|RN|HK|HD|HN|HS|GK|HE|HF|RZ|HI|HG|HO|HX|IK|IL|IN|J|JL|KL|KA|KS|KF|KE|KI|KT|KO|KN|KR|KC|KU|K|LD|LL|LA|L|OP|LM|LI|LB|LU|LÖ|HL|LG|MD|GN|MZ|MA|ML|MR|MY|AT|DM|MC|NZ|RM|RG|MM|ME|MB|MI|FG|DL|HC|MW|RL|MK|MG|MÜ|WS|MH|M|MS|NU|NB|ND|NM|NK|NW|NR|NI|NF|DZ|EB|OZ|TG|TO|N|OA|GM|OB|CA|EH|FW|OF|OL|OE|OG|BH|LR|OS|AA|GD|OH|KY|NP|WK|PB|PA|PE|PI|PS|P|PM|PR|RA|RV|RE|R|H|SB|WN|RS|RD|RT|BM|NE|GV|RP|SU|GL|RO|GÜ|RH|EG|RW|PN|SK|MQ|RU|SZ|RI|SL|SM|SC|HR|FZ|VS|SW|SN|CR|SE|SI|SO|LP|SG|NH|SP|IZ|ST|BF|TE|HV|OD|SR|S|AC|DW|ZW|TF|TS|TR|TÜ|UM|PZ|TP|UE|UN|UH|MN|KK|VB|V|AE|PL|RC|VG|GW|PW|VR|VK|KB|WA|WT|BE|WM|WE|AP|MO|WW|FB|WZ|WI|WB|JE|WF|WO|W|WÜ|BL|Z|GC)[- ]?[A-Z]{1,2}[- ]?\d{1,4}|(AIC|FDB|ABG|SLN|SAW|KLZ|BUL|ESB|NAB|SUL|WST|ABI|AZE|BTF|KÖT|DKB|FEU|ROT|ALZ|SMÜ|WER|AUR|NOR|DÜW|BRK|HAB|TÖL|WOR|BAD|BAR|BER|BIW|EBS|KEM|MÜB|PEG|BGL|BGD|REI|WIL|BKS|BIR|WAT|BOR|BOH|BOT|BRB|BLK|HHM|NEB|NMB|WSF|LEO|HDL|WMS|WZL|BÜS|CHA|KÖZ|ROD|WÜM|CLP|NEC|COC|ZEL|COE|CUX|DAH|LDS|DEG|DEL|RSL|DLG|DGF|LAN|HEI|MED|DON|KIB|ROK|JÜL|MON|SLE|EBE|EIC|HIG|WBS|BIT|PRÜ|LIB|EMD|WIT|ERH|HÖS|ERZ|ANA|ASZ|MAB|MEK|STL|SZB|FDS|HCH|HOR|WOL|FRG|GRA|WOS|FRI|FFB|GAP|GER|BRL|CLZ|GTH|NOH|HGW|GRZ|LÖB|NOL|WSW|DUD|HMÜ|OHA|KRU|HAL|HAM|HBS|QLB|HVL|NAU|HAS|EBN|GEO|HOH|HDH|ERK|HER|WAN|HEF|ROF|HBN|ALF|HSK|USI|NAI|REH|SAN|KÜN|ÖHR|HOL|WAR|ARN|BRG|GNT|HOG|WOH|KEH|MAI|PAR|RID|ROL|KLE|GEL|KUS|KYF|ART|SDH|LDK|DIL|MAL|VIB|LER|BNA|GHA|GRM|MTL|WUR|LEV|LIF|STE|WEL|LIP|VAI|LUP|HGN|LBZ|LWL|PCH|STB|DAN|MKK|SLÜ|MSP|TBB|MGH|MTK|BIN|MSH|EIL|HET|SGH|BID|MYK|MSE|MST|MÜR|WRN|MEI|GRH|RIE|MZG|MIL|OBB|BED|FLÖ|MOL|FRW|SEE|SRB|AIB|MOS|BCH|ILL|SOB|NMS|NEA|SEF|UFF|NEW|VOH|NDH|TDO|NWM|GDB|GVM|WIS|NOM|EIN|GAN|LAU|HEB|OHV|OSL|SFB|ERB|LOS|BSK|KEL|BSB|MEL|WTL|OAL|FÜS|MOD|OHZ|OPR|BÜR|PAF|PLÖ|CAS|GLA|REG|VIT|ECK|SIM|GOA|EMS|DIZ|GOH|RÜD|SWA|NES|KÖN|MET|LRO|BÜZ|DBR|ROS|TET|HRO|ROW|BRV|HIP|PAN|GRI|SHK|EIS|SRO|SOK|LBS|SCZ|MER|QFT|SLF|SLS|HOM|SLK|ASL|BBG|SBK|SFT|SHG|MGN|MEG|ZIG|SAD|NEN|OVI|SHA|BLB|SIG|SON|SPN|FOR|GUB|SPB|IGB|WND|STD|STA|SDL|OBG|HST|BOG|SHL|PIR|FTL|SEB|SÖM|SÜW|TIR|SAB|TUT|ANG|SDT|LÜN|LSZ|MHL|VEC|VER|VIE|OVL|ANK|OVP|SBG|UEM|UER|WLG|GMN|NVP|RDG|RÜG|DAU|FKB|WAF|WAK|SLZ|WEN|SOG|APD|WUG|GUN|ESW|WIZ|WES|DIN|BRA|BÜD|WHV|HWI|GHC|WTM|WOB|WUN|MAK|SEL|OCH|HOT|WDA)[- ]?(([A-Z][- ]?\d{1,4})|([A-Z]{2}[- ]?\d{1,3})))[- ]?(E|H)?$/.test(str), 'de-LI': str => /^FL[- ]?\d{1,5}[UZ]?$/.test(str), + 'fi-FI': str => /^(?=.{4,7})(([A-Z]{1,3}|[0-9]{1,3})[\s-]?([A-Z]{1,3}|[0-9]{1,5}))$/.test(str), 'pt-PT': str => /^([A-Z]{2}|[0-9]{2})[ -·]?([A-Z]{2}|[0-9]{2})[ -·]?([A-Z]{2}|[0-9]{2})$/.test(str), 'sq-AL': str => diff --git a/src/lib/isMobilePhone.js b/src/lib/isMobilePhone.js index 307fc791f..1e5570635 100644 --- a/src/lib/isMobilePhone.js +++ b/src/lib/isMobilePhone.js @@ -14,6 +14,7 @@ const phones = { 'ar-LY': /^((\+?218)|0)?(9[1-6]\d{7}|[1-8]\d{7,9})$/, 'ar-MA': /^(?:(?:\+|00)212|0)[5-7]\d{8}$/, 'ar-OM': /^((\+|00)968)?(9[1-9])\d{6}$/, + 'ar-PS': /^(\+?970|0)5[6|9](\d{7})$/, 'ar-SA': /^(!?(\+?966)|0)?5\d{8}$/, 'ar-SY': /^(!?(\+?963)|0)?9\d{8}$/, 'ar-TN': /^(\+?216)?[2459]\d{7}$/, @@ -29,21 +30,26 @@ const phones = { 'de-AT': /^(\+43|0)\d{1,4}\d{3,12}$/, 'de-CH': /^(\+41|0)([1-9])\d{1,9}$/, 'de-LU': /^(\+352)?((6\d1)\d{6})$/, + 'dv-MV': /^(\+?960)?(7[2-9]|91|9[3-9])\d{7}$/, 'el-GR': /^(\+?30|0)?(69\d{8})$/, 'en-AU': /^(\+?61|0)4\d{8}$/, + 'en-BM': /^(\+?1)?441(((3|7)\d{6}$)|(5[0-3][0-9]\d{4}$)|(59\d{5}))/, 'en-GB': /^(\+?44|0)7\d{9}$/, 'en-GG': /^(\+?44|0)1481\d{6}$/, 'en-GH': /^(\+233|0)(20|50|24|54|27|57|26|56|23|28|55|59)\d{7}$/, + 'en-GY': /^(\+592|0)6\d{6}$/, 'en-HK': /^(\+?852[-\s]?)?[456789]\d{3}[-\s]?\d{4}$/, 'en-MO': /^(\+?853[-\s]?)?[6]\d{3}[-\s]?\d{4}$/, 'en-IE': /^(\+?353|0)8[356789]\d{7}$/, 'en-IN': /^(\+?91|0)?[6789]\d{9}$/, 'en-KE': /^(\+?254|0)(7|1)\d{8}$/, + 'en-KI': /^((\+686|686)?)?( )?((6|7)(2|3|8)[0-9]{6})$/, 'en-MT': /^(\+?356|0)?(99|79|77|21|27|22|25)[0-9]{6}$/, 'en-MU': /^(\+?230|0)?\d{8}$/, + 'en-NA': /^(\+?264|0)(6|8)\d{7}$/, 'en-NG': /^(\+?234|0)?[789]\d{9}$/, 'en-NZ': /^(\+?64|0)[28]\d{7,9}$/, - 'en-PK': /^((\+92)|(0092))-{0,1}\d{3}-{0,1}\d{7}$|^\d{11}$|^\d{4}-\d{7}$/, + 'en-PK': /^((00|\+)?92|0)3[0-6]\d{8}$/, 'en-PH': /^(09|\+639)\d{9}$/, 'en-RW': /^(\+?250|0)?[7]\d{8}$/, 'en-SG': /^(\+65)?[3689]\d{7}$/, @@ -54,11 +60,13 @@ const phones = { 'en-ZA': /^(\+?27|0)\d{9}$/, 'en-ZM': /^(\+?26)?09[567]\d{7}$/, 'en-ZW': /^(\+263)[0-9]{9}$/, + 'en-BW': /^(\+?267)?(7[1-8]{1})\d{6}$/, 'es-AR': /^\+?549(11|[2368]\d)\d{8}$/, 'es-BO': /^(\+?591)?(6|7)\d{7}$/, 'es-CO': /^(\+?57)?3(0(0|1|2|4|5)|1\d|2[0-4]|5(0|1))\d{7}$/, 'es-CL': /^(\+?56|0)[2-9]\d{1}\d{7}$/, 'es-CR': /^(\+506)?[2-8]\d{7}$/, + 'es-CU': /^(\+53|0053)?5\d{7}/, 'es-DO': /^(\+?1)?8[024]9\d{7}$/, 'es-HN': /^(\+?504)?[9|8]\d{7}$/, 'es-EC': /^(\+?593|0)([2-7]|9[2-9])\d{7}$/, @@ -67,6 +75,7 @@ const phones = { 'es-MX': /^(\+?52)?(1|01)?\d{10,11}$/, 'es-PA': /^(\+?507)\d{7,8}$/, 'es-PY': /^(\+?595|0)9[9876]\d{7}$/, + 'es-SV': /^(\+?503)?[67]\d{7}$/, 'es-UY': /^(\+598|0)9[1-9][\d]{6}$/, 'es-VE': /^(\+?58)?(2|4)\d{9}$/, 'et-EE': /^(\+?372)?\s?(5|8[1-4])\s?([0-9]\s?){6,7}$/, @@ -74,13 +83,16 @@ const phones = { 'fi-FI': /^(\+?358|0)\s?(4(0|1|2|4|5|6)?|50)\s?(\d\s?){4,8}\d$/, 'fj-FJ': /^(\+?679)?\s?\d{3}\s?\d{4}$/, 'fo-FO': /^(\+?298)?\s?\d{2}\s?\d{2}\s?\d{2}$/, + 'fr-BF': /^(\+226|0)[67]\d{7}$/, + 'fr-CM': /^(\+?237)6[0-9]{8}$/, 'fr-FR': /^(\+?33|0)[67]\d{8}$/, 'fr-GF': /^(\+?594|0|00594)[67]\d{8}$/, 'fr-GP': /^(\+?590|0|00590)[67]\d{8}$/, 'fr-MQ': /^(\+?596|0|00596)[67]\d{8}$/, + 'fr-PF': /^(\+?689)?8[789]\d{6}$/, 'fr-RE': /^(\+?262|0|00262)[67]\d{8}$/, 'he-IL': /^(\+972|0)([23489]|5[012345689]|77)[1-9]\d{6}$/, - 'hu-HU': /^(\+?36)(20|30|70)\d{7}$/, + 'hu-HU': /^(\+?36|06)(20|30|31|50|70)\d{7}$/, 'id-ID': /^(\+?62|0)8(1[123456789]|2[1238]|3[1238]|5[12356789]|7[78]|9[56789]|8[123456789])([\s?|\d]{5,11})$/, 'it-IT': /^(\+?39)?\s?3\d{2} ?\d{6,7}$/, 'it-SM': /^((\+378)|(0549)|(\+390549)|(\+3780549))?6\d{5,9}$/, @@ -105,19 +117,22 @@ const phones = { 'pt-AO': /^(\+244)\d{9}$/, 'ro-RO': /^(\+?4?0)\s?7\d{2}(\/|\s|\.|\-)?\d{3}(\s|\.|\-)?\d{3}$/, 'ru-RU': /^(\+?7|8)?9\d{9}$/, - 'si-LK': /^(?:0|94|\+94)?(7(0|1|2|5|6|7|8)( |-)?\d)\d{6}$/, + 'si-LK': /^(?:0|94|\+94)?(7(0|1|2|4|5|6|7|8)( |-)?)\d{7}$/, 'sl-SI': /^(\+386\s?|0)(\d{1}\s?\d{3}\s?\d{2}\s?\d{2}|\d{2}\s?\d{3}\s?\d{3})$/, 'sk-SK': /^(\+?421)? ?[1-9][0-9]{2} ?[0-9]{3} ?[0-9]{3}$/, 'sq-AL': /^(\+355|0)6[789]\d{6}$/, 'sr-RS': /^(\+3816|06)[- \d]{5,9}$/, 'sv-SE': /^(\+?46|0)[\s\-]?7[\s\-]?[02369]([\s\-]?\d){7}$/, + 'tg-TJ': /^(\+?992)?[5][5]\d{7}$/, 'th-TH': /^(\+66|66|0)\d{9}$/, 'tr-TR': /^(\+?90|0)?5\d{9}$/, + 'tk-TM': /^(\+993|993|8)\d{8}$/, 'uk-UA': /^(\+?38|8)?0\d{9}$/, 'uz-UZ': /^(\+?998)?(6[125-79]|7[1-69]|88|9\d)\d{7}$/, 'vi-VN': /^((\+?84)|0)((3([2-9]))|(5([25689]))|(7([0|6-9]))|(8([1-9]))|(9([0-9])))([0-9]{7})$/, - 'zh-CN': /^((\+|00)86)?1([3456789][0-9]|4[579]|6[2567]|7[01235678]|9[012356789])[0-9]{8}$/, + 'zh-CN': /^((\+|00)86)?(1[3-9]|9[28])\d{9}$/, 'zh-TW': /^(\+?886\-?|0)?9\d{8}$/, + 'dz-BT': /^(\+?975|0)?(17|16|77|02)\d{6}$/, }; /* eslint-enable max-len */ diff --git a/src/lib/isPassportNumber.js b/src/lib/isPassportNumber.js index 76284b12f..4c38bfbbe 100644 --- a/src/lib/isPassportNumber.js +++ b/src/lib/isPassportNumber.js @@ -47,10 +47,10 @@ const passportRegexByCountryCode = { MZ: /^([A-Z]{2}\d{7})|(\d{2}[A-Z]{2}\d{5})$/, // MOZAMBIQUE MY: /^[AHK]\d{8}$/, // MALAYSIA NL: /^[A-Z]{2}[A-Z0-9]{6}\d$/, // NETHERLANDS - PO: /^[A-Z]{2}\d{7}$/, // POLAND + PL: /^[A-Z]{2}\d{7}$/, // POLAND PT: /^[A-Z]\d{6}$/, // PORTUGAL RO: /^\d{8,9}$/, // ROMANIA - RU: /^\d{2}\d{2}\d{6}$/, // RUSSIAN FEDERATION + RU: /^\d{9}$/, // RUSSIAN FEDERATION SE: /^\d{8}$/, // SWEDEN SL: /^(P)[A-Z]\d{7}$/, // SLOVANIA SK: /^[0-9A-Z]\d{7}$/, // SLOVAKIA diff --git a/src/lib/isPostalCode.js b/src/lib/isPostalCode.js index 915c27f2b..7ef17abcf 100644 --- a/src/lib/isPostalCode.js +++ b/src/lib/isPostalCode.js @@ -46,6 +46,7 @@ const patterns = { LT: /^LT\-\d{5}$/, LU: fourDigit, LV: /^LV\-\d{4}$/, + LK: fiveDigit, MX: fiveDigit, MT: /^[A-Za-z]{3}\s{0,1}\d{4}$/, MY: fiveDigit, diff --git a/src/lib/isURL.js b/src/lib/isURL.js index 7f6e0ba5f..aa6222a90 100644 --- a/src/lib/isURL.js +++ b/src/lib/isURL.js @@ -111,13 +111,17 @@ export default function isURL(url, options) { if (options.disallow_auth) { return false; } - if (split[0] === '' || split[0].substr(0, 1) === ':') { + if (split[0] === '') { return false; } auth = split.shift(); if (auth.indexOf(':') >= 0 && auth.split(':').length > 2) { return false; } + const [user, password] = auth.split(':'); + if (user === '' && password === '') { + return false; + } } hostname = split.join('@'); @@ -136,7 +140,7 @@ export default function isURL(url, options) { } } - if (port_str !== null) { + if (port_str !== null && port_str.length > 0) { port = parseInt(port_str, 10); if (!/^[0-9]+$/.test(port_str) || port <= 0 || port > 65535) { return false; diff --git a/src/lib/isUUID.js b/src/lib/isUUID.js index 61d938ac3..c026ca78c 100644 --- a/src/lib/isUUID.js +++ b/src/lib/isUUID.js @@ -1,14 +1,16 @@ import assertString from './util/assertString'; const uuid = { + 1: /^[0-9A-F]{8}-[0-9A-F]{4}-1[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i, + 2: /^[0-9A-F]{8}-[0-9A-F]{4}-2[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i, 3: /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{4}-[0-9A-F]{12}$/i, 4: /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, 5: /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i, all: /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i, }; -export default function isUUID(str, version = 'all') { +export default function isUUID(str, version) { assertString(str); - const pattern = uuid[version]; - return pattern && pattern.test(str); + const pattern = uuid[![undefined, null].includes(version) ? version : 'all']; + return !!pattern && pattern.test(str); } diff --git a/src/lib/isVAT.js b/src/lib/isVAT.js index 549bf336f..884b066ff 100644 --- a/src/lib/isVAT.js +++ b/src/lib/isVAT.js @@ -3,6 +3,7 @@ import assertString from './util/assertString'; export const vatMatchers = { GB: /^GB((\d{3} \d{4} ([0-8][0-9]|9[0-6]))|(\d{9} \d{3})|(((GD[0-4])|(HA[5-9]))[0-9]{2}))$/, IT: /^(IT)?[0-9]{11}$/, + NL: /^(NL)?[0-9]{9}B[0-9]{2}$/, }; export default function isVAT(str, countryCode) { diff --git a/src/lib/rtrim.js b/src/lib/rtrim.js index d10aaa9de..2d311574b 100644 --- a/src/lib/rtrim.js +++ b/src/lib/rtrim.js @@ -2,7 +2,16 @@ import assertString from './util/assertString'; export default function rtrim(str, chars) { assertString(str); - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping - const pattern = chars ? new RegExp(`[${chars.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}]+$`, 'g') : /(\s)+$/g; - return str.replace(pattern, ''); + if (chars) { + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping + const pattern = new RegExp(`[${chars.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}]+$`, 'g'); + return str.replace(pattern, ''); + } + // Use a faster and more safe than regex trim method https://blog.stevenlevithan.com/archives/faster-trim-javascript + let strIndex = str.length - 1; + while (/\s/.test(str.charAt(strIndex))) { + strIndex -= 1; + } + + return str.slice(0, strIndex + 1); } diff --git a/src/lib/unescape.js b/src/lib/unescape.js index 213a0f70b..feb255ac0 100644 --- a/src/lib/unescape.js +++ b/src/lib/unescape.js @@ -2,12 +2,15 @@ import assertString from './util/assertString'; export default function unescape(str) { assertString(str); - return (str.replace(/&/g, '&') - .replace(/"/g, '"') + return (str.replace(/"/g, '"') .replace(/'/g, "'") .replace(/</g, '<') .replace(/>/g, '>') .replace(///g, '/') .replace(/\/g, '\\') - .replace(/`/g, '`')); + .replace(/`/g, '`') + .replace(/&/g, '&')); + // & replacement has to be the last one to prevent + // bugs with intermediate strings containing escape sequences + // See: https://github.com/validatorjs/validator.js/issues/1827 } diff --git a/test/sanitizers.js b/test/sanitizers.js index 00ec35ab9..ecb0e128f 100644 --- a/test/sanitizers.js +++ b/test/sanitizers.js @@ -184,6 +184,9 @@ describe('Sanitizers', () => { 'Backtick: `': 'Backtick: `', + + 'Escaped string: &lt;': + 'Escaped string: <', }, }); }); diff --git a/test/validators.js b/test/validators.js index e9f5d8555..7e44da132 100644 --- a/test/validators.js +++ b/test/validators.js @@ -364,6 +364,7 @@ describe('Validators', () => { 'http://www.foobar.com/~foobar', 'http://user:pass@www.foobar.com/', 'http://user:@www.foobar.com/', + 'http://:pass@www.foobar.com/', 'http://user@www.foobar.com', 'http://127.0.0.1/', 'http://10.0.0.0/', @@ -535,6 +536,31 @@ describe('Validators', () => { }); }); + it('should validate URLs with column and no port', () => { + test({ + validator: 'isURL', + valid: [ + 'http://example.com:', + 'ftp://example.com:', + ], + invalid: [ + 'https://example.com:abc', + ], + }); + }); + + it('should validate sftp protocol URL containing column and no port', () => { + test({ + validator: 'isURL', + args: [{ + protocols: ['sftp'], + }], + valid: [ + 'sftp://user:pass@terminal.aws.test.nl:/incoming/things.csv', + ], + }); + }); + it('should validate protocol relative URLs', () => { test({ validator: 'isURL', @@ -1074,6 +1100,18 @@ describe('Validators', () => { 'domain.com/', '/more.com', 'domain.com�', + 'domain.co\u00A0m', + 'domain.co\u1680m', + 'domain.co\u2006m', + 'domain.co\u2028m', + 'domain.co\u2029m', + 'domain.co\u202Fm', + 'domain.co\u205Fm', + 'domain.co\u3000m', + 'domain.com\uDC00', + 'domain.co\uEFFFm', + 'domain.co\uFDDAm', + 'domain.co\uFFF4m', 'domain.com©', 'example.0', '192.168.0.9999', @@ -1118,6 +1156,18 @@ describe('Validators', () => { ], }); }); + it('should validate FQDN with wildcard option', () => { + test({ + validator: 'isFQDN', + args: [ + { allow_wildcard: true }, + ], + valid: [ + '*.example.com', + '*.shop.example.com', + ], + }); + }); it('should validate alpha strings', () => { test({ @@ -1447,6 +1497,24 @@ describe('Validators', () => { }); }); + it('should validate finnish alpha strings', () => { + test({ + validator: 'isAlpha', + args: ['fi-FI'], + valid: [ + 'äiti', + 'Öljy', + 'Åke', + 'testÖ', + ], + invalid: [ + 'AİıÖöÇ窺ĞğÜüZ', + 'äöå123', + '', + ], + }); + }); + it('should validate kurdish alpha strings', () => { test({ validator: 'isAlpha', @@ -1931,6 +1999,24 @@ describe('Validators', () => { }); }); + it('should validate finnish alphanumeric strings', () => { + test({ + validator: 'isAlphanumeric', + args: ['fi-FI'], + valid: [ + 'äiti124', + 'ÖLJY1234', + '123Åke', + '451åå23', + ], + invalid: [ + 'AİıÖöÇ窺ĞğÜüZ', + 'foo!!', + '', + ], + }); + }); + it('should validate german alphanumeric strings', () => { test({ validator: 'isAlphanumeric', @@ -2951,7 +3037,7 @@ describe('Validators', () => { test({ validator: 'isPassportNumber', - args: ['PO'], + args: ['PL'], valid: [ 'ZS 0000177', 'AN 3000011', @@ -2992,14 +3078,16 @@ describe('Validators', () => { validator: 'isPassportNumber', args: ['RU'], valid: [ - '26 32 636829', - '0121 345321', - '4398636928', + '2 32 636829', + '012 345321', + '439863692', ], invalid: [ - 'AZ 2R YU46J', - '012A 3D5321', - 'SF233D532T', + 'A 2R YU46J0', + '01A 3D5321', + 'SF233D53T', + '12345678', + '1234567890', ], }); @@ -4239,6 +4327,15 @@ describe('Validators', () => { valid: ['Foo', 'FOObar', 'BAZfoo'], invalid: ['bar', 'fobar', 'baxoof'], }); + + test({ + validator: 'contains', + args: ['foo', { + minOccurrences: 2, + }], + valid: ['foofoofoo', '12foo124foo', 'fofooofoooofoooo', 'foo1foo'], + invalid: ['foo', 'foobar', 'Fooofoo', 'foofo'], + }); }); it('should validate strings against a pattern', () => { @@ -4413,6 +4510,63 @@ describe('Validators', () => { 'AAAAAAAA-1111-1111-AAAG-111111111111', ], }); + test({ + validator: 'isUUID', + args: [undefined], + valid: [ + 'A117FBC9-4BED-3078-CF07-9141BA07C9F3', + 'A117FBC9-4BED-5078-AF07-9141BA07C9F3', + ], + invalid: [ + '', + 'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3', + 'A987FBC94BED3078CF079141BA07C9F3', + 'A11AAAAA-1111-1111-AAAG-111111111111', + ], + }); + test({ + validator: 'isUUID', + args: [null], + valid: [ + 'A127FBC9-4BED-3078-CF07-9141BA07C9F3', + ], + invalid: [ + '', + 'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3', + 'A127FBC9-4BED-3078-CF07-9141BA07C9F3xxx', + '912859', + 'A12AAAAA-1111-1111-AAAG-111111111111', + ], + }); + test({ + validator: 'isUUID', + args: [1], + valid: [ + 'E034B584-7D89-11E9-9669-1AECF481A97B', + ], + invalid: [ + 'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3', + 'AAAAAAAA-1111-2222-AAAG', + 'AAAAAAAA-1111-2222-AAAG-111111111111', + 'A987FBC9-4BED-4078-8F07-9141BA07C9F3', + 'A987FBC9-4BED-5078-AF07-9141BA07C9F3', + ], + }); + test({ + validator: 'isUUID', + args: [2], + valid: [ + 'A987FBC9-4BED-2078-CF07-9141BA07C9F3', + ], + invalid: [ + '', + 'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3', + '11111', + 'AAAAAAAA-1111-1111-AAAG-111111111111', + 'A987FBC9-4BED-4078-8F07-9141BA07C9F3', + 'A987FBC9-4BED-5078-AF07-9141BA07C9F3', + ], + }); test({ validator: 'isUUID', args: [3], @@ -4464,6 +4618,18 @@ describe('Validators', () => { 'A987FBC9-4BED-3078-CF07-9141BA07C9F3', ], }); + test({ + validator: 'isUUID', + args: [6], + valid: [], + invalid: [ + '987FBC97-4BED-1078-AF07-9141BA07C9F3', + '987FBC97-4BED-2078-AF07-9141BA07C9F3', + '987FBC97-4BED-3078-AF07-9141BA07C9F3', + '987FBC97-4BED-4078-AF07-9141BA07C9F3', + '987FBC97-4BED-5078-AF07-9141BA07C9F3', + ], + }); }); it('should validate a string that is in another string or array', () => { @@ -4686,6 +4852,27 @@ describe('Validators', () => { it('should validate identity cards', () => { const fixtures = [ + { + locale: 'LK', + valid: [ + '722222222v', + '722222222V', + '993151225x', + '993151225X', + '188888388x', + '935632124V', + '199931512253', + '200023125632', + ], + invalid: [ + '023125648V', + '023345621v', + '021354211X', + '055321231x', + '02135465462', + '199931512253X', + ], + }, { locale: 'PL', valid: [ @@ -4739,6 +4926,20 @@ describe('Validators', () => { 'Z1234567C', ], }, + { + locale: 'FI', + valid: [ + '131052-308T', // People born in 1900s + '131052A308T', // People born in 2000s + '131052+308T', // People born in 1800s + '131052-313Y', + ], + invalid: [ + '131052308T', + '131052-308T ', + '131052-308A', + ], + }, { locale: 'IN', valid: [ @@ -5790,6 +5991,23 @@ describe('Validators', () => { '00212408186135', ], }, + { + locale: 'dz-BT', + valid: [ + '+97517374354', + '+97517454971', + '77324646', + '016329712', + '97517265559', + ], + invalid: [ + '', + '9898347255', + '+96326626262', + '963372', + '0114152198', + ], + }, { locale: 'ar-OM', valid: [ @@ -5809,6 +6027,26 @@ describe('Validators', () => { '02122333', ], }, + { + locale: 'ar-PS', + valid: [ + '+970563459876', + '970592334218', + '0566372345', + '0598273583', + ], + invalid: [ + '+9759029487', + '97059123456789', + '598372348', + '97058aaaafjd', + '', + '05609123484', + '+97059', + '+970', + '97056', + ], + }, { locale: 'ar-SY', valid: [ @@ -6011,6 +6249,19 @@ describe('Validators', () => { '064349089895623459', ], }, + { + locale: 'hu-HU', + valid: [ + '06301234567', + '+36201234567', + '06701234567', + ], + invalid: [ + '1234', + '06211234567', + '+3620123456', + ], + }, { locale: 'mz-MZ', valid: [ @@ -6102,19 +6353,28 @@ describe('Validators', () => { { locale: 'zh-CN', valid: [ - '15323456787', '13523333233', - '13898728332', + '13838389438', + '14899230918', + '14999230918', + '15323456787', + '15052052020', + '16237108167', + '008616238234822', + '+8616238234822', + '16565600001', + '17269427292', + '17469427292', + '18199617480', + '19151751717', + '19651751717', '+8613238234822', '+8613487234567', '+8617823492338', '+8617823492338', - '16637108167', '+8616637108167', '+8616637108167', '+8616712341234', - '008618812341234', - '008618812341234', '+8619912341234', '+8619812341234', '+8619712341234', @@ -6123,17 +6383,25 @@ describe('Validators', () => { '+8619312341234', '+8619212341234', '+8619112341234', - '17269427292', - '16565600001', '+8617269427292', + '008618812341234', + '008618812341234', '008617269427292', - '16238234822', - '008616238234822', - '+8616238234822', + // Reserve number segments in the future. + '92138389438', + '+8692138389438', + '008692138389438', + '98199649964', + '+8698099649964', + '008698099649964', ], invalid: [ '12345', '', + '12038389438', + '12838389438', + '013838389438', + '+86-13838389438', '+08613811211114', '+008613811211114', '08613811211114', @@ -6159,6 +6427,26 @@ describe('Validators', () => { '0-987123456', ], }, + { + locale: 'en-BM', + valid: [ + '+14417974653', + '14413986653', + '4415370973', + '+14415005489', + ], + invalid: [ + '85763287', + '+14412020436', + '+14412236546', + '+14418245567', + '+14416546789', + '44087635627', + '+4418970973', + '', + '+1441897465', + ], + }, { locale: 'en-ZA', valid: [ @@ -6255,6 +6543,22 @@ describe('Validators', () => { '+233292345671', ], }, + { + locale: 'en-GY', + valid: [ + '+5926121234', + '06121234', + '06726381', + '+5926726381', + ], + invalid: [ + '5926121234', + '6121234', + '+592 6121234', + '05926121234', + '+592-6121234', + ], + }, { locale: 'en-HK', valid: [ @@ -6340,6 +6644,22 @@ describe('Validators', () => { '+254800723845', ], }, + { + locale: 'en-KI', + valid: [ + '+68673140000', + '68673059999', + '+68663000000', + '68663019999', + ], + invalid: [ + '+68653000000', + '68664019999', + '+68619019999', + '686123456789', + '+686733445', + ], + }, { locale: 'en-MT', valid: [ @@ -6465,6 +6785,31 @@ describe('Validators', () => { '+3361245789', ], }, + { + locale: 'fr-BF', + valid: [ + '+22661245789', + '+22665903092', + '+22672457898', + '+22673572346', + '061245789', + '071245783', + ], + invalid: [ + '0612457892', + '06124578980', + '0112457898', + '0212457898', + '0312457898', + '0412457898', + '0512457898', + '0812457898', + '0912457898', + '+22762457898', + '+226724578980', + '+22634523', + ], + }, { locale: 'fr-CA', valid: ['19876543210', '8005552222', '+15673628910'], @@ -6576,6 +6921,28 @@ describe('Validators', () => { '+26261245789', ], }, + { + locale: 'fr-PF', + valid: [ + '87123456', + '88123456', + '89123456', + '+68987123456', + '+68988123456', + '+68989123456', + '68987123456', + '68988123456', + '68989123456', + ], + invalid: [ + '7123456', + '86123456', + '87 12 34 56', + 'definitely not a number', + '01+68988123456', + '6898912345', + ], + }, { locale: 'ka-GE', valid: [ @@ -6732,6 +7099,27 @@ describe('Validators', () => { '66338855', ], }, + { + locale: ['en-NA'], + valid: [ + '+26466189012', + '+26461555804', + '+26461434221', + '+26487555169', + '+26481555663', + ], + invalid: [ + '12345', + '', + 'Vml2YW11cyBmZXJtZtesting123', + '+2641234567890', + '+2641234567', + '+2648143422', + '+264981234', + '4736338855', + '66338855', + ], + }, { locale: 'ru-RU', valid: [ @@ -6759,14 +7147,13 @@ describe('Validators', () => { '0786642116', '078 7642116', '078-7642116', - + '0749994567', ], invalid: [ '9912349956789', '12345', '1678123456', '0731234567', - '0749994567', '0797878674', ], }, @@ -7016,6 +7403,34 @@ describe('Validators', () => { '01234567', ], }, + { + locale: 'es-CU', + valid: [ + '+5351234567', + '005353216547', + '51234567', + '53214567', + ], + invalid: [ + '1234', + '+5341234567', + '0041234567', + '41234567', + '11234567', + '21234567', + '31234567', + '60303456', + '71234567', + '81234567', + '91234567', + '+5343216547', + '+5332165498', + '+53121234567', + '', + 'abc', + '+535123457', + ], + }, { locale: 'es-DO', valid: [ @@ -7161,6 +7576,30 @@ describe('Validators', () => { '+591993546843', ], }, + { + locale: 'es-SV', + valid: [ + '62136634', + '50361366631', + '+50361366634', + '+50361367217', + '+50361367460', + '+50371367632', + '+50371367767', + '+50371368314', + ], + invalid: [ + '+5032136663', + '21346663', + '+50321366663', + '12345', + 'El salvador', + 'this should fail', + '+5032222', + '+503 1111 1111', + '00 +503 1234 5678', + ], + }, { locale: 'es-UY', valid: [ @@ -7340,6 +7779,21 @@ describe('Validators', () => { '088-320000', ], }, + { + locale: 'fr-CM', + valid: [ + '+237677936141', + '237623456789', + '+237698124842', + '237693029202', + ], + invalid: [ + 'NotANumber', + '+(703)-572-2920', + '+237 623 45 67 890', + '+2379981247429', + ], + }, { locale: 'ko-KR', valid: [ @@ -7791,6 +8245,22 @@ describe('Validators', () => { '081234567891', ], }, + { + locale: 'tk-TM', + valid: [ + '+99312495154', + '99312130136', + '+99312918407', + '99312183399', + '812391717', + ], + invalid: [ + '12345', + '+99412495154', + '99412495154', + '998900066506', + ], + }, { locale: ['en-ZA', 'be-BY'], valid: [ @@ -7835,6 +8305,31 @@ describe('Validators', () => { '23274560591 ', ], }, + { + locale: 'en-BW', + valid: [ + '+26772868545', + '+26776368790', + '+26774560512', + '26774560591', + '26778560512', + '74560512', + '76710284', + ], + invalid: [ + '0799375902', + '12345', + '+2670745605448', + '2670745605482', + '+26779685451', + '+26770685451', + '267074560', + '2670ab5608', + '+267074560', + '70560512', + '79710284', + ], + }, { locale: 'az-AZ', valid: [ @@ -7976,6 +8471,64 @@ describe('Validators', () => { '09650000234', ], }, + { + locale: 'en-PK', + valid: [ + '+923412877421', + '+923001234567', + '00923001234567', + '923001234567', + '03001234567', + ], + invalid: [ + '+3001234567', + '+933001234567', + '+924001234567', + '+92300123456720', + '030012345672', + '30012345673', + '0030012345673', + '3001234567', + ], + }, + { + locale: ['tg-TJ'], + valid: [ + '+992553388551', + '+992553322551', + '992553388551', + '992553322551', + ], + invalid: [ + '12345', + '', + 'Vml2YW11cyBmZXJtZtesting123', + '+995563388559', + '+9955633559', + '19676338855', + '+992263388505', + '9923633885', + '99255363885', + '66338855', + ], + }, + { + locale: 'dv-MV', + valid: [ + '+960973256874', + '781246378', + '+960766354789', + '+960912354789', + ], + invalid: [ + '+96059234567', + '+96045789', + '7812463784', + '+960706985478', + '+960926985478', + 'NotANumber', + ], + }, ]; let allValid = []; @@ -10034,6 +10587,20 @@ describe('Validators', () => { 'ab1234', ], }, + { + locale: 'LK', + valid: [ + '11500', + '22200', + '10370', + '43000', + ], + invalid: [ + '1234', + '789389', + '982', + ], + }, ]; let allValid = []; @@ -10961,6 +11528,39 @@ describe('Validators', () => { 'FS AB 1234 A', ], }); + test({ + validator: 'isLicensePlate', + args: ['fi-FI'], + valid: [ + 'ABC-123', + 'ABC 123', + 'ABC123', + 'A100', + 'A 100', + 'A-100', + 'C10001', + 'C 10001', + 'C-10001', + '123-ABC', + '123 ABC', + '123ABC', + '123-A', + '123 A', + '123A', + '199AA', + '199 AA', + '199-AA', + ], + invalid: [ + ' ', + 'A-1', + 'A1A-100', + '1-A-2', + 'C1234567', + 'A B C 1 2 3', + 'abc-123', + ], + }); test({ validator: 'isLicensePlate', args: ['sq-AL'], @@ -11045,7 +11645,7 @@ describe('Validators', () => { ], }); }); - it('should validate english VAT numbers', () => { + it('should validate VAT numbers', () => { test({ validator: 'isVAT', args: ['GB'], @@ -11075,7 +11675,6 @@ describe('Validators', () => { 'GBHA499', ], }); - test({ validator: 'isVAT', args: ['IT'], @@ -11091,7 +11690,21 @@ describe('Validators', () => { 'IT123456789', ], }); - + test({ + validator: 'isVAT', + args: ['NL'], + valid: [ + 'NL123456789B10', + '123456789B10', + ], + invalid: [ + 'NL12345678 910', + 'NL 123456789101', + 'NL123456789B1', + 'GB12345678910', + 'NL123456789', + ], + }); test({ validator: 'isVAT', args: ['invalidCountryCode'],