You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					221 lines
				
				7.9 KiB
			
		
		
			
		
	
	
					221 lines
				
				7.9 KiB
			| 
											3 years ago
										 | // This function is copy-pasted from
 | ||
|  | // https://github.com/googlei18n/libphonenumber/blob/master/javascript/i18n/phonenumbers/phonenumberutil.js
 | ||
|  | // It hasn't been tested.
 | ||
|  | // Carriers codes aren't part of this library.
 | ||
|  | // Send a PR if you want to add them.
 | ||
|  | 
 | ||
|  | import Metadata from './metadata.js' | ||
|  | import format from './format_.js' | ||
|  | import getNumberType from './helpers/getNumberType.js' | ||
|  | import checkNumberLength from './helpers/checkNumberLength.js' | ||
|  | import getCountryCallingCode from './getCountryCallingCode.js' | ||
|  | 
 | ||
|  | const REGION_CODE_FOR_NON_GEO_ENTITY = '001' | ||
|  | 
 | ||
|  | /** | ||
|  |  * The prefix that needs to be inserted in front of a Colombian landline number | ||
|  |  * when dialed from a mobile phone in Colombia. | ||
|  |  */ | ||
|  | const COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX = '3' | ||
|  | 
 | ||
|  | /** | ||
|  |  * Returns a number formatted in such a way that it can be dialed from a mobile | ||
|  |  * phone in a specific region. If the number cannot be reached from the region | ||
|  |  * (e.g. some countries block toll-free numbers from being called outside of the | ||
|  |  * country), the method returns an empty string. | ||
|  |  * | ||
|  |  * @param {object} number - a `parse()`d phone number to be formatted. | ||
|  |  * @param {string} from_country - the region where the call is being placed. | ||
|  |  * @param {boolean} with_formatting - whether the number should be returned with | ||
|  |  *     formatting symbols, such as spaces and dashes. | ||
|  |  * @return {string} | ||
|  |  */ | ||
|  | export default function(number, from_country, with_formatting, metadata) { | ||
|  | 	metadata = new Metadata(metadata) | ||
|  | 
 | ||
|  | 	// Validate `from_country`.
 | ||
|  | 	if (!metadata.hasCountry(from_country)) { | ||
|  | 		throw new Error(`Unknown country: ${from_country}`) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	// Not using the extension, as that part cannot normally be dialed
 | ||
|  | 	// together with the main number.
 | ||
|  | 	number = { | ||
|  | 		phone: number.phone, | ||
|  | 		country: number.country | ||
|  | 	} | ||
|  | 
 | ||
|  | 	const number_type = getNumberType(number, undefined, metadata.metadata) | ||
|  | 	const is_valid_number = number_type === number | ||
|  | 
 | ||
|  | 	let formatted_number | ||
|  | 
 | ||
|  | 	if (country === from_country) { | ||
|  | 		const is_fixed_line_or_mobile = | ||
|  | 			number_type === 'FIXED_LINE' || | ||
|  | 			number_type === 'MOBILE' || | ||
|  | 			number_type === 'FIXED_LINE_OR_MOBILE' | ||
|  | 
 | ||
|  | 		// Carrier codes may be needed in some countries. We handle this here.
 | ||
|  | 		if (country === 'CO' && number_type === 'FIXED_LINE') { | ||
|  | 			formatted_number = formatNationalNumberWithCarrierCode( | ||
|  | 				number, | ||
|  | 				COLOMBIA_MOBILE_TO_FIXED_LINE_PREFIX | ||
|  | 			) | ||
|  | 		} | ||
|  | 		else if (country == 'BR' && is_fixed_line_or_mobile) { | ||
|  | 			formatted_number = | ||
|  | 				carrierCode ? | ||
|  | 				formatNationalNumberWithPreferredCarrierCode(number) : | ||
|  | 				// Brazilian fixed line and mobile numbers need to be dialed with a
 | ||
|  | 				// carrier code when called within Brazil. Without that, most of the
 | ||
|  | 				// carriers won't connect the call. Because of that, we return an
 | ||
|  | 				// empty string here.
 | ||
|  | 				'' | ||
|  | 		} else if (getCountryCallingCode(country, metadata.metadata) === '1') { | ||
|  | 			// For NANPA countries, we output international format for numbers that
 | ||
|  | 			// can be dialed internationally, since that always works, except for
 | ||
|  | 			// numbers which might potentially be short numbers, which are always
 | ||
|  | 			// dialled in national format.
 | ||
|  | 
 | ||
|  | 			// Select country for `checkNumberLength()`.
 | ||
|  | 			metadata.country(country) | ||
|  | 
 | ||
|  | 			if (can_be_internationally_dialled(number) && | ||
|  | 				checkNumberLength(number.phone, metadata) !== 'TOO_SHORT') { | ||
|  | 				formatted_number = format(number, 'INTERNATIONAL', metadata.metadata) | ||
|  | 			} | ||
|  | 			else { | ||
|  | 				formatted_number = format(number, 'NATIONAL', metadata.metadata) | ||
|  | 			} | ||
|  | 		} | ||
|  | 		else { | ||
|  | 			// For non-geographic countries, Mexican and Chilean fixed line and
 | ||
|  | 			// mobile numbers, we output international format for numbers that can be
 | ||
|  | 			// dialed internationally, as that always works.
 | ||
|  | 			if ( | ||
|  | 				( | ||
|  | 					country === REGION_CODE_FOR_NON_GEO_ENTITY | ||
|  | 					|| | ||
|  | 					// MX fixed line and mobile numbers should always be formatted in
 | ||
|  | 					// international format, even when dialed within MX. For national
 | ||
|  | 					// format to work, a carrier code needs to be used, and the correct
 | ||
|  | 					// carrier code depends on if the caller and callee are from the
 | ||
|  | 					// same local area. It is trickier to get that to work correctly than
 | ||
|  | 					// using international format, which is tested to work fine on all
 | ||
|  | 					// carriers.
 | ||
|  | 					//
 | ||
|  | 					// CL fixed line numbers need the national prefix when dialing in the
 | ||
|  | 					// national format, but don't have it when used for display. The
 | ||
|  | 					// reverse is true for mobile numbers. As a result, we output them in
 | ||
|  | 					// the international format to make it work.
 | ||
|  | 					//
 | ||
|  | 					// UZ mobile and fixed-line numbers have to be formatted in
 | ||
|  | 					// international format or prefixed with special codes like 03, 04
 | ||
|  | 					// (for fixed-line) and 05 (for mobile) for dialling successfully
 | ||
|  | 					// from mobile devices. As we do not have complete information on
 | ||
|  | 					// special codes and to be consistent with formatting across all
 | ||
|  | 					// phone types we return the number in international format here.
 | ||
|  | 					//
 | ||
|  | 					((country === 'MX' || country === 'CL' || country == 'UZ') && is_fixed_line_or_mobile) | ||
|  | 				) | ||
|  | 				&& | ||
|  | 				can_be_internationally_dialled(number) | ||
|  | 			) { | ||
|  | 				formatted_number = format(number, 'INTERNATIONAL') | ||
|  | 			} | ||
|  | 			else { | ||
|  | 				formatted_number = format(number, 'NATIONAL') | ||
|  | 			} | ||
|  | 		} | ||
|  | 	} | ||
|  | 	else if (is_valid_number && can_be_internationally_dialled(number)) { | ||
|  | 		// We assume that short numbers are not diallable from outside their region,
 | ||
|  | 		// so if a number is not a valid regular length phone number, we treat it as
 | ||
|  | 		// if it cannot be internationally dialled.
 | ||
|  | 		return with_formatting ? | ||
|  | 			format(number, 'INTERNATIONAL', metadata.metadata) : | ||
|  | 			format(number, 'E.164', metadata.metadata) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	if (!with_formatting) { | ||
|  | 		return diallable_chars(formatted_number) | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return formatted_number | ||
|  | } | ||
|  | 
 | ||
|  | function can_be_internationally_dialled(number) { | ||
|  | 	return true | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * A map that contains characters that are essential when dialling. That means | ||
|  |  * any of the characters in this map must not be removed from a number when | ||
|  |  * dialling, otherwise the call will not reach the intended destination. | ||
|  |  */ | ||
|  | const DIALLABLE_CHARACTERS = { | ||
|  | 	'0': '0', | ||
|  | 	'1': '1', | ||
|  | 	'2': '2', | ||
|  | 	'3': '3', | ||
|  | 	'4': '4', | ||
|  | 	'5': '5', | ||
|  | 	'6': '6', | ||
|  | 	'7': '7', | ||
|  | 	'8': '8', | ||
|  | 	'9': '9', | ||
|  | 	'+': '+', | ||
|  | 	'*': '*', | ||
|  | 	'#': '#' | ||
|  | } | ||
|  | 
 | ||
|  | function diallable_chars(formatted_number) { | ||
|  | 	let result = '' | ||
|  | 
 | ||
|  | 	let i = 0 | ||
|  | 	while (i < formatted_number.length) { | ||
|  | 		const character = formatted_number[i] | ||
|  | 		if (DIALLABLE_CHARACTERS[character]) { | ||
|  | 			result += character | ||
|  | 		} | ||
|  | 		i++ | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return result | ||
|  | } | ||
|  | 
 | ||
|  | function getPreferredDomesticCarrierCodeOrDefault() { | ||
|  | 	throw new Error('carrier codes are not part of this library') | ||
|  | } | ||
|  | 
 | ||
|  | function formatNationalNumberWithCarrierCode() { | ||
|  | 	throw new Error('carrier codes are not part of this library') | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * Formats a phone number in national format for dialing using the carrier as | ||
|  |  * specified in the preferred_domestic_carrier_code field of the PhoneNumber | ||
|  |  * object passed in. If that is missing, use the {@code fallbackCarrierCode} | ||
|  |  * passed in instead. If there is no {@code preferred_domestic_carrier_code}, | ||
|  |  * and the {@code fallbackCarrierCode} contains an empty string, return the | ||
|  |  * number in national format without any carrier code. | ||
|  |  * | ||
|  |  * <p>Use {@link #formatNationalNumberWithCarrierCode} instead if the carrier | ||
|  |  * code passed in should take precedence over the number's | ||
|  |  * {@code preferred_domestic_carrier_code} when formatting. | ||
|  |  * | ||
|  |  * @param {i18n.phonenumbers.PhoneNumber} number the phone number to be | ||
|  |  *     formatted. | ||
|  |  * @param {string} fallbackCarrierCode the carrier selection code to be used, if | ||
|  |  *     none is found in the phone number itself. | ||
|  |  * @return {string} the formatted phone number in national format for dialing | ||
|  |  *     using the number's preferred_domestic_carrier_code, or the | ||
|  |  *     {@code fallbackCarrierCode} passed in if none is found. | ||
|  |  */ | ||
|  | function formatNationalNumberWithPreferredCarrierCode(number) { | ||
|  | 	return formatNationalNumberWithCarrierCode( | ||
|  | 		number, | ||
|  | 		carrierCode | ||
|  | 	); | ||
|  | } |