libphonenumber-js
Version:
A simpler (and smaller) rewrite of Google Android's popular libphonenumber library
952 lines (788 loc) • 34.4 kB
JavaScript
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
// This is an enhanced port of Google Android `libphonenumber`'s
// `asyoutypeformatter.js` of 17th November, 2016.
//
// https://github.com/googlei18n/libphonenumber/blob/8d21a365061de2ba0675c878a710a7b24f74d2ae/javascript/i18n/phonenumbers/asyoutypeformatter.js
import Metadata from './metadata';
import { matches_entirely, VALID_DIGITS, VALID_PUNCTUATION, PLUS_CHARS, parse_phone_number_digits, parse_national_number_and_country_calling_code } from './common';
import { extract_formatted_phone_number, find_country_code, strip_national_prefix_and_carrier_code } from './parse';
import { FIRST_GROUP_PATTERN, format_national_number_using_format, local_to_international_style } from './format';
import { check_number_length_for_type } from './types';
// Used in phone number format template creation.
// Could be any digit, I guess.
var DUMMY_DIGIT = '9';
var DUMMY_DIGIT_MATCHER = new RegExp(DUMMY_DIGIT, 'g');
// I don't know why is it exactly `15`
var LONGEST_NATIONAL_PHONE_NUMBER_LENGTH = 15;
// Create a phone number consisting only of the digit 9 that matches the
// `number_pattern` by applying the pattern to the "longest phone number" string.
var LONGEST_DUMMY_PHONE_NUMBER = repeat(DUMMY_DIGIT, LONGEST_NATIONAL_PHONE_NUMBER_LENGTH);
// The digits that have not been entered yet will be represented by a \u2008,
// the punctuation space.
export var DIGIT_PLACEHOLDER = 'x'; // '\u2008' (punctuation space)
var DIGIT_PLACEHOLDER_MATCHER = new RegExp(DIGIT_PLACEHOLDER);
var DIGIT_PLACEHOLDER_MATCHER_GLOBAL = new RegExp(DIGIT_PLACEHOLDER, 'g');
// A pattern that is used to match character classes in regular expressions.
// An example of a character class is "[1-4]".
var CHARACTER_CLASS_PATTERN = /\[([^\[\]])*\]/g;
// Any digit in a regular expression that actually denotes a digit. For
// example, in the regular expression "80[0-2]\d{6,10}", the first 2 digits
// (8 and 0) are standalone digits, but the rest are not.
// Two look-aheads are needed because the number following \\d could be a
// two-digit number, since the phone number can be as long as 15 digits.
var STANDALONE_DIGIT_PATTERN = /\d(?=[^,}][^,}])/g;
// A pattern that is used to determine if a `format` is eligible
// to be used by the "as you type formatter".
// It is eligible when the `format` contains groups of the dollar sign
// followed by a single digit, separated by valid phone number punctuation.
// This prevents invalid punctuation (such as the star sign in Israeli star numbers)
// getting into the output of the "as you type formatter".
var ELIGIBLE_FORMAT_PATTERN = new RegExp('^' + '[' + VALID_PUNCTUATION + ']*' + '(\\$\\d[' + VALID_PUNCTUATION + ']*)+' + '$');
// This is the minimum length of the leading digits of a phone number
// to guarantee the first "leading digits pattern" for a phone number format
// to be preemptive.
var MIN_LEADING_DIGITS_LENGTH = 3;
var VALID_INCOMPLETE_PHONE_NUMBER = '[' + PLUS_CHARS + ']{0,1}' + '[' + VALID_PUNCTUATION + VALID_DIGITS + ']*';
var VALID_INCOMPLETE_PHONE_NUMBER_PATTERN = new RegExp('^' + VALID_INCOMPLETE_PHONE_NUMBER + '$', 'i');
var AsYouType = function () {
/**
* @param {string} [country_code] - The default country used for parsing non-international phone numbers.
* @param {Object} metadata
*/
function AsYouType(country_code, metadata) {
_classCallCheck(this, AsYouType);
this.options = {};
this.metadata = new Metadata(metadata);
if (country_code && this.metadata.hasCountry(country_code)) {
this.default_country = country_code;
}
this.reset();
}
// Not setting `options` to a constructor argument
// not to break backwards compatibility
// for older versions of the library.
_createClass(AsYouType, [{
key: 'input',
value: function input(text) {
// Parse input
var extracted_number = extract_formatted_phone_number(text) || '';
// Special case for a lone '+' sign
// since it's not considered a possible phone number.
if (!extracted_number) {
if (text && text.indexOf('+') >= 0) {
extracted_number = '+';
}
}
// Validate possible first part of a phone number
if (!matches_entirely(extracted_number, VALID_INCOMPLETE_PHONE_NUMBER_PATTERN)) {
return this.current_output;
}
return this.process_input(parse_phone_number_digits(extracted_number));
}
}, {
key: 'process_input',
value: function process_input(input) {
// If an out of position '+' sign detected
// (or a second '+' sign),
// then just drop it from the input.
if (input[0] === '+') {
if (!this.parsed_input) {
this.parsed_input += '+';
// If a default country was set
// then reset it because an explicitly international
// phone number is being entered
this.reset_countriness();
}
input = input.slice(1);
}
// Raw phone number
this.parsed_input += input;
// // Reset phone number validation state
// this.valid = false
// Add digits to the national number
this.national_number += input;
// TODO: Deprecated: rename `this.national_number`
// to `this.nationalNumber` and remove `.getNationalNumber()`.
// Try to format the parsed input
if (this.is_international()) {
if (!this.countryCallingCode) {
// No need to format anything
// if there's no national phone number.
// (e.g. just the country calling code)
if (!this.national_number) {
// Return raw phone number
return this.parsed_input;
}
// If one looks at country phone codes
// then he can notice that no one country phone code
// is ever a (leftmost) substring of another country phone code.
// So if a valid country code is extracted so far
// then it means that this is the country code.
// If no country phone code could be extracted so far,
// then just return the raw phone number,
// because it has no way of knowing
// how to format the phone number so far.
if (!this.extract_country_calling_code()) {
// Return raw phone number
return this.parsed_input;
}
// Initialize country-specific data
this.initialize_phone_number_formats_for_this_country_calling_code();
this.reset_format();
this.determine_the_country();
}
// `this.country` could be `undefined`,
// for instance, when there is ambiguity
// in a form of several different countries
// each corresponding to the same country phone code
// (e.g. NANPA: USA, Canada, etc),
// and there's not enough digits entered
// to reliably determine the country
// the phone number belongs to.
// Therefore, in cases of such ambiguity,
// each time something is input,
// try to determine the country
// (if it's not determined yet).
else if (!this.country) {
this.determine_the_country();
}
} else {
// Some national prefixes are substrings of other national prefixes
// (for the same country), therefore try to extract national prefix each time
// because a longer national prefix might be available at some point in time.
var previous_national_prefix = this.national_prefix;
this.national_number = this.national_prefix + this.national_number;
// Possibly extract a national prefix
this.extract_national_prefix();
if (this.national_prefix !== previous_national_prefix) {
// National number has changed
// (due to another national prefix been extracted)
// therefore national number has changed
// therefore reset all previous formatting data.
// (and leading digits matching state)
this.matching_formats = this.available_formats;
this.reset_format();
}
}
if (!this.should_format()) {
return this.format_as_non_formatted_number();
}
// Check the available phone number formats
// based on the currently available leading digits.
this.match_formats_by_leading_digits();
// Format the phone number (given the next digits)
var formatted_national_phone_number = this.format_national_phone_number(input);
// If the phone number could be formatted,
// then return it, possibly prepending with country phone code
// (for international phone numbers only)
if (formatted_national_phone_number) {
return this.full_phone_number(formatted_national_phone_number);
}
// If the phone number couldn't be formatted,
// then just fall back to the raw phone number.
return this.parsed_input;
}
}, {
key: 'format_as_non_formatted_number',
value: function format_as_non_formatted_number() {
if (this.is_international() && this.countryCallingCode) {
if (this.national_number) {
// For convenience, the public `.template` property
// contains the whole international number
// if the phone number being input is international:
// 'x' for the '+' sign, 'x'es for the country phone code,
// a spacebar and then the template for the national number digits.
this.template = DIGIT_PLACEHOLDER + repeat(DIGIT_PLACEHOLDER, this.countryCallingCode.length) + ' ' + repeat(DIGIT_PLACEHOLDER, this.national_number.length);
return '+' + this.countryCallingCode + ' ' + this.national_number;
}
return '+' + this.countryCallingCode;
}
return this.parsed_input;
}
}, {
key: 'format_national_phone_number',
value: function format_national_phone_number(next_digits) {
// Format the next phone number digits
// using the previously chosen phone number format.
//
// This is done here because if `attempt_to_format_complete_phone_number`
// was placed before this call then the `template`
// wouldn't reflect the situation correctly (and would therefore be inconsistent)
//
var national_number_formatted_with_previous_format = void 0;
if (this.chosen_format) {
national_number_formatted_with_previous_format = this.format_next_national_number_digits(next_digits);
}
// See if the input digits can be formatted properly already. If not,
// use the results from format_next_national_number_digits(), which does formatting
// based on the formatting pattern chosen.
var formatted_number = this.attempt_to_format_complete_phone_number();
// Just because a phone number doesn't have a suitable format
// that doesn't mean that the phone is invalid
// because phone number formats only format phone numbers,
// they don't validate them and some (rare) phone numbers
// are meant to stay non-formatted.
if (formatted_number) {
// if (this.country)
// {
// this.valid = true
// }
return formatted_number;
}
// For some phone number formats national prefix
// If the previously chosen phone number format
// didn't match the next (current) digit being input
// (leading digits pattern didn't match).
if (this.choose_another_format()) {
// And a more appropriate phone number format
// has been chosen for these `leading digits`,
// then format the national phone number (so far)
// using the newly selected phone number pattern.
// Will return `undefined` if it couldn't format
// the supplied national number
// using the selected phone number pattern.
return this.reformat_national_number();
}
// If could format the next (current) digit
// using the previously chosen phone number format
// then return the formatted number so far.
// If no new phone number format could be chosen,
// and couldn't format the supplied national number
// using the selected phone number pattern,
// then it will return `undefined`.
return national_number_formatted_with_previous_format;
}
}, {
key: 'reset',
value: function reset() {
// Input stripped of non-phone-number characters.
// Can only contain a possible leading '+' sign and digits.
this.parsed_input = '';
this.current_output = '';
// This contains the national prefix that has been extracted. It contains only
// digits without formatting.
this.national_prefix = '';
this.national_number = '';
this.reset_countriness();
this.reset_format();
// this.valid = false
return this;
}
}, {
key: 'reset_country',
value: function reset_country() {
if (this.is_international()) {
this.country = undefined;
} else {
this.country = this.default_country;
}
}
}, {
key: 'reset_countriness',
value: function reset_countriness() {
this.reset_country();
if (this.default_country && !this.is_international()) {
this.metadata.country(this.default_country);
this.countryCallingCode = this.metadata.countryCallingCode();
this.initialize_phone_number_formats_for_this_country_calling_code();
} else {
this.metadata.country(undefined);
this.countryCallingCode = undefined;
this.available_formats = [];
this.matching_formats = this.available_formats;
}
}
}, {
key: 'reset_format',
value: function reset_format() {
this.chosen_format = undefined;
this.template = undefined;
this.partially_populated_template = undefined;
this.last_match_position = -1;
}
// Format each digit of national phone number (so far)
// using the newly selected phone number pattern.
}, {
key: 'reformat_national_number',
value: function reformat_national_number() {
// Format each digit of national phone number (so far)
// using the selected phone number pattern.
return this.format_next_national_number_digits(this.national_number);
}
}, {
key: 'initialize_phone_number_formats_for_this_country_calling_code',
value: function initialize_phone_number_formats_for_this_country_calling_code() {
// Get all "eligible" phone number formats for this country
this.available_formats = this.metadata.formats().filter(function (format) {
return ELIGIBLE_FORMAT_PATTERN.test(format.internationalFormat());
});
this.matching_formats = this.available_formats;
}
}, {
key: 'match_formats_by_leading_digits',
value: function match_formats_by_leading_digits() {
var leading_digits = this.national_number;
// "leading digits" pattern list starts with
// one of a maximum length of 3 digits,
// and then with each additional digit
// a more precise "leading digits" pattern is specified.
var index_of_leading_digits_pattern = leading_digits.length - MIN_LEADING_DIGITS_LENGTH;
if (index_of_leading_digits_pattern < 0) {
index_of_leading_digits_pattern = 0;
}
this.matching_formats = this.matching_formats.filter(function (format) {
var leading_digits_pattern_count = format.leadingDigitsPatterns().length;
// Keep everything that isn't restricted by leading digits.
if (leading_digits_pattern_count === 0) {
return true;
}
var leading_digits_pattern_index = Math.min(index_of_leading_digits_pattern, leading_digits_pattern_count - 1);
var leading_digits_pattern = format.leadingDigitsPatterns()[leading_digits_pattern_index];
// Brackets are required for `^` to be applied to
// all or-ed (`|`) parts, not just the first one.
return new RegExp('^(' + leading_digits_pattern + ')').test(leading_digits);
});
// If there was a phone number format chosen
// and it no longer holds given the new leading digits then reset it.
// The test for this `if` condition is marked as:
// "Reset a chosen format when it no longer holds given the new leading digits".
// To construct a valid test case for this one can find a country
// in `PhoneNumberMetadata.xml` yielding one format for 3 `<leadingDigits>`
// and yielding another format for 4 `<leadingDigits>` (Australia in this case).
if (this.chosen_format && this.matching_formats.indexOf(this.chosen_format) === -1) {
this.reset_format();
}
}
}, {
key: 'should_format',
value: function should_format() {
// Start matching any formats at all when the national number
// entered so far is at least 3 digits long,
// otherwise format matching would give false negatives
// like when the digits entered so far are `2`
// and the leading digits pattern is `21` –
// it's quite obvious in this case that the format could be the one
// but due to the absence of further digits it would give false negative.
//
// Google could have provided leading digits patterns starting
// with a single digit but they chose not to (for whatever reasons).
//
return this.national_number >= MIN_LEADING_DIGITS_LENGTH;
}
// Check to see if there is an exact pattern match for these digits. If so, we
// should use this instead of any other formatting template whose
// `leadingDigitsPattern` also matches the input.
}, {
key: 'attempt_to_format_complete_phone_number',
value: function attempt_to_format_complete_phone_number() {
for (var _iterator = this.matching_formats, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
var _ref;
if (_isArray) {
if (_i >= _iterator.length) break;
_ref = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref = _i.value;
}
var format = _ref;
var matcher = new RegExp('^(?:' + format.pattern() + ')$');
if (!matcher.test(this.national_number)) {
continue;
}
if (!this.is_format_applicable(format)) {
continue;
}
// To leave the formatter in a consistent state
this.reset_format();
this.chosen_format = format;
var formatted_number = format_national_number_using_format(this.national_number, format, this.is_international(), this.national_prefix.length > 0, this.metadata);
// Set `this.template` and `this.partially_populated_template`.
//
// `else` case doesn't ever happen
// with the current metadata,
// but just in case.
//
/* istanbul ignore else */
if (this.create_formatting_template(format)) {
// Populate `this.partially_populated_template`
this.reformat_national_number();
} else {
// Prepend `+CountryCode` in case of an international phone number
var full_number = this.full_phone_number(formatted_number);
this.template = full_number.replace(/[\d\+]/g, DIGIT_PLACEHOLDER);
this.partially_populated_template = full_number;
}
return formatted_number;
}
}
// Prepends `+CountryCode` in case of an international phone number
}, {
key: 'full_phone_number',
value: function full_phone_number(formatted_national_number) {
if (this.is_international()) {
return '+' + this.countryCallingCode + ' ' + formatted_national_number;
}
return formatted_national_number;
}
// Extracts the country calling code from the beginning
// of the entered `national_number` (so far),
// and places the remaining input into the `national_number`.
}, {
key: 'extract_country_calling_code',
value: function extract_country_calling_code() {
var _parse_national_numbe = parse_national_number_and_country_calling_code(this.parsed_input, this.default_country, this.metadata),
countryCallingCode = _parse_national_numbe.countryCallingCode,
number = _parse_national_numbe.number;
if (!countryCallingCode) {
return;
}
this.countryCallingCode = countryCallingCode;
this.national_number = number;
this.metadata.chooseCountryByCountryCallingCode(countryCallingCode);
return this.metadata.selectedCountry() !== undefined;
}
}, {
key: 'extract_national_prefix',
value: function extract_national_prefix() {
this.national_prefix = '';
if (!this.metadata.selectedCountry()) {
return;
}
// Only strip national prefixes for non-international phone numbers
// because national prefixes can't be present in international phone numbers.
// Otherwise, while forgiving, it would parse a NANPA number `+1 1877 215 5230`
// first to `1877 215 5230` and then, stripping the leading `1`, to `877 215 5230`,
// and then it would assume that's a valid number which it isn't.
// So no forgiveness for grandmas here.
// The issue asking for this fix:
// https://github.com/catamphetamine/libphonenumber-js/issues/159
var _strip_national_prefi = strip_national_prefix_and_carrier_code(this.national_number, this.metadata),
potential_national_number = _strip_national_prefi.number;
// We require that the NSN remaining after stripping the national prefix and
// carrier code be long enough to be a possible length for the region.
// Otherwise, we don't do the stripping, since the original number could be
// a valid short number.
if (!this.metadata.possibleLengths() || this.is_possible_number(this.national_number) && !this.is_possible_number(potential_national_number)) {
// Verify the parsed national (significant) number for this country
var national_number_rule = new RegExp(this.metadata.nationalNumberPattern());
//
// If the original number (before stripping national prefix) was viable,
// and the resultant number is not, then prefer the original phone number.
// This is because for some countries (e.g. Russia) the same digit could be both
// a national prefix and a leading digit of a valid national phone number,
// like `8` is the national prefix for Russia and both
// `8 800 555 35 35` and `800 555 35 35` are valid numbers.
if (matches_entirely(this.national_number, national_number_rule) && !matches_entirely(potential_national_number, national_number_rule)) {
return;
}
}
this.national_prefix = this.national_number.slice(0, this.national_number.length - potential_national_number.length);
this.national_number = potential_national_number;
return this.national_prefix;
}
}, {
key: 'is_possible_number',
value: function is_possible_number(number) {
var validation_result = check_number_length_for_type(number, undefined, this.metadata);
switch (validation_result) {
case 'IS_POSSIBLE':
return true;
// case 'IS_POSSIBLE_LOCAL_ONLY':
// return !this.is_international()
default:
return false;
}
}
}, {
key: 'choose_another_format',
value: function choose_another_format() {
// When there are multiple available formats, the formatter uses the first
// format where a formatting template could be created.
for (var _iterator2 = this.matching_formats, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
var _ref2;
if (_isArray2) {
if (_i2 >= _iterator2.length) break;
_ref2 = _iterator2[_i2++];
} else {
_i2 = _iterator2.next();
if (_i2.done) break;
_ref2 = _i2.value;
}
var format = _ref2;
// If this format is currently being used
// and is still possible, then stick to it.
if (this.chosen_format === format) {
return;
}
// If this `format` is suitable for "as you type",
// then extract the template from this format
// and use it to format the phone number being input.
if (!this.is_format_applicable(format)) {
continue;
}
if (!this.create_formatting_template(format)) {
continue;
}
this.chosen_format = format;
// With a new formatting template, the matched position
// using the old template needs to be reset.
this.last_match_position = -1;
return true;
}
// No format matches the phone number,
// therefore set `country` to `undefined`
// (or to the default country).
this.reset_country();
// No format matches the national phone number entered
this.reset_format();
}
}, {
key: 'is_format_applicable',
value: function is_format_applicable(format) {
// If national prefix is mandatory for this phone number format
// and the user didn't input the national prefix,
// then this phone number format isn't suitable.
if (!this.is_international() && !this.national_prefix && format.nationalPrefixIsMandatoryWhenFormatting()) {
return false;
}
return true;
}
}, {
key: 'create_formatting_template',
value: function create_formatting_template(format) {
// The formatter doesn't format numbers when numberPattern contains '|', e.g.
// (20|3)\d{4}. In those cases we quickly return.
// (Though there's no such format in current metadata)
/* istanbul ignore if */
if (format.pattern().indexOf('|') >= 0) {
return;
}
// Get formatting template for this phone number format
var template = this.get_template_for_phone_number_format_pattern(format);
// If the national number entered is too long
// for any phone number format, then abort.
if (!template) {
return;
}
// This one is for national number only
this.partially_populated_template = template;
// For convenience, the public `.template` property
// contains the whole international number
// if the phone number being input is international:
// 'x' for the '+' sign, 'x'es for the country phone code,
// a spacebar and then the template for the formatted national number.
if (this.is_international()) {
this.template = DIGIT_PLACEHOLDER + repeat(DIGIT_PLACEHOLDER, this.countryCallingCode.length) + ' ' + template;
}
// For local numbers, replace national prefix
// with a digit placeholder.
else {
this.template = template.replace(/\d/g, DIGIT_PLACEHOLDER);
}
// This one is for the full phone number
return this.template;
}
// Generates formatting template for a phone number format
}, {
key: 'get_template_for_phone_number_format_pattern',
value: function get_template_for_phone_number_format_pattern(format) {
// A very smart trick by the guys at Google
var number_pattern = format.pattern()
// Replace anything in the form of [..] with \d
.replace(CHARACTER_CLASS_PATTERN, '\\d')
// Replace any standalone digit (not the one in `{}`) with \d
.replace(STANDALONE_DIGIT_PATTERN, '\\d');
// This match will always succeed,
// because the "longest dummy phone number"
// has enough length to accomodate any possible
// national phone number format pattern.
var dummy_phone_number_matching_format_pattern = LONGEST_DUMMY_PHONE_NUMBER.match(number_pattern)[0];
// If the national number entered is too long
// for any phone number format, then abort.
if (this.national_number.length > dummy_phone_number_matching_format_pattern.length) {
return;
}
// Prepare the phone number format
var number_format = this.get_format_format(format);
// Get a formatting template which can be used to efficiently format
// a partial number where digits are added one by one.
// Below `strict_pattern` is used for the
// regular expression (with `^` and `$`).
// This wasn't originally in Google's `libphonenumber`
// and I guess they don't really need it
// because they're not using "templates" to format phone numbers
// but I added `strict_pattern` after encountering
// South Korean phone number formatting bug.
//
// Non-strict regular expression bug demonstration:
//
// this.national_number : `111111111` (9 digits)
//
// number_pattern : (\d{2})(\d{3,4})(\d{4})
// number_format : `$1 $2 $3`
// dummy_phone_number_matching_format_pattern : `9999999999` (10 digits)
//
// '9999999999'.replace(new RegExp(/(\d{2})(\d{3,4})(\d{4})/g), '$1 $2 $3') = "99 9999 9999"
//
// template : xx xxxx xxxx
//
// But the correct template in this case is `xx xxx xxxx`.
// The template was generated incorrectly because of the
// `{3,4}` variability in the `number_pattern`.
//
// The fix is, if `this.national_number` has already sufficient length
// to satisfy the `number_pattern` completely then `this.national_number` is used
// instead of `dummy_phone_number_matching_format_pattern`.
var strict_pattern = new RegExp('^' + number_pattern + '$');
var national_number_dummy_digits = this.national_number.replace(/\d/g, DUMMY_DIGIT);
// If `this.national_number` has already sufficient length
// to satisfy the `number_pattern` completely then use it
// instead of `dummy_phone_number_matching_format_pattern`.
if (strict_pattern.test(national_number_dummy_digits)) {
dummy_phone_number_matching_format_pattern = national_number_dummy_digits;
}
// Generate formatting template for this phone number format
return dummy_phone_number_matching_format_pattern
// Format the dummy phone number according to the format
.replace(new RegExp(number_pattern), number_format)
// Replace each dummy digit with a DIGIT_PLACEHOLDER
.replace(DUMMY_DIGIT_MATCHER, DIGIT_PLACEHOLDER);
}
}, {
key: 'format_next_national_number_digits',
value: function format_next_national_number_digits(digits) {
// Using `.split('')` to iterate through a string here
// to avoid requiring `Symbol.iterator` polyfill.
// `.split('')` is generally not safe for Unicode,
// but in this particular case for `digits` it is safe.
// for (const digit of digits)
for (var _iterator3 = digits.split(''), _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) {
var _ref3;
if (_isArray3) {
if (_i3 >= _iterator3.length) break;
_ref3 = _iterator3[_i3++];
} else {
_i3 = _iterator3.next();
if (_i3.done) break;
_ref3 = _i3.value;
}
var digit = _ref3;
// If there is room for more digits in current `template`,
// then set the next digit in the `template`,
// and return the formatted digits so far.
// If more digits are entered than the current format could handle
if (this.partially_populated_template.slice(this.last_match_position + 1).search(DIGIT_PLACEHOLDER_MATCHER) === -1) {
// Reset the current format,
// so that the new format will be chosen
// in a subsequent `this.choose_another_format()` call
// later in code.
this.chosen_format = undefined;
this.template = undefined;
this.partially_populated_template = undefined;
return;
}
this.last_match_position = this.partially_populated_template.search(DIGIT_PLACEHOLDER_MATCHER);
this.partially_populated_template = this.partially_populated_template.replace(DIGIT_PLACEHOLDER_MATCHER, digit);
}
// Return the formatted phone number so far
return close_dangling_braces(this.partially_populated_template, this.last_match_position + 1).replace(DIGIT_PLACEHOLDER_MATCHER_GLOBAL, ' ');
}
}, {
key: 'is_international',
value: function is_international() {
return this.parsed_input && this.parsed_input[0] === '+';
}
}, {
key: 'get_format_format',
value: function get_format_format(format) {
if (this.is_international()) {
return local_to_international_style(format.internationalFormat());
}
// If national prefix formatting rule is set
// for this phone number format
if (format.nationalPrefixFormattingRule()) {
// If the user did input the national prefix
// (or if the national prefix formatting rule does not require national prefix)
// then maybe make it part of the phone number template
if (this.national_prefix || !format.usesNationalPrefix()) {
// Make the national prefix part of the phone number template
return format.format().replace(FIRST_GROUP_PATTERN, format.nationalPrefixFormattingRule());
}
}
return format.format();
}
// Determines the country of the phone number
// entered so far based on the country phone code
// and the national phone number.
}, {
key: 'determine_the_country',
value: function determine_the_country() {
this.country = find_country_code(this.countryCallingCode, this.national_number, this.metadata);
}
}, {
key: 'getNationalNumber',
value: function getNationalNumber() {
return this.national_number;
}
}]);
return AsYouType;
}();
export default AsYouType;
export function close_dangling_braces(template, cut_before) {
var retained_template = template.slice(0, cut_before);
var opening_braces = count_occurences('(', retained_template);
var closing_braces = count_occurences(')', retained_template);
var dangling_braces = opening_braces - closing_braces;
while (dangling_braces > 0 && cut_before < template.length) {
if (template[cut_before] === ')') {
dangling_braces--;
}
cut_before++;
}
return template.slice(0, cut_before);
}
// Counts all occurences of a symbol in a string.
// Unicode-unsafe (because using `.split()`).
export function count_occurences(symbol, string) {
var count = 0;
// Using `.split('')` to iterate through a string here
// to avoid requiring `Symbol.iterator` polyfill.
// `.split('')` is generally not safe for Unicode,
// but in this particular case for counting brackets it is safe.
// for (const character of string)
for (var _iterator4 = string.split(''), _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) {
var _ref4;
if (_isArray4) {
if (_i4 >= _iterator4.length) break;
_ref4 = _iterator4[_i4++];
} else {
_i4 = _iterator4.next();
if (_i4.done) break;
_ref4 = _i4.value;
}
var character = _ref4;
if (character === symbol) {
count++;
}
}
return count;
}
// Repeats a string (or a symbol) N times.
// http://stackoverflow.com/questions/202605/repeat-string-javascript
export function repeat(string, times) {
if (times < 1) {
return '';
}
var result = '';
while (times > 1) {
if (times & 1) {
result += string;
}
times >>= 1;
string += string;
}
return result + string;
}
//# sourceMappingURL=AsYouType.js.map