Skip to content

Commit 88e0d3d

Browse files
feat(isISO31661Alpha2/3): Add support for Kosovo (XK / XXK) (#2663)
* feat(isISO31661Alpha2/3): Add options to both validators to accept user assigned codes" * feat(isISO31661Alpha2/3): Add tests
1 parent c3dc37c commit 88e0d3d

File tree

6 files changed

+178
-67
lines changed

6 files changed

+178
-67
lines changed

README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,16 +111,16 @@ Validator | Description
111111
**isEthereumAddress(str)** | check if the string is an [Ethereum][Ethereum] address. Does not validate address checksums.
112112
**isFloat(str [, options])** | check if the string is a float.<br/><br/>`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.<br/><br/>`min` and `max` are equivalent to 'greater or equal' and 'less or equal', respectively while `gt` and `lt` are their strict counterparts.<br/><br/>`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', 'eo', '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`.
113113
**isFQDN(str [, options])** | check if the string is a fully qualified domain name (e.g. domain.com).<br/><br/>`options` is an object which defaults to `{ require_tld: true, allow_underscores: false, allow_trailing_dot: false, allow_numeric_tld: false, allow_wildcard: false, ignore_max_length: false }`.<br/><br/>`require_tld` - If set to false the validator will not check if the domain includes a TLD.<br/>`allow_underscores` - if set to true, the validator will allow underscores in the domain.<br/>`allow_trailing_dot` - if set to true, the validator will allow the domain to end with a `.` character.<br/>`allow_numeric_tld` - if set to true, the validator will allow the TLD of the domain to be made up solely of numbers.<br />`allow_wildcard` - if set to true, the validator will allow domains starting with `*.` (e.g. `*.example.com` or `*.shop.example.com`).<br/>`ignore_max_length` - if set to true, the validator will not check for the standard max length of a domain.<br/>
114-
**isFreightContainerID(str)** | alias for `isISO6346`, check if the string is a valid [ISO 6346](https://en.wikipedia.org/wiki/ISO_6346) shipping container identification.
114+
**isFreightContainerID(str)** | alias for `isISO6346`, check if the string is a valid [ISO 6346](https://en.wikipedia.org/wiki/ISO_6346) shipping container identification.
115115
**isFullWidth(str)** | check if the string contains any full-width chars.
116116
**isHalfWidth(str)** | check if the string contains any half-width chars.
117117
**isHash(str, algorithm)** | check if the string is a hash of type algorithm.<br/><br/>Algorithm is one of `['crc32', 'crc32b', 'md4', 'md5', 'ripemd128', 'ripemd160', 'sha1', 'sha256', 'sha384', 'sha512', 'tiger128', 'tiger160', 'tiger192']`.
118118
**isHexadecimal(str)** | check if the string is a hexadecimal number.
119119
**isHexColor(str [, options])** | check if the string is a hexadecimal color. <br/><br/>`options` is an object that defaults to `{ require_hashtag: false }`.<br />Options: <br/> `require_hashtag`: Enforce # prefix, default false.
120120
**isHSL(str)** | check if the string is an HSL (hue, saturation, lightness, optional alpha) color based on [CSS Colors Level 4 specification][CSS Colors Level 4 Specification].<br/><br/>Comma-separated format supported. Space-separated format supported with the exception of a few edge cases (ex: `hsl(200grad+.1%62%/1)`).
121-
**isIBAN(str, [, options])** | check if the string is an IBAN (International Bank Account Number).<br/><br/>`options` is an object which accepts two attributes: `whitelist`: where you can restrict IBAN codes you want to receive data from and `blacklist`: where you can remove some of the countries from the current list. For both you can use an array with the following values `['AD','AE','AL','AT','AZ','BA','BE','BG','BH','BR','BY','CH','CR','CY','CZ','DE','DK','DO','EE','EG','ES','FI','FO','FR','GB','GE','GI','GL','GR','GT','HR','HU','IE','IL','IQ','IR','IS','IT','JO','KW','KZ','LB','LC','LI','LT','LU','LV','MC','MD','ME','MK','MR','MT','MU','MZ','NL','NO','PK','PL','PS','PT','QA','RO','RS','SA','SC','SE','SI','SK','SM','SV','TL','TN','TR','UA','VA','VG','XK']`.
121+
**isIBAN(str, [, options])** | check if the string is an IBAN (International Bank Account Number).<br/><br/>`options` is an object which accepts two attributes: `whitelist`: where you can restrict IBAN codes you want to receive data from and `blacklist`: where you can remove some of the countries from the current list. For both you can use an array with the following values `['AD','AE','AL','AT','AZ','BA','BE','BG','BH','BR','BY','CH','CR','CY','CZ','DE','DK','DO','EE','EG','ES','FI','FO','FR','GB','GE','GI','GL','GR','GT','HR','HU','IE','IL','IQ','IR','IS','IT','JO','KW','KZ','LB','LC','LI','LT','LU','LV','MC','MD','ME','MK','MR','MT','MU','MZ','NL','NO','PK','PL','PS','PT','QA','RO','RS','SA','SC','SE','SI','SK','SM','SV','TL','TN','TR','UA','VA','VG','XK']`.
122122
**isIdentityCard(str [, locale])** | check if the string is a valid identity card code.<br/><br/>`locale` is one of `['LK', 'PL', 'ES', 'FI', 'IN', 'IT', 'IR', 'MZ', 'NO', 'TH', 'zh-TW', 'he-IL', 'ar-LY', 'ar-TN', 'zh-CN', 'zh-HK', 'PK']` OR `'any'`. If 'any' is used, function will check if any of the locales match.<br/><br/>Defaults to 'any'.
123-
**isIMEI(str [, options]))** | check if the string is a valid [IMEI number][IMEI]. IMEI should be of format `###############` or `##-######-######-#`.<br/><br/>`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.
123+
**isIMEI(str [, options]))** | check if the string is a valid [IMEI number][IMEI]. IMEI should be of format `###############` or `##-######-######-#`.<br/><br/>`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.
124124
**isIn(str, values)** | check if the string is in an array of allowed values.
125125
**isInt(str [, options])** | check if the string is an integer.<br/><br/>`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).
126126
**isIP(str [, options])** | check if the string is an IP address (version 4 or 6).<br/><br/>`options` is an object that defaults to `{ version: '' }`.<br/><br/>**Options:**<br/>`version`: defines which IP version to compare to. Accepted values: `4`, `6`, `'4'`, `'6'`.
@@ -130,18 +130,18 @@ Validator | Description
130130
**isISO6346(str)** | check if the string is a valid [ISO 6346](https://en.wikipedia.org/wiki/ISO_6346) shipping container identification.
131131
**isISO6391(str)** | check if the string is a valid [ISO 639-1][ISO 639-1] language code.
132132
**isISO8601(str [, options])** | check if the string is a valid [ISO 8601][ISO 8601] date. <br/>`options` is an object which defaults to `{ strict: false, strictSeparator: false }`. If `strict` is true, date strings with invalid dates like `2009-02-29` will be invalid. If `strictSeparator` is true, date strings with date and time separated by anything other than a T will be invalid.
133-
**isISO15924(str)** | check if the string is a valid [ISO 15924][ISO 15924] officially assigned script code.
134-
**isISO31661Alpha2(str)** | check if the string is a valid [ISO 3166-1 alpha-2][ISO 3166-1 alpha-2] officially assigned country code.
135-
**isISO31661Alpha3(str)** | check if the string is a valid [ISO 3166-1 alpha-3][ISO 3166-1 alpha-3] officially assigned country code.
133+
**isISO15924(str)** | check if the string is a valid [ISO 15924][ISO 15924] officially assigned script code.
134+
**isISO31661Alpha2(str [, options])** | check if the string is a valid [ISO 3166-1 alpha-2][ISO 3166-1 alpha-2] officially assigned country code. <br/>`options` is an object which can contain the key `userAssignedCodes`: an array of custom codes that are not officially assigned (e.g. `['XK']`).
135+
**isISO31661Alpha3(str [, options])** | check if the string is a valid [ISO 3166-1 alpha-3][ISO 3166-1 alpha-3] officially assigned country code. <br/>`options` is an object which can contain the key `userAssignedCodes`: an array of custom codes that are not officially assigned (e.g. `['XXK']`).
136136
**isISO31661Numeric(str)** | check if the string is a valid [ISO 3166-1 numeric][ISO 3166-1 numeric] officially assigned country code.
137137
**isISO4217(str)** | check if the string is a valid [ISO 4217][ISO 4217] officially assigned currency code.
138138
**isISRC(str)** | check if the string is an [ISRC][ISRC].
139139
**isISSN(str [, options])** | check if the string is an [ISSN][ISSN].<br/><br/>`options` is an object which defaults to `{ case_sensitive: false, require_hyphen: false }`. If `case_sensitive` is true, ISSNs with a lowercase `'x'` as the check digit are rejected.
140140
**isJSON(str [, options])** | check if the string is valid JSON (note: uses JSON.parse).<br/><br/>`options` is an object which defaults to `{ allow_primitives: false }`. If `allow_primitives` is true, the primitives 'true', 'false' and 'null' are accepted as valid JSON values.
141-
**isJWT(str)** | check if the string is valid JWT token.
142-
**isLatLong(str [, options])** | check if the string is a valid latitude-longitude coordinate in the format `lat,long` or `lat, long`.<br/><br/>`options` is an object that defaults to `{ checkDMS: false }`. Pass `checkDMS` as `true` to validate DMS(degrees, minutes, and seconds) latitude-longitude format.
143-
**isLength(str [, options])** | check if the string's length falls in a range and equal to any of the integers of the `discreteLengths` array if provided.<br/><br/>`options` is an object which defaults to `{ min: 0, max: undefined, discreteLengths: undefined }`. Note: this function takes into account surrogate pairs.
144-
**isLicensePlate(str, locale)** | check if the string matches the format of a country's license plate.<br/><br/>`locale` is one of `['cs-CZ', 'de-DE', 'de-LI', 'en-IN', 'en-SG', 'en-PK', 'es-AR', 'hu-HU', 'pt-BR', 'pt-PT', 'sq-AL', 'sv-SE']` or `'any'`.
141+
**isJWT(str)** | check if the string is valid JWT token.
142+
**isLatLong(str [, options])** | check if the string is a valid latitude-longitude coordinate in the format `lat,long` or `lat, long`.<br/><br/>`options` is an object that defaults to `{ checkDMS: false }`. Pass `checkDMS` as `true` to validate DMS(degrees, minutes, and seconds) latitude-longitude format.
143+
**isLength(str [, options])** | check if the string's length falls in a range and equal to any of the integers of the `discreteLengths` array if provided.<br/><br/>`options` is an object which defaults to `{ min: 0, max: undefined, discreteLengths: undefined }`. Note: this function takes into account surrogate pairs.
144+
**isLicensePlate(str, locale)** | check if the string matches the format of a country's license plate.<br/><br/>`locale` is one of `['cs-CZ', 'de-DE', 'de-LI', 'en-IN', 'en-SG', 'en-PK', 'es-AR', 'hu-HU', 'pt-BR', 'pt-PT', 'sq-AL', 'sv-SE']` or `'any'`.
145145
**isLocale(str)** | check if the string is a locale.
146146
**isLowercase(str)** | check if the string is lowercase.
147147
**isLuhnNumber(str)** | check if the string passes the [Luhn algorithm check](https://en.wikipedia.org/wiki/Luhn_algorithm).

src/lib/isISO31661Alpha2.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,24 @@ const validISO31661Alpha2CountriesCodes = new Set([
2929
'ZA', 'ZM', 'ZW',
3030
]);
3131

32-
export default function isISO31661Alpha2(str) {
32+
const alpha2CountryCode = /^[a-zA-Z]{2}$/;
33+
34+
export default function isISO31661Alpha2(str, options = {}) {
3335
assertString(str);
36+
37+
const { userAssignedCodes } = options;
38+
const validUserAssignedCodes = (userAssignedCodes || [])
39+
.reduce((accumulator, userAssignedCode) => {
40+
if (alpha2CountryCode.test(userAssignedCode)) {
41+
accumulator.push(userAssignedCode.toUpperCase());
42+
}
43+
return accumulator;
44+
}, []);
45+
46+
if (validUserAssignedCodes.includes(str.toUpperCase())) {
47+
return true;
48+
}
49+
3450
return validISO31661Alpha2CountriesCodes.has(str.toUpperCase());
3551
}
3652

src/lib/isISO31661Alpha3.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,23 @@ const validISO31661Alpha3CountriesCodes = new Set([
2020
'VEN', 'VNM', 'VGB', 'VIR', 'WLF', 'ESH', 'YEM', 'ZMB', 'ZWE',
2121
]);
2222

23-
export default function isISO31661Alpha3(str) {
23+
const alpha3CountryCode = /^[a-zA-Z]{3}$/;
24+
25+
export default function isISO31661Alpha3(str, options = {}) {
2426
assertString(str);
27+
28+
const { userAssignedCodes } = options;
29+
const validUserAssignedCodes = (userAssignedCodes || [])
30+
.reduce((accumulator, userAssignedCode) => {
31+
if (alpha3CountryCode.test(userAssignedCode)) {
32+
accumulator.push(userAssignedCode.toUpperCase());
33+
}
34+
return accumulator;
35+
}, []);
36+
37+
if (validUserAssignedCodes.includes(str.toUpperCase())) {
38+
return true;
39+
}
40+
2541
return validISO31661Alpha3CountriesCodes.has(str.toUpperCase());
2642
}

test/validators.test.js

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -12471,61 +12471,6 @@ describe('Validators', () => {
1247112471
});
1247212472
});
1247312473

12474-
it('should validate ISO 3166-1 alpha 2 country codes', () => {
12475-
// from https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
12476-
test({
12477-
validator: 'isISO31661Alpha2',
12478-
valid: [
12479-
'FR',
12480-
'fR',
12481-
'GB',
12482-
'PT',
12483-
'CM',
12484-
'JP',
12485-
'PM',
12486-
'ZW',
12487-
'MM',
12488-
'cc',
12489-
'GG',
12490-
],
12491-
invalid: [
12492-
'',
12493-
'FRA',
12494-
'AA',
12495-
'PI',
12496-
'RP',
12497-
'WV',
12498-
'WL',
12499-
'UK',
12500-
'ZZ',
12501-
],
12502-
});
12503-
});
12504-
12505-
it('should validate ISO 3166-1 alpha 3 country codes', () => {
12506-
// from https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3
12507-
test({
12508-
validator: 'isISO31661Alpha3',
12509-
valid: [
12510-
'ABW',
12511-
'HND',
12512-
'KHM',
12513-
'RWA',
12514-
],
12515-
invalid: [
12516-
'',
12517-
'FR',
12518-
'fR',
12519-
'GB',
12520-
'PT',
12521-
'CM',
12522-
'JP',
12523-
'PM',
12524-
'ZW',
12525-
],
12526-
});
12527-
});
12528-
1252912474
it('should validate ISO 3166-1 numeric country codes', () => {
1253012475
// from https://en.wikipedia.org/wiki/ISO_3166-1_numeric
1253112476
test({
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import test from '../testFunctions';
2+
3+
describe('isISO31661Alpha2', () => {
4+
it('should validate ISO 3166-1 alpha 2 country codes', () => {
5+
// from https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
6+
test({
7+
validator: 'isISO31661Alpha2',
8+
valid: [
9+
'FR',
10+
'fR',
11+
'GB',
12+
'PT',
13+
'CM',
14+
'JP',
15+
'PM',
16+
'ZW',
17+
'MM',
18+
'cc',
19+
'GG',
20+
],
21+
invalid: [
22+
'',
23+
'FRA',
24+
'AA',
25+
'PI',
26+
'RP',
27+
'WV',
28+
'WL',
29+
'UK',
30+
'ZZ',
31+
],
32+
});
33+
});
34+
35+
it('should validate user assigned alpha 2 code if provided', () => {
36+
test({
37+
validator: 'isISO31661Alpha2',
38+
args: [{ userAssignedCodes: ['XK', 'xl', '', 'x'] }],
39+
valid: ['BE', 'FR', 'GB', 'US', 'XK', 'XL'],
40+
invalid: ['XA', 'XB'],
41+
});
42+
});
43+
44+
it('should not validate user assigned alpha 2 not valid code if provided', () => {
45+
test({
46+
validator: 'isISO31661Alpha2',
47+
args: [{ userAssignedCodes: ['', 'x', 'XXX'] }],
48+
valid: ['FR'],
49+
invalid: ['XXX', 'X'],
50+
});
51+
});
52+
53+
it('should still validate ISO 3166-1 alpha 2 country codes if the options object is empty', () => {
54+
test({
55+
validator: 'isISO31661Alpha2',
56+
args: [{}],
57+
valid: ['FR', 'US'],
58+
invalid: ['XK'],
59+
});
60+
});
61+
62+
it('should still validate ISO 3166-1 alpha 2 country codes if the userAssignedCodes option is empty', () => {
63+
test({
64+
validator: 'isISO31661Alpha2',
65+
args: [{ userAssignedCodes: [] }],
66+
valid: ['FR', 'US'],
67+
invalid: ['XK'],
68+
});
69+
});
70+
});
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import test from '../testFunctions';
2+
3+
describe('isISO31661Alpha3', () => {
4+
it('should validate ISO 3166-1 alpha 3 country codes', () => {
5+
// from https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3
6+
test({
7+
validator: 'isISO31661Alpha3',
8+
valid: [
9+
'ABW',
10+
'HND',
11+
'KHM',
12+
'RWA',
13+
],
14+
invalid: [
15+
'',
16+
'FR',
17+
'fR',
18+
'GB',
19+
'PT',
20+
'CM',
21+
'JP',
22+
'PM',
23+
'ZW',
24+
'XXK',
25+
],
26+
});
27+
});
28+
29+
it('should validate user assigned ISO 3166-1 alpha 3 code if provided', () => {
30+
test({
31+
validator: 'isISO31661Alpha3',
32+
args: [{ userAssignedCodes: ['XXK', 'xxl'] }],
33+
valid: ['BEL', 'FRA', 'GBR', 'USA', 'XXK', 'XXL'],
34+
invalid: ['XXA', 'GGG'],
35+
});
36+
});
37+
38+
it('should not validate user assigned ISO 3166-1 alpha 3 not valid code if provided', () => {
39+
test({
40+
validator: 'isISO31661Alpha3',
41+
args: [{ userAssignedCodes: ['', 'x', 'XX', 'XXXX'] }],
42+
valid: ['FRA'],
43+
invalid: ['XX', 'XXXX', 'X'],
44+
});
45+
});
46+
47+
it('should still validate ISO 3166-1 alpha 3 country codes if the options object is empty', () => {
48+
test({
49+
validator: 'isISO31661Alpha3',
50+
args: [{}],
51+
valid: ['FRA', 'USA'],
52+
invalid: ['XXK'],
53+
});
54+
});
55+
56+
it('should still validate ISO 3166-1 alpha 3 country codes if the userAssignedCodes option is empty', () => {
57+
test({
58+
validator: 'isISO31661Alpha3',
59+
args: [{ userAssignedCodes: [] }],
60+
valid: ['FRA', 'USA'],
61+
invalid: ['XXK'],
62+
});
63+
});
64+
});

0 commit comments

Comments
 (0)