Socket
Socket
Sign inDemoInstall

libphonenumber-js

Package Overview
Dependencies
Maintainers
1
Versions
392
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.9 to 0.1.10

build/tools/compress.js

131

build/as you type.js

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

exports.count_occurences = count_occurences;
exports.repeat = repeat;

@@ -37,5 +38,5 @@ var _metadata = require('../metadata.min');

// The digits that have not been entered yet will be represented by a \u2008,
// the punctuation space.
var DIGIT_PLACEHOLDER = ' '; // This is an enhanced port of Google Android `libphonenumber`'s
// Used in phone number format template creation.
// Could be any digit, I guess.
var DUMMY_DIGIT = '9'; // This is an enhanced port of Google Android `libphonenumber`'s
// `asyoutypeformatter.js` of 17th November, 2016.

@@ -45,2 +46,12 @@ //

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.
var DIGIT_PLACEHOLDER = ' ';
var DIGIT_PLACEHOLDER_MATCHER = new RegExp(DIGIT_PLACEHOLDER);

@@ -73,3 +84,3 @@ var DIGIT_PLACEHOLDER_MATCHER_GLOBAL = new RegExp(DIGIT_PLACEHOLDER, 'g');

var VALID_INCOMPLETE_PHONE_NUMBER = '[' + _parse.PLUS_CHARS + ']{0,1}' + '[' + _parse.VALID_PUNCTUATION + _parse.VALID_DIGITS + ']+';
var VALID_INCOMPLETE_PHONE_NUMBER = '[' + _parse.PLUS_CHARS + ']{0,1}' + '[' + _parse.VALID_PUNCTUATION + _parse.VALID_DIGITS + ']*';

@@ -94,33 +105,20 @@ var VALID_INCOMPLETE_PHONE_NUMBER_PATTERN = new RegExp('^' + VALID_INCOMPLETE_PHONE_NUMBER + '$', 'i');

value: function input(text) {
// this.original_input += text
// Parse input
var extracted_number = (0, _parse.extract_formatted_phone_number)(text, function (number) {
return (0, _common.matches_entirely)(VALID_INCOMPLETE_PHONE_NUMBER_PATTERN, number);
});
var extracted_number = (0, _parse.extract_formatted_phone_number)(text);
var _parse_phone_number = (0, _parse.parse_phone_number)(extracted_number);
var number = _parse_phone_number.number;
var is_international = _parse_phone_number.is_international;
// Special case for just the leading '+'
if (!extracted_number && text.indexOf('+') >= 0) {
is_international = true;
// Special case for a lone '+' sign
// since it's not considered a possible phone number.
if (!extracted_number) {
if (text.indexOf('+') >= 0) {
extracted_number = '+';
}
}
var parsed_input = '';
if (is_international) {
parsed_input += '+';
// Validate possible first part of a phone number
if (!(0, _common.matches_entirely)(VALID_INCOMPLETE_PHONE_NUMBER_PATTERN, extracted_number)) {
return this.current_output;
}
if (number) {
parsed_input += number;
}
// Feed the parsed input character-by-character
var _iteratorNormalCompletion = true;

@@ -131,3 +129,3 @@ var _didIteratorError = false;

try {
for (var _iterator = (0, _getIterator3.default)(parsed_input), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
for (var _iterator = (0, _getIterator3.default)((0, _parse.parse_phone_number)(extracted_number)), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var character = _step.value;

@@ -261,3 +259,3 @@

// then return the formatted number so far.
if (this.current_format) {
if (national_number_formatted_with_previous_format) {
return this.full_phone_number(national_number_formatted_with_previous_format);

@@ -304,3 +302,3 @@ }

this.current_format = undefined;
this.chosen_format = undefined;

@@ -310,2 +308,3 @@ this.last_match_position = 0;

this.formatting_template = undefined;
this.partially_populated_formatting_template = undefined;

@@ -546,3 +545,3 @@ this.national_prefix_is_part_of_formatting_template = false;

// and is still possible, then stick to it.
if (this.current_format === format) {
if (this.chosen_format === format) {
return;

@@ -555,3 +554,3 @@ }

if (this.create_formatting_template(format)) {
this.current_format = format;
this.chosen_format = format;

@@ -613,24 +612,25 @@ // With a new formatting template, the matched position

// Get a formatting template which can be used to efficiently format a
// partial number where digits are added one by one.
// 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';
// 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];
var matches = longest_phone_number.match(number_pattern);
// This match will always succeed
var phone_number = matches[0];
// No formatting template can be created if the number of digits entered so
// far is longer than the maximum the current formatting rule can accommodate.
if (phone_number.length < this.national_number.length) {
// 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;
}
return this.formatting_template = phone_number
// Formats the number according to numberFormat
// Create formatting template for this phone number format
this.formatting_template = dummy_phone_number_matching_format_pattern
// Format the dummy phone number according to the format
.replace(new RegExp(number_pattern, 'g'), number_format)
// Replaces each digit with character DIGIT_PLACEHOLDER
.replace(new RegExp('9', 'g'), DIGIT_PLACEHOLDER);
// Replace each dummy digit with a DIGIT_PLACEHOLDER
.replace(DUMMY_DIGIT_MATCHER, DIGIT_PLACEHOLDER);
return this.partially_populated_formatting_template = this.formatting_template;
}

@@ -643,9 +643,9 @@ }, {

// 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);
if (this.chosen_format && this.partially_populated_formatting_template.slice(this.last_match_position + 1).search(DIGIT_PLACEHOLDER_MATCHER) >= 0) {
var digit_pattern_start = this.partially_populated_formatting_template.search(DIGIT_PLACEHOLDER_MATCHER);
this.partially_populated_formatting_template = this.partially_populated_formatting_template.replace(DIGIT_PLACEHOLDER_MATCHER, digit);
this.last_match_position = digit_pattern_start;
// Return the formatted phone number so far
return close_dangling_braces(this.formatting_template, digit_pattern_start + 1).replace(DIGIT_PLACEHOLDER_MATCHER_GLOBAL, ' ');
return close_dangling_braces(this.partially_populated_formatting_template, digit_pattern_start + 1).replace(DIGIT_PLACEHOLDER_MATCHER_GLOBAL, ' ');
}

@@ -655,7 +655,9 @@

// Reset the current format flag,
// Reset the current format,
// so that the new format will be chosen
// in a subsequent `this.choose_another_format()` call
// later in code.
this.current_format = undefined;
this.chosen_format = undefined;
this.formatting_template = undefined;
this.partially_populated_formatting_template = undefined;
}

@@ -732,2 +734,23 @@ }, {

}
// Repeats a string (or a symbol) N times.
// http://stackoverflow.com/questions/202605/repeat-string-javascript
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=as you type.js.map

@@ -22,2 +22,13 @@ "use strict";

exports.get_metadata_by_country_phone_code = get_metadata_by_country_phone_code;
exports.get_types = get_types;
exports.get_type_fixed_line = get_type_fixed_line;
exports.get_type_mobile = get_type_mobile;
exports.get_type_toll_free = get_type_toll_free;
exports.get_type_premium_rate = get_type_premium_rate;
exports.get_type_personal_number = get_type_personal_number;
exports.get_type_voice_mail = get_type_voice_mail;
exports.get_type_uan = get_type_uan;
exports.get_type_pager = get_type_pager;
exports.get_type_voip = get_type_voip;
exports.get_type_shared_cost = get_type_shared_cost;
function get_phone_code(country_metadata) {

@@ -101,2 +112,50 @@ return country_metadata[0];

}
function get_types(country_metadata) {
return country_metadata[9];
}
function get_type(country_metadata, index) {
return get_types(country_metadata) ? get_types(country_metadata)[index] : undefined;
}
function get_type_fixed_line(country_metadata) {
return get_type(country_metadata, 0);
}
function get_type_mobile(country_metadata) {
return get_type(country_metadata, 1);
}
function get_type_toll_free(country_metadata) {
return get_type(country_metadata, 2);
}
function get_type_premium_rate(country_metadata) {
return get_type(country_metadata, 3);
}
function get_type_personal_number(country_metadata) {
return get_type(country_metadata, 4);
}
function get_type_voice_mail(country_metadata) {
return get_type(country_metadata, 5);
}
function get_type_uan(country_metadata) {
return get_type(country_metadata, 6);
}
function get_type_pager(country_metadata) {
return get_type(country_metadata, 7);
}
function get_type_voip(country_metadata) {
return get_type(country_metadata, 8);
}
function get_type_shared_cost(country_metadata) {
return get_type(country_metadata, 9);
}
//# sourceMappingURL=metadata.js.map

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

exports.replace_characters = replace_characters;
exports.extract_possible_number = extract_possible_number;
exports.is_viable_phone_number = is_viable_phone_number;

@@ -28,2 +27,4 @@ exports.extract_formatted_phone_number = extract_formatted_phone_number;

exports.is_national_phone_number = is_national_phone_number;
exports.get_number_type = get_number_type;
exports.is_of_type = is_of_type;

@@ -103,5 +104,3 @@ var _common = require('./common');

// Regular expression of trailing characters that we want to remove. We remove
// all characters that are not alpha or numerical characters. The hash character
// is retained here, as it may signify the previous block was an extension.
// Regular expression of trailing characters that we want to remove.
var AFTER_PHONE_NUMBER_END_PATTERN = new RegExp('[^' + VALID_DIGITS + ']+$');

@@ -210,3 +209,3 @@

// If the phone number is not viable, then abort.
if (!formatted_phone_number) {
if (!is_viable_phone_number(formatted_phone_number)) {
return {};

@@ -266,2 +265,8 @@ }

country = find_country_code(country_phone_code, national_number);
// Just in case there's a bug in Google's metadata
/* istanbul ignore if */
if (!country) {
return {};
}
}

@@ -335,17 +340,2 @@

// Attempts to extract a possible number from the string passed in.
function extract_possible_number(text) {
var starts_at = text.search(PHONE_NUMBER_START_PATTERN);
if (starts_at < 0) {
return '';
}
return text
// Trim everything to the left of the phone number
.slice(starts_at)
// Remove trailing non-numerical characters
.replace(AFTER_PHONE_NUMBER_END_PATTERN, '');
}
// Checks to see if the string of characters could possibly be a phone number at

@@ -363,23 +353,25 @@ // all. At the moment, checks to see that the string begins with at least 2

function extract_formatted_phone_number(text) {
var is_valid = arguments.length <= 1 || arguments[1] === undefined ? is_viable_phone_number : arguments[1];
if (!text || text.length > MAX_INPUT_STRING_LENGTH) {
return;
return '';
}
// Extracts a piece of text possibly containing a phone number
text = extract_possible_number(text);
// Attempt to extract a possible number from the string passed in
if (is_valid(text)) {
return text;
var starts_at = text.search(PHONE_NUMBER_START_PATTERN);
if (starts_at < 0) {
return '';
}
return text
// Trim everything to the left of the phone number
.slice(starts_at)
// Remove trailing non-numerical characters
.replace(AFTER_PHONE_NUMBER_END_PATTERN, '');
}
// Parses a formatted phone number
// and returns `{ is_international, number }`
// where `number` is either national (significant) phone number
// or an international phone number with the leading '+' stripped.
// Parses a formatted phone number.
function parse_phone_number(number) {
if (!number) {
return {};
return '';
}

@@ -393,3 +385,7 @@

return { number: number, is_international: is_international };
if (is_international) {
return '+' + number;
}
return number;
}

@@ -403,9 +399,5 @@

//
function parse_phone_number_and_country_phone_code(_number) {
var _parse_phone_number = parse_phone_number(_number);
function parse_phone_number_and_country_phone_code(number) {
number = parse_phone_number(number);
var number = _parse_phone_number.number;
var is_international = _parse_phone_number.is_international;
if (!number) {

@@ -417,6 +409,9 @@ return {};

// then don't extract country phone code.
if (!is_international) {
if (number[0] !== '+') {
return { number: number };
}
// Strip the leading '+' sign
number = number.slice(1);
// Fast abortion: country codes do not begin with a '0'

@@ -492,42 +487,41 @@ if (number[0] === '0') {

function find_country_code(country_phone_code, national_phone_number) {
// Is always defined, because `country_phone_code` is always valid
var possible_country_codes = _metadata2.default.country_phone_code_to_countries[country_phone_code];
// Is always non-empty, because `country_phone_code` is always valid
var possible_countries = _metadata2.default.country_phone_code_to_countries[country_phone_code];
// Iterate possible countries backwards
// because the first one is the default (main) one.
var i = void 0;
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
// Look for leading digits for countries
i = possible_country_codes.length - 1;
while (i > 0) {
var country_code = possible_country_codes[i];
try {
for (var _iterator2 = (0, _getIterator3.default)(possible_countries), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var country_code = _step2.value;
var country = _metadata2.default.countries[country_code];
var country = _metadata2.default.countries[country_code];
if ((0, _metadata3.get_leading_digits)(country)) {
if (national_phone_number && national_phone_number.search((0, _metadata3.get_leading_digits)(country)) === 0) {
return country_code;
// Leading digits check would be the simplest one
if ((0, _metadata3.get_leading_digits)(country)) {
if (national_phone_number && national_phone_number.search((0, _metadata3.get_leading_digits)(country)) === 0) {
return country_code;
}
}
// Else perform full validation with all of those bulky
// fixed-line/mobile/etc regular expressions.
else if (get_number_type(national_phone_number, country)) {
return country_code;
}
}
i--;
}
// Leading digits not matched,
// just phone number validation will do.
// Now start from the default one.
i = 0;
while (i < possible_country_codes.length) {
var _country_code = possible_country_codes[i];
var _country = _metadata2.default.countries[_country_code];
if (is_national_phone_number(national_phone_number, _country)) {
return _country_code;
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
i++;
}
// No country matched this national phone number
}

@@ -546,4 +540,81 @@

// If leading digits are specified, then check them.
if ((0, _metadata3.get_leading_digits)(country_metadata)) {
if (national_number.indexOf((0, _metadata3.get_leading_digits)(country_metadata)) !== 0) {
return false;
}
}
return (0, _common.matches_entirely)((0, _metadata3.get_national_number_pattern)(country_metadata), national_number);
}
// Finds out national phone number type (fixed line, mobile, etc)
function get_number_type(national_number, country_metadata) {
// Is this national number even valid for this country
if (!is_of_type(national_number, (0, _metadata3.get_national_number_pattern)(country_metadata))) {
return;
}
if (is_of_type(national_number, (0, _metadata3.get_type_mobile)(country_metadata))) {
if (is_of_type(national_number, (0, _metadata3.get_type_fixed_line)(country_metadata))) {
return 'FIXED_LINE_OR_MOBILE';
}
return 'MOBILE';
}
// Is it fixed line number
if (is_of_type(national_number, (0, _metadata3.get_type_fixed_line)(country_metadata))) {
return 'FIXED_LINE';
}
if (is_of_type(national_number, (0, _metadata3.get_type_toll_free)(country_metadata))) {
return 'TOLL_FREE';
}
if (is_of_type(national_number, (0, _metadata3.get_type_premium_rate)(country_metadata))) {
return 'PREMIUM_RATE';
}
if (is_of_type(national_number, (0, _metadata3.get_type_personal_number)(country_metadata))) {
return 'PERSONAL_NUMBER';
}
if (is_of_type(national_number, (0, _metadata3.get_type_voice_mail)(country_metadata))) {
return 'VOICEMAIL';
}
if (is_of_type(national_number, (0, _metadata3.get_type_uan)(country_metadata))) {
return 'UAN';
}
if (is_of_type(national_number, (0, _metadata3.get_type_pager)(country_metadata))) {
return 'PAGER';
}
if (is_of_type(national_number, (0, _metadata3.get_type_voip)(country_metadata))) {
return 'VOIP';
}
if (is_of_type(national_number, (0, _metadata3.get_type_shared_cost)(country_metadata))) {
return 'SHARED_COST';
}
}
function is_of_type(national_number, type) {
// // Check if any possible number lengths are present;
// // if so, we use them to avoid checking
// // the validation pattern if they don't match.
// // If they are absent, this means they match
// // the general description, which we have
// // already checked before a specific number type.
// if (get_possible_lengths(type) &&
// get_possible_lengths(type).indexOf(national_number.length) === -1)
// {
// return false
// }
// get_type_pattern(type) === type
return (0, _common.matches_entirely)(type, national_number);
}
//# sourceMappingURL=parse.js.map

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

0.1.10 / 30.11.2016
===================
* Turned out those numerous bulky regular expressions (`<fixedLine/>`, `<mobile/>`, etc) are actually required to reliably infer country from country calling code and national phone number in cases where there are multiple countries assigned to the same country phone code (e.g. NANPA), so I've included those big regular expressions for those ambiguous cases which increased metadata size by 20 KiloBytes resulting in a total of 90 KiloBytes for the metadata.
0.1.9 / 30.11.2016

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

{
"name": "libphonenumber-js",
"version": "0.1.9",
"version": "0.1.10",
"description": "A simpler (and smaller) rewrite of Google Android's famous libphonenumber library",

@@ -5,0 +5,0 @@ "main": "index.common.js",

@@ -15,3 +15,3 @@ # libphonenumber-js

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.
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 90 KiloBytes.

@@ -21,3 +21,3 @@ ## 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
* Metadata size is just about 90 KiloBytes while the original `libphonenumber` metadata size is about 200 KiloBytes
* Better "as you type" formatting

@@ -125,2 +125,6 @@ * 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)

## Bug reporting
If you spot any inconsistencies with the [original Google's `libphonenumber`](https://libphonenumber.appspot.com/) then create an issue in this repo.
## Contributing

@@ -127,0 +131,0 @@

import path from 'path'
import fs from 'fs'
import compress from '../source/compress'
import compress from '../source/tools/compress'

@@ -6,0 +6,0 @@ const input = fs.readFileSync(path.join(__dirname, '../metadata.json'), 'utf8')

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

import generate from '../source/generate'
import generate from '../source/tools/generate'

@@ -3,0 +3,0 @@ import path from 'path'

@@ -49,2 +49,12 @@ // This is an enhanced port of Google Android `libphonenumber`'s

// Used in phone number format template creation.
// Could be any digit, I guess.
const DUMMY_DIGIT = '9'
const DUMMY_DIGIT_MATCHER = new RegExp(DUMMY_DIGIT, 'g')
// I don't know why is it exactly `15`
const 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.
const 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,

@@ -91,3 +101,3 @@ // the punctuation space.

VALID_DIGITS +
']+'
']*'

@@ -112,31 +122,24 @@ const VALID_INCOMPLETE_PHONE_NUMBER_PATTERN = new RegExp('^' + VALID_INCOMPLETE_PHONE_NUMBER + '$', 'i')

{
// this.original_input += text
// Parse input
let extracted_number = extract_formatted_phone_number(text, number => matches_entirely(VALID_INCOMPLETE_PHONE_NUMBER_PATTERN, number))
let extracted_number = extract_formatted_phone_number(text)
let { number, is_international } = parse_phone_number(extracted_number)
// Special case for just the leading '+'
if (!extracted_number && text.indexOf('+') >= 0)
// Special case for a lone '+' sign
// since it's not considered a possible phone number.
if (!extracted_number)
{
is_international = true
if (text.indexOf('+') >= 0)
{
extracted_number = '+'
}
}
let parsed_input = ''
if (is_international)
// Validate possible first part of a phone number
if (!matches_entirely(VALID_INCOMPLETE_PHONE_NUMBER_PATTERN, extracted_number))
{
parsed_input += '+'
return this.current_output
}
if (number)
{
parsed_input += number
}
// Feed the parsed input character-by-character
for (let character of parsed_input)
for (let character of parse_phone_number(extracted_number))
{

@@ -268,3 +271,3 @@ this.current_output = this.input_character(character)

// then return the formatted number so far.
if (this.current_format)
if (national_number_formatted_with_previous_format)
{

@@ -313,3 +316,3 @@ return this.full_phone_number(national_number_formatted_with_previous_format)

this.current_format = undefined
this.chosen_format = undefined

@@ -319,2 +322,3 @@ this.last_match_position = 0

this.formatting_template = undefined
this.partially_populated_formatting_template = undefined

@@ -518,3 +522,3 @@ this.national_prefix_is_part_of_formatting_template = false

// and is still possible, then stick to it.
if (this.current_format === format)
if (this.chosen_format === format)
{

@@ -529,3 +533,3 @@ return

{
this.current_format = format
this.chosen_format = format

@@ -576,16 +580,14 @@ // With a new formatting template, the matched position

// Get a formatting template which can be used to efficiently format a
// partial number where digits are added one by one.
// 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'
// This match will always succeed,
// because the "longest dummy phone number"
// has enough length to accomodate any possible
// national phone number format pattern.
const dummy_phone_number_matching_format_pattern = LONGEST_DUMMY_PHONE_NUMBER.match(number_pattern)[0]
const matches = longest_phone_number.match(number_pattern)
// This match will always succeed
const phone_number = matches[0]
// No formatting template can be created if the number of digits entered so
// far is longer than the maximum the current formatting rule can accommodate.
if (phone_number.length < this.national_number.length)
// 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)
{

@@ -595,7 +597,10 @@ return

return this.formatting_template = phone_number
// Formats the number according to numberFormat
// Create formatting template for this phone number format
this.formatting_template = dummy_phone_number_matching_format_pattern
// Format the dummy phone number according to the format
.replace(new RegExp(number_pattern, 'g'), number_format)
// Replaces each digit with character DIGIT_PLACEHOLDER
.replace(new RegExp('9', 'g'), DIGIT_PLACEHOLDER)
// Replace each dummy digit with a DIGIT_PLACEHOLDER
.replace(DUMMY_DIGIT_MATCHER, DIGIT_PLACEHOLDER)
return this.partially_populated_formatting_template = this.formatting_template
}

@@ -608,10 +613,10 @@

// 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)
if (this.chosen_format && this.partially_populated_formatting_template.slice(this.last_match_position + 1).search(DIGIT_PLACEHOLDER_MATCHER) >= 0)
{
const digit_pattern_start = this.formatting_template.search(DIGIT_PLACEHOLDER_MATCHER)
this.formatting_template = this.formatting_template.replace(DIGIT_PLACEHOLDER_MATCHER, digit)
const digit_pattern_start = this.partially_populated_formatting_template.search(DIGIT_PLACEHOLDER_MATCHER)
this.partially_populated_formatting_template = this.partially_populated_formatting_template.replace(DIGIT_PLACEHOLDER_MATCHER, digit)
this.last_match_position = digit_pattern_start
// Return the formatted phone number so far
return close_dangling_braces(this.formatting_template, digit_pattern_start + 1)
return close_dangling_braces(this.partially_populated_formatting_template, digit_pattern_start + 1)
.replace(DIGIT_PLACEHOLDER_MATCHER_GLOBAL, ' ')

@@ -622,7 +627,9 @@ }

// Reset the current format flag,
// Reset the current format,
// so that the new format will be chosen
// in a subsequent `this.choose_another_format()` call
// later in code.
this.current_format = undefined
this.chosen_format = undefined
this.formatting_template = undefined
this.partially_populated_formatting_template = undefined
}

@@ -681,2 +688,27 @@

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 ''
}
let result = ''
while (times > 1)
{
if (times & 1)
{
result += string
}
times >>= 1
string += string
}
return result + string
}

@@ -95,2 +95,62 @@ export function get_phone_code(country_metadata)

return metadata.countries[country_code]
}
export function get_types(country_metadata)
{
return country_metadata[9]
}
function get_type(country_metadata, index)
{
return get_types(country_metadata) ? get_types(country_metadata)[index] : undefined
}
export function get_type_fixed_line(country_metadata)
{
return get_type(country_metadata, 0)
}
export function get_type_mobile(country_metadata)
{
return get_type(country_metadata, 1)
}
export function get_type_toll_free(country_metadata)
{
return get_type(country_metadata, 2)
}
export function get_type_premium_rate(country_metadata)
{
return get_type(country_metadata, 3)
}
export function get_type_personal_number(country_metadata)
{
return get_type(country_metadata, 4)
}
export function get_type_voice_mail(country_metadata)
{
return get_type(country_metadata, 5)
}
export function get_type_uan(country_metadata)
{
return get_type(country_metadata, 6)
}
export function get_type_pager(country_metadata)
{
return get_type(country_metadata, 7)
}
export function get_type_voip(country_metadata)
{
return get_type(country_metadata, 8)
}
export function get_type_shared_cost(country_metadata)
{
return get_type(country_metadata, 9)
}

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

get_leading_digits,
get_metadata_by_country_phone_code
get_metadata_by_country_phone_code,
get_type_fixed_line,
get_type_mobile,
get_type_toll_free,
get_type_premium_rate,
get_type_personal_number,
get_type_voice_mail,
get_type_uan,
get_type_pager,
get_type_voip,
get_type_shared_cost
}

@@ -97,5 +107,3 @@ from './metadata'

// Regular expression of trailing characters that we want to remove. We remove
// all characters that are not alpha or numerical characters. The hash character
// is retained here, as it may signify the previous block was an extension.
// Regular expression of trailing characters that we want to remove.
const AFTER_PHONE_NUMBER_END_PATTERN = new RegExp('[^' + VALID_DIGITS + ']+$')

@@ -212,3 +220,3 @@

// If the phone number is not viable, then abort.
if (!formatted_phone_number)
if (!is_viable_phone_number(formatted_phone_number))
{

@@ -275,2 +283,9 @@ return {}

country = find_country_code(country_phone_code, national_number)
// Just in case there's a bug in Google's metadata
/* istanbul ignore if */
if (!country)
{
return {}
}
}

@@ -329,19 +344,2 @@

// Attempts to extract a possible number from the string passed in.
export function extract_possible_number(text)
{
const starts_at = text.search(PHONE_NUMBER_START_PATTERN)
if (starts_at < 0)
{
return ''
}
return text
// Trim everything to the left of the phone number
.slice(starts_at)
// Remove trailing non-numerical characters
.replace(AFTER_PHONE_NUMBER_END_PATTERN, '')
}
// Checks to see if the string of characters could possibly be a phone number at

@@ -360,22 +358,26 @@ // all. At the moment, checks to see that the string begins with at least 2

export function extract_formatted_phone_number(text, is_valid = is_viable_phone_number)
export function extract_formatted_phone_number(text)
{
if (!text || text.length > MAX_INPUT_STRING_LENGTH)
{
return
return ''
}
// Extracts a piece of text possibly containing a phone number
text = extract_possible_number(text)
// Attempt to extract a possible number from the string passed in
if (is_valid(text))
const starts_at = text.search(PHONE_NUMBER_START_PATTERN)
if (starts_at < 0)
{
return text
return ''
}
return text
// Trim everything to the left of the phone number
.slice(starts_at)
// Remove trailing non-numerical characters
.replace(AFTER_PHONE_NUMBER_END_PATTERN, '')
}
// Parses a formatted phone number
// and returns `{ is_international, number }`
// where `number` is either national (significant) phone number
// or an international phone number with the leading '+' stripped.
// Parses a formatted phone number.
export function parse_phone_number(number)

@@ -385,3 +387,3 @@ {

{
return {}
return ''
}

@@ -395,3 +397,8 @@

return { number, is_international }
if (is_international)
{
return `+${number}`
}
return number
}

@@ -405,5 +412,5 @@

//
export function parse_phone_number_and_country_phone_code(_number)
export function parse_phone_number_and_country_phone_code(number)
{
const { number, is_international } = parse_phone_number(_number)
number = parse_phone_number(number)

@@ -417,3 +424,3 @@ if (!number)

// then don't extract country phone code.
if (!is_international)
if (number[0] !== '+')
{

@@ -423,2 +430,5 @@ return { number }

// Strip the leading '+' sign
number = number.slice(1)
// Fast abortion: country codes do not begin with a '0'

@@ -506,17 +516,10 @@ if (number[0] === '0')

{
// Is always defined, because `country_phone_code` is always valid
const possible_country_codes = metadata.country_phone_code_to_countries[country_phone_code]
// Is always non-empty, because `country_phone_code` is always valid
const possible_countries = metadata.country_phone_code_to_countries[country_phone_code]
// Iterate possible countries backwards
// because the first one is the default (main) one.
let i
// Look for leading digits for countries
i = possible_country_codes.length - 1
while (i > 0)
for (let country_code of possible_countries)
{
const country_code = possible_country_codes[i]
const country = metadata.countries[country_code]
// Leading digits check would be the simplest one
if (get_leading_digits(country))

@@ -530,25 +533,9 @@ {

}
i--
}
// Leading digits not matched,
// just phone number validation will do.
// Now start from the default one.
i = 0
while (i < possible_country_codes.length)
{
const country_code = possible_country_codes[i]
const country = metadata.countries[country_code]
if (is_national_phone_number(national_phone_number, country))
// Else perform full validation with all of those bulky
// fixed-line/mobile/etc regular expressions.
else if (get_number_type(national_phone_number, country))
{
return country_code
}
i++
}
// No country matched this national phone number
}

@@ -568,3 +555,96 @@

// If leading digits are specified, then check them.
if (get_leading_digits(country_metadata))
{
if (national_number.indexOf(get_leading_digits(country_metadata)) !== 0)
{
return false
}
}
return matches_entirely(get_national_number_pattern(country_metadata), national_number)
}
// Finds out national phone number type (fixed line, mobile, etc)
export function get_number_type(national_number, country_metadata)
{
// Is this national number even valid for this country
if (!is_of_type(national_number, get_national_number_pattern(country_metadata)))
{
return
}
if (is_of_type(national_number, get_type_mobile(country_metadata)))
{
if (is_of_type(national_number, get_type_fixed_line(country_metadata)))
{
return 'FIXED_LINE_OR_MOBILE'
}
return 'MOBILE'
}
// Is it fixed line number
if (is_of_type(national_number, get_type_fixed_line(country_metadata)))
{
return 'FIXED_LINE'
}
if (is_of_type(national_number, get_type_toll_free(country_metadata)))
{
return 'TOLL_FREE'
}
if (is_of_type(national_number, get_type_premium_rate(country_metadata)))
{
return 'PREMIUM_RATE'
}
if (is_of_type(national_number, get_type_personal_number(country_metadata)))
{
return 'PERSONAL_NUMBER'
}
if (is_of_type(national_number, get_type_voice_mail(country_metadata)))
{
return 'VOICEMAIL'
}
if (is_of_type(national_number, get_type_uan(country_metadata)))
{
return 'UAN'
}
if (is_of_type(national_number, get_type_pager(country_metadata)))
{
return 'PAGER'
}
if (is_of_type(national_number, get_type_voip(country_metadata)))
{
return 'VOIP'
}
if (is_of_type(national_number, get_type_shared_cost(country_metadata)))
{
return 'SHARED_COST'
}
}
export function is_of_type(national_number, type)
{
// // Check if any possible number lengths are present;
// // if so, we use them to avoid checking
// // the validation pattern if they don't match.
// // If they are absent, this means they match
// // the general description, which we have
// // already checked before a specific number type.
// if (get_possible_lengths(type) &&
// get_possible_lengths(type).indexOf(national_number.length) === -1)
// {
// return false
// }
// get_type_pattern(type) === type
return matches_entirely(type, national_number)
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

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