diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 21686d855..b4e532908 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
- node-version: [14, 12, 10, 8, 6]
+ node-version: [20, 18, 16, 14, 12, 10, 8, 6]
name: Run tests on Node.js ${{ matrix.node-version }}
steps:
- name: Setup Node.js ${{ matrix.node-version }}
@@ -20,10 +20,10 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v2
- name: Install dependencies
- run: npm install
+ run: npm install --legacy-peer-deps
- name: Run tests
run: npm test
- - if: matrix.node-version == 14
+ - if: matrix.node-version == 20
name: Send coverage info to Codecov
uses: codecov/codecov-action@v1
with:
diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml
index b4b62f1b9..ccc202ca2 100644
--- a/.github/workflows/npm-publish.yml
+++ b/.github/workflows/npm-publish.yml
@@ -5,20 +5,23 @@ on:
jobs:
publish:
runs-on: ubuntu-20.04
+ permissions:
+ contents: read
+ id-token: write
steps:
- - name: Setup Node.js 14
- uses: actions/setup-node@v2-beta
+ - name: Setup Node.js 18
+ uses: actions/setup-node@v3
with:
- node-version: 14
+ node-version: 18
check-latest: true
registry-url: https://registry.npmjs.org/
- name: Checkout Repository
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
- name: Install Dependencies
run: npm install
- name: Run Tests
run: npm test
- name: Publish Package to NPM Registry
- run: npm publish
+ run: npm publish --provenance
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_SECRET}}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8d27cf979..581908fdd 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,37 @@
+# 13.12.0
+
+### New Features / Validators
+
+- [#2143](https://github.com/validatorjs/validator.js/pull/2143) `isAbaRouting` @songyuew
+
+### Fixes, New Locales and Enhancements
+
+- [#2207](https://github.com/validatorjs/validator.js/pull/2207) `isLicensePlate` add Pakistani `en-PK` locale @anasshakil
+- [#2208](https://github.com/validatorjs/validator.js/issues/2208) `isPort` fix invalid leading zeros @anasshakil
+- [#2224](https://github.com/validatorjs/validator.js/pull/2224) `isTaxID` added Argentina `es-AR` locale @estefrare
+- [#2257](https://github.com/validatorjs/validator.js/pull/2257) `isDate` timezone offset fix @tomaspanek
+- [#2265](https://github.com/validatorjs/validator.js/pull/2265) `isPassportNumber` added `ZA` locale @GMorris-professional
+- `isMobilePhone`:
+ - [#2267](https://github.com/validatorjs/validator.js/pull/2267) added `en-MW` locale @SimranSiddiqui
+ - [#2140](https://github.com/validatorjs/validator.js/pull/2140) fix `am-AM` locale @AlexKrupko
+- [#2271](https://github.com/validatorjs/validator.js/pull/2271) `isPostalAddress` fix `NL` locale @RobinvanderVliet
+- [#2273](https://github.com/validatorjs/validator.js/pull/2273) `isISO4217` add `SLE` currency @urg
+- [#2278](https://github.com/validatorjs/validator.js/pull/2278) `isStrongPassword` fix symbolRegex to include `\` @nandavikas
+- [#2279](https://github.com/validatorjs/validator.js/pull/2279) `isVAT` fixed `KZ` locale @MatthieuLemoine
+- [#2285](https://github.com/validatorjs/validator.js/pull/2285) `isAlpha`, `isAlphanumeric` added `eo` locale @RobinvanderVliet
+- [#2320](https://github.com/validatorjs/validator.js/pull/2320) `isIBAN` add Algeria `DZ` locale @thibault-lr
+- [#2343](https://github.com/validatorjs/validator.js/pull/2343) `isVAT`improve `AU` locale @matthewberryman
+- [#2345](https://github.com/validatorjs/validator.js/pull/2345) `isUUID` add support for v7 @ruscon
+- [#2358](https://github.com/validatorjs/validator.js/pull/2358) `isTaxID` add Ukraine `uk-UA` locale @arttiger
+- [#2381](https://github.com/validatorjs/validator.js/pull/2381) `isDate` disallow hiphen before year @Sumit-tech-joshi
+- **Doc fixes and others:**
+ - [#2276](https://github.com/validatorjs/validator.js/pull/2276) @meyfa
+ - [#2341](https://github.com/validatorjs/validator.js/pull/2341) @WikiRik
+ - [#2364](https://github.com/validatorjs/validator.js/pull/2364) @rubiin
+ - [#2368](https://github.com/validatorjs/validator.js/pull/2368) @ZhulinskiiDanil
+ - [#2371](https://github.com/validatorjs/validator.js/pull/2371) @devmanbud
+ - [#2386](https://github.com/validatorjs/validator.js/pull/2386) @alinaghale88
+
# 13.11.0
### New Features / Validators
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..c7da04163
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,37 @@
+# Contributing to validator.js
+Welcome to validator.js repository!! We appreciate your interest in contributing to this open library and for helping our community grow.
+
+## How to Contribute
+### Code Contribution
+In general, we follow the "fork-and-pull" Git workflow.
+
+1. [Fork](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project) the repository on GitHub
+2. Clone the project to your local machine
+3. Work on your fork
+ * Make your changes and additions
+ - Most of your changes should be focused on src/ and test/ folders and/or [README.md](https://github.com/validatorjs/validator.js/blob/master/README.md).
+ - Files such as validator.js, validator.min.js and files in lib/ folder are autogenerated when running tests (npm test) and need not to be changed **manually**.
+ * Change or add tests if needed
+ * Run tests and make sure they pass
+ * Add changes to README.md if needed
+4. Commit changes to your own branch
+5. **Make sure** you merge the latest from "upstream" and resolve conflicts if there is any
+6. Repeat step 3(3) above
+7. Push your work back up to your fork
+8. Submit a Pull request so that we can review your changes
+
+#### Run Tests
+Tests are using mocha. To run the tests use:
+
+```sh
+$ npm test
+```
+
+### Financial Contribution
+We welcome financial contributions on our [open collective](https://opencollective.com/validatorjs).
+
+You can opt to become a [backer](https://opencollective.com/validatorjs#backer) or a [sponsor](https://opencollective.com/validatorjs#sponsor) and help our project sustain over time.
+
+Thank you to the people who have already contributed:
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 3e56bd51d..5b8bb7d68 100644
--- a/README.md
+++ b/README.md
@@ -72,16 +72,6 @@ CDN
```
-## Contributors
-
-[Become a backer](https://opencollective.com/validatorjs#backer)
-
-[Become a sponsor](https://opencollective.com/validatorjs#sponsor)
-
-Thank you to the people who have already contributed:
-
-
-
## Validators
Here is a list of the validators currently available.
@@ -90,16 +80,17 @@ Validator | Description
--------------------------------------- | --------------------------------------
**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.
+**isAbaRouting(str)** | check if the string is an ABA routing number for US bank account / cheque.
**isAfter(str [, options])** | check if the string is a date that is after the specified date.
`options` is an object that defaults to `{ comparisonDate: Date().toString() }`.
**Options:**
`comparisonDate`: Date to compare to. Defaults to `Date().toString()` (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', 'bn', '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', 'kk-KZ', 'ko-KR', 'ja-JP', 'ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'si-LK', 'sl-SI', 'sk-SK', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'th-TH', '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', 'bn', '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', 'kk-KZ', 'ko-KR', 'ja-JP','ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'si-LK', 'sl-SI', 'sk-SK', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'th-TH', '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', 'bn', '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-IR', 'fi-FI', 'fr-CA', 'fr-FR', 'he', 'hi-IN', 'hu-HU', 'it-IT', 'kk-KZ', 'ko-KR', 'ja-JP', 'ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'si-LK', 'sl-SI', 'sk-SK', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'th-TH', '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', 'bn', '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-IR', 'fi-FI', 'fr-CA', 'fr-FR', 'he', 'hi-IN', 'hu-HU', 'it-IT', 'kk-KZ', 'ko-KR', 'ja-JP','ku-IQ', 'nb-NO', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-BR', 'pt-PT', 'ru-RU', 'si-LK', 'sl-SI', 'sk-SK', 'sr-RS', 'sr-RS@latin', 'sv-SE', 'th-TH', '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 [, options])** | check if the string is base32 encoded. `options` is optional and defaults to `{ crockford: false }`.
When `crockford` is true it tests the given base32 encoded string using [Crockford's base32 alternative][Crockford Base32].
**isBase58(str)** | check if the string is base58 encoded.
**isBase64(str [, options])** | check if the string is base64 encoded. `options` is optional and defaults to `{ urlSafe: false }`
when `urlSafe` is true it tests the given base64 encoded string is [url safe][Base64 URL Safe].
**isBefore(str [, date])** | check if the string is a date that is before the specified date.
**isBIC(str)** | check if the string is a BIC (Bank Identification Code) or SWIFT code.
-**isBoolean(str [, options])** | check if the string is a boolean.
`options` is an object which defaults to `{ loose: false }`. If `loose` is is set to false, the validator will strictly match ['true', 'false', '0', '1']. If `loose` is set to true, the validator will also match 'yes', 'no', and will match a valid boolean string of any case. (e.g.: ['true', 'True', 'TRUE']).
+**isBoolean(str [, options])** | check if the string is a boolean.
`options` is an object which defaults to `{ loose: false }`. If `loose` is set to false, the validator will strictly match ['true', 'false', '0', '1']. If `loose` is set to true, the validator will also match 'yes', 'no', and will match a valid boolean string of any case. (e.g.: ['true', 'True', 'TRUE']).
**isBtcAddress(str)** | check if the string is a valid BTC address.
**isByteLength(str [, options])** | check if the string's length (in UTF-8 bytes) falls in a range.
`options` is an object which defaults to `{ min: 0, max: undefined }`.
**isCreditCard(str [, options])** | check if the string is a credit card number.
`options` is an optional object that can be supplied with the following key(s): `provider` is an optional key whose value should be a string, and defines the company issuing the credit card. Valid values include `['amex', 'dinersclub', 'discover', 'jcb', 'mastercard', 'unionpay', 'visa']` or blank will check for any provider.
@@ -142,21 +133,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 the string matches the format of a country's license plate.
`locale` is one of `['cs-CZ', 'de-DE', 'de-LI', 'en-IN', 'es-AR', 'hu-HU', 'pt-BR', 'pt-PT', 'sq-AL', 'sv-SE']` or `'any'`.
+**isLicensePlate(str, locale)** | check if the string matches the format of a country's license plate.
`locale` is one of `['cs-CZ', 'de-DE', 'de-LI', 'en-IN', 'en-PK', 'es-AR', 'hu-HU', 'pt-BR', 'pt-PT', 'sq-AL', 'sv-SE']` or `'any'`.
**isLocale(str)** | check if the string is a locale.
**isLowercase(str)** | check if the string is lowercase.
**isLuhnNumber(str)** | check if the string passes the [Luhn algorithm check](https://en.wikipedia.org/wiki/Luhn_algorithm).
**isMACAddress(str [, options])** | 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'. The options also allow a `eui` property to specify if it needs to be validated against EUI-48 or EUI-64. The accepted values of `eui` are: 48, 64.
**isMagnetURI(str)** | check if the string is a [Magnet URI format][Magnet URI Format].
-**isMailtoURI(str, [, options])** | check if the string is a [Magnet URI format][Mailto URI Format].
`options` is an object of validating emails inside the URI (check `isEmail`s options for details).
+**isMailtoURI(str, [, options])** | check if the string is a [Mailto URI format][Mailto URI Format].
`options` is an object of validating emails inside the URI (check `isEmail`s options for details).
**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][MIME 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-EH', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-PS', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'az-AZ', 'az-LB', 'az-LY', 'be-BY', 'bg-BG', 'bn-BD', 'bs-BA', 'ca-AD', 'cs-CZ', 'da-DK', 'de-AT', 'de-CH', 'de-DE', 'de-LU', 'dv-MV', 'dz-BT', 'el-CY', 'el-GR', 'en-AG', 'en-AI', 'en-AU', 'en-BM', 'en-BS', 'en-BW', 'en-CA', 'en-GB', 'en-GG', 'en-GH', 'en-GY', 'en-HK', 'en-IE', 'en-IN', 'en-JM', 'en-KE', 'en-KI', 'en-KN', 'en-LS', 'en-MO', 'en-MT', 'en-MU', 'en-NG', 'en-NZ', 'en-PG', 'en-PH', 'en-PK', 'en-RW', 'en-SG', 'en-SL', 'en-SS', 'en-TZ', 'en-UG', 'en-US', 'en-ZA', 'en-ZM', 'en-ZW', 'es-AR', 'es-BO', 'es-CL', 'es-CO', 'es-CR', 'es-CU', 'es-DO', 'es-EC', 'es-ES', 'es-HN', 'es-MX', 'es-NI', 'es-PA', 'es-PE', 'es-PY', 'es-SV', 'es-UY', 'es-VE', 'et-EE', 'fa-AF', 'fa-IR', 'fi-FI', 'fj-FJ', 'fo-FO', 'fr-BE', 'fr-BF', 'fr-BJ', 'fr-CD', 'fr-CF', 'fr-FR', 'fr-GF', 'fr-GP', 'fr-MQ', 'fr-PF', 'fr-RE', 'fr-WF', 'ga-IE', 'he-IL', 'hu-HU', 'id-ID', 'ir-IR', 'it-IT', 'it-SM', 'ja-JP', 'ka-GE', 'kk-KZ', 'kl-GL', 'ko-KR', 'ky-KG', 'lt-LT', 'mg-MG', 'mn-MN', 'ms-MY', 'my-MM', 'mz-MZ', 'nb-NO', 'ne-NP', 'nl-AW', 'nl-BE', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-AO', 'pt-BR', 'pt-PT', 'ro-Md', 'ro-RO', 'ru-RU', 'si-LK', 'sk-SK', 'sl-SI', 'so-SO', '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']` 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-EH', 'ar-IQ', 'ar-JO', 'ar-KW', 'ar-PS', 'ar-SA', 'ar-SD', 'ar-SY', 'ar-TN', 'ar-YE', 'az-AZ', 'az-LB', 'az-LY', 'be-BY', 'bg-BG', 'bn-BD', 'bs-BA', 'ca-AD', 'cs-CZ', 'da-DK', 'de-AT', 'de-CH', 'de-DE', 'de-LU', 'dv-MV', 'dz-BT', 'el-CY', 'el-GR', 'en-AG', 'en-AI', 'en-AU', 'en-BM', 'en-BS', 'en-BW', 'en-CA', 'en-GB', 'en-GG', 'en-GH', 'en-GY', 'en-HK', 'en-IE', 'en-IN', 'en-JM', 'en-KE', 'en-KI', 'en-KN', 'en-LS', 'en-MO', 'en-MT', 'en-MU', 'en-MW', 'en-NG', 'en-NZ', 'en-PG', 'en-PH', 'en-PK', 'en-RW', 'en-SG', 'en-SL', 'en-SS', 'en-TZ', 'en-UG', 'en-US', 'en-ZA', 'en-ZM', 'en-ZW', 'es-AR', 'es-BO', 'es-CL', 'es-CO', 'es-CR', 'es-CU', 'es-DO', 'es-EC', 'es-ES', 'es-HN', 'es-MX', 'es-NI', 'es-PA', 'es-PE', 'es-PY', 'es-SV', 'es-UY', 'es-VE', 'et-EE', 'fa-AF', 'fa-IR', 'fi-FI', 'fj-FJ', 'fo-FO', 'fr-BE', 'fr-BF', 'fr-BJ', 'fr-CD', 'fr-CF', 'fr-FR', 'fr-GF', 'fr-GP', 'fr-MQ', 'fr-PF', 'fr-RE', 'fr-WF', 'ga-IE', 'he-IL', 'hu-HU', 'id-ID', 'ir-IR', 'it-IT', 'it-SM', 'ja-JP', 'ka-GE', 'kk-KZ', 'kl-GL', 'ko-KR', 'ky-KG', 'lt-LT', 'mg-MG', 'mn-MN', 'ms-MY', 'my-MM', 'mz-MZ', 'nb-NO', 'ne-NP', 'nl-AW', 'nl-BE', 'nl-NL', 'nn-NO', 'pl-PL', 'pt-AO', 'pt-BR', 'pt-PT', 'ro-Md', 'ro-RO', 'ru-RU', 'si-LK', 'sk-SK', 'sl-SI', 'so-SO', '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']` 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` 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', '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', 'AZ', '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', 'JM', 'JP', 'KR', 'KZ', 'LI', 'LT', 'LU', 'LV', 'LY', 'MT', 'MX', 'MY', 'MZ', 'NL', 'NZ', 'PH', 'PK', 'PL', 'PT', 'RO', 'RU', 'SE', 'SL', 'SK', 'TH', 'TR', 'UA', 'US']`.
+**isPassportNumber(str, countryCode)** | check if the string is a valid passport number.
`countryCode` is one of `['AM', 'AR', 'AT', 'AU', 'AZ', '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', 'JM', 'JP', 'KR', 'KZ', 'LI', 'LT', 'LU', 'LV', 'LY', 'MT', 'MX', 'MY', 'MZ', 'NL', 'NZ', 'PH', 'PK', 'PL', 'PT', 'RO', 'RU', 'SE', 'SL', 'SK', 'TH', 'TR', 'UA', 'US', 'ZA']`.
**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', 'BA', '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', 'MG', 'MT', 'MX', 'MY', 'NL', 'NO', 'NP', 'NZ', 'PL', 'PR', 'PT', 'RO', 'RU', 'SA', 'SE', 'SG', 'SI', 'SK', 'TH', 'TN', 'TW', 'UA', 'US', 'ZA', 'ZM']` OR `'any'`. If 'any' is used, function will check if any of the locales match. Locale list is `validator.isPostalCodeLocales`.
**isRFC3339(str)** | check if the string is a valid [RFC 3339][RFC 3339] date.
@@ -167,7 +158,7 @@ Validator | Description
**isSlug(str)** | check if the string is of type slug.
**isStrongPassword(str [, options])** | check if the string can be considered a strong password 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 }`
**isTime(str [, options])** | check if the string is a valid time e.g. [`23:01:59`, new Date().toLocaleTimeString()].
`options` is an object which can contain the keys `hourFormat` or `mode`.
`hourFormat` is a key and defaults to `'hour24'`.
`mode` is a key and defaults to `'default'`.
`hourFomat` can contain the values `'hour12'` or `'hour24'`, `'hour24'` will validate hours in 24 format and `'hour12'` will validate hours in 12 format.
`mode` can contain the values `'default'` or `'withSeconds'`, `'default'` will validate `HH:MM` format, `'withSeconds'` will validate the `HH:MM:SS` format.
-**isTaxID(str, locale)** | check if the string 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-CA', 'en-GB', 'en-IE', 'en-US', 'es-ES', 'et-EE', 'fi-FI', 'fr-BE', 'fr-CA', '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' ]`.
+**isTaxID(str, locale)** | check if the string 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-CA', 'en-GB', 'en-IE', 'en-US', 'es-AR', 'es-ES', 'et-EE', 'fi-FI', 'fr-BE', 'fr-CA', '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', 'uk-UA']`.
**isURL(str [, options])** | check if the string is a 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 to 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 to false isURL will not check if host is present in the URL.
`require_port` - if set to true isURL will check if port is present in the URL.
`allow_protocol_relative_urls` - if set to true protocol relative URLs will be allowed.
`allow_fragments` - if set to false isURL will return false if fragments are present.
`allow_query_components` - if set to false isURL will return false if query components are present.
`validate_length` - if set to 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 1, 2, 3, 4 or 5).
**isVariableWidth(str)** | check if the string contains a mixture of full and half-width chars.
@@ -201,33 +192,6 @@ XSS sanitization was removed from the library in [2d5d6999](https://github.com/v
For an alternative, have a look at Yahoo's [xss-filters library](https://github.com/yahoo/xss-filters) or at [DOMPurify](https://github.com/cure53/DOMPurify).
-## Contributing
-
-In general, we follow the "fork-and-pull" Git workflow.
-
-1. Fork the repo on GitHub
-2. Clone the project to your own machine
-3. Work on your fork
- 1. Make your changes and additions
- - Most of your changes should be focused on `src/` and `test/` folders and/or `README.md`.
- - Files such as `validator.js`, `validator.min.js` and files in `lib/` folder are autogenerated when running tests (`npm test`) and need not to be changed **manually**.
- 2. Change or add tests if needed
- 3. Run tests and make sure they pass
- 4. Add changes to README.md if needed
-4. Commit changes to your own branch
-5. **Make sure** you merge the latest from "upstream" and resolve conflicts if there is any
-6. Repeat step 3(3) above
-7. Push your work back up to your fork
-8. Submit a Pull request so that we can review your changes
-
-## Tests
-
-Tests are using mocha, to run the tests use:
-
-```sh
-$ npm test
-```
-
## Maintainers
- [chriso](https://github.com/chriso) - **Chris O'Hara** (author)
diff --git a/package.json b/package.json
index 3f088d3ce..854657f4d 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "validator",
"description": "String validation and sanitization",
- "version": "13.11.0",
+ "version": "13.12.0",
"sideEffects": false,
"homepage": "https://github.com/validatorjs/validator.js",
"files": [
@@ -51,6 +51,7 @@
"rimraf": "^3.0.0",
"rollup": "^0.47.0",
"rollup-plugin-babel": "^4.0.1",
+ "timezone-mock": "^1.3.6",
"uglify-js": "^3.0.19"
},
"scripts": {
diff --git a/src/index.js b/src/index.js
index bef4cfff4..ca0651de1 100644
--- a/src/index.js
+++ b/src/index.js
@@ -18,6 +18,7 @@ import isTime from './lib/isTime';
import isBoolean from './lib/isBoolean';
import isLocale from './lib/isLocale';
+import isAbaRouting from './lib/isAbaRouting';
import isAlpha, { locales as isAlphaLocales } from './lib/isAlpha';
import isAlphanumeric, { locales as isAlphanumericLocales } from './lib/isAlphanumeric';
import isNumeric from './lib/isNumeric';
@@ -126,7 +127,7 @@ import isStrongPassword from './lib/isStrongPassword';
import isVAT from './lib/isVAT';
-const version = '13.11.0';
+const version = '13.12.0';
const validator = {
version,
@@ -146,6 +147,7 @@ const validator = {
isBoolean,
isIBAN,
isBIC,
+ isAbaRouting,
isAlpha,
isAlphaLocales,
isAlphanumeric,
diff --git a/src/lib/alpha.js b/src/lib/alpha.js
index d540ed1cf..8c37934ff 100644
--- a/src/lib/alpha.js
+++ b/src/lib/alpha.js
@@ -35,6 +35,7 @@ export const alpha = {
he: /^[א-ת]+$/,
fa: /^['آاءأؤئبپتثجچحخدذرزژسشصضطظعغفقکگلمنوهةی']+$/i,
bn: /^['ঀঁংঃঅআইঈউঊঋঌএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলশষসহ়ঽািীুূৃৄেৈোৌ্ৎৗড়ঢ়য়ৠৡৢৣৰৱ৲৳৴৵৶৷৸৹৺৻']+$/,
+ eo: /^[ABCĈD-GĜHĤIJĴK-PRSŜTUŬVZ]+$/i,
'hi-IN': /^[\u0900-\u0961]+[\u0972-\u097F]*$/i,
'si-LK': /^[\u0D80-\u0DFF]+$/,
};
@@ -75,6 +76,7 @@ export const alphanumeric = {
he: /^[0-9א-ת]+$/,
fa: /^['0-9آاءأؤئبپتثجچحخدذرزژسشصضطظعغفقکگلمنوهةی۱۲۳۴۵۶۷۸۹۰']+$/i,
bn: /^['ঀঁংঃঅআইঈউঊঋঌএঐওঔকখগঘঙচছজঝঞটঠডঢণতথদধনপফবভমযরলশষসহ়ঽািীুূৃৄেৈোৌ্ৎৗড়ঢ়য়ৠৡৢৣ০১২৩৪৫৬৭৮৯ৰৱ৲৳৴৵৶৷৸৹৺৻']+$/,
+ eo: /^[0-9ABCĈD-GĜHĤIJĴK-PRSŜTUŬVZ]+$/i,
'hi-IN': /^[\u0900-\u0963]+[\u0966-\u097F]*$/i,
'si-LK': /^[0-9\u0D80-\u0DFF]+$/,
};
@@ -125,7 +127,7 @@ for (let locale, i = 0; i < bengaliLocales.length; i++) {
// Source: https://en.wikipedia.org/wiki/Decimal_mark
export const dotDecimal = ['ar-EG', 'ar-LB', 'ar-LY'];
export const commaDecimal = [
- 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'el-GR', 'en-ZM', 'es-ES', 'fr-CA', 'fr-FR',
+ 'bg-BG', 'cs-CZ', 'da-DK', 'de-DE', 'el-GR', 'en-ZM', 'eo', 'es-ES', 'fr-CA', 'fr-FR',
'id-ID', 'it-IT', 'ku-IQ', 'hi-IN', 'hu-HU', 'nb-NO', 'nn-NO', 'nl-NL', 'pl-PL', 'pt-PT',
'ru-RU', 'kk-KZ', 'si-LK', 'sl-SI', 'sr-RS@latin', 'sr-RS', 'sv-SE', 'tr-TR', 'uk-UA', 'vi-VN',
];
diff --git a/src/lib/isAbaRouting.js b/src/lib/isAbaRouting.js
new file mode 100644
index 000000000..0c6fd7fb2
--- /dev/null
+++ b/src/lib/isAbaRouting.js
@@ -0,0 +1,20 @@
+import assertString from './util/assertString';
+
+// http://www.brainjar.com/js/validation/
+// https://www.aba.com/news-research/research-analysis/routing-number-policy-procedures
+// series reserved for future use are excluded
+const isRoutingReg = /^(?!(1[3-9])|(20)|(3[3-9])|(4[0-9])|(5[0-9])|(60)|(7[3-9])|(8[1-9])|(9[0-2])|(9[3-9]))[0-9]{9}$/;
+
+export default function isAbaRouting(str) {
+ assertString(str);
+
+ if (!isRoutingReg.test(str)) return false;
+
+ let checkSumVal = 0;
+ for (let i = 0; i < str.length; i++) {
+ if (i % 3 === 0) checkSumVal += str[i] * 3;
+ else if (i % 3 === 1) checkSumVal += str[i] * 7;
+ else checkSumVal += str[i] * 1;
+ }
+ return (checkSumVal % 10 === 0);
+}
diff --git a/src/lib/isDate.js b/src/lib/isDate.js
index 9f1c6926b..dc69b3bc1 100644
--- a/src/lib/isDate.js
+++ b/src/lib/isDate.js
@@ -22,7 +22,7 @@ function zip(date, format) {
}
export default function isDate(input, options) {
- if (typeof options === 'string') { // Allow backward compatbility for old format isDate(input [, format])
+ if (typeof options === 'string') { // Allow backward compatibility for old format isDate(input [, format])
options = merge({ format: options }, default_date_options);
} else {
options = merge(options, default_date_options);
@@ -49,6 +49,11 @@ export default function isDate(input, options) {
let fullYear = dateObj.y;
+ // Check if the year starts with a hyphen
+ if (fullYear.startsWith('-')) {
+ return false; // Hyphen before year is not allowed
+ }
+
if (dateObj.y.length === 2) {
const parsedYear = parseInt(dateObj.y, 10);
@@ -65,7 +70,19 @@ export default function isDate(input, options) {
}
}
- return new Date(`${fullYear}-${dateObj.m}-${dateObj.d}`).getDate() === +dateObj.d;
+ let month = dateObj.m;
+
+ if (dateObj.m.length === 1) {
+ month = `0${dateObj.m}`;
+ }
+
+ let day = dateObj.d;
+
+ if (dateObj.d.length === 1) {
+ day = `0${dateObj.d}`;
+ }
+
+ return new Date(`${fullYear}-${month}-${day}T00:00:00.000Z`).getUTCDate() === +dateObj.d;
}
if (!options.strictMode) {
diff --git a/src/lib/isIBAN.js b/src/lib/isIBAN.js
index dd226b1da..5edcf83a5 100644
--- a/src/lib/isIBAN.js
+++ b/src/lib/isIBAN.js
@@ -24,6 +24,7 @@ const ibanRegexThroughCountryCode = {
DE: /^(DE[0-9]{2})\d{18}$/,
DK: /^(DK[0-9]{2})\d{14}$/,
DO: /^(DO[0-9]{2})[A-Z]{4}\d{20}$/,
+ DZ: /^(DZ\d{24})$/,
EE: /^(EE[0-9]{2})\d{16}$/,
EG: /^(EG[0-9]{2})\d{25}$/,
ES: /^(ES[0-9]{2})\d{20}$/,
diff --git a/src/lib/isISO4217.js b/src/lib/isISO4217.js
index 0738614c9..076d5a614 100644
--- a/src/lib/isISO4217.js
+++ b/src/lib/isISO4217.js
@@ -20,7 +20,7 @@ const validISO4217CurrencyCodes = new Set([
'PAB', 'PEN', 'PGK', 'PHP', 'PKR', 'PLN', 'PYG',
'QAR',
'RON', 'RSD', 'RUB', 'RWF',
- 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLL', 'SOS', 'SRD', 'SSP', 'STN', 'SVC', 'SYP', 'SZL',
+ 'SAR', 'SBD', 'SCR', 'SDG', 'SEK', 'SGD', 'SHP', 'SLE', 'SLL', 'SOS', 'SRD', 'SSP', 'STN', 'SVC', 'SYP', 'SZL',
'THB', 'TJS', 'TMT', 'TND', 'TOP', 'TRY', 'TTD', 'TWD', 'TZS',
'UAH', 'UGX', 'USD', 'USN', 'UYI', 'UYU', 'UYW', 'UZS',
'VES', 'VND', 'VUV',
diff --git a/src/lib/isInt.js b/src/lib/isInt.js
index 8047a6969..edd67f75a 100644
--- a/src/lib/isInt.js
+++ b/src/lib/isInt.js
@@ -9,10 +9,7 @@ export default function isInt(str, options) {
// Get the regex to use for testing, based on whether
// leading zeroes are allowed or not.
- let regex = (
- options.hasOwnProperty('allow_leading_zeroes') && !options.allow_leading_zeroes ?
- int : intLeadingZeroes
- );
+ const regex = options.allow_leading_zeroes === false ? int : intLeadingZeroes;
// Check min/max/lt/gt
let minCheckPassed = (!options.hasOwnProperty('min') || str >= options.min);
diff --git a/src/lib/isLicensePlate.js b/src/lib/isLicensePlate.js
index 48f8ebe99..8476f2f9e 100644
--- a/src/lib/isLicensePlate.js
+++ b/src/lib/isLicensePlate.js
@@ -18,6 +18,7 @@ const validators = {
/^[A-Z]{2}[- ]?((\d{3}[- ]?(([A-Z]{2})|T))|(R[- ]?\d{3}))$/.test(str),
'sv-SE': str =>
/^[A-HJ-PR-UW-Z]{3} ?[\d]{2}[A-HJ-PR-UW-Z1-9]$|(^[A-ZÅÄÖ ]{2,7}$)/.test(str.trim()),
+ 'en-PK': str => /(^[A-Z]{2}((\s|-){0,1})[0-9]{3,4}((\s|-)[0-9]{2}){0,1}$)|(^[A-Z]{3}((\s|-){0,1})[0-9]{3,4}((\s|-)[0-9]{2}){0,1}$)|(^[A-Z]{4}((\s|-){0,1})[0-9]{3,4}((\s|-)[0-9]{2}){0,1}$)|(^[A-Z]((\s|-){0,1})[0-9]{4}((\s|-)[0-9]{2}){0,1}$)/.test(str.trim()),
};
export default function isLicensePlate(str, locale) {
diff --git a/src/lib/isMailtoURI.js b/src/lib/isMailtoURI.js
index 0dd95b6a9..67748a553 100644
--- a/src/lib/isMailtoURI.js
+++ b/src/lib/isMailtoURI.js
@@ -41,7 +41,7 @@ export default function isMailtoURI(url, options) {
return false;
}
- const [to = '', queryString = ''] = url.replace('mailto:', '').split('?');
+ const [to, queryString = ''] = url.replace('mailto:', '').split('?');
if (!to && !queryString) {
return true;
diff --git a/src/lib/isMobilePhone.js b/src/lib/isMobilePhone.js
index 1da97ce88..4d8192191 100644
--- a/src/lib/isMobilePhone.js
+++ b/src/lib/isMobilePhone.js
@@ -2,7 +2,7 @@ import assertString from './util/assertString';
/* eslint-disable max-len */
const phones = {
- 'am-AM': /^(\+?374|0)((10|[9|7][0-9])\d{6}$|[2-4]\d{7}$)/,
+ 'am-AM': /^(\+?374|0)(33|4[134]|55|77|88|9[13-689])\d{6}$/,
'ar-AE': /^((\+?971)|0)?5[024568]\d{7}$/,
'ar-BH': /^(\+?973)?(3|6)\d{7}$/,
'ar-DZ': /^(\+?213|0)(5|6|7)\d{8}$/,
@@ -56,6 +56,7 @@ const phones = {
'en-LS': /^(\+?266)(22|28|57|58|59|27|52)\d{6}$/,
'en-MT': /^(\+?356|0)?(99|79|77|21|27|22|25)[0-9]{6}$/,
'en-MU': /^(\+?230|0)?\d{8}$/,
+ 'en-MW': /^(\+?265|0)(((77|88|31|99|98|21)\d{7})|(((111)|1)\d{6})|(32000\d{4}))$/,
'en-NA': /^(\+?264|0)(6|8)\d{7}$/,
'en-NG': /^(\+?234|0)?[789]\d{9}$/,
'en-NZ': /^(\+?64|0)[28]\d{7,9}$/,
diff --git a/src/lib/isPassportNumber.js b/src/lib/isPassportNumber.js
index 11d01e8d1..c1803fb50 100644
--- a/src/lib/isPassportNumber.js
+++ b/src/lib/isPassportNumber.js
@@ -11,7 +11,7 @@ const passportRegexByCountryCode = {
AR: /^[A-Z]{3}\d{6}$/, // ARGENTINA
AT: /^[A-Z]\d{7}$/, // AUSTRIA
AU: /^[A-Z]\d{7}$/, // AUSTRALIA
- AZ: /^[A-Z]{2,3}\d{7,8}$/, // AZERBAIJAN
+ AZ: /^[A-Z]{1}\d{8}$/, // AZERBAIJAN
BE: /^[A-Z]{2}\d{6}$/, // BELGIUM
BG: /^\d{9}$/, // BULGARIA
BR: /^[A-Z]{2}\d{6}$/, // BRAZIL
@@ -66,6 +66,7 @@ const passportRegexByCountryCode = {
TR: /^[A-Z]\d{8}$/, // TURKEY
UA: /^[A-Z]{2}\d{6}$/, // UKRAINE
US: /^\d{9}$/, // UNITED STATES
+ ZA: /^[TAMD]\d{8}$/, // SOUTH AFRICA
};
/**
diff --git a/src/lib/isPort.js b/src/lib/isPort.js
index 0b316b78c..0a9ddce1d 100644
--- a/src/lib/isPort.js
+++ b/src/lib/isPort.js
@@ -1,5 +1,5 @@
import isInt from './isInt';
export default function isPort(str) {
- return isInt(str, { min: 0, max: 65535 });
+ return isInt(str, { allow_leading_zeroes: false, min: 0, max: 65535 });
}
diff --git a/src/lib/isPostalCode.js b/src/lib/isPostalCode.js
index e6213914f..99cba290b 100644
--- a/src/lib/isPostalCode.js
+++ b/src/lib/isPostalCode.js
@@ -52,7 +52,7 @@ const patterns = {
MX: fiveDigit,
MT: /^[A-Za-z]{3}\s{0,1}\d{4}$/,
MY: fiveDigit,
- NL: /^\d{4}\s?[a-z]{2}$/i,
+ NL: /^[1-9]\d{3}\s?(?!sa|sd|ss)[a-z]{2}$/i,
NO: fourDigit,
NP: /^(10|21|22|32|33|34|44|45|56|57)\d{3}$|^(977)$/i,
NZ: fourDigit,
diff --git a/src/lib/isStrongPassword.js b/src/lib/isStrongPassword.js
index 5db901fa3..8fe9223b7 100644
--- a/src/lib/isStrongPassword.js
+++ b/src/lib/isStrongPassword.js
@@ -4,7 +4,7 @@ import assertString from './util/assertString';
const upperCaseRegex = /^[A-Z]$/;
const lowerCaseRegex = /^[a-z]$/;
const numberRegex = /^[0-9]$/;
-const symbolRegex = /^[-#!$@£%^&*()_+|~=`{}\[\]:";'<>?,.\/ ]$/;
+const symbolRegex = /^[-#!$@£%^&*()_+|~=`{}\[\]:";'<>?,.\/\\ ]$/;
const defaultOptions = {
minLength: 8,
diff --git a/src/lib/isTaxID.js b/src/lib/isTaxID.js
index 933783f44..d13229f69 100644
--- a/src/lib/isTaxID.js
+++ b/src/lib/isTaxID.js
@@ -376,6 +376,30 @@ function enUsCheck(tin) {
return enUsGetPrefixes().indexOf(tin.slice(0, 2)) !== -1;
}
+/*
+ * es-AR validation function
+ * Clave Única de Identificación Tributaria (CUIT/CUIL)
+ * Sourced from:
+ * - https://servicioscf.afip.gob.ar/publico/abc/ABCpaso2.aspx?id_nivel1=3036&id_nivel2=3040&p=Conceptos%20b%C3%A1sicos
+ * - https://es.wikipedia.org/wiki/Clave_%C3%9Anica_de_Identificaci%C3%B3n_Tributaria
+ */
+
+function esArCheck(tin) {
+ let accum = 0;
+ let digits = tin.split('');
+ let digit = parseInt(digits.pop(), 10);
+ for (let i = 0; i < digits.length; i++) {
+ accum += digits[9 - i] * (2 + (i % 6));
+ }
+ let verif = 11 - (accum % 11);
+ if (verif === 11) {
+ verif = 0;
+ } else if (verif === 10) {
+ verif = 9;
+ }
+ return digit === verif;
+}
+
/*
* es-ES validation function
* (Documento Nacional de Identidad (DNI)
@@ -1117,6 +1141,21 @@ function svSeCheck(tin) {
return algorithms.luhnCheck(tin.replace(/\W/, ''));
}
+/**
+ * uk-UA validation function
+ * Verify TIN validity by calculating check (last) digit (variant of MOD 11)
+ */
+function ukUaCheck(tin) {
+ // Calculate check digit
+ const digits = tin.split('').map(a => parseInt(a, 10));
+ const multipliers = [-1, 5, 7, 9, 4, 6, 10, 5, 7];
+ let checksum = 0;
+ for (let i = 0; i < multipliers.length; i++) {
+ checksum += digits[i] * multipliers[i];
+ }
+ return checksum % 11 === 10 ? digits[9] === 0 : digits[9] === checksum % 11;
+}
+
// Locale lookup objects
/*
@@ -1137,6 +1176,7 @@ const taxIdFormat = {
'en-GB': /^\d{10}$|^(?!GB|NK|TN|ZZ)(?![DFIQUV])[A-Z](?![DFIQUVO])[A-Z]\d{6}[ABCD ]$/i,
'en-IE': /^\d{7}[A-W][A-IW]{0,1}$/i,
'en-US': /^\d{2}[- ]{0,1}\d{7}$/,
+ 'es-AR': /(20|23|24|27|30|33|34)[0-9]{8}[0-9]/,
'es-ES': /^(\d{0,8}|[XYZKLM]\d{7})[A-HJ-NP-TV-Z]$/i,
'et-EE': /^[1-6]\d{6}(00[1-9]|0[1-9][0-9]|[1-6][0-9]{2}|70[0-9]|710)\d$/,
'fi-FI': /^\d{6}[-+A]\d{3}[0-9A-FHJ-NPR-Y]$/i,
@@ -1156,6 +1196,7 @@ const taxIdFormat = {
'sk-SK': /^\d{6}\/{0,1}\d{3,4}$/,
'sl-SI': /^[1-9]\d{7}$/,
'sv-SE': /^(\d{6}[-+]{0,1}\d{4}|(18|19|20)\d{6}[-+]{0,1}\d{4})$/,
+ 'uk-UA': /^\d{10}$/,
};
// taxIdFormat locale aliases
taxIdFormat['lb-LU'] = taxIdFormat['fr-LU'];
@@ -1175,6 +1216,7 @@ const taxIdCheck = {
'en-CA': isCanadianSIN,
'en-IE': enIeCheck,
'en-US': enUsCheck,
+ 'es-AR': esArCheck,
'es-ES': esEsCheck,
'et-EE': etEeCheck,
'fi-FI': fiFiCheck,
@@ -1194,6 +1236,7 @@ const taxIdCheck = {
'sk-SK': skSkCheck,
'sl-SI': slSiCheck,
'sv-SE': svSeCheck,
+ 'uk-UA': ukUaCheck,
};
// taxIdCheck locale aliases
taxIdCheck['lb-LU'] = taxIdCheck['fr-LU'];
diff --git a/src/lib/isUUID.js b/src/lib/isUUID.js
index c026ca78c..512141df6 100644
--- a/src/lib/isUUID.js
+++ b/src/lib/isUUID.js
@@ -6,6 +6,7 @@ const uuid = {
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,
+ 7: /^[0-9A-F]{8}-[0-9A-F]{4}-7[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,
};
diff --git a/src/lib/isVAT.js b/src/lib/isVAT.js
index ece7d8560..50fcf52e0 100644
--- a/src/lib/isVAT.js
+++ b/src/lib/isVAT.js
@@ -1,6 +1,22 @@
import assertString from './util/assertString';
import * as algorithms from './util/algorithms';
+const AU = (str) => {
+ const match = str.match(/^(AU)?(\d{11})$/);
+ if (!match) {
+ return false;
+ }
+ // @see {@link https://abr.business.gov.au/Help/AbnFormat}
+ const weights = [10, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19];
+ str = str.replace(/^AU/, '');
+ const ABN = (parseInt(str.slice(0, 1), 10) - 1).toString() + str.slice(1);
+ let total = 0;
+ for (let i = 0; i < 11; i++) {
+ total += weights[i] * ABN.charAt(i);
+ }
+ return (total !== 0 && total % 89 === 0);
+};
+
const CH = (str) => {
// @see {@link https://www.ech.ch/de/ech/ech-0097/5.2.0}
const hasValidCheckNumber = (digits) => {
@@ -68,14 +84,14 @@ export const vatMatchers = {
*/
AL: str => /^(AL)?\w{9}[A-Z]$/.test(str),
MK: str => /^(MK)?\d{13}$/.test(str),
- AU: str => /^(AU)?\d{11}$/.test(str),
+ AU,
BY: str => /^(УНП )?\d{9}$/.test(str),
CA: str => /^(CA)?\d{9}$/.test(str),
IS: str => /^(IS)?\d{5,6}$/.test(str),
IN: str => /^(IN)?\d{15}$/.test(str),
ID: str => /^(ID)?(\d{15}|(\d{2}.\d{3}.\d{3}.\d{1}-\d{3}.\d{3}))$/.test(str),
IL: str => /^(IL)?\d{9}$/.test(str),
- KZ: str => /^(KZ)?\d{9}$/.test(str),
+ KZ: str => /^(KZ)?\d{12}$/.test(str),
NZ: str => /^(NZ)?\d{9}$/.test(str),
NG: str => /^(NG)?(\d{12}|(\d{8}-\d{4}))$/.test(str),
NO: str => /^(NO)?\d{9}MVA$/.test(str),
diff --git a/test/validators.test.js b/test/validators.test.js
index 6bf812d15..3928a1c5c 100644
--- a/test/validators.test.js
+++ b/test/validators.test.js
@@ -1,5 +1,6 @@
import assert from 'assert';
import fs from 'fs';
+import timezone_mock from 'timezone-mock';
import { format } from 'util';
import vm from 'vm';
import validator from '../src/index';
@@ -2047,6 +2048,25 @@ describe('Validators', () => {
});
});
+ it('should validate Esperanto alpha strings', () => {
+ test({
+ validator: 'isAlpha',
+ args: ['eo'],
+ valid: [
+ 'saluton',
+ 'eĥoŝanĝoĉiuĵaŭde',
+ 'EĤOŜANĜOĈIUĴAŬDE',
+ 'Esperanto',
+ 'LaŭLudovikoZamenhofBongustasFreŝaĈeĥaManĝaĵoKunSpicoj',
+ ],
+ invalid: [
+ 'qwxyz',
+ '1887',
+ 'qwxyz 1887',
+ ],
+ });
+ });
+
it('should error on invalid locale', () => {
test({
validator: 'isAlpha',
@@ -2734,6 +2754,24 @@ describe('Validators', () => {
});
});
+ it('should validate Esperanto alphanumeric strings', () => {
+ test({
+ validator: 'isAlphanumeric',
+ args: ['eo'],
+ valid: [
+ 'saluton',
+ 'eĥoŝanĝoĉiuĵaŭde0123456789',
+ 'EĤOŜANĜOĈIUĴAŬDE0123456789',
+ 'Esperanto1887',
+ 'LaŭLudovikoZamenhofBongustasFreŝaĈeĥaManĝaĵoKunSpicoj',
+ ],
+ invalid: [
+ 'qwxyz',
+ 'qwxyz 1887',
+ ],
+ });
+ });
+
it('should error on invalid locale', () => {
test({
validator: 'isAlphanumeric',
@@ -2854,6 +2892,7 @@ describe('Validators', () => {
'',
'-1',
'65536',
+ '0080',
],
});
});
@@ -2925,11 +2964,11 @@ describe('Validators', () => {
validator: 'isPassportNumber',
args: ['AZ'],
valid: [
- 'AZE16175905',
- 'AA1617595',
+ 'A16175905',
+ 'A16175958',
],
invalid: [
- 'A12345843',
+ 'AZ1234584',
],
});
@@ -3647,6 +3686,21 @@ describe('Validators', () => {
'7903699371',
],
});
+
+ test({
+ validator: 'isPassportNumber',
+ args: ['ZA'],
+ valid: [
+ 'T12345678',
+ 'A12345678',
+ 'M12345678',
+ 'D12345678',
+ ],
+ invalid: [
+ '123456789',
+ 'Z12345678',
+ ],
+ });
});
it('should validate decimal numbers', () => {
@@ -5020,6 +5074,7 @@ describe('Validators', () => {
'A987FBC9-4BED-3078-CF07-9141BA07C9F3',
'A987FBC9-4BED-4078-8F07-9141BA07C9F3',
'A987FBC9-4BED-5078-AF07-9141BA07C9F3',
+ '018C544A-D384-7000-BB74-3B1738ABE43C',
],
invalid: [
'',
@@ -5037,6 +5092,7 @@ describe('Validators', () => {
valid: [
'A117FBC9-4BED-3078-CF07-9141BA07C9F3',
'A117FBC9-4BED-5078-AF07-9141BA07C9F3',
+ '018C544A-D384-7000-BB74-3B1738ABE43C',
],
invalid: [
'',
@@ -5050,6 +5106,7 @@ describe('Validators', () => {
args: [null],
valid: [
'A127FBC9-4BED-3078-CF07-9141BA07C9F3',
+ '018C544A-D384-7000-BB74-3B1738ABE43C',
],
invalid: [
'',
@@ -5071,6 +5128,7 @@ describe('Validators', () => {
'AAAAAAAA-1111-2222-AAAG-111111111111',
'A987FBC9-4BED-4078-8F07-9141BA07C9F3',
'A987FBC9-4BED-5078-AF07-9141BA07C9F3',
+ '018C544A-D384-7000-BB74-3B1738ABE43C',
],
});
test({
@@ -5086,6 +5144,7 @@ describe('Validators', () => {
'AAAAAAAA-1111-1111-AAAG-111111111111',
'A987FBC9-4BED-4078-8F07-9141BA07C9F3',
'A987FBC9-4BED-5078-AF07-9141BA07C9F3',
+ '018C544A-D384-7000-BB74-3B1738ABE43C',
],
});
test({
@@ -5101,6 +5160,7 @@ describe('Validators', () => {
'AAAAAAAA-1111-1111-AAAG-111111111111',
'A987FBC9-4BED-4078-8F07-9141BA07C9F3',
'A987FBC9-4BED-5078-AF07-9141BA07C9F3',
+ '018C544A-D384-7000-BB74-3B1738ABE43C',
],
});
test({
@@ -5119,6 +5179,7 @@ describe('Validators', () => {
'AAAAAAAA-1111-1111-AAAG-111111111111',
'A987FBC9-4BED-5078-AF07-9141BA07C9F3',
'A987FBC9-4BED-3078-CF07-9141BA07C9F3',
+ '018C544A-D384-7000-BB74-3B1738ABE43C',
],
});
test({
@@ -5137,6 +5198,7 @@ describe('Validators', () => {
'AAAAAAAA-1111-1111-AAAG-111111111111',
'9c858901-8a57-4791-81fe-4c455b099bc9',
'A987FBC9-4BED-3078-CF07-9141BA07C9F3',
+ '018C544A-D384-7000-BB74-3B1738ABE43C',
],
});
test({
@@ -5149,6 +5211,26 @@ describe('Validators', () => {
'987FBC97-4BED-3078-AF07-9141BA07C9F3',
'987FBC97-4BED-4078-AF07-9141BA07C9F3',
'987FBC97-4BED-5078-AF07-9141BA07C9F3',
+ '018C544A-D384-7000-BB74-3B1738ABE43C',
+ ],
+ });
+ test({
+ validator: 'isUUID',
+ args: [7],
+ valid: [
+ '018C544A-D384-7000-BB74-3B1738ABE43C',
+ ],
+ invalid: [
+ '',
+ 'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3',
+ '934859',
+ 'AAAAAAAA-1111-1111-AAAG-111111111111',
+ 'A987FBC9-4BED-5078-AF07-9141BA07C9F3',
+ 'A987FBC9-4BED-3078-CF07-9141BA07C9F3',
+ '713ae7e3-cb32-45f9-adcb-7c4fa86b90c1',
+ '625e63f3-58f5-40b7-83a1-a72ad31acffb',
+ '57b73598-8764-4ad0-a76a-679bb6640eb1',
+ '9c858901-8a57-4791-81fe-4c455b099bc9',
],
});
});
@@ -5231,6 +5313,26 @@ describe('Validators', () => {
});
});
+ it('should validate ABA routing number', () => {
+ test({
+ validator: 'isAbaRouting',
+ valid: [
+ '322070381',
+ '011103093',
+ '263170175',
+ '124303065',
+ ],
+ invalid: [
+ '426317017',
+ '789456124',
+ '603558459',
+ 'qwerty',
+ '12430306',
+ '382070381',
+ ],
+ });
+ });
+
it('should validate IBAN', () => {
test({
validator: 'isIBAN',
@@ -5258,6 +5360,7 @@ describe('Validators', () => {
'IR200170000000339545727003',
'MZ97123412341234123412341',
'MA64011519000001205000534921',
+ 'DZ580002100001113000000570',
],
invalid: [
'XX22YYY1234567890123',
@@ -6631,20 +6734,39 @@ describe('Validators', () => {
{
locale: 'am-AM',
valid: [
- '+37410324123',
- '+37422298765',
- '+37431276521',
- '022698763',
- '37491987654',
- '+37494567890',
+ '+37433123456',
+ '+37441123456',
+ '+37443123456',
+ '+37444123456',
+ '+37455123456',
+ '+37477123456',
+ '+37488123456',
+ '+37491123456',
+ '+37493123456',
+ '+37494123456',
+ '+37495123456',
+ '+37496123456',
+ '+37498123456',
+ '+37499123456',
+ '055123456',
+ '37455123456',
],
invalid: [
'12345',
- '+37411498855',
- '+37411498123',
+ '+37403498855',
+ '+37416498123',
'05614988556',
'',
'37456789000',
+ '37486789000',
+ '+37431312345',
+ '+37430312345',
+ '+37460123456',
+ '+37410324123',
+ '+37422298765',
+ '+37431276521',
+ '022698763',
+ '+37492123456',
],
},
{
@@ -7715,6 +7837,25 @@ describe('Validators', () => {
'+255800723845',
],
},
+ {
+ locale: 'en-MW',
+ valid: [
+ '+265994563785',
+ '+265111785436',
+ '+265318596857',
+ '0320008744',
+ '01256258',
+ '0882541896',
+ '+265984563214',
+ ],
+ invalid: [
+ '58563',
+ '+2658256258',
+ '0896328741',
+ '0708574896',
+ '+26570857489635',
+ ],
+ },
{
locale: 'es-PE',
valid: [
@@ -11420,6 +11561,7 @@ describe('Validators', () => {
'MYR',
'SGD',
'USD',
+ 'SLE',
],
invalid: [
'',
@@ -11840,6 +11982,13 @@ describe('Validators', () => {
'3950IO',
'3997 GH',
],
+ invalid: [
+ '1234',
+ '0603 JV',
+ '5194SA',
+ '9164 SD',
+ '1841SS',
+ ],
},
{
locale: 'NP',
@@ -12477,6 +12626,27 @@ describe('Validators', () => {
'28-1234567',
'96-1234567'],
});
+ test({
+ validator: 'isTaxID',
+ args: ['es-AR'],
+ valid: [
+ '20271633638',
+ '23274986069',
+ '27333234519',
+ '30678561165',
+ '33693450239',
+ '30534868460',
+ '23111111129',
+ '34557619099'],
+ invalid: [
+ '20-27163363-8',
+ '20.27163363.8',
+ '33693450231',
+ '69345023',
+ '693450233123123',
+ '3369ew50231',
+ '34557619095'],
+ });
test({
validator: 'isTaxID',
args: ['es-ES'],
@@ -12786,6 +12956,19 @@ describe('Validators', () => {
'19640823-32333',
'1964082332333'],
});
+ test({
+ validator: 'isTaxID',
+ args: ['uk-UA'],
+ valid: [
+ '3006321856',
+ '3003102490',
+ '2164212906'],
+ invalid: [
+ '2565975632',
+ '256597563287',
+ 'КС00123456',
+ '2896235845'],
+ });
test({
validator: 'isTaxID',
valid: [
@@ -12851,6 +13034,7 @@ describe('Validators', () => {
'+&DxJ=X7-4L8jRCD',
'etV*p%Nr6w&H%FeF',
'£3.ndSau_7',
+ 'VaLIDWith\\Symb0l',
],
invalid: [
'',
@@ -12916,6 +13100,8 @@ describe('Validators', () => {
'2019-02-29', // non-leap year
'2020-04-31', // invalid date
'2020/03-15', // mixed delimiter
+ '-2020-04-19',
+ '-2023/05/24',
],
});
test({
@@ -13054,6 +13240,17 @@ describe('Validators', () => {
'29.02.2020',
],
});
+ // emulating Pacific time zone offset & time
+ // which could potentially result in UTC conversion issues
+ timezone_mock.register('US/Pacific');
+ test({
+ validator: 'isDate',
+ valid: [
+ new Date(2016, 2, 29),
+ '2017-08-04',
+ ],
+ });
+ timezone_mock.unregister();
});
it('should validate time', () => {
test({
@@ -13506,6 +13703,30 @@ describe('Validators', () => {
],
invalid: ['mh04ad0045', 'invalidlicenseplate', '4578', '', 'GJ054GH4785'],
});
+ test({
+ validator: 'isLicensePlate',
+ args: ['en-PK'],
+ valid: [
+ 'P 1789',
+ 'RL745',
+ 'RIR 5421',
+ 'KHI 201',
+ 'LB6571',
+ 'LHR-786-23',
+ 'AJGB 816-10',
+ 'LES 7891 06',
+ 'IDS 7871',
+ 'LEH 4607 15',
+ ],
+ invalid: [
+ 'ajgb 816-10',
+ ' 278-37',
+ 'ABZ-27',
+ '',
+ 'ABC-123-',
+ 'D 272',
+ ],
+ });
});
it('should validate VAT numbers', () => {
test({
@@ -13884,10 +14105,24 @@ describe('Validators', () => {
validator: 'isVAT',
args: ['AU'],
valid: [
+ 'AU53004085616',
+ '53004085616',
+ 'AU65613309809',
+ '65613309809',
+ 'AU34118972998',
+ '34118972998',
+ ],
+ invalid: [
+ 'AU65613309808',
+ '65613309808',
+ 'AU55613309809',
+ '55613309809',
+ 'AU65613319809',
+ '65613319809',
+ 'AU34117972998',
+ '34117972998',
'AU12345678901',
'12345678901',
- ],
- invalid: [
'AU 12345678901',
'1234567890',
],
@@ -13970,11 +14205,11 @@ describe('Validators', () => {
validator: 'isVAT',
args: ['KZ'],
valid: [
- 'KZ123456789',
- '123456789',
+ 'KZ123456789012',
+ '123456789012',
],
invalid: [
- 'KZ 123456789',
+ 'KZ 123456789012',
'12345678',
],
});