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.
 
 
 
 
 

708 lines
27 KiB

/**
* @license
* Copyright (C) 2018 The Libphonenumber Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @fileoverview Utility for international phone numbers.
* Functionality includes formatting, parsing and validation.
* (based on the java implementation).
*
* NOTE: A lot of methods in this class require Region Code strings. These must
* be provided using CLDR two-letter region-code format. These should be in
* upper-case. The list of the codes can be found here:
* http://www.unicode.org/cldr/charts/30/supplemental/territory_information.html
*
* @author James Wright
*/
goog.provide('i18n.phonenumbers.ShortNumberInfo');
goog.require('goog.proto2.PbLiteSerializer');
goog.require('i18n.phonenumbers.PhoneMetadata');
goog.require('i18n.phonenumbers.PhoneNumber');
goog.require('i18n.phonenumbers.PhoneNumberDesc');
goog.require('i18n.phonenumbers.PhoneNumberUtil');
goog.require('i18n.phonenumbers.metadata');
goog.require('i18n.phonenumbers.shortnumbermetadata');
/**
* @constructor
* @private
*/
i18n.phonenumbers.ShortNumberInfo = function() {
/**
* A mapping from region code to the short-number metadata for that region.
* @type {Object.<string, i18n.phonenumbers.PhoneMetadata>}
*/
this.regionToMetadataMap = {};
};
goog.addSingletonGetter(i18n.phonenumbers.ShortNumberInfo);
/**
* In these countries, if extra digits are added to an emergency number, it no
* longer connects to the emergency service.
* @const
* @type {!Array<string>}
* @private
*/
i18n.phonenumbers.ShortNumberInfo.
REGIONS_WHERE_EMERGENCY_NUMBERS_MUST_BE_EXACT_ = [
'BR',
'CL',
'NI'
];
/**
* @enum {number} Cost categories of short numbers.
*/
i18n.phonenumbers.ShortNumberInfo.ShortNumberCost = {
TOLL_FREE: 0,
STANDARD_RATE: 1,
PREMIUM_RATE: 2,
UNKNOWN_COST: 3
};
/**
* Returns a list with the region codes that match the specific country calling
* code. For non-geographical country calling codes, the region code 001 is
* returned. Also, in the case of no region code being found, an empty list
* is returned.
* @param {number} countryCallingCode
* @return {!Array<string>} The region codes that match the given country code.
* @private
*/
i18n.phonenumbers.ShortNumberInfo.prototype.getRegionCodesForCountryCode_ =
function(countryCallingCode) {
var regionCodes = i18n.phonenumbers.metadata
.countryCodeToRegionCodeMap[countryCallingCode];
return regionCodes ? regionCodes : [];
};
/**
* Helper method to check that the country calling code of the number matches
* the region it's being dialed from.
* @param {i18n.phonenumbers.PhoneNumber} number
* @param {?string} regionDialingFrom
* @return {boolean}
* @private
*/
i18n.phonenumbers.ShortNumberInfo.prototype.regionDialingFromMatchesNumber_ =
function(number, regionDialingFrom) {
var regionCodes = this.getRegionCodesForCountryCode_(
number.getCountryCodeOrDefault());
return regionDialingFrom != null && regionCodes.includes(regionDialingFrom);
};
/**
* Check whether a short number is a possible number when dialed from the given
* region. This provides a more lenient check than
* {@link #isValidShortNumberForRegion}.
*
* @param {i18n.phonenumbers.PhoneNumber} number the short number to check
* @param {string} regionDialingFrom the region from which the number is dialed
* @return {boolean} whether the number is a possible short number
*/
i18n.phonenumbers.ShortNumberInfo.prototype.isPossibleShortNumberForRegion =
function(number, regionDialingFrom) {
if (!this.regionDialingFromMatchesNumber_(number, regionDialingFrom)) {
return false;
}
var phoneMetadata = this.getMetadataForRegion_(regionDialingFrom);
if (!phoneMetadata) {
return false;
}
var numberLength = this.getNationalSignificantNumber_(number).length;
return phoneMetadata.getGeneralDesc().possibleLengthArray().includes(
numberLength);
};
/**
* Check whether a short number is a possible number. If a country calling code
* is shared by multiple regions, this returns true if it's possible in any of
* them. This provides a more lenient check than {@link #isValidShortNumber}.
* See {@link #isPossibleShortNumberForRegion(PhoneNumber, String)} for details.
*
* @param {i18n.phonenumbers.PhoneNumber} number the short number to check
* @return {boolean} whether the number is a possible short number
*/
i18n.phonenumbers.ShortNumberInfo.prototype.isPossibleShortNumber =
function(number) {
var regionCodes = this.getRegionCodesForCountryCode_(
number.getCountryCodeOrDefault());
var shortNumberLength = this.getNationalSignificantNumber_(number).length;
for (var i = 0; i < regionCodes.length; i++) {
var region = regionCodes[i];
var phoneMetadata = this.getMetadataForRegion_(region);
if (!phoneMetadata) {
continue;
}
var possibleLengths = phoneMetadata.getGeneralDesc().possibleLengthArray();
if (possibleLengths.includes(shortNumberLength)) {
return true;
}
}
return false;
};
/**
* Tests whether a short number matches a valid pattern in a region. Note that
* this doesn't verify the number is actually in use, which is impossible to
* tell by just looking at the number itself.
*
* @param {i18n.phonenumbers.PhoneNumber} number the short number for which we
* want to test the validity
* @param {?string} regionDialingFrom the region from which the number is dialed
* @return {boolean} whether the short number matches a valid pattern
*/
i18n.phonenumbers.ShortNumberInfo.prototype.isValidShortNumberForRegion =
function(number, regionDialingFrom) {
if (!this.regionDialingFromMatchesNumber_(number, regionDialingFrom)) {
return false;
}
var phoneMetadata = this.getMetadataForRegion_(regionDialingFrom);
if (!phoneMetadata) {
return false;
}
var shortNumber = this.getNationalSignificantNumber_(number);
var generalDesc = phoneMetadata.getGeneralDesc();
if (!this.matchesPossibleNumberAndNationalNumber_(shortNumber, generalDesc)) {
return false;
}
var shortNumberDesc = phoneMetadata.getShortCode();
return this.matchesPossibleNumberAndNationalNumber_(shortNumber,
shortNumberDesc);
};
/**
* Tests whether a short number matches a valid pattern. If a country calling
* code is shared by multiple regions, this returns true if it's valid in any of
* them. Note that this doesn't verify the number is actually in use, which is
* impossible to tell by just looking at the number itself. See
* {@link #isValidShortNumberForRegion(PhoneNumber, String)} for details.
*
* @param {i18n.phonenumbers.PhoneNumber} number the short number for which we
* want to test the validity
* @return {boolean} whether the short number matches a valid pattern
*/
i18n.phonenumbers.ShortNumberInfo.prototype.isValidShortNumber =
function(number) {
var regionCodes = this.getRegionCodesForCountryCode_(
number.getCountryCodeOrDefault());
var regionCode = this.getRegionCodeForShortNumberFromRegionList_(number,
regionCodes);
if (regionCodes.length > 1 && regionCode != null) {
// If a matching region had been found for the phone number from among two
// or more regions, then we have already implicitly verified its validity
// for that region.
return true;
}
return this.isValidShortNumberForRegion(number, regionCode);
};
/**
* Gets the expected cost category of a short number when dialed from a region
* (however, nothing is implied about its validity). If it is important that the
* number is valid, then its validity must first be checked using
* {@link #isValidShortNumberForRegion}. Note that emergency numbers are always
* considered toll-free. Example usage:
* <pre>{@code
* // The region for which the number was parsed and the region we subsequently
* // check against need not be the same. Here we parse the number in the US and
* // check it for Canada.
* PhoneNumber number = phoneUtil.parse("110", "US");
* ...
* String regionCode = "CA";
* ShortNumberInfo shortInfo = ShortNumberInfo.getInstance();
* if (shortInfo.isValidShortNumberForRegion(shortNumber, regionCode)) {
* ShortNumberCost cost = shortInfo.getExpectedCostForRegion(number,
* regionCode);
* // Do something with the cost information here.
* }}</pre>
*
* @param {i18n.phonenumbers.PhoneNumber} number the short number for which we
* want to know the expected cost category
* @param {string} regionDialingFrom the region from which the number is dialed
* @return {i18n.phonenumbers.ShortNumberInfo.ShortNumberCost} the expected cost
* category for that region of the short number. Returns UNKNOWN_COST if the
* number does not match a cost category. Note that an invalid number may
* match any cost category.
* @package
*/
// @VisibleForTesting
i18n.phonenumbers.ShortNumberInfo.prototype.getExpectedCostForRegion =
function(number, regionDialingFrom) {
var ShortNumberCost = i18n.phonenumbers.ShortNumberInfo.ShortNumberCost;
if (!this.regionDialingFromMatchesNumber_(number, regionDialingFrom)) {
return ShortNumberCost.UNKNOWN_COST;
}
var phoneMetadata = this.getMetadataForRegion_(regionDialingFrom);
if (!phoneMetadata) {
return ShortNumberCost.UNKNOWN_COST;
}
var shortNumber = this.getNationalSignificantNumber_(number);
if (!phoneMetadata.getGeneralDesc().possibleLengthArray().includes(
shortNumber.length)) {
return ShortNumberCost.UNKNOWN_COST;
}
if (this.matchesPossibleNumberAndNationalNumber_(
shortNumber, phoneMetadata.getPremiumRate())) {
return ShortNumberCost.PREMIUM_RATE;
}
if (this.matchesPossibleNumberAndNationalNumber_(
shortNumber, phoneMetadata.getStandardRate())) {
return ShortNumberCost.STANDARD_RATE;
}
if (this.matchesPossibleNumberAndNationalNumber_(
shortNumber, phoneMetadata.getTollFree())) {
return ShortNumberCost.TOLL_FREE;
}
if (this.isEmergencyNumber(shortNumber, regionDialingFrom)) {
// Emergency numbers are implicitly toll-free
return ShortNumberCost.TOLL_FREE;
}
return ShortNumberCost.UNKNOWN_COST;
};
/**
* Gets the expected cost category of a short number (however, nothing is
* implied about its validity). If the country calling code is unique to a
* region, this method behaves exactly the same as
* {@link #getExpectedCostForRegion(PhoneNumber, String)}. However, if the
* country calling code is shared by multiple regions, then it returns the
* highest cost in the sequence PREMIUM_RATE, UNKNOWN_COST, STANDARD_RATE,
* TOLL_FREE. The reason for the position of UNKNOWN_COST in this order is that
* if a number is UNKNOWN_COST in one region but STANDARD_RATE or TOLL_FREE in
* another, its expected cost cannot be estimated as one of the latter since it
* might be a PREMIUM_RATE number.
* <p>
* For example, if a number is STANDARD_RATE in the US, but TOLL_FREE in Canada,
* the expected cost returned by this method will be STANDARD_RATE, since the
* NANPA countries share the same country calling code.
* <p>
* Note: If the region from which the number is dialed is known, it is highly
* preferable to call {@link #getExpectedCostForRegion(PhoneNumber, String)}
* instead.
*
* @param {i18n.phonenumbers.PhoneNumber} number the short number for which we
* want to know the expected cost category
* @return {i18n.phonenumbers.ShortNumberInfo.ShortNumberCost} the highest
* expected cost category of the short number in the region(s) with the
* given country calling code
* @package
*/
// @VisibleForTesting
i18n.phonenumbers.ShortNumberInfo.prototype.getExpectedCost = function(number) {
var ShortNumberCost = i18n.phonenumbers.ShortNumberInfo.ShortNumberCost;
var regionCodes = this.getRegionCodesForCountryCode_(
number.getCountryCodeOrDefault());
if (regionCodes.length === 0) {
return ShortNumberCost.UNKNOWN_COST;
}
if (regionCodes.length === 1) {
return this.getExpectedCostForRegion(number, regionCodes[0]);
}
var cost = ShortNumberCost.TOLL_FREE;
for (var i = 0; i < regionCodes.length; i++) {
var regionCode = regionCodes[i];
var costForRegion = this.getExpectedCostForRegion(number, regionCode);
switch (costForRegion) {
case ShortNumberCost.PREMIUM_RATE:
return ShortNumberCost.PREMIUM_RATE;
case ShortNumberCost.UNKNOWN_COST:
cost = ShortNumberCost.UNKNOWN_COST;
break;
case ShortNumberCost.STANDARD_RATE:
if (cost !== ShortNumberCost.UNKNOWN_COST) {
cost = ShortNumberCost.STANDARD_RATE;
}
break;
case ShortNumberCost.TOLL_FREE:
// Do nothing.
break;
default:
throw new Error('Unrecognized cost for region: ' + costForRegion);
}
}
return cost;
};
/**
* Helper method to get the region code for a given phone number, from a list
* of possible region codes. If the list contains more than one region, the
* first region for which the number is valid is returned.
* @param {!i18n.phonenumbers.PhoneNumber} number
* @param {Array<string>} regionCodes
* @return {?string}
* @private
*/
i18n.phonenumbers.ShortNumberInfo.prototype.getRegionCodeForShortNumberFromRegionList_ =
function(number, regionCodes) {
if (regionCodes.length === 0) {
return null;
} else if (regionCodes.length === 1) {
return regionCodes[0];
}
var nationalNumber = this.getNationalSignificantNumber_(number);
for (var i = 0; i < regionCodes.length; i++) {
var regionCode = regionCodes[i];
var phoneMetadata = this.getMetadataForRegion_(regionCode);
if (phoneMetadata && this.matchesPossibleNumberAndNationalNumber_(
nationalNumber, phoneMetadata.getShortCode())) {
return regionCode;
}
}
return null;
};
/**
* Convenience method to get a list of what regions the library has metadata for
* @return {!Array<string>} the list of region codes
* @package
*/
i18n.phonenumbers.ShortNumberInfo.prototype.getSupportedRegions = function() {
return Object.keys(i18n.phonenumbers.shortnumbermetadata.countryToMetadata)
.filter(function(regionCode) {
return isNaN(regionCode);
});
};
/**
* Gets a valid short number for the specified region.
*
* @param {?string} regionCode the region for which an example short number is
* needed
* @return {string} a valid short number for the specified region. Returns an
* empty string when the metadata does not contain such information.
* @package
*/
i18n.phonenumbers.ShortNumberInfo.prototype.getExampleShortNumber =
function(regionCode) {
var phoneMetadata = this.getMetadataForRegion_(regionCode);
if (!phoneMetadata) {
return '';
}
var desc = phoneMetadata.getShortCode();
if (desc.hasExampleNumber()) {
return desc.getExampleNumber() || '';
}
return '';
};
/**
* Gets a valid short number for the specified cost category.
*
* @param {string} regionCode the region for which an example short number is
* needed
* @param {i18n.phonenumbers.ShortNumberInfo.ShortNumberCost} cost the cost
* category of number that is needed
* @return {string} a valid short number for the specified region and cost
* category. Returns an empty string when the metadata does not contain such
* information, or the cost is UNKNOWN_COST.
*/
i18n.phonenumbers.ShortNumberInfo.prototype.getExampleShortNumberForCost =
function(regionCode, cost) {
var phoneMetadata = this.getMetadataForRegion_(regionCode);
if (!phoneMetadata) {
return '';
}
var ShortNumberCost = i18n.phonenumbers.ShortNumberInfo.ShortNumberCost;
var desc = null;
switch (cost) {
case ShortNumberCost.TOLL_FREE:
desc = phoneMetadata.getTollFree();
break;
case ShortNumberCost.STANDARD_RATE:
desc = phoneMetadata.getStandardRate();
break;
case ShortNumberCost.PREMIUM_RATE:
desc = phoneMetadata.getPremiumRate();
break;
default:
// UNKNOWN_COST numbers are computed by the process of elimination from
// the other cost categories.
}
if (desc && desc.hasExampleNumber()) {
return desc.getExampleNumber() || '';
}
return '';
};
/**
* Returns true if the given number, exactly as dialed, might be used to
* connect to an emergency service in the given region.
* <p>
* This method accepts a string, rather than a PhoneNumber, because it needs
* to distinguish cases such as "+1 911" and "911", where the former may not
* connect to an emergency service in all cases but the latter would. This
* method takes into account cases where the number might contain formatting,
* or might have additional digits appended (when it is okay to do that in
* the specified region).
*
* @param {string} number the phone number to test
* @param {string} regionCode the region where the phone number is being
* dialed
* @return {boolean} whether the number might be used to connect to an
* emergency service in the given region
*/
i18n.phonenumbers.ShortNumberInfo.prototype.connectsToEmergencyNumber =
function(number, regionCode) {
return this.matchesEmergencyNumberHelper_(number, regionCode,
true /* allows prefix match */);
};
/**
* Returns true if the given number exactly matches an emergency service
* number in the given region.
* <p>
* This method takes into account cases where the number might contain
* formatting, but doesn't allow additional digits to be appended. Note that
* {@code isEmergencyNumber(number, region)} implies
* {@code connectsToEmergencyNumber(number, region)}.
*
* @param {string} number the phone number to test
* @param {string} regionCode the region where the phone number is being
* dialed
* @return {boolean} whether the number exactly matches an emergency services
* number in the given region.
*/
i18n.phonenumbers.ShortNumberInfo.prototype.isEmergencyNumber =
function(number, regionCode) {
return this.matchesEmergencyNumberHelper_(number, regionCode,
false /* doesn't allow prefix match */);
};
/**
* @param {?string} regionCode The region code to get metadata for
* @return {?i18n.phonenumbers.PhoneMetadata} The region code's metadata, or
* null if it is not available or the region code is invalid.
* @private
*/
i18n.phonenumbers.ShortNumberInfo.prototype.getMetadataForRegion_ =
function(regionCode) {
if (!regionCode) {
return null;
}
regionCode = regionCode.toUpperCase();
var metadata = this.regionToMetadataMap[regionCode];
if (metadata == null) {
/** @type {goog.proto2.PbLiteSerializer} */
var serializer = new goog.proto2.PbLiteSerializer();
var metadataSerialized =
i18n.phonenumbers.shortnumbermetadata.countryToMetadata[regionCode];
if (metadataSerialized == null) {
return null;
}
metadata = /** @type {i18n.phonenumbers.PhoneMetadata} */ (
serializer.deserialize(i18n.phonenumbers.PhoneMetadata.getDescriptor(),
metadataSerialized));
this.regionToMetadataMap[regionCode] = metadata;
}
return metadata;
};
/**
* @param {string} number the number to match against
* @param {string} regionCode the region code to check against
* @param {boolean} allowPrefixMatch whether to allow prefix matching
* @return {boolean} True iff the number matches an emergency number for that
* particular region.
* @private
*/
i18n.phonenumbers.ShortNumberInfo.prototype.matchesEmergencyNumberHelper_ =
function(number, regionCode, allowPrefixMatch) {
var possibleNumber = i18n.phonenumbers.PhoneNumberUtil
.extractPossibleNumber(number);
if (i18n.phonenumbers.PhoneNumberUtil.LEADING_PLUS_CHARS_PATTERN
.test(possibleNumber)) {
return false;
}
var metadata = this.getMetadataForRegion_(regionCode);
if (metadata == null || !metadata.hasEmergency()) {
return false;
}
var normalizedNumber = i18n.phonenumbers.PhoneNumberUtil
.normalizeDigitsOnly(possibleNumber);
var allowPrefixMatchForRegion = allowPrefixMatch &&
!i18n.phonenumbers.ShortNumberInfo
.REGIONS_WHERE_EMERGENCY_NUMBERS_MUST_BE_EXACT_.includes(regionCode);
var emergencyNumberPattern = metadata.getEmergency()
.getNationalNumberPatternOrDefault();
var result = i18n.phonenumbers.PhoneNumberUtil.matchesEntirely(
emergencyNumberPattern, normalizedNumber);
return result ||
(allowPrefixMatchForRegion &&
i18n.phonenumbers.PhoneNumberUtil
.matchesPrefix(emergencyNumberPattern, normalizedNumber));
};
/**
* Given a valid short number, determines whether it is carrier-specific
* (however, nothing is implied about its validity). Carrier-specific numbers
* may connect to a different end-point, or not connect at all, depending on
* the user's carrier. If it is important that the number is valid, then its
* validity must first be checked using {@link #isValidShortNumber} or
* {@link #isValidShortNumberForRegion}.
*
* @param {i18n.phonenumbers.PhoneNumber} number the valid short number to
* check
* @return {boolean} whether the short number is carrier-specific, assuming the
* input was a valid short number
*/
i18n.phonenumbers.ShortNumberInfo.prototype.isCarrierSpecific =
function(number) {
var regionCodes = this.getRegionCodesForCountryCode_(
number.getCountryCodeOrDefault());
var regionCode = this.getRegionCodeForShortNumberFromRegionList_(number,
regionCodes);
var nationalNumber = this.getNationalSignificantNumber_(number);
var phoneMetadata = this.getMetadataForRegion_(regionCode);
return !!phoneMetadata && this.matchesPossibleNumberAndNationalNumber_(
nationalNumber, phoneMetadata.getCarrierSpecific());
};
/**
* Given a valid short number, determines whether it is carrier-specific when
* dialed from the given region (however, nothing is implied about its
* validity). Carrier-specific numbers may connect to a different end-point, or
* not connect at all, depending on the user's carrier. If it is important that
* the number is valid, then its validity must first be checked using
* {@link #isValidShortNumber} or {@link #isValidShortNumberForRegion}. Returns
* false if the number doesn't match the region provided.
*
* @param {i18n.phonenumbers.PhoneNumber} number the valid short number to
* check
* @param {string} regionDialingFrom the region from which the number is dialed
* @return {boolean} whether the short number is carrier-specific in the
* provided region, assuming the input was a valid short number
*/
i18n.phonenumbers.ShortNumberInfo.prototype.isCarrierSpecificForRegion =
function(number, regionDialingFrom) {
if (!this.regionDialingFromMatchesNumber_(number, regionDialingFrom)) {
return false;
}
var nationalNumber = this.getNationalSignificantNumber_(number);
var phoneMetadata = this.getMetadataForRegion_(regionDialingFrom);
return !!phoneMetadata && this.matchesPossibleNumberAndNationalNumber_(
nationalNumber, phoneMetadata.getCarrierSpecific());
};
/**
* Given a valid short number, determines whether it is an SMS service
* (however, nothing is implied about its validity). An SMS service is where the
* primary or only intended usage is to receive and/or send text messages
* (SMSs). This includes MMS as MMS numbers downgrade to SMS if the other party
* isn't MMS-capable. If it is important that the number is valid, then its
* validity must first be checked using {@link #isValidShortNumber} or {@link
* #isValidShortNumberForRegion}. Returns false if the number doesn't match the
* region provided.
*
* @param {i18n.phonenumbers.PhoneNumber} number the valid short number to
* check
* @param {string} regionDialingFrom the region from which the number is dialed
* @return {boolean} whether the short number is an SMS service in the provided
* region, assuming the input was a valid short number
*/
i18n.phonenumbers.ShortNumberInfo.prototype.isSmsServiceForRegion =
function(number, regionDialingFrom) {
if (!this.regionDialingFromMatchesNumber_(number, regionDialingFrom)) {
return false;
}
var phoneMetadata = this.getMetadataForRegion_(regionDialingFrom);
var nationalNumber = this.getNationalSignificantNumber_(number);
return !!phoneMetadata && this.matchesPossibleNumberAndNationalNumber_(
nationalNumber, phoneMetadata.getSmsServices());
};
/**
* Gets the national significant number of a phone number. Note a national
* significant number doesn't contain a national prefix or any formatting.
* <p>
* This is a temporary duplicate of the {@code getNationalSignificantNumber}
* method from {@code PhoneNumberUtil}. Ultimately a canonical static version
* should exist in a separate utility class (to prevent {@code ShortNumberInfo}
* needing to depend on PhoneNumberUtil).
*
* @param {i18n.phonenumbers.PhoneNumber} number the phone number for which the
* national significant number is needed.
* @return {string} the national significant number of the PhoneNumber object
* passed in.
* @private
*/
i18n.phonenumbers.ShortNumberInfo.prototype.getNationalSignificantNumber_ =
function(number) {
if (!number.hasNationalNumber()) {
return '';
}
/** @type {string} */
var nationalNumber = '' + number.getNationalNumber();
// If leading zero(s) have been set, we prefix this now. Note that a single
// leading zero is not the same as a national prefix; leading zeros should be
// dialled no matter whether you are dialling from within or outside the
// country, national prefixes are added when formatting nationally if
// applicable.
if (number.hasItalianLeadingZero() && number.getItalianLeadingZero() &&
number.getNumberOfLeadingZerosOrDefault() > 0) {
return Array(number.getNumberOfLeadingZerosOrDefault() + 1).join('0') +
nationalNumber;
}
return nationalNumber;
};
/**
* Helper method to add in a performance optimization.
* TODO: Once we have benchmarked ShortNumberInfo, consider if it is worth
* keeping this performance optimization.
* @param {string} number
* @param {i18n.phonenumbers.PhoneNumberDesc} numberDesc
* @return {boolean}
* @private
*/
i18n.phonenumbers.ShortNumberInfo.prototype
.matchesPossibleNumberAndNationalNumber_ = function(number, numberDesc) {
if (numberDesc.possibleLengthArray().length > 0 &&
!numberDesc.possibleLengthArray().includes(number.length)) {
return false;
}
return i18n.phonenumbers.PhoneNumberUtil.matchesEntirely(
numberDesc.getNationalNumberPatternOrDefault(), number.toString());
};