Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

libphonenumber-js

Package Overview
Dependencies
Maintainers
1
Versions
395
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

libphonenumber-js - npm Package Compare versions

Comparing version 0.1.4 to 0.1.5

510

build/as you type.js

@@ -19,2 +19,5 @@ 'use strict';

exports.close_dangling_braces = close_dangling_braces;
exports.count_occurences = count_occurences;
var _metadata = require('../metadata.min');

@@ -28,2 +31,4 @@

var _format = require('./format');
var _common = require('./common');

@@ -35,3 +40,3 @@

// the punctuation space.
// This is a port of Google Android `libphonenumber`'s
var DIGIT_PLACEHOLDER = ' '; // This is an enhanced port of Google Android `libphonenumber`'s
// `asyoutypeformatter.js` of 17th November, 2016.

@@ -41,7 +46,4 @@ //

var DIGIT_PLACEHOLDER = ' ';
var DIGIT_PATTERN = new RegExp(DIGIT_PLACEHOLDER);
var DIGIT_PLACEHOLDER_MATCHER = new RegExp(DIGIT_PLACEHOLDER);
var SEPARATOR_BEFORE_NATIONAL_NUMBER = ' ';
// A pattern that is used to match character classes in regular expressions.

@@ -66,18 +68,7 @@ // An example of a character class is [1-4].

// A set of characters that, if found in a national prefix formatting rules, are
// an indicator to us that we should separate the national prefix from the
// number when formatting.
var NATIONAL_PREFIX_SEPARATORS_PATTERN = /[- ]/;
// This is the minimum length of national number accrued that is required to
// trigger the formatter. The first element of the leadingDigitsPattern of
// each numberFormat contains a regular expression that matches up to this
// number of digits.
// 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;
// A pattern that is used to determine if the national prefix formatting rule
// has the first group only, i.e., does not start with the national prefix.
// Note that the pattern explicitly allows for unbalanced parentheses.
var FIRST_GROUP_ONLY_PREFIX_PATTERN = /^\(?\$1\)?$/;
var VALID_INCOMPLETE_PHONE_NUMBER = '[' + _parse.PLUS_CHARS + ']{0,1}' + '[' + _parse.VALID_PUNCTUATION + _parse.VALID_DIGITS + ']+';

@@ -94,2 +85,3 @@

this.country_metadata = _metadata2.default.countries[country_code];
this.initialize_possible_formats();
}

@@ -103,3 +95,3 @@

value: function input(text) {
this.original_input += text;
// this.original_input += text

@@ -167,87 +159,110 @@ // Parse input

// If an out of position '+' sign detected
// (or a second '+' sign)
// (or a second '+' sign),
// then just don't allow it being input.
if (this.parsed_input) {
this.able_to_format = false;
} else {
this.parsed_input += character;
this.prefix_before_national_number = '+';
return this.current_output;
}
} else {
this.parsed_input += character;
this.national_number += character;
}
// A digit then
else {
this.national_number += character;
}
this.parsed_input += character;
// Try to format the parsed input
if (!this.able_to_format) {
// When we are unable to format because of reasons other than that
// formatting chars have been entered, it can be due to really long IDDs or
// NDDs. If that is the case, we might be able to do formatting again after
// extracting them.
if (this.is_international()) {
if (this.is_international()) {
if (!this.country_phone_code) {
// 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 (this.extract_country_phone_code()) {
return this.attempt_to_choose_formatting_pattern_with_national_prefix_extracted();
// If the possible phone number formats
// haven't been initialized during instance creation,
// then do it.
if (!this.country_code) {
this.initialize_possible_formats();
}
return '+' + this.country_phone_code;
}
} else if (this.extract_longer_national_prefix()) {
// Add an additional space to separate long NDD and national significant
// number for readability. We don't set shouldAddSpaceAfterNationalPrefix_
// to true, since we don't want this to change later when we choose
// formatting templates.
this.prefix_before_national_number += SEPARATOR_BEFORE_NATIONAL_NUMBER;
return this.attempt_to_choose_formatting_pattern_with_national_prefix_extracted();
// Return raw phone number
return this.parsed_input;
}
return this.parsed_input;
} else {
if (!this.national_prefix) {
// Possibly extract a national prefix
this.extract_national_prefix();
} else if (!this.able_to_format) {
if (!this.extract_longer_national_prefix()) {
// Return raw phone number
return this.parsed_input;
}
}
}
// We start to attempt to format only when at least MIN_LEADING_DIGITS_LENGTH
// digits (the plus sign is counted as a digit as well for this purpose) have
// been entered.
// Format the next phone number digit
// since the previously chose phone number format
// still holds.
//
// This is done here because if `attempt_to_format_complete_phone_number`
// was placed before this call then the `formatting_template`
// wouldn't reflect the situation correctly (and would therefore be inconsistent)
//
var national_number_formatted_with_previous_format = this.format_next_national_number_digit(character);
if (this.parsed_input.length < MIN_LEADING_DIGITS_LENGTH) {
return this.parsed_input;
}
// See if the input digits can be formatted properly already. If not,
// use the results from format_next_national_number_digit(), which does formatting
// based on the formatting pattern chosen.
if (this.parsed_input.length === MIN_LEADING_DIGITS_LENGTH) {
if (this.is_international()) {
this.expecting_country_calling_code = true;
} else {
// No IDD or plus sign is found, might be entering in national format.
this.national_prefix = this.extract_national_prefix();
return this.attempt_to_choose_formatting_pattern();
}
}
var formatted_number = this.attempt_to_format_complete_phone_number();
if (this.expecting_country_calling_code) {
if (this.extract_country_phone_code()) {
this.expecting_country_calling_code = false;
}
return this.prefix_before_national_number + this.national_number;
if (formatted_number) {
return formatted_number;
}
if (this.possible_formats.length === 0) {
return this.attempt_to_choose_formatting_pattern();
}
this.filter_possible_formats_by_leading_digits();
// The formatting patterns are already chosen.
// If the previously chosen phone number format
// didn't match the next digit being input
// (leading digits).
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.
var national_number = this.input_national_number_digit(character);
var formatted_national_number = this.reformat_national_number();
// See if the accrued digits can be formatted properly already. If not,
// use the results from input_national_number_digit(), which does formatting
// based on the formatting pattern chosen.
var formatted_number = this.attempt_to_format_complete_phone_number();
if (formatted_national_number) {
return this.full_phone_number(formatted_national_number);
}
if (formatted_number) {
return formatted_number;
// Couldn't format the supplied national number
// using the selected phone number pattern.
// Return raw phone number.
return this.parsed_input;
}
this.narrow_down_possible_formats(this.national_number);
// If no new phone number format could be chosen,
// then can't format the phone.
if (!this.current_format) {
this.able_to_format = false;
if (this.refresh_format()) {
return this.retype_national_number();
// Return raw phone number
return this.parsed_input;
}
return this.able_to_format ? this.full_phone_number(national_number) : this.parsed_input;
if (national_number_formatted_with_previous_format) {
return this.full_phone_number(national_number_formatted_with_previous_format);
}
// Couldn't format the supplied national number
// using the selected phone number pattern.
// Return raw phone number
return this.parsed_input;
}

@@ -257,4 +272,4 @@ }, {

value: function clear() {
// Input text so far, can contain any characters
this.original_input = '';
// // Input text so far, can contain any characters
// this.original_input = ''

@@ -267,9 +282,2 @@ // Input stripped of non-phone-number characters.

this.expecting_country_calling_code = false;
// This contains anything that has been entered so far preceding the national
// significant number, and it is formatted (e.g. with space inserted). For
// example, this can contain IDD, country code, and/or NDD, etc.
this.prefix_before_national_number = '';
// This contains the national prefix that has been extracted. It contains only

@@ -279,6 +287,10 @@ // digits without formatting.

this.should_add_space_after_national_prefix = false;
this.national_number = '';
this.country_phone_code = '';
if (!this.country_code) {
this.country_metadata = undefined;
}
this.clear_formatting();

@@ -289,7 +301,8 @@ }

value: function clear_formatting() {
// This indicates whether AsYouTypeFormatter is currently doing the formatting.
this.able_to_format = true;
this.possible_formats = [];
this.possible_formats = undefined;
this.current_format = undefined;
this.last_match_position = 0;

@@ -299,13 +312,14 @@

// The pattern from numberFormat that is currently used to create formattingTemplate.
this.current_formatting_pattern = undefined;
this.national_prefix_is_part_of_formatting_template = false;
}
// Format each digit of national phone number (so far)
// using the newly selected phone number pattern.
}, {
key: 'retype_national_number',
value: function retype_national_number() {
if (!this.national_number) {
return this.prefix_before_national_number;
}
var national_number = void 0;
key: 'reformat_national_number',
value: function reformat_national_number() {
// Format each digit of national phone number (so far)
// using the selected phone number pattern.
var formatted_national_number = void 0;
var _iteratorNormalCompletion2 = true;

@@ -319,3 +333,3 @@ var _didIteratorError2 = false;

national_number = this.input_national_number_digit(character);
formatted_national_number = this.format_next_national_number_digit(character);
}

@@ -337,3 +351,3 @@ } catch (err) {

return this.able_to_format ? this.full_phone_number(national_number) : this.parsed_input;
return formatted_national_number;
}

@@ -345,33 +359,7 @@ }, {

this.expecting_country_calling_code = false;
return this.attempt_to_choose_formatting_pattern();
return this.format_national_number();
}
}, {
key: 'attempt_to_choose_formatting_pattern',
value: function attempt_to_choose_formatting_pattern() {
// We start to attempt to format only when at least MIN_LEADING_DIGITS_LENGTH
// digits of national number (excluding national prefix) have been entered.
if (this.national_number.length < MIN_LEADING_DIGITS_LENGTH) {
return this.full_phone_number(this.national_number);
}
this.refresh_possible_formats(this.national_number);
// See if the accrued digits can be formatted properly already.
var formatted_number = this.attempt_to_format_complete_phone_number();
if (formatted_number) {
return formatted_number;
}
if (this.refresh_format()) {
return this.retype_national_number();
}
return this.parsed_input;
}
}, {
key: 'refresh_possible_formats',
value: function refresh_possible_formats(leading_digits) {
key: 'initialize_possible_formats',
value: function initialize_possible_formats() {
if (!this.country_metadata) {

@@ -381,16 +369,30 @@ return;

var national_prefix = (0, _metadata3.get_national_prefix)(this.country_metadata);
this.possible_formats = (0, _metadata3.get_formats)(this.country_metadata).filter(function (format) {
// Get all "eligible" phone number formats for this country
this.available_formats = (0, _metadata3.get_formats)(this.country_metadata).filter(function (format) {
return ELIGIBLE_FORMAT_PATTERN.test((0, _metadata3.get_format_international_format)(format));
});
this.narrow_down_possible_formats(leading_digits);
this.possible_formats = this.available_formats;
}
}, {
key: 'narrow_down_possible_formats',
value: function narrow_down_possible_formats(leading_digits) {
key: 'filter_possible_formats_by_leading_digits',
value: function filter_possible_formats_by_leading_digits() {
var leading_digits = this.national_number;
// "leading digits" patterns start with a maximum 3 digits,
// and then with each additional digit
// a more precise "leading digits" pattern is specified.
// They could make "leading digits" patterns start
// with a maximum of a single digit, but they didn't,
// so it's possible that some phone number formats
// will be falsely rejected until there are at least
// 3 digits in the national (significant) number being input.
var index_of_leading_digits_pattern = leading_digits.length - MIN_LEADING_DIGITS_LENGTH;
this.possible_formats = this.possible_formats.filter(function (format) {
if (index_of_leading_digits_pattern < 0) {
index_of_leading_digits_pattern = 0;
}
this.possible_formats = this.get_possible_formats().filter(function (format) {
var leading_digits_pattern_count = (0, _metadata3.get_format_leading_digits_patterns)(format).length;

@@ -403,8 +405,19 @@

var suitable_leading_digits_pattern_index = Math.min(index_of_leading_digits_pattern, leading_digits_pattern_count - 1);
var leading_digits_pattern = (0, _metadata3.get_format_leading_digits_patterns)(format)[suitable_leading_digits_pattern_index];
return leading_digits.search(leading_digits_pattern) === 0;
var leading_digits_pattern_index = Math.min(index_of_leading_digits_pattern, leading_digits_pattern_count - 1);
var leading_digits_pattern = (0, _metadata3.get_format_leading_digits_patterns)(format)[leading_digits_pattern_index];
return new RegExp('^' + leading_digits_pattern).test(leading_digits);
});
}
}, {
key: 'get_possible_formats',
value: function get_possible_formats() {
var leading_digits = this.national_number;
if (leading_digits.length <= MIN_LEADING_DIGITS_LENGTH) {
return this.available_formats;
}
return this.possible_formats;
}
// Check to see if there is an exact pattern match for these digits. If so, we

@@ -422,13 +435,10 @@ // should use this instead of any other formatting template whose

try {
for (var _iterator3 = (0, _getIterator3.default)(this.possible_formats), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
for (var _iterator3 = (0, _getIterator3.default)(this.get_possible_formats()), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var format = _step3.value;
var pattern = (0, _metadata3.get_format_pattern)(format);
var pattern_matcher = new RegExp('^(?:' + pattern + ')$');
var matcher = new RegExp('^(?:' + (0, _metadata3.get_format_pattern)(format) + ')$');
if (pattern_matcher.test(this.national_number)) {
this.should_add_space_after_national_prefix = NATIONAL_PREFIX_SEPARATORS_PATTERN.test((0, _metadata3.get_format_national_prefix_formatting_rule)(format, this.country_metadata));
if (matcher.test(this.national_number)) {
var formatted_national_number = (0, _format.format_national_number_using_format)(this.national_number, format, this.is_international(), this.national_prefix, this.country_metadata);
var formatted_national_number = this.national_number.replace(new RegExp(pattern, 'g'), this.get_format_format(format));
return this.full_phone_number(formatted_national_number);

@@ -453,5 +463,3 @@ }

// Combines the national number with any prefix (IDD/+ and country code or
// national prefix) that was collected. A space will be inserted between them if
// the current formatting template indicates this to be suitable.
// Combines the national number with the appropriate prefix

@@ -461,16 +469,12 @@ }, {

value: function full_phone_number(formatted_national_number) {
if (this.should_add_space_after_national_prefix && this.prefix_before_national_number && this.prefix_before_national_number[this.prefix_before_national_number.length - 1] !== SEPARATOR_BEFORE_NATIONAL_NUMBER) {
// We want to add a space after the national prefix if the national prefix
// formatting rule indicates that this would normally be done, with the
// exception of the case where we already appended a space because the NDD
// was surprisingly long.
return this.prefix_before_national_number + SEPARATOR_BEFORE_NATIONAL_NUMBER + formatted_national_number;
if (this.is_international()) {
return '+' + this.country_phone_code + ' ' + formatted_national_number;
}
return this.prefix_before_national_number + formatted_national_number;
return formatted_national_number;
}
// Extracts the country calling code from the beginning of nationalNumber to
// prefixBeforeNationalNumber when they are available, and places the remaining
// input into nationalNumber.
// Extracts the country calling code from the beginning
// of the entered `national_number` (so far),
// and places the remaining input into the `national_number`.

@@ -503,11 +507,5 @@ }, {

this.country_phone_code = country_phone_code;
this.national_number = number;
this.prefix_before_national_number += country_phone_code + SEPARATOR_BEFORE_NATIONAL_NUMBER;
// When we have successfully extracted the IDD,
// the previously extracted national prefix
// should be cleared because it is no longer valid.
this.national_prefix = '';
return this.country_metadata = (0, _metadata3.get_metadata_by_country_phone_code)(country_phone_code, _metadata2.default);

@@ -523,19 +521,14 @@ }

value: function extract_longer_national_prefix() {
if (this.national_prefix) {
// Put the extracted national prefix back to the national number
// before attempting to extract a new national prefix.
this.national_number = this.national_prefix + this.national_number;
// Remove the previously extracted national prefix from prefixBeforeNationalNumber. We
// cannot simply set it to empty string because people sometimes incorrectly
// enter national prefix after the country code, e.g. +44 (0)20-1234-5678.
var index_of_previous_national_prefix = this.prefix_before_national_number.lastIndexOf(this.national_prefix);
this.prefix_before_national_number = this.prefix_before_national_number.slice(0, index_of_previous_national_prefix);
if (!this.national_prefix) {
return;
}
return this.national_prefix !== this.extract_national_prefix();
// Put the extracted national prefix back to the national number
// before attempting to extract a new national prefix.
this.national_number = this.national_prefix + this.national_number;
var previously_extracted_national_prefix = this.national_prefix;
this.extract_national_prefix();
return this.national_prefix !== previously_extracted_national_prefix;
}
// Returns the national prefix extracted, or an empty string if it is not present.
}, {

@@ -547,5 +540,7 @@ key: 'extract_national_prefix',

if (this.country_metadata) {
// Small performance optimization for NANPA countries
// which can't have `1` (national prefix) as the
// first digit of a national (significant) number
if (this.is_NANPA_number_with_international_prefix()) {
national_number_starts_at = 1;
this.prefix_before_national_number += '1' + SEPARATOR_BEFORE_NATIONAL_NUMBER;
} else if ((0, _metadata3.get_national_prefix_for_parsing)(this.country_metadata)) {

@@ -558,3 +553,2 @@ var national_prefix_for_parsing = new RegExp('^(?:' + (0, _metadata3.get_national_prefix_for_parsing)(this.country_metadata) + ')');

national_number_starts_at = matches[0].length;
this.prefix_before_national_number += this.national_number.substring(0, national_number_starts_at);
}

@@ -564,4 +558,5 @@ }

this.national_prefix = this.national_number.slice(0, national_number_starts_at);
this.national_number = this.national_number.slice(national_number_starts_at);
return this.national_number.slice(0, national_number_starts_at);
return this.national_prefix;
}

@@ -586,4 +581,4 @@

}, {
key: 'refresh_format',
value: function refresh_format() {
key: 'choose_another_format',
value: function choose_another_format() {
// When there are multiple available formats, the formatter uses the first

@@ -596,18 +591,19 @@ // format where a formatting template could be created.

try {
for (var _iterator4 = (0, _getIterator3.default)(this.possible_formats), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
for (var _iterator4 = (0, _getIterator3.default)(this.get_possible_formats()), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var format = _step4.value;
var pattern = (0, _metadata3.get_format_pattern)(format);
if (this.current_formatting_pattern === pattern) {
return false;
// If this format is currently being used
// and is still possible, then stick to it.
if (this.current_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.create_formatting_template(format)) {
this.current_formatting_pattern = pattern;
this.current_format = format;
this.should_add_space_after_national_prefix = NATIONAL_PREFIX_SEPARATORS_PATTERN.test((0, _metadata3.get_format_national_prefix_formatting_rule)(format, this.country_metadata));
// With a new formatting template, the matched position using the old
// template needs to be reset.
// With a new formatting template, the matched position
// using the old template needs to be reset.
this.last_match_position = 0;

@@ -632,4 +628,2 @@

}
this.able_to_format = false;
}

@@ -650,16 +644,19 @@ }, {

.replace(CHARACTER_CLASS_PATTERN, '\\d')
// Replace any standalone digit (not the one in d{}) with \d
// Replace any standalone digit (not the one in `{}`) with \d
.replace(STANDALONE_DIGIT_PATTERN, '\\d');
return this.formatting_template = this.get_formatting_template(number_pattern, this.get_format_format(format));
}
var number_format = this.get_format_format(format);
this.national_prefix_is_part_of_formatting_template = false;
// Gets a formatting template which can be used to efficiently format a
// partial number where digits are added one by one.
if (this.national_prefix) {
this.national_prefix_is_part_of_formatting_template = true;
var national_prefix_formatting_rule = (0, _metadata3.get_format_national_prefix_formatting_rule)(format, this.country_metadata);
number_format = number_format.replace(_format.FIRST_GROUP_PATTERN, national_prefix_formatting_rule);
}
}, {
key: 'get_formatting_template',
value: function get_formatting_template(number_pattern, number_format) {
// Creates a phone number consisting only of the digit 9 that matches the
// numberPattern by applying the pattern to the longestPhoneNumber string.
// Get a formatting template which can be used to efficiently format a
// partial number where digits are added one by one.
// 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_phone_number = '999999999999999';

@@ -677,3 +674,3 @@

return phone_number
return this.formatting_template = phone_number
// Formats the number according to numberFormat

@@ -685,21 +682,23 @@ .replace(new RegExp(number_pattern, 'g'), number_format)

}, {
key: 'input_national_number_digit',
value: function input_national_number_digit(digit) {
if (this.formatting_template && this.formatting_template.slice(this.last_match_position).search(DIGIT_PATTERN) >= 0) {
var digit_pattern_start = this.formatting_template.search(DIGIT_PATTERN);
this.formatting_template = this.formatting_template.replace(DIGIT_PATTERN, digit);
key: 'format_next_national_number_digit',
value: function format_next_national_number_digit(digit) {
// If there is room for more digits in current `formatting_template`,
// then set the next digit in the `formatting_template`,
// and return the formatted digits so far.
if (this.formatting_template && this.formatting_template.slice(this.last_match_position + 1).search(DIGIT_PLACEHOLDER_MATCHER) >= 0) {
var digit_pattern_start = this.formatting_template.search(DIGIT_PLACEHOLDER_MATCHER);
this.formatting_template = this.formatting_template.replace(DIGIT_PLACEHOLDER_MATCHER, digit);
this.last_match_position = digit_pattern_start;
return this.formatting_template.slice(0, digit_pattern_start + 1);
// Return the formatted phone number so far
return close_dangling_braces(this.formatting_template, digit_pattern_start + 1);
}
if (this.possible_formats.length === 1) {
// More digits are entered than we could handle, and there are
// no other valid patterns to try.
this.able_to_format = false;
}
// else, we just reset the formatting pattern
// More digits are entered than the current format could handle
this.current_formatting_pattern = undefined;
return this.parsed_input;
// Reset the current format flag,
// so that the new format will be chosen
// in a subsequent `this.choose_another_format()` call
// later in code.
this.current_format = undefined;
}

@@ -714,9 +713,4 @@ }, {

value: function get_format_format(format) {
// // Always prefer international formatting rules over national ones,
// // because national formatting rules could contain
// // local formatting rules for numbers entered without area code.
// get_format_international_format(format)
if (this.is_international()) {
return (0, _metadata3.get_format_international_format)(format);
return (0, _format.local_to_international_style)((0, _metadata3.get_format_international_format)(format));
}

@@ -731,3 +725,53 @@

exports.default = as_you_type;
module.exports = exports['default'];
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
function count_occurences(symbol, string) {
var count = 0;
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
for (var _iterator5 = (0, _getIterator3.default)(string), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var character = _step5.value;
if (character === symbol) {
count++;
}
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
}
}
return count;
}
//# sourceMappingURL=as you type.js.map

@@ -6,2 +6,3 @@ 'use strict';

});
exports.FIRST_GROUP_PATTERN = undefined;

@@ -13,2 +14,3 @@ var _getIterator2 = require('babel-runtime/core-js/get-iterator');

exports.default = format;
exports.format_national_number_using_format = format_national_number_using_format;
exports.format_national_number = format_national_number;

@@ -69,3 +71,3 @@ exports.local_to_international_style = local_to_international_style;

case 'International':
var national_number = format_national_number(number, 'International', country_metadata);
var national_number = format_national_number(number, 'International', false, country_metadata);
return '+' + (0, _metadata3.get_phone_code)(country_metadata) + ' ' + national_number;

@@ -77,3 +79,3 @@

case 'National':
return format_national_number(number, 'National', country_metadata);
return format_national_number(number, 'National', false, country_metadata);
}

@@ -86,22 +88,20 @@ }

// group actually used in the pattern will be matched.
var FIRST_GROUP_PATTERN = /(\$\d)/;
var FIRST_GROUP_PATTERN = exports.FIRST_GROUP_PATTERN = /(\$\d)/;
function format_national_number(number, format_as, country_metadata) {
var format = choose_format_for_number((0, _metadata3.get_formats)(country_metadata), number);
function format_national_number_using_format(number, format, international, enforce_national_prefix, country_metadata) {
var national_prefix_formatting_rule = (0, _metadata3.get_format_national_prefix_formatting_rule)(format, country_metadata);
if (!format) {
return number;
}
var national_prefix_may_be_omitted = !enforce_national_prefix && (0, _metadata3.get_format_national_prefix_is_optional_when_formatting)(format, country_metadata);
var pattern_to_match = new RegExp((0, _metadata3.get_format_pattern)(format));
if (!international && !national_prefix_may_be_omitted) {
var _national_prefix_formatting_rule = (0, _metadata3.get_format_national_prefix_formatting_rule)(format, country_metadata);
var national_prefix_formatting_rule = (0, _metadata3.get_format_national_prefix_formatting_rule)(format, country_metadata);
var pattern_to_match = new RegExp((0, _metadata3.get_format_pattern)(format));
if (format_as === 'National' && !(0, _metadata3.get_format_national_prefix_is_optional_when_formatting)(format, country_metadata) && national_prefix_formatting_rule) {
return number.replace(pattern_to_match, (0, _metadata3.get_format_format)(format).replace(FIRST_GROUP_PATTERN, national_prefix_formatting_rule));
return number.replace(pattern_to_match, (0, _metadata3.get_format_format)(format).replace(FIRST_GROUP_PATTERN, _national_prefix_formatting_rule));
}
var formatted_number = number.replace(pattern_to_match, format_as === 'International' ? (0, _metadata3.get_format_international_format)(format) : (0, _metadata3.get_format_format)(format));
var formatted_number = number.replace(new RegExp((0, _metadata3.get_format_pattern)(format)), international ? (0, _metadata3.get_format_international_format)(format) : (0, _metadata3.get_format_format)(format));
if (format_as === 'International') {
if (international) {
return local_to_international_style(formatted_number);

@@ -113,2 +113,12 @@ }

function format_national_number(number, format_as, enforce_national_prefix, country_metadata) {
var format = choose_format_for_number((0, _metadata3.get_formats)(country_metadata), number);
if (!format) {
return number;
}
return format_national_number_using_format(number, format, format_as === 'International', enforce_national_prefix, country_metadata);
}
function choose_format_for_number(available_formats, national_number) {

@@ -115,0 +125,0 @@ var _iteratorNormalCompletion = true;

@@ -0,1 +1,6 @@

0.1.5 / 29.11.2016
===================
* Better `asYouType` (better than Google's original "as you type" formatter)
0.1.0 / 28.11.2016

@@ -2,0 +7,0 @@ ===================

@@ -11,5 +11,5 @@ 'use strict'

exports.as_you_type = require('./build/as you type')
exports.asYouType = require('./build/as you type')
exports.as_you_type = require('./build/as you type').default
exports.asYouType = require('./build/as you type').default
// exports['default'] = ...
{
"name": "libphonenumber-js",
"version": "0.1.4",
"version": "0.1.5",
"description": "A simpler (and smaller) rewrite of Google Android's famous libphonenumber library",

@@ -31,4 +31,4 @@ "main": "index.common.js",

"test": "mocha --compilers js:babel-core/register --colors --bail --reporter spec test/ --recursive",
"test-coverage": "istanbul cover node_modules/mocha/bin/_mocha -- --compilers js:babel-core/register --colors --reporter dot test/ --recursive",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --compilers js:babel-core/register --colors --reporter spec test/ --recursive",
"test-coverage": "istanbul cover -x \"build/**\" node_modules/mocha/bin/_mocha -- --compilers js:babel-core/register --colors --reporter dot test/ --recursive",
"test-travis": "istanbul cover -x \"build/**\" node_modules/mocha/bin/_mocha --report lcovonly -- --compilers js:babel-core/register --colors --reporter spec test/ --recursive",
"browser-build": "WEBPACK_ENV=build webpack",

@@ -35,0 +35,0 @@ "browser-build-dev": "WEBPACK_ENV=dev webpack --progress --colors --watch",

@@ -7,24 +7,26 @@ # libphonenumber-js

A simpler (and smaller) rewrite of Google Android's famous `libphonenumber` library.
A simpler (and smaller) rewrite of Google Android's famous `libphonenumber` library: easy phone number parsing and formatting in javascript.
## LibPhoneNumber
`libphonenumber` is a phone number formatting and parsing library released by Google, originally developed for (and currently used in) Google's [Android](https://en.wikipedia.org/wiki/Android_(operating_system)) mobile phone operating system. Obviously, implementing a rigorous phone number formatting and parsing library was crucial for the phone OS overall usability (back then, in the early 2000s, it was originally meant to be a phone after all, not just a SnapChat device).
`libphonenumber` is a phone number formatting and parsing library released by Google, originally developed for (and currently used in) Google's [Android](https://en.wikipedia.org/wiki/Android_(operating_system)) mobile phone operating system. Implementing a rigorous phone number formatting and parsing library was crucial for the phone OS overall usability (back then, in the early 2000s, it was originally meant to be a phone after all, not just a SnapChat device).
`libphonenumber-js` is a simplified javascript port of the original `libphonenumber` library (written in C++ and Java because those are the programming languages used in Android OS). While `libphonenumber` has an [official javascript port](https://github.com/googlei18n/libphonenumber/tree/master/javascript) which is being maintained by Google, it is tightly coupled to Google's `closure` javascript utility framework. It still can be compiled into [one big bundle](http://stackoverflow.com/questions/18678031/how-to-host-the-google-libphonenumber-locally/) which weighs 220 KiloBytes — quite a size for a phone number input component. It [can be customized](https://github.com/leodido/i18n.phonenumbers.js) too in a sense of which countries metadata to include but that wouldn't be an option for a worldwide solution.
`libphonenumber-js` is a simplified pure javascript port of the original `libphonenumber` library (written in C++ and Java because those are the programming languages used in Android OS). While `libphonenumber` has an [official javascript port](https://github.com/googlei18n/libphonenumber/tree/master/javascript) which is being maintained by Google, it is tightly coupled to Google's `closure` javascript utility framework. It still can be compiled into [one big bundle](http://stackoverflow.com/questions/18678031/how-to-host-the-google-libphonenumber-locally/) which weighs 220 KiloBytes — quite a size for a phone number input component. It [can be reduced](https://github.com/leodido/i18n.phonenumbers.js) to a specific set of countries only but that wouldn't be an option for a worldwide international solution.
One part of me was curious about how all this phone matching machinery worked, and another part of me was curious if there's a way to reduce those 220 KiloBytes to something more reasonable while also getting rid of the `closure` library and rewrite it all in pure javascript. So, that was my little hackathon for a couple of weeks, and seems that it succeeded. The resulting library does everything a modern web application needs while maintaining a much slimmer size of about 70 KiloBytes.
One part of me was curious about how all this phone matching machinery worked, and another part of me was curious if there's a way to reduce those 220 KiloBytes to something more reasonable while also getting rid of the `closure` library and rewriting it all in pure javascript. So, that was my little hackathon for a couple of weeks, and seems that it succeeded. The resulting library does everything a modern web application needs while maintaining a much smaller size of about 70 KiloBytes.
## Difference from Google's `libphonenumber`
* Pure javascript, doesn't require any 3rd party libraries
* Metadata size is just about 70 KiloBytes while the original `libphonenumber` metadata size is about 200 KiloBytes
* When formatting international numbers replaces all braces, dashes, etc with spaces (because that's the logical thing to do, and leaving braces in an international number isn't)
* Better "as you type" formatting
* Doesn't parse alphabetic phone numbers like `1-800-GOT-MILK` as we don't use telephone sets in the XXIst century that much (and we have phonebooks in your mobile phones)
* Doesn't handle carrier codes: they're only used in Colombia and Brazil, and only when dialing within those countries from a mobile phone to a fixed line number (the locals surely already know those carrier codes by themselves)
* Doesn't use `possibleDigits` data to speed up phone number pre-validation (it just skips to the regular expression check itself)
* Assumes all phone numbers being `format`ted are internationally diallable, because that's the only type of phone numbers users are supposed to be inputting on websites (no one inputs short codes, emergency telephone numbers like `911`, etc.)
* Doesn't parse phone numbers with extensions (again, this is not the type of phone numbers users should input on websites — they're supposed to input their personal mobile phone numbers, or home stationary phone numbers if they're living in an area where celltowers don't have a good signal, not their business/enterprise stationary phone numbers)
* Doesn't use `possibleDigits` data to speed up phone number pre-validation (it just skips to the regular expression check itself)
* Doesn't distinguish between fixed line, mobile, pager, voicemail, toll free and other XXth century bullsh*t
* Doesn't format phone numbers for "out of country dialing", e.g. `011 ...` in the US (again, just use the `+...` notation accepted worldwide for mobile phones)
* Doesn't parse `tel:...` URIs ([RFC 3966](https://www.ietf.org/rfc/rfc3966.txt)) because it's not relevant for user-facing web experience
* When formatting international numbers replaces all braces, dashes, etc with spaces (because that's the logical thing to do, and leaving braces in an international number isn't)

@@ -112,3 +114,3 @@ ## Installation

Creates a formatter for partially entered phone number. The two-letter `country_code` is optional and if specified restricts the phone number being input to the specified country. The instance of this class has two methods:
Creates a formatter for partially entered phone number. The two-letter `country_code` is optional and, if specified, restricts the phone number being input to the specified country. The instance of this class has two methods:

@@ -115,0 +117,0 @@ * `input(text)` — takes any text and appends it to the input; returns the formatted phone number

@@ -1,2 +0,2 @@

// This is a port of Google Android `libphonenumber`'s
// This is an enhanced port of Google Android `libphonenumber`'s
// `asyoutypeformatter.js` of 17th November, 2016.

@@ -18,3 +18,2 @@ //

get_format_national_prefix_formatting_rule,
get_format_national_prefix_is_optional_when_formatting,
get_format_leading_digits_patterns,

@@ -39,2 +38,10 @@ get_metadata_by_country_phone_code

{
FIRST_GROUP_PATTERN,
format_national_number_using_format,
local_to_international_style
}
from './format'
import
{
matches_entirely

@@ -47,6 +54,4 @@ }

const DIGIT_PLACEHOLDER = '\u2008'
const DIGIT_PATTERN = new RegExp(DIGIT_PLACEHOLDER)
const DIGIT_PLACEHOLDER_MATCHER = new RegExp(DIGIT_PLACEHOLDER)
const SEPARATOR_BEFORE_NATIONAL_NUMBER = ' '
// A pattern that is used to match character classes in regular expressions.

@@ -77,18 +82,7 @@ // An example of a character class is [1-4].

// A set of characters that, if found in a national prefix formatting rules, are
// an indicator to us that we should separate the national prefix from the
// number when formatting.
const NATIONAL_PREFIX_SEPARATORS_PATTERN = /[- ]/
// This is the minimum length of national number accrued that is required to
// trigger the formatter. The first element of the leadingDigitsPattern of
// each numberFormat contains a regular expression that matches up to this
// number of digits.
// 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.
const MIN_LEADING_DIGITS_LENGTH = 3
// A pattern that is used to determine if the national prefix formatting rule
// has the first group only, i.e., does not start with the national prefix.
// Note that the pattern explicitly allows for unbalanced parentheses.
const FIRST_GROUP_ONLY_PREFIX_PATTERN = /^\(?\$1\)?$/
const VALID_INCOMPLETE_PHONE_NUMBER =

@@ -111,2 +105,3 @@ '[' + PLUS_CHARS + ']{0,1}' +

this.country_metadata = metadata.countries[country_code]
this.initialize_possible_formats()
}

@@ -119,3 +114,3 @@

{
this.original_input += text
// this.original_input += text

@@ -161,107 +156,127 @@ // Parse input

// If an out of position '+' sign detected
// (or a second '+' sign)
// (or a second '+' sign),
// then just don't allow it being input.
if (this.parsed_input)
{
this.able_to_format = false
return this.current_output
}
else
{
this.parsed_input += character
this.prefix_before_national_number = '+'
}
}
// A digit then
else
{
this.parsed_input += character
this.national_number += character
}
this.parsed_input += character
// Try to format the parsed input
if (!this.able_to_format)
if (this.is_international())
{
// When we are unable to format because of reasons other than that
// formatting chars have been entered, it can be due to really long IDDs or
// NDDs. If that is the case, we might be able to do formatting again after
// extracting them.
if (this.is_international())
if (!this.country_phone_code)
{
// 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 (this.extract_country_phone_code())
{
return this.attempt_to_choose_formatting_pattern_with_national_prefix_extracted()
// If the possible phone number formats
// haven't been initialized during instance creation,
// then do it.
if (!this.country_code)
{
this.initialize_possible_formats()
}
return '+' + this.country_phone_code
}
// Return raw phone number
return this.parsed_input
}
else if (this.extract_longer_national_prefix())
}
else
{
if (!this.national_prefix)
{
// Add an additional space to separate long NDD and national significant
// number for readability. We don't set shouldAddSpaceAfterNationalPrefix_
// to true, since we don't want this to change later when we choose
// formatting templates.
this.prefix_before_national_number += SEPARATOR_BEFORE_NATIONAL_NUMBER
return this.attempt_to_choose_formatting_pattern_with_national_prefix_extracted()
// Possibly extract a national prefix
this.extract_national_prefix()
}
return this.parsed_input
else if (!this.able_to_format)
{
if (!this.extract_longer_national_prefix())
{
// Return raw phone number
return this.parsed_input
}
}
}
// We start to attempt to format only when at least MIN_LEADING_DIGITS_LENGTH
// digits (the plus sign is counted as a digit as well for this purpose) have
// been entered.
// Format the next phone number digit
// since the previously chose phone number format
// still holds.
//
// This is done here because if `attempt_to_format_complete_phone_number`
// was placed before this call then the `formatting_template`
// wouldn't reflect the situation correctly (and would therefore be inconsistent)
//
const national_number_formatted_with_previous_format = this.format_next_national_number_digit(character)
if (this.parsed_input.length < MIN_LEADING_DIGITS_LENGTH)
// See if the input digits can be formatted properly already. If not,
// use the results from format_next_national_number_digit(), which does formatting
// based on the formatting pattern chosen.
const formatted_number = this.attempt_to_format_complete_phone_number()
if (formatted_number)
{
return this.parsed_input
return formatted_number
}
if (this.parsed_input.length === MIN_LEADING_DIGITS_LENGTH)
this.filter_possible_formats_by_leading_digits()
// If the previously chosen phone number format
// didn't match the next digit being input
// (leading digits).
if (this.choose_another_format())
{
if (this.is_international())
{
this.expecting_country_calling_code = true
}
else
{
// No IDD or plus sign is found, might be entering in national format.
this.national_prefix = this.extract_national_prefix()
return this.attempt_to_choose_formatting_pattern()
}
}
// 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.
if (this.expecting_country_calling_code)
{
if (this.extract_country_phone_code())
const formatted_national_number = this.reformat_national_number()
if (formatted_national_number)
{
this.expecting_country_calling_code = false
return this.full_phone_number(formatted_national_number)
}
return this.prefix_before_national_number + this.national_number
// Couldn't format the supplied national number
// using the selected phone number pattern.
// Return raw phone number.
return this.parsed_input
}
if (this.possible_formats.length === 0)
// If no new phone number format could be chosen,
// then can't format the phone.
if (!this.current_format)
{
return this.attempt_to_choose_formatting_pattern()
}
this.able_to_format = false
// The formatting patterns are already chosen.
const national_number = this.input_national_number_digit(character)
// See if the accrued digits can be formatted properly already. If not,
// use the results from input_national_number_digit(), which does formatting
// based on the formatting pattern chosen.
const formatted_number = this.attempt_to_format_complete_phone_number()
if (formatted_number)
{
return formatted_number
// Return raw phone number
return this.parsed_input
}
this.narrow_down_possible_formats(this.national_number)
if (this.refresh_format())
if (national_number_formatted_with_previous_format)
{
return this.retype_national_number()
return this.full_phone_number(national_number_formatted_with_previous_format)
}
return this.able_to_format ? this.full_phone_number(national_number) : this.parsed_input
// Couldn't format the supplied national number
// using the selected phone number pattern.
// Return raw phone number
return this.parsed_input
}

@@ -271,4 +286,4 @@

{
// Input text so far, can contain any characters
this.original_input = ''
// // Input text so far, can contain any characters
// this.original_input = ''

@@ -281,9 +296,2 @@ // Input stripped of non-phone-number characters.

this.expecting_country_calling_code = false
// This contains anything that has been entered so far preceding the national
// significant number, and it is formatted (e.g. with space inserted). For
// example, this can contain IDD, country code, and/or NDD, etc.
this.prefix_before_national_number = ''
// This contains the national prefix that has been extracted. It contains only

@@ -293,6 +301,11 @@ // digits without formatting.

this.should_add_space_after_national_prefix = false
this.national_number = ''
this.country_phone_code = ''
if (!this.country_code)
{
this.country_metadata = undefined
}
this.clear_formatting()

@@ -303,7 +316,8 @@ }

{
// This indicates whether AsYouTypeFormatter is currently doing the formatting.
this.able_to_format = true
this.possible_formats = []
this.possible_formats = undefined
this.current_format = undefined
this.last_match_position = 0

@@ -313,20 +327,18 @@

// The pattern from numberFormat that is currently used to create formattingTemplate.
this.current_formatting_pattern = undefined
this.national_prefix_is_part_of_formatting_template = false
}
retype_national_number()
// Format each digit of national phone number (so far)
// using the newly selected phone number pattern.
reformat_national_number()
{
if (!this.national_number)
{
return this.prefix_before_national_number
}
let national_number
// Format each digit of national phone number (so far)
// using the selected phone number pattern.
let formatted_national_number
for (let character of this.national_number)
{
national_number = this.input_national_number_digit(character)
formatted_national_number = this.format_next_national_number_digit(character)
}
return this.able_to_format ? this.full_phone_number(national_number) : this.parsed_input
return formatted_national_number
}

@@ -338,36 +350,7 @@

this.expecting_country_calling_code = false
return this.attempt_to_choose_formatting_pattern()
return this.format_national_number()
}
attempt_to_choose_formatting_pattern()
initialize_possible_formats()
{
// We start to attempt to format only when at least MIN_LEADING_DIGITS_LENGTH
// digits of national number (excluding national prefix) have been entered.
if (this.national_number.length < MIN_LEADING_DIGITS_LENGTH)
{
return this.full_phone_number(this.national_number)
}
this.refresh_possible_formats(this.national_number)
// See if the accrued digits can be formatted properly already.
const formatted_number = this.attempt_to_format_complete_phone_number()
if (formatted_number)
{
return formatted_number
}
if (this.refresh_format())
{
return this.retype_national_number()
}
return this.parsed_input
}
refresh_possible_formats(leading_digits)
{
if (!this.country_metadata)

@@ -378,5 +361,4 @@ {

const national_prefix = get_national_prefix(this.country_metadata)
this.possible_formats = get_formats(this.country_metadata).filter((format) =>
// Get all "eligible" phone number formats for this country
this.available_formats = get_formats(this.country_metadata).filter((format) =>
{

@@ -386,11 +368,27 @@ return ELIGIBLE_FORMAT_PATTERN.test(get_format_international_format(format))

this.narrow_down_possible_formats(leading_digits)
this.possible_formats = this.available_formats
}
narrow_down_possible_formats(leading_digits)
filter_possible_formats_by_leading_digits()
{
const index_of_leading_digits_pattern = leading_digits.length - MIN_LEADING_DIGITS_LENGTH
const leading_digits = this.national_number
this.possible_formats = this.possible_formats.filter((format) =>
// "leading digits" patterns start with a maximum 3 digits,
// and then with each additional digit
// a more precise "leading digits" pattern is specified.
// They could make "leading digits" patterns start
// with a maximum of a single digit, but they didn't,
// so it's possible that some phone number formats
// will be falsely rejected until there are at least
// 3 digits in the national (significant) number being input.
let 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.possible_formats = this.get_possible_formats().filter((format) =>
{
const leading_digits_pattern_count = get_format_leading_digits_patterns(format).length

@@ -404,8 +402,20 @@

const suitable_leading_digits_pattern_index = Math.min(index_of_leading_digits_pattern, leading_digits_pattern_count - 1)
const leading_digits_pattern = get_format_leading_digits_patterns(format)[suitable_leading_digits_pattern_index]
return leading_digits.search(leading_digits_pattern) === 0
const leading_digits_pattern_index = Math.min(index_of_leading_digits_pattern, leading_digits_pattern_count - 1)
const leading_digits_pattern = get_format_leading_digits_patterns(format)[leading_digits_pattern_index]
return new RegExp('^' + leading_digits_pattern).test(leading_digits)
})
}
get_possible_formats()
{
const leading_digits = this.national_number
if (leading_digits.length <= MIN_LEADING_DIGITS_LENGTH)
{
return this.available_formats
}
return this.possible_formats
}
// Check to see if there is an exact pattern match for these digits. If so, we

@@ -416,13 +426,17 @@ // should use this instead of any other formatting template whose

{
for (let format of this.possible_formats)
for (let format of this.get_possible_formats())
{
const pattern = get_format_pattern(format)
const pattern_matcher = new RegExp('^(?:' + pattern + ')$')
const matcher = new RegExp('^(?:' + get_format_pattern(format) + ')$')
if (pattern_matcher.test(this.national_number))
if (matcher.test(this.national_number))
{
this.should_add_space_after_national_prefix = NATIONAL_PREFIX_SEPARATORS_PATTERN.test(get_format_national_prefix_formatting_rule(format, this.country_metadata))
const formatted_national_number = format_national_number_using_format
(
this.national_number,
format,
this.is_international(),
this.national_prefix,
this.country_metadata
)
const formatted_national_number = this.national_number.replace(new RegExp(pattern, 'g'), this.get_format_format(format))
return this.full_phone_number(formatted_national_number)

@@ -433,26 +447,16 @@ }

// Combines the national number with any prefix (IDD/+ and country code or
// national prefix) that was collected. A space will be inserted between them if
// the current formatting template indicates this to be suitable.
// Combines the national number with the appropriate prefix
full_phone_number(formatted_national_number)
{
if (this.should_add_space_after_national_prefix &&
this.prefix_before_national_number &&
this.prefix_before_national_number[this.prefix_before_national_number.length - 1] !== SEPARATOR_BEFORE_NATIONAL_NUMBER)
if (this.is_international())
{
// We want to add a space after the national prefix if the national prefix
// formatting rule indicates that this would normally be done, with the
// exception of the case where we already appended a space because the NDD
// was surprisingly long.
return this.prefix_before_national_number +
SEPARATOR_BEFORE_NATIONAL_NUMBER +
formatted_national_number
return '+' + this.country_phone_code + ' ' + formatted_national_number
}
return this.prefix_before_national_number + formatted_national_number
return formatted_national_number
}
// Extracts the country calling code from the beginning of nationalNumber to
// prefixBeforeNationalNumber when they are available, and places the remaining
// input into nationalNumber.
// Extracts the country calling code from the beginning
// of the entered `national_number` (so far),
// and places the remaining input into the `national_number`.
extract_country_phone_code()

@@ -483,11 +487,5 @@ {

this.country_phone_code = country_phone_code
this.national_number = number
this.prefix_before_national_number += country_phone_code + SEPARATOR_BEFORE_NATIONAL_NUMBER
// When we have successfully extracted the IDD,
// the previously extracted national prefix
// should be cleared because it is no longer valid.
this.national_prefix = ''
return this.country_metadata = get_metadata_by_country_phone_code(country_phone_code, metadata)

@@ -501,19 +499,16 @@ }

{
if (this.national_prefix)
if (!this.national_prefix)
{
// Put the extracted national prefix back to the national number
// before attempting to extract a new national prefix.
this.national_number = this.national_prefix + this.national_number
// Remove the previously extracted national prefix from prefixBeforeNationalNumber. We
// cannot simply set it to empty string because people sometimes incorrectly
// enter national prefix after the country code, e.g. +44 (0)20-1234-5678.
const index_of_previous_national_prefix = this.prefix_before_national_number.lastIndexOf(this.national_prefix)
this.prefix_before_national_number = this.prefix_before_national_number.slice(0, index_of_previous_national_prefix)
return
}
return this.national_prefix !== this.extract_national_prefix()
// Put the extracted national prefix back to the national number
// before attempting to extract a new national prefix.
this.national_number = this.national_prefix + this.national_number
const previously_extracted_national_prefix = this.national_prefix
this.extract_national_prefix()
return this.national_prefix !== previously_extracted_national_prefix
}
// Returns the national prefix extracted, or an empty string if it is not present.
extract_national_prefix()

@@ -525,6 +520,8 @@ {

{
// Small performance optimization for NANPA countries
// which can't have `1` (national prefix) as the
// first digit of a national (significant) number
if (this.is_NANPA_number_with_international_prefix())
{
national_number_starts_at = 1
this.prefix_before_national_number += '1' + SEPARATOR_BEFORE_NATIONAL_NUMBER
}

@@ -540,3 +537,2 @@ else if (get_national_prefix_for_parsing(this.country_metadata))

national_number_starts_at = matches[0].length
this.prefix_before_national_number += this.national_number.substring(0, national_number_starts_at)
}

@@ -546,4 +542,5 @@ }

this.national_prefix = this.national_number.slice(0, national_number_starts_at)
this.national_number = this.national_number.slice(national_number_starts_at)
return this.national_number.slice(0, national_number_starts_at)
return this.national_prefix
}

@@ -569,23 +566,24 @@

refresh_format()
choose_another_format()
{
// When there are multiple available formats, the formatter uses the first
// format where a formatting template could be created.
for (let format of this.possible_formats)
for (let format of this.get_possible_formats())
{
const pattern = get_format_pattern(format)
if (this.current_formatting_pattern === pattern)
// If this format is currently being used
// and is still possible, then stick to it.
if (this.current_format === format)
{
return false
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.create_formatting_template(format))
{
this.current_formatting_pattern = pattern
this.current_format = format
this.should_add_space_after_national_prefix = NATIONAL_PREFIX_SEPARATORS_PATTERN.test(get_format_national_prefix_formatting_rule(format, this.country_metadata))
// With a new formatting template, the matched position using the old
// template needs to be reset.
// With a new formatting template, the matched position
// using the old template needs to be reset.
this.last_match_position = 0

@@ -596,4 +594,2 @@

}
this.able_to_format = false
}

@@ -615,14 +611,20 @@

.replace(CHARACTER_CLASS_PATTERN, '\\d')
// Replace any standalone digit (not the one in d{}) with \d
// Replace any standalone digit (not the one in `{}`) with \d
.replace(STANDALONE_DIGIT_PATTERN, '\\d')
return this.formatting_template = this.get_formatting_template(number_pattern, this.get_format_format(format))
}
let number_format = this.get_format_format(format)
this.national_prefix_is_part_of_formatting_template = false
// Gets a formatting template which can be used to efficiently format a
// partial number where digits are added one by one.
get_formatting_template(number_pattern, number_format)
{
// Creates a phone number consisting only of the digit 9 that matches the
// numberPattern by applying the pattern to the longestPhoneNumber string.
if (this.national_prefix)
{
this.national_prefix_is_part_of_formatting_template = true
const national_prefix_formatting_rule = get_format_national_prefix_formatting_rule(format, this.country_metadata)
number_format = number_format.replace(FIRST_GROUP_PATTERN, national_prefix_formatting_rule)
}
// Get a formatting template which can be used to efficiently format a
// partial number where digits are added one by one.
// 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.
const longest_phone_number = '999999999999999'

@@ -641,3 +643,3 @@

return phone_number
return this.formatting_template = phone_number
// Formats the number according to numberFormat

@@ -649,23 +651,24 @@ .replace(new RegExp(number_pattern, 'g'), number_format)

input_national_number_digit(digit)
format_next_national_number_digit(digit)
{
if (this.formatting_template && this.formatting_template.slice(this.last_match_position).search(DIGIT_PATTERN) >= 0)
// If there is room for more digits in current `formatting_template`,
// then set the next digit in the `formatting_template`,
// and return the formatted digits so far.
if (this.formatting_template && this.formatting_template.slice(this.last_match_position + 1).search(DIGIT_PLACEHOLDER_MATCHER) >= 0)
{
const digit_pattern_start = this.formatting_template.search(DIGIT_PATTERN)
this.formatting_template = this.formatting_template.replace(DIGIT_PATTERN, digit)
const digit_pattern_start = this.formatting_template.search(DIGIT_PLACEHOLDER_MATCHER)
this.formatting_template = this.formatting_template.replace(DIGIT_PLACEHOLDER_MATCHER, digit)
this.last_match_position = digit_pattern_start
return this.formatting_template.slice(0, digit_pattern_start + 1)
// Return the formatted phone number so far
return close_dangling_braces(this.formatting_template, digit_pattern_start + 1)
}
if (this.possible_formats.length === 1)
{
// More digits are entered than we could handle, and there are
// no other valid patterns to try.
this.able_to_format = false
}
// else, we just reset the formatting pattern
// More digits are entered than the current format could handle
this.current_formatting_pattern = undefined
return this.parsed_input
// Reset the current format flag,
// so that the new format will be chosen
// in a subsequent `this.choose_another_format()` call
// later in code.
this.current_format = undefined
}

@@ -680,10 +683,5 @@

{
// // Always prefer international formatting rules over national ones,
// // because national formatting rules could contain
// // local formatting rules for numbers entered without area code.
// get_format_international_format(format)
if (this.is_international())
{
return get_format_international_format(format)
return local_to_international_style(get_format_international_format(format))
}

@@ -693,2 +691,39 @@

}
}
export function close_dangling_braces(template, cut_before)
{
const retained_template = template.slice(0, cut_before)
const opening_braces = count_occurences('(', retained_template)
const closing_braces = count_occurences(')', retained_template)
let 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
export function count_occurences(symbol, string)
{
let count = 0
for (let character of string)
{
if (character === symbol)
{
count++
}
}
return count
}

@@ -69,3 +69,3 @@ // This is a port of Google Android `libphonenumber`'s

case 'International':
const national_number = format_national_number(number, 'International', country_metadata)
const national_number = format_national_number(number, 'International', false, country_metadata)
return `+${get_phone_code(country_metadata)} ${national_number}`

@@ -77,3 +77,3 @@

case 'National':
return format_national_number(number, 'National', country_metadata)
return format_national_number(number, 'National', false, country_metadata)
}

@@ -86,21 +86,16 @@ }

// group actually used in the pattern will be matched.
const FIRST_GROUP_PATTERN = /(\$\d)/
export const FIRST_GROUP_PATTERN = /(\$\d)/
export function format_national_number(number, format_as, country_metadata)
export function format_national_number_using_format(number, format, international, enforce_national_prefix, country_metadata)
{
const format = choose_format_for_number(get_formats(country_metadata), number)
const national_prefix_formatting_rule = get_format_national_prefix_formatting_rule(format, country_metadata)
if (!format)
const national_prefix_may_be_omitted = !enforce_national_prefix && get_format_national_prefix_is_optional_when_formatting(format, country_metadata)
if (!international && !national_prefix_may_be_omitted)
{
return number
}
const national_prefix_formatting_rule = get_format_national_prefix_formatting_rule(format, country_metadata)
const pattern_to_match = new RegExp(get_format_pattern(format))
const pattern_to_match = new RegExp(get_format_pattern(format))
const national_prefix_formatting_rule = get_format_national_prefix_formatting_rule(format, country_metadata)
if (format_as === 'National' &&
!get_format_national_prefix_is_optional_when_formatting(format, country_metadata) &&
national_prefix_formatting_rule)
{
return number.replace(pattern_to_match,

@@ -110,5 +105,5 @@ get_format_format(format).replace(FIRST_GROUP_PATTERN, national_prefix_formatting_rule))

const formatted_number = number.replace(pattern_to_match, format_as === 'International' ? get_format_international_format(format) : get_format_format(format))
const formatted_number = number.replace(new RegExp(get_format_pattern(format)), international ? get_format_international_format(format) : get_format_format(format))
if (format_as === 'International')
if (international)
{

@@ -121,2 +116,14 @@ return local_to_international_style(formatted_number)

export function format_national_number(number, format_as, enforce_national_prefix, country_metadata)
{
const format = choose_format_for_number(get_formats(country_metadata), number)
if (!format)
{
return number
}
return format_national_number_using_format(number, format, format_as === 'International', enforce_national_prefix, country_metadata)
}
function choose_format_for_number(available_formats, national_number)

@@ -123,0 +130,0 @@ {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc