@yext/phonenumber-util 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.js ADDED
@@ -0,0 +1,380 @@
1
+ import { AREA_CODE_LIST } from './areaCodeList.js';
2
+ import { PHONE_FORMATS } from './phoneFormats.js';
3
+
4
+ const DASHES = '-\u2010-\u2015\u2212\u30FC\uFF0D';
5
+ const SLASHES = '\uFF0F/';
6
+ const DOTS = '\uFF0E.';
7
+ const WHITESPACE = ' \u00A0\u00AD\u200B\u2060\u3000';
8
+ const BRACKETS = '()\\[\\]\uFF08\uFF09\uFF3B\uFF3D';
9
+ const TILDES = '~\u2053\u223C\uFF5E';
10
+ const VALID_DIGITS = '0-9';
11
+ const PLUS_CHARS = '\\+';
12
+
13
+ const VALID_PUNCTUATION = `${DASHES}${SLASHES}${DOTS}${WHITESPACE}${BRACKETS}${TILDES}`;
14
+
15
+ const VALID_PHONE_NUMBER = new RegExp(
16
+ `(?:(?:${PLUS_CHARS}?[${VALID_DIGITS}]{1,3}[${VALID_PUNCTUATION}]*)?` + // Country code (optional)
17
+ `(?:\\(?[${VALID_DIGITS}]{1,4}\\)?[${VALID_PUNCTUATION}]*)?` + // Area code (optional)
18
+ `(?:[${VALID_DIGITS}]{1,4}[${VALID_PUNCTUATION}]*){1,5}` + // Phone number segments
19
+ `[${VALID_DIGITS}]{1,4})`, // Final segment
20
+ );
21
+
22
+ /**
23
+ * Formats a phone number into the E.164 international standard.
24
+ *
25
+ * This function takes the components of a phone number and formats it into the
26
+ * E.164 standard, which includes the region code and the local number. The format
27
+ *
28
+ * @param {Object} phoneParts - An object containing parts of the phone number.
29
+ * @param {string} phoneParts.areaCode - The area code of the phone number.
30
+ * @param {string} phoneParts.regionCode - The region code of the phone number.
31
+ * @param {string} phoneParts.localNumber - The local part of the phone number.
32
+ * @returns {string|null} The formatted phone number in E.164 format, or null if the region code or local number is not present.
33
+ */
34
+ export const formatPhoneNumberForE164 = ({
35
+ regionCode,
36
+ areaCode,
37
+ localNumber,
38
+ }) => {
39
+ if ((regionCode !== '1' || areaCode) && regionCode && localNumber) {
40
+ // A US number passed with area code decoupled from the localNumber. Assumes the format:
41
+ // regionCode: 1, areaCode: 310, localNumber: 3496200
42
+ if (regionCode === '1' && areaCode && localNumber.length === 7) {
43
+ return `+1${areaCode}${localNumber}`;
44
+ }
45
+ // Combine the region code and the formatted local number - this assumes US localNumber includes area code
46
+ // This is for all intl and all US with format:
47
+ // regionCode: 1, localNumber: 3103496200
48
+ return areaCode ? `+1${localNumber}` : `+${regionCode}${localNumber}`;
49
+ }
50
+
51
+ return null;
52
+ };
53
+
54
+ /**
55
+ * Formats a phone number into a tel: link format.
56
+ *
57
+ * This function takes the components of a phone number and formats it into a
58
+ * `tel:` link, which can be used in HTML for clickable phone numbers.
59
+ *
60
+ * @param {Object} phoneParts - An object containing parts of the phone number.
61
+ * @param {string} phoneParts.regionCode - The region code of the phone number.
62
+ * @param {string} phoneParts.areaCode - The area code of the phone number.
63
+ * @param {string} phoneParts.localNumber - The local part of the phone number.
64
+ * @returns {string|null} The formatted phone number link, or null if the local number is not present.
65
+ */
66
+ export const formatPhoneNumberLink = ({
67
+ regionCode,
68
+ areaCode,
69
+ localNumber,
70
+ }) => {
71
+ if (localNumber) {
72
+ if (regionCode === '1') {
73
+ return areaCode
74
+ ? `tel:+1${areaCode}${localNumber}`
75
+ : `tel:${localNumber}`;
76
+ } else {
77
+ return `tel:+${regionCode}${localNumber}`;
78
+ }
79
+ }
80
+
81
+ return null;
82
+ };
83
+
84
+ /**
85
+ * Validates a phone number based on a regex pattern and the ability to extract useful parts.
86
+ *
87
+ * This function first checks the phone number against a predefined regular expression pattern
88
+ * to determine its validity. It then uses the `getPhoneParts` function to extract relevant parts
89
+ * of the phone number and further confirms its validity based on the presence of these parts.
90
+ *
91
+ * @param {string} phoneNumber - The phone number to validate.
92
+ * @returns {boolean} Returns true if the phone number is valid, otherwise false.
93
+ */
94
+ export const isValidPhoneNumber = (phoneNumber) => {
95
+ // Check the big chunky regex for phone validity
96
+ const phonePattern = new RegExp(VALID_PHONE_NUMBER, 'ig');
97
+ if (phonePattern.test(phoneNumber)) {
98
+ const phoneParts = getPhoneParts(phoneNumber);
99
+
100
+ // Also check for phone validity by ability to extract useful parts.
101
+ // This will also confirm area codes / region codes are valid.
102
+ if (
103
+ phoneParts &&
104
+ phoneParts.localNumber &&
105
+ phoneParts.regionCode &&
106
+ (phoneParts.areaCode || phoneParts.regionCode !== '1')
107
+ ) {
108
+ return true;
109
+ }
110
+ }
111
+ return false;
112
+ };
113
+
114
+ /**
115
+ * Extracts and formats parts of a phone number, including area code, region code, and local number.
116
+ *
117
+ * This function takes a phone number and optionally a region code, then processes it to extract
118
+ * relevant parts like the area code, region code, and local number. It also validates the phone
119
+ * number and ensures it conforms to specific formats, particularly for US numbers.
120
+ *
121
+ * @param {string} phoneNumber - The phone number to process.
122
+ * @returns {Object} An object containing relevant phone number information.
123
+ * @property {string|null} areaCode - The area code of the phone number.
124
+ * @property {string|null} e164 - The E.164 formatted version of the phone number.
125
+ * @property {string|null} href - A formatted phone number link.
126
+ * @property {string|null} localNumber - The local part of the phone number.
127
+ * @property {string} rawNumber - The original raw phone number. Unsanitized.
128
+ * @property {string|null} regionCode - The region code of the phone number.
129
+ */
130
+ export const getPhoneParts = (phoneNumber) => {
131
+ const regionCodeLengths = [1, 2, 3];
132
+ let phoneParts = {
133
+ areaCode: null,
134
+ e164: null,
135
+ format: null,
136
+ formattedNumber: null,
137
+ href: null,
138
+ localNumber: null,
139
+ rawNumber: phoneNumber,
140
+ regionCode: null,
141
+ };
142
+
143
+ if (!phoneNumber) {
144
+ return phoneParts;
145
+ }
146
+
147
+ // Remove all non-digit characters except the leading '+'
148
+ let strippedPhoneNumber = sanitizeRawNumber(phoneNumber);
149
+
150
+ // The shortest length for a phone number (that we care about) is 7 digits.
151
+ // The longest phone number is 15 digits.
152
+ if (
153
+ strippedPhoneNumber.replace(/\D/g, '').length >= 7 &&
154
+ strippedPhoneNumber.replace(/\D/g, '').length <= 15
155
+ ) {
156
+ // Extract the region code if not explicitly provided and it is part of the
157
+ // phone number
158
+ if (strippedPhoneNumber.startsWith('+')) {
159
+ // US number formatted with +12065551234
160
+ if (
161
+ strippedPhoneNumber.length === 12 &&
162
+ strippedPhoneNumber.startsWith('+1')
163
+ ) {
164
+ phoneParts.regionCode = '1';
165
+ phoneParts.localNumber = strippedPhoneNumber.slice(2); // Strip out the "+1"
166
+ phoneParts.areaCode = phoneParts.localNumber.slice(0, 3); // Grab the area code
167
+ }
168
+ // Otherwise, an intl number which may have 1, 2 or 3 digit region
169
+ else if (
170
+ strippedPhoneNumber.length >= 7 &&
171
+ strippedPhoneNumber.length <= 14
172
+ ) {
173
+ // Try to match the phone number with each possible region code length
174
+ for (let length of regionCodeLengths) {
175
+ let match = strippedPhoneNumber.match(
176
+ new RegExp(`^\\+(\\d{${length}})(\\d+)`),
177
+ );
178
+ if (match && PHONE_FORMATS[match[1]]) {
179
+ phoneParts.regionCode = match[1];
180
+ phoneParts.localNumber = match[2];
181
+ break;
182
+ }
183
+ }
184
+ }
185
+ }
186
+ // If no region code is provided, assume US with the format 3109309000 after being stripped of non-numeric values.
187
+ // We'll try and derive the area code by looking it up against the known area codes.
188
+ else if (strippedPhoneNumber.length === 10) {
189
+ if (AREA_CODE_LIST.indexOf(strippedPhoneNumber.substring(0, 3)) !== -1) {
190
+ phoneParts.regionCode = '1';
191
+ phoneParts.areaCode = strippedPhoneNumber.substring(0, 3);
192
+ phoneParts.localNumber = strippedPhoneNumber.substring(3);
193
+ }
194
+ }
195
+ // If no region code is provided, assume US with the format 9309000 after being stripped of non-numeric values.
196
+ // This is not able to be validated or formatted since it lacks an area code.
197
+ else if (strippedPhoneNumber.length === 7) {
198
+ phoneParts.regionCode = '1';
199
+ phoneParts.localNumber = strippedPhoneNumber;
200
+ }
201
+
202
+ // Default to region code 1 for US numbers if none is provided
203
+ if (
204
+ strippedPhoneNumber.length === 11 &&
205
+ strippedPhoneNumber.startsWith('1')
206
+ ) {
207
+ phoneParts.regionCode = '1';
208
+ phoneParts.localNumber = strippedPhoneNumber.slice(1);
209
+ phoneParts.areaCode = phoneParts.localNumber.slice(0, 3);
210
+ }
211
+
212
+ // US likes a format that isn't as common
213
+ if (phoneParts.localNumber && phoneParts.regionCode === '1') {
214
+ // Specific format for US numbers with areaCode (206-930-9000).
215
+ if (phoneParts.localNumber.length === 10) {
216
+ phoneParts.areaCode = phoneParts.localNumber.slice(0, 3);
217
+ }
218
+ } else if (phoneParts.localNumber) {
219
+ // General format for shorter numbers
220
+ phoneParts.localNumber = phoneParts.localNumber.replace(/\D/g, '');
221
+ }
222
+ }
223
+
224
+ // Unset any known invalid area codes. We only care about region 1 (USA).
225
+ if (
226
+ AREA_CODE_LIST.indexOf(phoneParts.areaCode) === -1 ||
227
+ phoneParts.regionCode !== '1'
228
+ ) {
229
+ phoneParts.areaCode = null;
230
+ }
231
+
232
+ if (phoneParts.localNumber && phoneParts.regionCode) {
233
+ phoneParts.href = formatPhoneNumberLink(phoneParts);
234
+ phoneParts.e164 = formatPhoneNumberForE164(phoneParts);
235
+ phoneParts.format = findPhoneFormat(phoneParts);
236
+ phoneParts.formattedNumber = formatPhoneNumber(phoneParts);
237
+
238
+ // If there are left over x's, the formatting ran into something unexpected.
239
+ // This may be ok depending on the region and their phone number formats.
240
+ // But it does mean we don't want to display this number.
241
+ if (
242
+ phoneParts.formattedNumber &&
243
+ phoneParts.formattedNumber.indexOf('x') !== -1
244
+ ) {
245
+ // Since `rawNumber` isn't sanitized, we'll use a simple format that we
246
+ // are assured to be safe.
247
+ phoneParts.formattedNumber = strippedPhoneNumber;
248
+ }
249
+ }
250
+
251
+ return phoneParts;
252
+ };
253
+
254
+ /**
255
+ * Sanitizes a phone number by removing all non-numeric characters
256
+ * except for the leading plus sign (+) if it exists.
257
+ *
258
+ * @param {string} phoneNumber - The raw phone number input.
259
+ * @returns {string} - The sanitized phone number containing only digits and an optional leading plus sign.
260
+ */
261
+ export const sanitizeRawNumber = (phoneNumber) => {
262
+ return phoneNumber.replace(/(?!^\+)\D/g, '');
263
+ };
264
+
265
+ /**
266
+ * Finds valid phone numbers in a given text string.
267
+ *
268
+ * This function uses a regular expression to locate potential phone numbers in the text.
269
+ * Valid matches are then processed to extract relevant information.
270
+ *
271
+ * @param {string} text - The text string to search for phone numbers.
272
+ * @returns {Array<Object>} An array of objects, each containing the index, lastIndex, and parts of the valid phone numbers found.
273
+ * @property {number} index - The starting index of the phone number in the text.
274
+ * @property {number} lastIndex - The ending index of the phone number in the text.
275
+ * @property {Object} phoneParts - The parts of the phone number, as returned by the getPhoneParts function.
276
+ */
277
+ export const findNumbersInString = (text) => {
278
+ const regex = new RegExp(VALID_PHONE_NUMBER, 'g');
279
+ let matches = [];
280
+ let match;
281
+
282
+ // Regex finds possible matches. Go through each of them to further validate and extract relevant info.
283
+ while ((match = regex.exec(text)) !== null) {
284
+ let number = match[0].trim(); // Access the captured group
285
+
286
+ // Ensure number is not just a partial match by checking it contains at least 6 digits.
287
+ if (
288
+ number.replace(new RegExp(`[${VALID_PUNCTUATION}]`, 'g'), '').length >= 6
289
+ ) {
290
+ const index = text.indexOf(number);
291
+ const lastIndex = index + number.length;
292
+ const phoneParts = getPhoneParts(number);
293
+
294
+ // Presumed phone numbers may be invalidated by omission of formattedNumber from getPhoneParts.
295
+ // This will prevent short-numbers that ommit area code from being fetched from a larger string since it may be unreliable.
296
+ if (phoneParts.formattedNumber) {
297
+ matches.push({
298
+ index,
299
+ lastIndex,
300
+ ...phoneParts,
301
+ });
302
+ }
303
+ }
304
+ }
305
+
306
+ return matches;
307
+ };
308
+
309
+ /**
310
+ * Finds the phone number format for a given region code.
311
+ *
312
+ * This function retrieves the phone number format corresponding to the provided
313
+ * region code from the PHONE_FORMATS object. If the region code is not found,
314
+ * it defaults to the format for region code '1' (US).
315
+ *
316
+ * @param {Object} params - The parameters for formatting the phone number.
317
+ * @param {string} regionCode - The region code to look up the phone number format.
318
+ * @param {string} params.e164 - The E.164 formatted phone number to format. Example: `+12065551234`.
319
+ * @returns {string} The phone number format for the given region code in the format of "(xxx) xxx-xxxx".
320
+ */
321
+ export const findPhoneFormat = ({ regionCode, e164 }) => {
322
+ const formatRaw = PHONE_FORMATS[regionCode];
323
+ const numberLength = e164 && e164.replace(/\D/g, '').length;
324
+ // If the region isn't defined or no matching length is found in the PHONE_FORMATS, we'll fall back to the US format.
325
+ let format = PHONE_FORMATS[1];
326
+
327
+ if (formatRaw && numberLength) {
328
+ // The PHONE_FORMATS will have arrays for regions with inconsistent number lengths / formats.
329
+ if (Array.isArray(formatRaw)) {
330
+ formatRaw.forEach((value) => {
331
+ const templateLength = value.split('x').length - 1;
332
+ if (numberLength === templateLength) {
333
+ format = value;
334
+ }
335
+ });
336
+ }
337
+ // Some region (such as the US) will have a consistent format, so we expect a string.
338
+ else if (formatRaw) {
339
+ format = formatRaw;
340
+ }
341
+ }
342
+
343
+ return format;
344
+ };
345
+
346
+ /**
347
+ * Formats a phone number according to a specified format.
348
+ *
349
+ * This function takes a desired format string and an E.164 formatted phone number,
350
+ * then formats the phone number according to the provided format. The format string
351
+ * uses 'x' characters to represent digits from the phone number.
352
+ *
353
+ * @param {Object} params - The parameters for formatting the phone number.
354
+ * @param {string} params.format - The desired format for the phone number. Example: `(xxx) xxx-xxxx`.
355
+ * @param {string} params.e164 - The E.164 formatted phone number to format. Example: `+12065551234`.
356
+ * @returns {string|null} The formatted phone number, or null if the E.164 number or format is not provided.
357
+ */
358
+ export const formatPhoneNumber = ({ format, e164 }) => {
359
+ let formattedNumber = '';
360
+
361
+ if (e164 && format) {
362
+ // Remove the leading '+' and let the format handle it.
363
+ const strippedPhone = e164.replace(/\D/g, '');
364
+ let phoneIndex = strippedPhone.length - 1;
365
+
366
+ // Traverse backward so we can omit country code in some formats (like US).
367
+ for (let i = format.length; i >= 0; i--) {
368
+ if (format[i]) {
369
+ if (format[i].toLowerCase() === 'x' && strippedPhone[phoneIndex]) {
370
+ formattedNumber = strippedPhone[phoneIndex] + formattedNumber;
371
+ phoneIndex -= 1;
372
+ } else {
373
+ formattedNumber = format[i] + formattedNumber;
374
+ }
375
+ }
376
+ }
377
+ }
378
+
379
+ return formattedNumber || null;
380
+ };
@@ -0,0 +1,212 @@
1
+ export const PHONE_FORMATS = {
2
+ 1: '(xxx) xxx-xxxx', // United States
3
+ 7: '+x xxx xxx-xx-xx', // Russia
4
+ 20: '+xx x xxxxxxxx', // Egypt
5
+ 27: '+xx xx xxx xxxx', // South Africa
6
+ 30: '+xx xxx xxx xxxx', // Greece
7
+ 31: '+xx xx xxx xxxx', // Netherlands
8
+ 32: '+xx xxx xx xx xx', // Belgium
9
+ 33: '+xx x xx xx xx xx', // France
10
+ 34: '+xx xxx xx xx xx', // Spain
11
+ 36: '+xx xx xxx xxxx', // Hungary
12
+ 39: '+xx xxx xxx xxxx', // Italy
13
+ 40: '+xx xxx xxx xxxx', // Romania
14
+ 41: '+xx xx xxx xx xx', // Switzerland
15
+ 43: '+xx xxx xxx xxxx', // Austria
16
+ 44: '+xx xxxx xxxxxx', // United Kingdom
17
+ 45: '+xx xx xx xx xx', // Denmark
18
+ 46: '+xx xx xxx xx xx', // Sweden
19
+ 47: '+xx xxx xx xxx', // Norway
20
+ 48: '+xx xxx xxx xxx', // Poland
21
+ 49: [
22
+ '+xx xx xxxxxx',
23
+ '+xx xx xxxxxxx',
24
+ '+xx xx xxxxxxxx',
25
+ '+xx xxx xxxxxxxx',
26
+ ], // Germany
27
+ 51: '+xx xxx xxx xxx', // Peru
28
+ 52: '+xx x xxxx xxxx', // Mexico
29
+ 53: '+x xxx xxxx', // Cuba
30
+ 54: '+xx xx xxxx xxxx', // Argentina
31
+ 55: '+xx xx xxxx xxxx', // Brazil
32
+ 56: '+xx x xxxx xxxx', // Chile
33
+ 57: '+xx xxx xxx xxxx', // Colombia
34
+ 58: '+xx xxx xxx xxxx', // Venezuela
35
+ 60: '+xx xx xxx xxxx', // Malaysia
36
+ 61: '+xx xxxx xxxx', // Australia
37
+ 62: '+xx xxx xxx xxx', // Indonesia
38
+ 63: '+xx xxx xxx xxxx', // Philippines
39
+ 64: '+xx xxx xxx xxxx', // New Zealand
40
+ 65: '+xx xxxx xxxx', // Singapore
41
+ 66: '+xx xx xxx xxxx', // Thailand
42
+ 81: '+xx xx xxxx xxxx', // Japan
43
+ 82: '+xx xx xxx xxxx', // South Korea
44
+ 84: '+xx xxx xxxx xxxx', // Vietnam
45
+ 86: '+xx xxx xxxx xxxx', // China
46
+ 90: '+xx xxx xxx xxxx', // Turkey
47
+ 91: '+xx xx xxxx xxxx', // India
48
+ 92: '+xx xxx xxx xxxx', // Pakistan
49
+ 93: '+xx xx xxx xxxx', // Afghanistan
50
+ 94: '+xx xx xxx xxxx', // Sri Lanka
51
+ 95: '+xx xxx xxx xxxx', // Myanmar
52
+ 98: '+xx xxx xxx xxxx', // Iran
53
+ 211: '+xxx xxx xxxx', // South Sudan
54
+ 212: '+xxx xx xx xx xx', // Morocco
55
+ 213: '+xxx xx xx xx', // Algeria
56
+ 216: '+xxx xx xxx', // Tunisia
57
+ 218: '+xxx xx xxx xxx', // Libya
58
+ 220: '+xxx xxx xxxx', // Gambia
59
+ 221: '+xxx xxx xxx xxx', // Senegal
60
+ 222: '+xxx xxx xxxx', // Mauritania
61
+ 223: '+xxx xxx xxxx', // Mali
62
+ 224: '+xxx xxx xxx xxx', // Guinea
63
+ 225: '+xxx xx xx xx xx', // Ivory Coast
64
+ 226: '+xxx xx xx xx xx', // Burkina Faso
65
+ 227: '+xxx xx xx xx xx', // Niger
66
+ 228: '+xxx xxx xxx xxx', // Togo
67
+ 229: '+xxx xx xx xx xx', // Benin
68
+ 230: '+xxx xxxx xxxx', // Mauritius
69
+ 231: '+xxx xx xx xx xx', // Liberia
70
+ 232: '+xxx xxx xxxx', // Sierra Leone
71
+ 233: '+xxx xxx xxxx', // Ghana
72
+ 234: '+xxx xxx xxxx xxxx', // Nigeria
73
+ 235: '+xxx xx xx xx xx', // Chad
74
+ 236: '+xxx xx xx xx xx', // Central African Republic
75
+ 237: '+xxx xxxx xxxx', // Cameroon
76
+ 238: '+xxx xxxx xxxx', // Cape Verde
77
+ 239: '+xxx xxxx xxxx', // Sao Tome and Principe
78
+ 240: '+xxx xxx xxxx xxxx', // Equatorial Guinea
79
+ 241: '+xxx xxx xxxx xxxx', // Gabon
80
+ 242: '+xxx xxx xxxx xxxx', // Republic of the Congo
81
+ 243: '+xxx xxx xxxx xxxx', // Democratic Republic of the Congo
82
+ 244: '+xxx xxx xxxx xxxx', // Angola
83
+ 245: '+xxx xxx xxxx xxxx', // Guinea-Bissau
84
+ 246: '+xxx xxx xxxx', // British Indian Ocean Territory
85
+ 248: '+xxx xxxx xxxx', // Seychelles
86
+ 249: '+xxx xxx xxxx xxxx', // Sudan
87
+ 250: '+xxx xxx xxxx xxxx', // Rwanda
88
+ 251: '+xxx xxx xxxx xxxx', // Ethiopia
89
+ 252: '+xxx xxx xxxx xxxx', // Somalia
90
+ 253: '+xxx xxx xxxx xxxx', // Djibouti
91
+ 254: '+xxx xxx xxxx xxxx', // Kenya
92
+ 255: '+xxx xxx xxxx xxxx', // Tanzania
93
+ 256: '+xxx xxx xxxx xxxx', // Uganda
94
+ 257: '+xxx xx xx xx xx', // Burundi
95
+ 258: '+xxx xxx xxxx xxxx', // Mozambique
96
+ 260: '+xxx xxx xxxx xxxx', // Zambia
97
+ 261: '+xxx xx xx xx xx', // Madagascar
98
+ 263: '+xxx xxx xxxx xxxx', // Zimbabwe
99
+ 264: '+xxx xxx xxxx xxxx', // Namibia
100
+ 265: '+xxx xxx xxxx xxxx', // Malawi
101
+ 266: '+xxx xx xx xx xx', // Lesotho
102
+ 267: '+xxx xxx xxxx xxxx', // Botswana
103
+ 268: '+xxx xx xx xx xx', // Eswatini
104
+ 269: '+xxx xx xx xx xx', // Comoros
105
+ 290: '+xxx xxxx xxxx', // Saint Helena
106
+ 291: '+xxx xxx xxxx xxxx', // Eritrea
107
+ 297: '+xxx xxxx xxxx', // Aruba
108
+ 298: '+xxx xxx xxx', // Faroe Islands
109
+ 299: '+xxx xxx xxx xxx', // Greenland
110
+ 350: '+xxx xxx xxxx xxxx', // Gibraltar
111
+ 351: '+xxx xxx xxxx xxxx', // Portugal
112
+ 352: '+xxx xxx xxxx xxxx', // Luxembourg
113
+ 353: '+xxx xxx xxxx xxxx', // Ireland
114
+ 354: '+xxx xxx xxxx xxxx', // Iceland
115
+ 355: '+xxx xxx xxxx xxxx', // Albania
116
+ 356: '+xxx xx xx xx xx', // Malta
117
+ 357: '+xxx xxx xxxx xxxx', // Cyprus
118
+ 358: '+xxx xxx xxxx xxxx', // Finland
119
+ 359: '+xxx xxx xxxx xxxx', // Bulgaria
120
+ 370: '+xxx xxx xxxx xxxx', // Lithuania
121
+ 371: '+xxx xxx xxxx xxxx', // Latvia
122
+ 372: '+xxx xxx xxxx xxxx', // Estonia
123
+ 373: '+xxx xxx xxxx xxxx', // Moldova
124
+ 374: '+xxx xxx xxxx xxxx', // Armenia
125
+ 375: '+xxx xxx xxxx xxxx', // Belarus
126
+ 376: '+xxx xxx xxxx xxxx', // Andorra
127
+ 377: '+xxx xxx xxxx xxxx', // Monaco
128
+ 378: '+xxx xxx xxxx xxxx', // San Marino
129
+ 379: '+xxx xxx xxxx xxxx', // Vatican
130
+ 380: '+xxx xxx xxxx xxxx', // Ukraine
131
+ 381: '+xxx xxx xxxx xxxx', // Serbia
132
+ 382: '+xxx xxx xxxx xxxx', // Montenegro
133
+ 383: '+xxx xxx xxxx xxxx', // Kosovo
134
+ 385: '+xxx xxx xxxx xxxx', // Croatia
135
+ 386: '+xxx xxx xxxx xxxx', // Slovenia
136
+ 387: '+xxx xxx xxxx xxxx', // Bosnia and Herzegovina
137
+ 389: '+xxx xxx xxxx xxxx', // North Macedonia
138
+ 420: '+xxx xxx xxxx xxxx', // Czech Republic
139
+ 421: '+xxx xxx xxxx xxxx', // Slovakia
140
+ 423: '+xxx xxxx xxxx xxxx', // Liechtenstein
141
+ 500: '+xxx xxxx xxxx', // Falkland Islands
142
+ 501: '+xxx xxxx xxxx', // Belize
143
+ 502: '+xxx xxxx xxxx', // Guatemala
144
+ 503: '+xxx xxxx xxxx', // El Salvador
145
+ 504: '+xxx xxxx xxxx', // Honduras
146
+ 505: '+xxx xxxx xxxx', // Nicaragua
147
+ 506: '+xxx xxxx xxxx', // Costa Rica
148
+ 507: '+xxx xxxx xxxx', // Panama
149
+ 508: '+xxx xxxx xxxx', // Saint Pierre and Miquelon
150
+ 509: '+xxx xxxx xxxx', // Haiti
151
+ 590: '+xxx xxxx xxxx', // Saint Martin
152
+ 591: '+xxx xxx xxxx xxxx', // Bolivia
153
+ 592: '+xxx xxxx xxxx', // Guyana
154
+ 593: '+xxx xxx xxxx xxxx', // Ecuador
155
+ 594: '+xxx xxxx xxxx', // French Guiana
156
+ 595: '+xxx xxx xxxx xxxx', // Paraguay
157
+ 596: '+xxx xxxx xxxx', // Martinique
158
+ 597: '+xxx xxxx xxxx', // Suriname
159
+ 598: '+xxx xxx xxxx xxxx', // Uruguay
160
+ 599: '+xxx xxxx xxxx xxxx', // Curaçao
161
+ 670: '+xxx xxxx xxxx', // East Timor
162
+ 672: '+xxx xxxx xxxx', // Antarctica
163
+ 673: '+xxx xxxx xxxx', // Brunei
164
+ 674: '+xxx xxxx xxxx', // Nauru
165
+ 675: '+xxx xxxx xxxx xxxx', // Papua New Guinea
166
+ 676: '+xxx xxxx xxxx xxxx', // Tonga
167
+ 677: '+xxx xxxx xxxx xxxx', // Solomon Islands
168
+ 678: '+xxx xxxx xxxx xxxx', // Vanuatu
169
+ 679: '+xxx xxxx xxxx xxxx', // Fiji
170
+ 680: '+xxx xxxx xxxx xxxx', // Palau
171
+ 681: '+xxx xxxx xxxx xxxx', // Wallis and Futuna
172
+ 682: '+xxx xxxx xxxx xxxx', // Cook Islands
173
+ 683: '+xxx xxxx xxxx xxxx', // Niue
174
+ 685: '+xxx xxxx xxxx xxxx', // Samoa
175
+ 686: '+xxx xxxx xxxx xxxx', // Kiribati
176
+ 687: '+xxx xxxx xxxx xxxx', // New Caledonia
177
+ 688: '+xxx xxxx xxxx xxxx', // Tuvalu
178
+ 689: '+xxx xxxx xxxx xxxx', // French Polynesia
179
+ 690: '+xxx xxxx xxxx xxxx', // Tokelau
180
+ 691: '+xxx xxxx xxxx xxxx', // Micronesia
181
+ 692: '+xxx xxxx xxxx xxxx', // Marshall Islands
182
+ 850: '+xxx xxxx xxxx xxxx', // North Korea
183
+ 852: '+xxx xxxx xxxx xxxx', // Hong Kong
184
+ 853: '+xxx xxxx xxxx xxxx', // Macau
185
+ 855: '+xxx xxx xxxx xxxx', // Cambodia
186
+ 856: '+xxx xxxx xxxx xxxx', // Laos
187
+ 880: '+xxx xxx xxxx xxxx', // Bangladesh
188
+ 886: '+xxx xxxx xxxx xxxx', // Taiwan
189
+ 960: '+xxx xxx xxxx xxxx', // Maldives
190
+ 961: '+xxx xxx xxxx xxxx', // Lebanon
191
+ 962: '+xxx xxxx xxxx xxxx', // Jordan
192
+ 963: '+xxx xxxx xxxx xxxx', // Syria
193
+ 964: '+xxx xxxx xxxx xxxx', // Iraq
194
+ 965: '+xxx xxxx xxxx xxxx', // Kuwait
195
+ 966: '+xxx xxxx xxxx xxxx', // Saudi Arabia
196
+ 967: '+xxx xxxx xxxx xxxx', // Yemen
197
+ 968: '+xxx xxxx xxxx xxxx', // Oman
198
+ 970: '+xxx xxx xxxx xxxx', // Palestine
199
+ 971: '+xxx xxx xxxx xxxx', // United Arab Emirates
200
+ 972: '+xxx xxxx xxxx xxxx', // Israel
201
+ 973: '+xxx xxxx xxxx xxxx', // Bahrain
202
+ 974: '+xxx xxxx xxxx xxxx', // Qatar
203
+ 975: '+xxx xxxx xxxx xxxx', // Bhutan
204
+ 976: '+xxx xxx xxxx xxxx', // Mongolia
205
+ 977: '+xxx xxxx xxxx xxxx', // Nepal
206
+ 992: '+xxx xxxx xxxx xxxx', // Tajikistan
207
+ 993: '+xxx xxx xxxx xxxx', // Turkmenistan
208
+ 994: '+xxx xxx xxxx xxxx', // Azerbaijan
209
+ 995: '+xxx xxxx xxxx xxxx', // Georgia
210
+ 996: '+xxx xxxx xxxx xxxx', // Kyrgyzstan
211
+ 998: '+xxx xxxx xxxx xxxx', // Uzbekistan
212
+ };
@@ -0,0 +1,6 @@
1
+ export default {
2
+ test: {
3
+ globals: true,
4
+ environment: 'node',
5
+ },
6
+ };