@sprucelabs/schema 32.1.64 → 32.2.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.
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export declare function isValidNumber(number: string): boolean;
|
|
2
|
-
export default function formatPhoneNumber(
|
|
2
|
+
export default function formatPhoneNumber(value: string, shouldFailSilently?: boolean): string;
|
|
3
3
|
export declare function isDummyNumber(phone: string): boolean;
|
|
@@ -1,69 +1,124 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
1
|
+
var _a;
|
|
2
|
+
const LETTER_PATTERN = /[a-zA-Z]/;
|
|
3
|
+
const DEFAULT_CODE_SEPARATOR = ' ';
|
|
4
|
+
const COUNTRY_FORMATS = [
|
|
5
|
+
{
|
|
6
|
+
code: '92',
|
|
7
|
+
groupSizes: [4, 7],
|
|
8
|
+
groupSeparator: ' ',
|
|
9
|
+
validDigits: [9, 10, 11],
|
|
10
|
+
detect: ({ digits, hasExplicitPlus }) => digits.startsWith('92') && (hasExplicitPlus || digits.length > 10),
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
code: '90',
|
|
14
|
+
groupSizes: [3, 3, 4],
|
|
15
|
+
groupSeparator: ' ',
|
|
16
|
+
validDigits: [10],
|
|
17
|
+
detect: ({ digits, hasExplicitPlus }) => digits.startsWith('90') && (hasExplicitPlus || digits.length > 10),
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
code: '49',
|
|
21
|
+
groupSizes: [3, 3, 4],
|
|
22
|
+
groupSeparator: ' ',
|
|
23
|
+
validDigits: [10],
|
|
24
|
+
detect: ({ digits, hasExplicitPlus }) => digits.startsWith('49') && (hasExplicitPlus || digits.length > 10),
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
code: '1',
|
|
28
|
+
groupSizes: [3, 3, 4],
|
|
29
|
+
groupSeparator: '-',
|
|
30
|
+
validDigits: [10],
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
const DEFAULT_COUNTRY = (_a = COUNTRY_FORMATS.find((format) => format.code === '1')) !== null && _a !== void 0 ? _a : COUNTRY_FORMATS[0];
|
|
27
34
|
export function isValidNumber(number) {
|
|
28
35
|
var _a;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
return (formatted === null || formatted === void 0 ? void 0 : formatted.length) === 11 || (formatted === null || formatted === void 0 ? void 0 : formatted.length) === 12;
|
|
32
|
-
}
|
|
33
|
-
function stripCode(number) {
|
|
34
|
-
let code = `1`; // Default to North American country code
|
|
35
|
-
const cleaned = number.replace(/(?!^\+)[^\d]/g, '');
|
|
36
|
-
// Explicitly check for '+' sign to distinguish international codes
|
|
37
|
-
if (cleaned.startsWith('+90') ||
|
|
38
|
-
(cleaned.startsWith('90') && cleaned.length > 10)) {
|
|
39
|
-
code = `90`;
|
|
36
|
+
if (LETTER_PATTERN.test(number)) {
|
|
37
|
+
return false;
|
|
40
38
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
const parsed = parseInput(number);
|
|
40
|
+
const countryFormat = detectCountryFormat(parsed);
|
|
41
|
+
const localDigits = stripCountryCodeFromDigits(parsed.digits, countryFormat.code);
|
|
42
|
+
if (!localDigits.length) {
|
|
43
|
+
return false;
|
|
44
44
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
code = `1`;
|
|
45
|
+
if ((_a = countryFormat.validDigits) === null || _a === void 0 ? void 0 : _a.length) {
|
|
46
|
+
return countryFormat.validDigits.includes(localDigits.length);
|
|
48
47
|
}
|
|
49
|
-
return
|
|
48
|
+
return true;
|
|
50
49
|
}
|
|
51
|
-
export default function formatPhoneNumber(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (!formatted) {
|
|
50
|
+
export default function formatPhoneNumber(value, shouldFailSilently = true) {
|
|
51
|
+
var _a;
|
|
52
|
+
if (LETTER_PATTERN.test(value)) {
|
|
55
53
|
if (!shouldFailSilently) {
|
|
56
54
|
throw new Error('INVALID_PHONE_NUMBER');
|
|
57
55
|
}
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
const parsed = parseInput(value);
|
|
59
|
+
const countryFormat = detectCountryFormat(parsed);
|
|
60
|
+
const localDigits = stripCountryCodeFromDigits(parsed.digits, countryFormat.code);
|
|
61
|
+
if (!localDigits.length) {
|
|
62
|
+
if (!shouldFailSilently) {
|
|
63
|
+
throw new Error('INVALID_PHONE_NUMBER');
|
|
60
64
|
}
|
|
65
|
+
return value;
|
|
61
66
|
}
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
67
|
+
const formattedLocal = formatLocalDigits(localDigits, countryFormat);
|
|
68
|
+
const codeSeparator = (_a = countryFormat.codeSeparator) !== null && _a !== void 0 ? _a : DEFAULT_CODE_SEPARATOR;
|
|
69
|
+
const formatted = formattedLocal
|
|
70
|
+
? `+${countryFormat.code}${codeSeparator}${formattedLocal}`
|
|
71
|
+
: `+${countryFormat.code}`;
|
|
72
|
+
return formatted.trim();
|
|
65
73
|
}
|
|
66
74
|
export function isDummyNumber(phone) {
|
|
67
75
|
const cleanedValue = phone.replace(/\D/g, '');
|
|
68
76
|
return cleanedValue.startsWith('1555') || cleanedValue.startsWith('555');
|
|
69
77
|
}
|
|
78
|
+
function parseInput(original) {
|
|
79
|
+
const digits = original.replace(/\D/g, '');
|
|
80
|
+
const hasExplicitPlus = original.trim().startsWith('+');
|
|
81
|
+
return {
|
|
82
|
+
original,
|
|
83
|
+
digits,
|
|
84
|
+
hasExplicitPlus,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function detectCountryFormat(input) {
|
|
88
|
+
if (!input.digits.length) {
|
|
89
|
+
return DEFAULT_COUNTRY;
|
|
90
|
+
}
|
|
91
|
+
if (input.hasExplicitPlus) {
|
|
92
|
+
const explicitMatch = COUNTRY_FORMATS.find((format) => input.digits.startsWith(format.code));
|
|
93
|
+
if (explicitMatch) {
|
|
94
|
+
return explicitMatch;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const detected = COUNTRY_FORMATS.find((format) => format.detect ? format.detect(input) : false);
|
|
98
|
+
return detected !== null && detected !== void 0 ? detected : DEFAULT_COUNTRY;
|
|
99
|
+
}
|
|
100
|
+
function stripCountryCodeFromDigits(digits, code) {
|
|
101
|
+
if (digits.startsWith(code)) {
|
|
102
|
+
return digits.slice(code.length);
|
|
103
|
+
}
|
|
104
|
+
return digits;
|
|
105
|
+
}
|
|
106
|
+
function formatLocalDigits(digits, format) {
|
|
107
|
+
if (!digits.length) {
|
|
108
|
+
return '';
|
|
109
|
+
}
|
|
110
|
+
const parts = [];
|
|
111
|
+
let index = 0;
|
|
112
|
+
for (const size of format.groupSizes) {
|
|
113
|
+
if (index >= digits.length) {
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
const nextIndex = Math.min(index + size, digits.length);
|
|
117
|
+
parts.push(digits.slice(index, nextIndex));
|
|
118
|
+
index = nextIndex;
|
|
119
|
+
}
|
|
120
|
+
if (index < digits.length) {
|
|
121
|
+
parts.push(digits.slice(index));
|
|
122
|
+
}
|
|
123
|
+
return parts.join(format.groupSeparator);
|
|
124
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export declare function isValidNumber(number: string): boolean;
|
|
2
|
-
export default function formatPhoneNumber(
|
|
2
|
+
export default function formatPhoneNumber(value: string, shouldFailSilently?: boolean): string;
|
|
3
3
|
export declare function isDummyNumber(phone: string): boolean;
|
|
@@ -3,71 +3,124 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.isValidNumber = isValidNumber;
|
|
4
4
|
exports.default = formatPhoneNumber;
|
|
5
5
|
exports.isDummyNumber = isDummyNumber;
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
]
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
6
|
+
const LETTER_PATTERN = /[a-zA-Z]/;
|
|
7
|
+
const DEFAULT_CODE_SEPARATOR = ' ';
|
|
8
|
+
const COUNTRY_FORMATS = [
|
|
9
|
+
{
|
|
10
|
+
code: '92',
|
|
11
|
+
groupSizes: [4, 7],
|
|
12
|
+
groupSeparator: ' ',
|
|
13
|
+
validDigits: [9, 10, 11],
|
|
14
|
+
detect: ({ digits, hasExplicitPlus }) => digits.startsWith('92') && (hasExplicitPlus || digits.length > 10),
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
code: '90',
|
|
18
|
+
groupSizes: [3, 3, 4],
|
|
19
|
+
groupSeparator: ' ',
|
|
20
|
+
validDigits: [10],
|
|
21
|
+
detect: ({ digits, hasExplicitPlus }) => digits.startsWith('90') && (hasExplicitPlus || digits.length > 10),
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
code: '49',
|
|
25
|
+
groupSizes: [3, 3, 4],
|
|
26
|
+
groupSeparator: ' ',
|
|
27
|
+
validDigits: [10],
|
|
28
|
+
detect: ({ digits, hasExplicitPlus }) => digits.startsWith('49') && (hasExplicitPlus || digits.length > 10),
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
code: '1',
|
|
32
|
+
groupSizes: [3, 3, 4],
|
|
33
|
+
groupSeparator: '-',
|
|
34
|
+
validDigits: [10],
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
const DEFAULT_COUNTRY = COUNTRY_FORMATS.find((format) => format.code === '1') ?? COUNTRY_FORMATS[0];
|
|
32
38
|
function isValidNumber(number) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return formatted?.length === 11 || formatted?.length === 12;
|
|
36
|
-
}
|
|
37
|
-
function stripCode(number) {
|
|
38
|
-
let code = `1`; // Default to North American country code
|
|
39
|
-
const cleaned = number.replace(/(?!^\+)[^\d]/g, '');
|
|
40
|
-
// Explicitly check for '+' sign to distinguish international codes
|
|
41
|
-
if (cleaned.startsWith('+90') ||
|
|
42
|
-
(cleaned.startsWith('90') && cleaned.length > 10)) {
|
|
43
|
-
code = `90`;
|
|
39
|
+
if (LETTER_PATTERN.test(number)) {
|
|
40
|
+
return false;
|
|
44
41
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
const parsed = parseInput(number);
|
|
43
|
+
const countryFormat = detectCountryFormat(parsed);
|
|
44
|
+
const localDigits = stripCountryCodeFromDigits(parsed.digits, countryFormat.code);
|
|
45
|
+
if (!localDigits.length) {
|
|
46
|
+
return false;
|
|
48
47
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
code = `1`;
|
|
48
|
+
if (countryFormat.validDigits?.length) {
|
|
49
|
+
return countryFormat.validDigits.includes(localDigits.length);
|
|
52
50
|
}
|
|
53
|
-
return
|
|
51
|
+
return true;
|
|
54
52
|
}
|
|
55
|
-
function formatPhoneNumber(
|
|
56
|
-
|
|
57
|
-
const formatted = formatNumberWithCode(phoneWithoutCode, code);
|
|
58
|
-
if (!formatted) {
|
|
53
|
+
function formatPhoneNumber(value, shouldFailSilently = true) {
|
|
54
|
+
if (LETTER_PATTERN.test(value)) {
|
|
59
55
|
if (!shouldFailSilently) {
|
|
60
56
|
throw new Error('INVALID_PHONE_NUMBER');
|
|
61
57
|
}
|
|
62
|
-
|
|
63
|
-
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
const parsed = parseInput(value);
|
|
61
|
+
const countryFormat = detectCountryFormat(parsed);
|
|
62
|
+
const localDigits = stripCountryCodeFromDigits(parsed.digits, countryFormat.code);
|
|
63
|
+
if (!localDigits.length) {
|
|
64
|
+
if (!shouldFailSilently) {
|
|
65
|
+
throw new Error('INVALID_PHONE_NUMBER');
|
|
64
66
|
}
|
|
67
|
+
return value;
|
|
65
68
|
}
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
+
const formattedLocal = formatLocalDigits(localDigits, countryFormat);
|
|
70
|
+
const codeSeparator = countryFormat.codeSeparator ?? DEFAULT_CODE_SEPARATOR;
|
|
71
|
+
const formatted = formattedLocal
|
|
72
|
+
? `+${countryFormat.code}${codeSeparator}${formattedLocal}`
|
|
73
|
+
: `+${countryFormat.code}`;
|
|
74
|
+
return formatted.trim();
|
|
69
75
|
}
|
|
70
76
|
function isDummyNumber(phone) {
|
|
71
77
|
const cleanedValue = phone.replace(/\D/g, '');
|
|
72
78
|
return cleanedValue.startsWith('1555') || cleanedValue.startsWith('555');
|
|
73
79
|
}
|
|
80
|
+
function parseInput(original) {
|
|
81
|
+
const digits = original.replace(/\D/g, '');
|
|
82
|
+
const hasExplicitPlus = original.trim().startsWith('+');
|
|
83
|
+
return {
|
|
84
|
+
original,
|
|
85
|
+
digits,
|
|
86
|
+
hasExplicitPlus,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function detectCountryFormat(input) {
|
|
90
|
+
if (!input.digits.length) {
|
|
91
|
+
return DEFAULT_COUNTRY;
|
|
92
|
+
}
|
|
93
|
+
if (input.hasExplicitPlus) {
|
|
94
|
+
const explicitMatch = COUNTRY_FORMATS.find((format) => input.digits.startsWith(format.code));
|
|
95
|
+
if (explicitMatch) {
|
|
96
|
+
return explicitMatch;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const detected = COUNTRY_FORMATS.find((format) => format.detect ? format.detect(input) : false);
|
|
100
|
+
return detected ?? DEFAULT_COUNTRY;
|
|
101
|
+
}
|
|
102
|
+
function stripCountryCodeFromDigits(digits, code) {
|
|
103
|
+
if (digits.startsWith(code)) {
|
|
104
|
+
return digits.slice(code.length);
|
|
105
|
+
}
|
|
106
|
+
return digits;
|
|
107
|
+
}
|
|
108
|
+
function formatLocalDigits(digits, format) {
|
|
109
|
+
if (!digits.length) {
|
|
110
|
+
return '';
|
|
111
|
+
}
|
|
112
|
+
const parts = [];
|
|
113
|
+
let index = 0;
|
|
114
|
+
for (const size of format.groupSizes) {
|
|
115
|
+
if (index >= digits.length) {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
const nextIndex = Math.min(index + size, digits.length);
|
|
119
|
+
parts.push(digits.slice(index, nextIndex));
|
|
120
|
+
index = nextIndex;
|
|
121
|
+
}
|
|
122
|
+
if (index < digits.length) {
|
|
123
|
+
parts.push(digits.slice(index));
|
|
124
|
+
}
|
|
125
|
+
return parts.join(format.groupSeparator);
|
|
126
|
+
}
|