UNPKG

8.04 kBJavaScriptView Raw
1// This function is copy-pasted from
2// https://github.com/googlei18n/libphonenumber/blob/master/javascript/i18n/phonenumbers/phonenumberutil.js
3// It hasn't been tested.
4// Carriers codes aren't part of this library.
5// Send a PR if you want to add them.
6
7import Metadata from './metadata'
8import format from './format_'
9import getNumberType from './helpers/getNumberType'
10import checkNumberLength from './helpers/checkNumberLength'
11import getCountryCallingCode from './getCountryCallingCode'
12
13const REGION_CODE_FOR_NON_GEO_ENTITY = '001'
14
15/**
16 * The prefix that needs to be inserted in front of a Colombian landline number
17 * when dialed from a mobile phone in Colombia.
18 */
19const COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX = '3'
20
21/**
22 * Returns a number formatted in such a way that it can be dialed from a mobile
23 * phone in a specific region. If the number cannot be reached from the region
24 * (e.g. some countries block toll-free numbers from being called outside of the
25 * country), the method returns an empty string.
26 *
27 * @param {object} number - a `parse()`d phone number to be formatted.
28 * @param {string} from_country - the region where the call is being placed.
29 * @param {boolean} with_formatting - whether the number should be returned with
30 * formatting symbols, such as spaces and dashes.
31 * @return {string}
32 */
33export default function(number, from_country, with_formatting, metadata) {
34 metadata = new Metadata(metadata)
35
36 // Validate `from_country`.
37 if (!metadata.hasCountry(from_country)) {
38 throw new Error(`Unknown country: ${from_country}`)
39 }
40
41 // Not using the extension, as that part cannot normally be dialed
42 // together with the main number.
43 number = {
44 phone: number.phone,
45 country: number.country
46 }
47
48 const number_type = getNumberType(number, undefined, metadata.metadata)
49 const is_valid_number = number_type === number
50
51 let formatted_number
52
53 if (country === from_country) {
54 const is_fixed_line_or_mobile =
55 number_type === 'FIXED_LINE' ||
56 number_type === 'MOBILE' ||
57 number_type === 'FIXED_LINE_OR_MOBILE'
58
59 // Carrier codes may be needed in some countries. We handle this here.
60 if (country === 'CO' && number_type === 'FIXED_LINE') {
61 formatted_number = formatNationalNumberWithCarrierCode(
62 number,
63 COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX
64 )
65 }
66 else if (country == 'BR' && is_fixed_line_or_mobile) {
67 formatted_number =
68 carrierCode ?
69 formatNationalNumberWithPreferredCarrierCode(number) :
70 // Brazilian fixed line and mobile numbers need to be dialed with a
71 // carrier code when called within Brazil. Without that, most of the
72 // carriers won't connect the call. Because of that, we return an
73 // empty string here.
74 ''
75 } else if (getCountryCallingCode(country, metadata.metadata) === '1') {
76 // For NANPA countries, we output international format for numbers that
77 // can be dialed internationally, since that always works, except for
78 // numbers which might potentially be short numbers, which are always
79 // dialled in national format.
80
81 // Select country for `checkNumberLength()`.
82 metadata.country(country)
83
84 if (can_be_internationally_dialled(number) &&
85 checkNumberLength(number.phone, metadata) !== 'TOO_SHORT') {
86 formatted_number = format(number, 'INTERNATIONAL', metadata.metadata)
87 }
88 else {
89 formatted_number = format(number, 'NATIONAL', metadata.metadata)
90 }
91 }
92 else {
93 // For non-geographic countries, Mexican and Chilean fixed line and
94 // mobile numbers, we output international format for numbers that can be
95 // dialed internationally, as that always works.
96 if (
97 (
98 country === REGION_CODE_FOR_NON_GEO_ENTITY
99 ||
100 // MX fixed line and mobile numbers should always be formatted in
101 // international format, even when dialed within MX. For national
102 // format to work, a carrier code needs to be used, and the correct
103 // carrier code depends on if the caller and callee are from the
104 // same local area. It is trickier to get that to work correctly than
105 // using international format, which is tested to work fine on all
106 // carriers.
107 //
108 // CL fixed line numbers need the national prefix when dialing in the
109 // national format, but don't have it when used for display. The
110 // reverse is true for mobile numbers. As a result, we output them in
111 // the international format to make it work.
112 //
113 // UZ mobile and fixed-line numbers have to be formatted in
114 // international format or prefixed with special codes like 03, 04
115 // (for fixed-line) and 05 (for mobile) for dialling successfully
116 // from mobile devices. As we do not have complete information on
117 // special codes and to be consistent with formatting across all
118 // phone types we return the number in international format here.
119 //
120 ((country === 'MX' || country === 'CL' || country == 'UZ') && is_fixed_line_or_mobile)
121 )
122 &&
123 can_be_internationally_dialled(number)
124 ) {
125 formatted_number = format(number, 'INTERNATIONAL')
126 }
127 else {
128 formatted_number = format(number, 'NATIONAL')
129 }
130 }
131 }
132 else if (is_valid_number && can_be_internationally_dialled(number)) {
133 // We assume that short numbers are not diallable from outside their region,
134 // so if a number is not a valid regular length phone number, we treat it as
135 // if it cannot be internationally dialled.
136 return with_formatting ?
137 format(number, 'INTERNATIONAL', metadata.metadata) :
138 format(number, 'E.164', metadata.metadata)
139 }
140
141 if (!with_formatting) {
142 return diallable_chars(formatted_number)
143 }
144
145 return formatted_number
146}
147
148function can_be_internationally_dialled(number) {
149 return true
150}
151
152/**
153 * A map that contains characters that are essential when dialling. That means
154 * any of the characters in this map must not be removed from a number when
155 * dialling, otherwise the call will not reach the intended destination.
156 */
157const DIALLABLE_CHARACTERS = {
158 '0': '0',
159 '1': '1',
160 '2': '2',
161 '3': '3',
162 '4': '4',
163 '5': '5',
164 '6': '6',
165 '7': '7',
166 '8': '8',
167 '9': '9',
168 '+': '+',
169 '*': '*',
170 '#': '#'
171}
172
173function diallable_chars(formatted_number) {
174 let result = ''
175
176 let i = 0
177 while (i < formatted_number.length) {
178 const character = formatted_number[i]
179 if (DIALLABLE_CHARACTERS[character]) {
180 result += character
181 }
182 i++
183 }
184
185 return result
186}
187
188function getPreferredDomesticCarrierCodeOrDefault() {
189 throw new Error('carrier codes are not part of this library')
190}
191
192function formatNationalNumberWithCarrierCode() {
193 throw new Error('carrier codes are not part of this library')
194}
195
196/**
197 * Formats a phone number in national format for dialing using the carrier as
198 * specified in the preferred_domestic_carrier_code field of the PhoneNumber
199 * object passed in. If that is missing, use the {@code fallbackCarrierCode}
200 * passed in instead. If there is no {@code preferred_domestic_carrier_code},
201 * and the {@code fallbackCarrierCode} contains an empty string, return the
202 * number in national format without any carrier code.
203 *
204 * <p>Use {@link #formatNationalNumberWithCarrierCode} instead if the carrier
205 * code passed in should take precedence over the number's
206 * {@code preferred_domestic_carrier_code} when formatting.
207 *
208 * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be
209 * formatted.
210 * @param {string} fallbackCarrierCode the carrier selection code to be used, if
211 * none is found in the phone number itself.
212 * @return {string} the formatted phone number in national format for dialing
213 * using the number's preferred_domestic_carrier_code, or the
214 * {@code fallbackCarrierCode} passed in if none is found.
215 */
216function formatNationalNumberWithPreferredCarrierCode(number) {
217 return formatNationalNumberWithCarrierCode(
218 number,
219 carrierCode
220 );
221}
\No newline at end of file