@yext/phonenumber-util 0.3.0 → 0.3.1
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/.github/workflows/pull-request.yml +3 -0
- package/package.json +8 -8
- package/src/__tests__/geo.test.js +72 -0
- package/src/areaCodeList.js +10 -0
- package/src/base.js +2 -2
- package/src/daylightSavings.js +2 -0
- package/src/phoneCodes.js +12 -0
- package/src/phoneFormats.js +0 -1
- package/src/timezones.js +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yext/phonenumber-util",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"author": "bajohnson@hearsaycorp.com",
|
|
5
5
|
"license": "BSD-3-Clause",
|
|
6
6
|
"description": "Utility for extracting and validating phone numbers",
|
|
@@ -25,16 +25,16 @@
|
|
|
25
25
|
"make-badges": "istanbul-badges-readme"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@eslint/js": "^9.
|
|
29
|
-
"@vitest/coverage-v8": "^3.2.
|
|
30
|
-
"eslint": "^9.
|
|
28
|
+
"@eslint/js": "^9.31.0",
|
|
29
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
30
|
+
"eslint": "^9.31.0",
|
|
31
31
|
"generate-license-file": "4.0.0",
|
|
32
|
-
"globals": "^16.
|
|
32
|
+
"globals": "^16.3.0",
|
|
33
33
|
"husky": "^9.1.7",
|
|
34
34
|
"istanbul-badges-readme": "^1.9.0",
|
|
35
|
-
"lint-staged": "^16.1.
|
|
36
|
-
"prettier": "^3.
|
|
37
|
-
"vitest": "^3.2.
|
|
35
|
+
"lint-staged": "^16.1.2",
|
|
36
|
+
"prettier": "^3.6.2",
|
|
37
|
+
"vitest": "^3.2.4"
|
|
38
38
|
},
|
|
39
39
|
"eslintConfig": {},
|
|
40
40
|
"lint-staged": {
|
|
@@ -6,6 +6,10 @@ import {
|
|
|
6
6
|
findTimeFromAreaCode,
|
|
7
7
|
findRegionFromRegionCode,
|
|
8
8
|
} from '../geo.js';
|
|
9
|
+
import { AREA_CODE_LIST } from '../areaCodeList.js';
|
|
10
|
+
import { AREA_CODES, REGION_CODES } from '../phoneCodes.js';
|
|
11
|
+
import { PHONE_FORMATS } from '../phoneFormats.js';
|
|
12
|
+
|
|
9
13
|
import { describe, it, expect } from 'vitest';
|
|
10
14
|
|
|
11
15
|
const invalidPhone = {
|
|
@@ -184,6 +188,74 @@ const canadianPhone = {
|
|
|
184
188
|
},
|
|
185
189
|
};
|
|
186
190
|
|
|
191
|
+
describe('Validate that every allow-list area code has matching geo and time info', () => {
|
|
192
|
+
it('should ensure every area code in AREA_CODE_LIST has a matching region code in AREA_CODES', () => {
|
|
193
|
+
AREA_CODE_LIST.forEach((areaCode) => {
|
|
194
|
+
const areaCodeInfo = AREA_CODES[areaCode];
|
|
195
|
+
|
|
196
|
+
if (!areaCodeInfo) {
|
|
197
|
+
console.warn(
|
|
198
|
+
`Area code ${areaCode} does not have a matching AREA_CODES entry.`,
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
expect(areaCodeInfo).toBeDefined();
|
|
203
|
+
expect(areaCodeInfo).not.toBeNull();
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
Object.keys(AREA_CODES).forEach((areaCode) => {
|
|
207
|
+
const exists = AREA_CODE_LIST.includes(areaCode);
|
|
208
|
+
|
|
209
|
+
if (!exists) {
|
|
210
|
+
console.warn(
|
|
211
|
+
`Area code ${areaCode} does not have a matching AREA_CODE_LIST entry.`,
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
expect(exists).toBe(true);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('should ensure every area code in AREA_CODE_LIST has a matching timezone', () => {
|
|
220
|
+
AREA_CODE_LIST.forEach((areaCode) => {
|
|
221
|
+
const timezone = findTimeFromAreaCode(
|
|
222
|
+
areaCode,
|
|
223
|
+
new Date('2024-07-15T08:00:00'),
|
|
224
|
+
);
|
|
225
|
+
expect(timezone).toBeDefined();
|
|
226
|
+
expect(timezone).not.toBeNull();
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
it('should ensure every region code in REGION_CODES has a matching phone format', () => {
|
|
231
|
+
Object.keys(REGION_CODES).forEach((regionCode) => {
|
|
232
|
+
const phoneFormat = PHONE_FORMATS[regionCode];
|
|
233
|
+
|
|
234
|
+
if (!phoneFormat) {
|
|
235
|
+
console.warn(
|
|
236
|
+
`Region code ${regionCode} does not have a matching PHONE_FORMATS entry.`,
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
expect(phoneFormat).toBeDefined();
|
|
241
|
+
expect(phoneFormat).not.toBeNull();
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
Object.keys(PHONE_FORMATS).forEach((regionCode) => {
|
|
245
|
+
const regionInfo = REGION_CODES[regionCode];
|
|
246
|
+
|
|
247
|
+
if (!regionInfo) {
|
|
248
|
+
console.warn(
|
|
249
|
+
`Region code ${regionCode} does not have a matching REGION_CODES entry.`,
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
expect(regionInfo).toBeDefined();
|
|
254
|
+
expect(regionInfo).not.toBeNull();
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
187
259
|
describe('Daylight Savings', () => {
|
|
188
260
|
it('should correctly be determined if the time given is or is not within daylight savings time', () => {
|
|
189
261
|
const daylightSavings = new Date('2024-07-15T12:00:00');
|
package/src/areaCodeList.js
CHANGED
|
@@ -38,6 +38,7 @@ export const AREA_CODE_LIST = [
|
|
|
38
38
|
'242',
|
|
39
39
|
'246',
|
|
40
40
|
'248',
|
|
41
|
+
'249',
|
|
41
42
|
'250',
|
|
42
43
|
'251',
|
|
43
44
|
'252',
|
|
@@ -46,6 +47,7 @@ export const AREA_CODE_LIST = [
|
|
|
46
47
|
'256',
|
|
47
48
|
'260',
|
|
48
49
|
'262',
|
|
50
|
+
'263',
|
|
49
51
|
'264',
|
|
50
52
|
'267',
|
|
51
53
|
'268',
|
|
@@ -98,15 +100,18 @@ export const AREA_CODE_LIST = [
|
|
|
98
100
|
'350',
|
|
99
101
|
'351',
|
|
100
102
|
'352',
|
|
103
|
+
'354',
|
|
101
104
|
'357',
|
|
102
105
|
'360',
|
|
103
106
|
'361',
|
|
104
107
|
'363',
|
|
105
108
|
'364',
|
|
106
109
|
'365',
|
|
110
|
+
'367',
|
|
107
111
|
'368',
|
|
108
112
|
'369',
|
|
109
113
|
'380',
|
|
114
|
+
'382',
|
|
110
115
|
'385',
|
|
111
116
|
'386',
|
|
112
117
|
'387',
|
|
@@ -150,11 +155,13 @@ export const AREA_CODE_LIST = [
|
|
|
150
155
|
'458',
|
|
151
156
|
'463',
|
|
152
157
|
'464',
|
|
158
|
+
'468',
|
|
153
159
|
'469',
|
|
154
160
|
'470',
|
|
155
161
|
'471',
|
|
156
162
|
'472',
|
|
157
163
|
'473',
|
|
164
|
+
'474',
|
|
158
165
|
'475',
|
|
159
166
|
'478',
|
|
160
167
|
'479',
|
|
@@ -236,6 +243,7 @@ export const AREA_CODE_LIST = [
|
|
|
236
243
|
'580',
|
|
237
244
|
'581',
|
|
238
245
|
'582',
|
|
246
|
+
'584',
|
|
239
247
|
'585',
|
|
240
248
|
'586',
|
|
241
249
|
'587',
|
|
@@ -301,6 +309,7 @@ export const AREA_CODE_LIST = [
|
|
|
301
309
|
'680',
|
|
302
310
|
'681',
|
|
303
311
|
'682',
|
|
312
|
+
'683',
|
|
304
313
|
'684',
|
|
305
314
|
'686',
|
|
306
315
|
'688',
|
|
@@ -343,6 +352,7 @@ export const AREA_CODE_LIST = [
|
|
|
343
352
|
'743',
|
|
344
353
|
'747',
|
|
345
354
|
'748',
|
|
355
|
+
'753',
|
|
346
356
|
'754',
|
|
347
357
|
'757',
|
|
348
358
|
'758',
|
package/src/base.js
CHANGED
|
@@ -322,8 +322,8 @@ export const findNumbersInString = (text) => {
|
|
|
322
322
|
if (
|
|
323
323
|
number.replace(new RegExp(`[${VALID_PUNCTUATION}]`, 'g'), '').length >= 6
|
|
324
324
|
) {
|
|
325
|
-
const index =
|
|
326
|
-
const lastIndex =
|
|
325
|
+
const index = match.index;
|
|
326
|
+
const lastIndex = regex.lastIndex;
|
|
327
327
|
const phoneParts = getPhoneParts(number);
|
|
328
328
|
|
|
329
329
|
// Presumed phone numbers may be invalidated by omission of formattedNumber from getPhoneParts.
|
package/src/daylightSavings.js
CHANGED
package/src/phoneCodes.js
CHANGED
|
@@ -568,6 +568,7 @@ export const AREA_CODES = {
|
|
|
568
568
|
778: { name: 'British Columbia', code: 'BC', region: CANADA },
|
|
569
569
|
204: { name: 'Manitoba', code: 'MB', region: CANADA },
|
|
570
570
|
431: { name: 'Manitoba', code: 'MB', region: CANADA },
|
|
571
|
+
584: { name: 'Manitoba', code: 'MB', region: CANADA },
|
|
571
572
|
506: { name: 'New Brunswick', code: 'NB', region: CANADA },
|
|
572
573
|
709: { name: 'Newfoundland and Labrador', code: 'NL', region: CANADA },
|
|
573
574
|
782: {
|
|
@@ -581,30 +582,39 @@ export const AREA_CODES = {
|
|
|
581
582
|
region: CANADA,
|
|
582
583
|
},
|
|
583
584
|
226: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
585
|
+
249: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
584
586
|
289: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
585
587
|
343: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
586
588
|
365: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
589
|
+
382: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
587
590
|
416: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
588
591
|
437: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
589
592
|
519: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
590
593
|
548: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
591
594
|
613: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
592
595
|
647: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
596
|
+
683: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
593
597
|
705: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
598
|
+
753: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
594
599
|
742: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
595
600
|
807: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
596
601
|
942: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
597
602
|
905: { name: 'Ontario', code: 'ON', region: CANADA },
|
|
603
|
+
263: { name: 'Quebec', code: 'QC', region: CANADA },
|
|
604
|
+
354: { name: 'Quebec', code: 'QC', region: CANADA },
|
|
605
|
+
367: { name: 'Quebec', code: 'QC', region: CANADA },
|
|
598
606
|
387: { name: 'Quebec', code: 'QC', region: CANADA },
|
|
599
607
|
418: { name: 'Quebec', code: 'QC', region: CANADA },
|
|
600
608
|
438: { name: 'Quebec', code: 'QC', region: CANADA },
|
|
601
609
|
450: { name: 'Quebec', code: 'QC', region: CANADA },
|
|
610
|
+
468: { name: 'Quebec', code: 'QC', region: CANADA },
|
|
602
611
|
514: { name: 'Quebec', code: 'QC', region: CANADA },
|
|
603
612
|
579: { name: 'Quebec', code: 'QC', region: CANADA },
|
|
604
613
|
581: { name: 'Quebec', code: 'QC', region: CANADA },
|
|
605
614
|
819: { name: 'Quebec', code: 'QC', region: CANADA },
|
|
606
615
|
873: { name: 'Quebec', code: 'QC', region: CANADA },
|
|
607
616
|
306: { name: 'Saskatchewan', code: 'SK', region: CANADA },
|
|
617
|
+
474: { name: 'Saskatchewan', code: 'SK', region: CANADA },
|
|
608
618
|
639: { name: 'Saskatchewan', code: 'SK', region: CANADA },
|
|
609
619
|
867: {
|
|
610
620
|
name: 'Yukon, Northwest Territories, and Nunavut',
|
|
@@ -708,6 +718,7 @@ export const REGION_CODES = {
|
|
|
708
718
|
679: { name: 'Fiji', code: 'FJ', flag: '🇫🇯' },
|
|
709
719
|
358: { name: 'Finland', code: 'FI', flag: '🇫🇮' },
|
|
710
720
|
33: { name: 'France', code: 'FR', flag: '🇫🇷' },
|
|
721
|
+
594: { name: 'French Guiana', code: 'GF', flag: '🇬🇫' },
|
|
711
722
|
689: { name: 'French Polynesia', code: 'PF', flag: '🇵🇫' },
|
|
712
723
|
241: { name: 'Gabon', code: 'GA', flag: '🇬🇦' },
|
|
713
724
|
220: { name: 'Gambia', code: 'GM', flag: '🇬🇲' },
|
|
@@ -761,6 +772,7 @@ export const REGION_CODES = {
|
|
|
761
772
|
223: { name: 'Mali', code: 'ML', flag: '🇲🇱' },
|
|
762
773
|
356: { name: 'Malta', code: 'MT', flag: '🇲🇹' },
|
|
763
774
|
692: { name: 'Marshall Islands', code: 'MH', flag: '🇲🇭' },
|
|
775
|
+
596: { name: 'Martinique', code: 'MQ', flag: '🇲🇶' },
|
|
764
776
|
222: { name: 'Mauritania', code: 'MR', flag: '🇲🇷' },
|
|
765
777
|
230: { name: 'Mauritius', code: 'MU', flag: '🇲🇺' },
|
|
766
778
|
262: { name: 'Mayotte, Reunion', code: 'YT/RE', flag: '🇾🇹/🇷🇪' },
|
package/src/phoneFormats.js
CHANGED
|
@@ -145,7 +145,6 @@ export const PHONE_FORMATS = {
|
|
|
145
145
|
269: '+xxx xxx xx xx', // Comoros
|
|
146
146
|
290: '+xxx xxxx', // Saint Helena
|
|
147
147
|
291: '+xxx x xxx xxx', // Eritrea
|
|
148
|
-
295: '+xxx xxx xxxx', // San Marino
|
|
149
148
|
297: '+xxx xxx xxxx', // Aruba
|
|
150
149
|
298: '+xxx xxx xxx', // Faroe Islands
|
|
151
150
|
299: '+xxx xx xx xx', // Greenland
|
package/src/timezones.js
CHANGED
|
@@ -118,6 +118,11 @@ export const STATES_WITH_MULTIPLE_TIMEZONES = {
|
|
|
118
118
|
458: ['-08:00', '-07:00'],
|
|
119
119
|
541: ['-08:00', '-07:00'],
|
|
120
120
|
},
|
|
121
|
+
Saskatchewan: {
|
|
122
|
+
306: ['-07:00', '-06:00', '-05:00'],
|
|
123
|
+
474: ['-07:00', '-06:00', '-05:00'],
|
|
124
|
+
639: ['-07:00', '-06:00', '-05:00'],
|
|
125
|
+
},
|
|
121
126
|
'South Dakota': {
|
|
122
127
|
605: ['-06:00', '-07:00'],
|
|
123
128
|
},
|
|
@@ -142,7 +147,9 @@ export const STATES_WITH_MULTIPLE_TIMEZONES = {
|
|
|
142
147
|
807: ['-05:00', '-06:00'],
|
|
143
148
|
},
|
|
144
149
|
Quebec: {
|
|
150
|
+
367: ['-04:00'],
|
|
145
151
|
418: ['-04:00'],
|
|
152
|
+
581: ['-04:00'],
|
|
146
153
|
},
|
|
147
154
|
'Newfoundland and Labrador': {
|
|
148
155
|
709: ['-03:30', '-04:00'],
|