GithubHelp home page GithubHelp logo

catamphetamine / libphonenumber-js Goto Github PK

View Code? Open in Web Editor NEW
2.7K 30.0 217.0 10.73 MB

A simpler (and smaller) rewrite of Google Android's libphonenumber library in javascript

Home Page: https://catamphetamine.gitlab.io/libphonenumber-js/

License: MIT License

JavaScript 98.10% Shell 0.06% Batchfile 0.02% HTML 1.81%
phone number

libphonenumber-js's Introduction

libphonenumber-js

npm version npm downloads coverage

A simpler and smaller rewrite of Google Android's libphonenumber library in javascript.

See Demo

If you’re trying to build a React component with it, take a look at react-phone-number-input.

LibPhoneNumber

Google's libphonenumber is an ultimate phone number formatting and parsing library developed by Google for Android phones. It is written in C++ and Java, and, while it has an official autogenerated javascript port, that port is tightly coupled to Google's closure javascript framework, and, when compiled into a bundle, weighs about 550 kB (350 kB code + 200 kB metadata).

With many websites today asking for user's phone number, the internet could benefit from a simpler and smaller library that would just get the parsing and formatting right, and that's what libphonenumber-js is.

Difference from Google's libphonenumber

  • Smaller footprint: 145 kB (65 kB code + 80 kB sufficient metadata) vs the original Google's 550 kB (350 kB code + 200 kB full metadata).

  • Can search for phone numbers in text (Google's autogenerated javascript port can't).

  • Aims at parsing and formatting people's phone numbers while skipping all other "special" cases like:

    • Emergency phone numbers like 911.

    • "Short codes": short SMS-only numbers like 12345.

    • Numbers starting with a *, like *555.

    • Alphabetic phone numbers like 1-800-GOT-MILK: people don't input their phone numbers like that, it's only used in advertisement.

    • "Two-in-one" phone numbers with "combined" extensions like (530) 583-6985 x302/x2303 that in fact represent two separate phone numbers, because the library can only return a single phone number when parsing a string.

    • Overall, doesn't support formatting non-"conventional" numbers like numbers with the "area code" omitted or "alternative" "short" numbers like Australian 13-smart numbers. For example, when dialing phone numbers within the same "area", people sometimes skip the "area code", and dial, say, 456-789 instead of (123) 456-789. Google's libphonenumber supports formatting such numbers (with "area code" omitted) because it is used for dialing on the Android phone operating system. Because libphonenumber-js isn't a phone operating system and is not used for actual dialing — only for inputting internationally-dialable personal phone numbers — it doesn't format such "short" phone numbers because it doesn't need to support those.

    • Any other "miscellaneous" cases that're considered irrelevant for the task.

  • Doesn't provide "geolocation" by a phone number.

  • Doesn't use hyphens or brackets when formatting international phone numbers, only whitespace (seems more logical this way).

  • Doesn't set .country to "001" when parsing "non-geographic" phone numbers (like mobile satellite communications services). Instead, .country is undefined in those cases, and a developer can call .isNonGeographic() method of the PhoneNumber instance to find out whether the parsed phone number is a "non-geographic" one.

  • Doesn't provide the equivalent of libphonenumber's formatNumberForMobileDialing() function that formats a number for dialing using a mobile phone within the country: dialing local numbers from a mobile phone is a bit more complicated in some countries like Brazil or Colombia where they require adding "carrier codes" when making a call. Since libphonenumber-js is not a dialing library (we're not Android phone operaing system), it doesn't prepend any "carrier codes" when formatting phone numbers, though it does parse such "carrier codes" correctly.

GitHub

On March 9th, 2020, GitHub, Inc. silently banned my account (erasing all my repos, issues and comments, even in my employer's private repos) without any notice or explanation. Because of that, all source codes had to be promptly moved to GitLab. The GitHub repo is now only used as a backup (you can star the repo there too), and the primary repo is now the GitLab one. Issues can be reported in any repo.

Install

via npm

$ npm install libphonenumber-js --save

via yarn

$ yarn add libphonenumber-js

If you're not using a bundler then use a standalone version from a CDN.

Use

Parse phone number

import parsePhoneNumber from 'libphonenumber-js'

const phoneNumber = parsePhoneNumber(' 8 (800) 555-35-35 ', 'RU')
if (phoneNumber) {
  phoneNumber.country === 'RU'
  phoneNumber.number === '+78005553535'
  phoneNumber.isPossible() === true
  phoneNumber.isValid() === true
  // Note: `.getType()` requires `/max` metadata: see below for an explanation.
  phoneNumber.getType() === 'TOLL_FREE'
}

Validate phone number

import {
  isPossiblePhoneNumber,
  isValidPhoneNumber,
  validatePhoneNumberLength
} from 'libphonenumber-js'

isPossiblePhoneNumber('8 (800) 555-35-35', 'RU') === true
isValidPhoneNumber('8 (800) 555-35-35', 'RU') === true

validatePhoneNumberLength('8 (800) 555', 'RU') === 'TOO_SHORT'
validatePhoneNumberLength('8 (800) 555-35-35', 'RU') === undefined // Length is valid.

isPossiblePhoneNumber() only validates phone number length, while isValidPhoneNumber() validates both phone number length and the actual phone number digits.

validatePhoneNumberLength() is just a more detailed version of isPossiblePhoneNumber() — if the phone number length is invalid, it returns the actual reason: TOO_SHORT, TOO_LONG, etc.

Format phone number

import parsePhoneNumber from 'libphonenumber-js'

const phoneNumber = parsePhoneNumber('+12133734253')

phoneNumber.formatInternational() === '+1 213 373 4253'
phoneNumber.formatNational() === '(213) 373-4253'
phoneNumber.getURI() === 'tel:+12133734253'

"As You Type" formatter

import { AsYouType } from 'libphonenumber-js'

new AsYouType().input('+12133734')
// Outputs: '+1 213 373 4'

new AsYouType('US').input('2133734')
// Outputs: '(213) 373-4'

Full-text search

import { findPhoneNumbersInText } from 'libphonenumber-js'

findPhoneNumbersInText(`
  For tech support call +7 (800) 555-35-35 internationally
  or reach a local US branch at (213) 373-4253 ext. 1234.
`, 'US')

// Outputs:
//
// [{
//   number: PhoneNumber {
//     country: 'RU',
//     countryCallingCode: '7',
//     number: '+78005553535',
//     nationalNumber: '8005553535'
//   },
//   startsAt : 22,
//   endsAt   : 40
// }, {
//   number: PhoneNumber {
//     country: 'US',
//     countryCallingCode: '1',
//     number: '+12133734253',
//     nationalNumber: '2133734253',
//     ext: '1234'
//   },
//   startsAt : 86,
//   endsAt   : 110
// }]

"min" vs "max" vs "mobile" vs "core"

This library provides different "metadata" sets, "metadata" being a list of phone number parsing and formatting rules for all countries. The complete list of those rules is huge, so this library provides a way to optimize bundle size by choosing between max, min, mobile and "custom" metadata:

  • max — The complete metadata set, is about 145 kilobytes in size (libphonenumber-js/metadata.max.json). Choose this when you need the most strict version of isValid(), or if you need to detect phone number type ("fixed line", "mobile", etc).

  • min — (default) The smallest metadata set, is about 80 kilobytes in size (libphonenumber-js/metadata.min.json). Choose this by default: when you don't need to detect phone number type ("fixed line", "mobile", etc), or when a basic version of isValid() is enough. The min metadata set doesn't contain the regular expressions for phone number digits validation (via .isValid()) and detecting phone number type (via .getType()) for most countries. In this case, .isValid() still performs some basic phone number validation (for example, checks phone number length), but it doesn't validate phone number digits themselves the way max metadata validation does.

  • mobile — The complete metadata set for dealing with mobile numbers only, is about 95 kilobytes in size (libphonenumber-js/metadata.mobile.json). Choose this when you need max metadata and when you only accept mobile numbers. Other phone number types will still be parseable, but they won't be recognized as being "valid" (.isValid() will return false).

To use a particular metadata set, simply import functions from a relevant sub-package:

  • libphonenumber-js/max
  • libphonenumber-js/min
  • libphonenumber-js/mobile

Importing functions directly from libphonenumber-js effectively results in using the min metadata.

Sometimes (rarely) not all countries are needed, and in those cases developers may want to generate their own "custom" metadata set. For those cases, there's libphonenumber-js/core sub-package which doesn't come pre-packaged with any default metadata set and instead accepts metadata as the last argument of each exported function.

Definitions

Country code

A "country code" is a two-letter ISO country code (like US).

This library supports all officially assigned ISO alpha-2 country codes, plus a few extra ones like: AC (Ascension Island), TA (Tristan da Cunha), XK (Kosovo).

To check whether a country code is supported, use isSupportedCountry() function.

Non-geographic

There're several calling codes that don't belong to any country:

Such phone numbering plans are called "non-geographic", and their phone numbers have country set to undefined.

National (significant) number

"National (significant) number" are the national phone number digits (without "national prefix"). For example, +1 213 373 4253 (or (213) 373-4253 in national format) is a US phone number and its national (significant) number is 213 373 4253. Another example is +33 1 45 45 32 45 (or 01 45 45 32 45 in national format) which is a French phone number where they add 0 "national prefix" when writing phone numbers in national format; in this case the national (significant) number is 1 45 45 32 45.

Country calling code

"Country calling code" are the digits between the + and the national (significant) number when the number is written in international format. E.g. for US country calling code is 1 and for France it's 33. Several countries can share the same "country calling code", e.g. NANPA countries like USA and Canada sharing the same 1 country calling code.

API

parsePhoneNumber(string, defaultCountry?: string | options?: object): PhoneNumber

Parses a phone number from string.

Can be imported both as a "default" export and as a "named" export parsePhoneNumberFromString.

import parsePhoneNumber from 'libphonenumber-js'
// Or: import { parsePhoneNumberFromString as parsePhoneNumber } from 'libphonenumber-js'

const phoneNumber = parsePhoneNumber('(213) 373-42-53 ext. 1234', 'US')
if (phoneNumber) {
  console.log(phoneNumber.formatNational())
}

Returns an instance of PhoneNumber class, or undefined if no phone number could be parsed: for example, when the string contains no phone number, or the phone number starts with a non-existent country calling code, etc.

Available options:

  • defaultCountry: string — Default country for parsing numbers written in non-international form (without a + sign). Will be ignored when parsing numbers written in international form (with a + sign). Instead of passing it as options.defaultCountry, one could also pass it as a standalone defaultCountry argument (for convenience).

  • defaultCallingCode: string — Default calling code for parsing numbers written in non-international form (without a + sign). Will be ignored when parsing numbers written in international form (with a + sign). It could be specified when parsing phone numbers belonging to "non-geographic numbering plans" which by nature don't have a country code, making the defaultCountry option unusable.

  • extract: boolean — Defines the "strictness" of parsing a phone number. By default, the extract flag is true meaning that it will attempt to extract the phone number from an input string like "My phone number is (213) 373-4253 and my hair is blue". This could be thought of as "less strict" parsing. To make it "more strict", one could pass extract: false flag, in which case the function will attempt to parse the input string as if the whole string was a phone number. Applied to the example above, it would return undefined because the entire string is not a phone number, but for input string "(213) 373-4253" it would return a parsed PhoneNumber.

If a developer wants to know the exact reason why the phone number couldn't be parsed then they can use parsePhoneNumberWithError() function which throws the exact error:

import { parsePhoneNumberWithError, ParseError } from 'libphonenumber-js'

try {
  const phoneNumber = parsePhoneNumberWithError('(213) 373-42-53 ext. 1234', {
    defaultCountry: 'US'
  })
} catch (error) {
  if (error instanceof ParseError) {
    // Not a phone number, non-existent country, etc.
    console.log(error.message)
  } else {
    throw error
  }
}
Possible errors
  • NOT_A_NUMBER — When the supplied string is not a phone number. For example, when there are no digits: "abcde", "+".

  • INVALID_COUNTRY

    • When defaultCountry doesn't exist (or isn't supported by this library yet): parsePhoneNumber('(111) 222-3333', 'XX').
    • When parsing a non-international number without a defaultCountry: parsePhoneNumber('(111) 222-3333').
    • When an international number's country calling code doesn't exist: parsePhoneNumber('+9991112223333').
  • TOO_SHORT — When the number is too short. For example, just 1 or 2 digits: "1", "+12".

  • TOO_LONG — When the national (significant) number is too long (17 digits max) or when the string being parsed is too long (250 characters max).

Strictness

By default, the parsing function will attempt to extract a phone number from an input string even in cases like "Support: (213) 373-4253 (robot)", which mimicks the behavior of the original Google's libphonenumber library, and is the default behavior for legacy reasons. However, if "strict" input validation is required, one can pass extract: false flag to demand that the whole input string be a viable phone number.

parsePhoneNumber('Call: (213) 373-4253', 'US') === PhoneNumber

// When parsing the same string with `extract: false` flag,
// it will return `undefined`, because a phone number can't
// contain letters or a colon.
parsePhoneNumber('Call: (213) 373-4253', {
  defaultCountry: 'US',
  extract: false
}) === undefined

parsePhoneNumber('(213) 373-4253', {
  defaultCountry: 'US',
  extract: false
}) === PhoneNumber

PhoneNumber

PhoneNumber class instance has the following properties:

  • number: string — The phone number in E.164 format. Example: "+12133734253".
  • countryCallingCode: string — The country calling code. Example: "1".
  • nationalNumber: string — The national (significant) number. Example: "2133734253".
  • country: string? — The country code. Example: "US". Will be undefined when no country could be derived from the phone number. For example, when several countries have the same countryCallingCode and the nationalNumber doesn't look like it belongs to any of them. Or when a number belongs to a non-geographic numbering plan.
  • ext: string? — The phone number extension, if any. Example: "1234".
  • carrierCode: string? — The "carrier code", if any. Example: "15". "Carrier codes" are only used in Colombia and Brazil and only when dialing within those countries from a mobile phone to a fixed line number.

PhoneNumber class instance provides the following methods:

setExt(ext: string)

Sets a phone number extension of a phone number. Could be useful when formatting phone numbers stored as two separate fields: the phone number itself and the extension part.

const phone = "+12133734253"
const phoneExt = "1234"

const phoneNumber = parsePhoneNumber(phone)
if (phoneNumber) {
  if (phoneExt) {
    phoneNumber.setExt(phoneExt)
  }
  // Returns "(213) 373-4253 ext. 1234"
  return phoneNumber.formatNational()
}

format(format: string, [options]): string

Formats the phone number into a string according to a format.

Available formats:

  • NATIONAL — Example: "(213) 373-4253"
  • INTERNATIONAL — Example: "+1 213 373 4253"
  • E.164 — Example: "+12133734253"
  • RFC3966 (the phone number URI) — Example: "tel:+12133734253;ext=123"
  • IDD"Out-of-country" dialing format. Example: "011 7 800 555 35 35" for +7 800 555 35 35 being called out of options.fromCountry === "US". If no options.fromCountry was passed or if there's no default IDD prefix for options.fromCountry then returns undefined.

Available options:

  • formatExtension(number, extension) — Formats number and extension into a string. By default returns ${number} ext. ${extension} for almost all countries with rare exceptions of some special cases like ${number} x${extension} for UK.

  • nationalPrefix: Boolean — Some phone numbers can be formatted both with national prefix and without it. In such cases the library defaults to "with national prefix" (for legacy reasons). Pass nationalPrefix: false option to force formatting without national prefix in such cases.

Examples:

import parsePhoneNumber from 'libphonenumber-js'

const phoneNumber = parsePhoneNumber('+12133734253')

phoneNumber.format("NATIONAL") === '(213) 373-4253'
phoneNumber.format("INTERNATIONAL") === '+1 213 373 4253'
phoneNumber.format("RFC3966") === 'tel:+12133734253'

// Aliases
phoneNumber.formatNational() === phoneNumber.format("NATIONAL")
phoneNumber.formatInternational() === phoneNumber.format("INTERNATIONAL")
phoneNumber.getURI() === phoneNumber.format("RFC3966")

isPossible(): boolean

Checks if the phone number is "possible". Only checks the phone number length, doesn't check the actual phone number digits against any regular expressions.

isValid(): boolean

Checks if the phone number is "valid". First checks the phone number length and then checks the phone number digits against all available regular expressions.

By default the library uses "minimal" metadata which is only 75 kilobytes in size but also doesn't include the precise validation regular expressions resulting in less strict validation rules (some very basic validation like length check is still included for each country). If you don't mind the extra 65 kilobytes of metadata then use "full" metadata instead (140 kilobytes). Google's library always uses "full" metadata so it will yield different isValidNumber() results compared to the "minimal" metadata used by default in this library.

See an example illustrating different results when using /min vs /max vs /mobile

import parseMin from 'libphonenumber-js/min'
import parseMax from 'libphonenumber-js/max'
import parseMobile from 'libphonenumber-js/mobile'

// Mobile numbers in Singapore starting from `8`
// can only have the second digit in the range of `0..8`.
// Here the second digit is `9` which makes it an invalid mobile number.
// This is a "strict" (advanced) validation rule and is
// not included in the (default) "min" bundle.

// The basic number length check passes (`8..11`) and the
// "loose" national number validation regexp check passes too:
// `(?:1\d{3}|[369]|7000|8(?:\d{2})?)\d{7}`.
parseMin('+6589555555').isValid() === true

// The "advanced" validation regexp for mobile numbers is
// `(?:8[1-8]|9[0-8])\\d{6}` and possible lengths are `8`.
parseMax('+6589555555').isValid() === false
parseMobile('+6589555555').isValid() === false

See "Using phone number validation feature" for choosing between isPossible() and isValid().

getPossibleCountries(): string[]

Returns a list of countries this phone number could possibly belong to.

Can be used when parsing complete international phone numbers containing a "calling code" that is shared between several countries. If parsing such a phone number returns country: undefined then getPossibleCountries() function could be used to somehow speculate about what country could this phone number possibly belong to.

getType(): string?

Returns phone number type (fixed line, mobile, toll free, etc) or undefined (if the number is invalid or if there are no phone number type regular expressions for this country in metadata).

By default the library uses "minimal" metadata which is only 75 kilobytes in size but also doesn't include the regular expressions for determining a specific phone number type (fixed line, mobile, toll free, etc) resulting in getType() returning undefined for most countries. If you don't mind the extra 65 kilobytes of metadata then use "full" metadata instead (140 kilobytes). Google's library always uses "full" metadata so it will yield different getNumberType() results compared to the "minimal" metadata used by default in this library.

The list of possible return values

  • MOBILE — Cellphones.
  • FIXED_LINE — Stationary phones.
  • FIXED_LINE_OR_MOBILE — Could be MOBILE or FIXED_LINE.
  • PREMIUM_RATE — Callers are charged by call or per minute. SMS text messages are also subject to charge.
  • TOLL_FREE — Free to call from anywhere.
  • SHARED_COST — "An intermediate level of telephone call billing where the charge for calling a particular international or long-distance phone number is partially, but not entirely, paid for by the recipient".
  • VOIP — "IP telephony". Calls are made over the Internet rather than via the conventional telephone-only lines.
  • PERSONAL_NUMBER — Phones connected by satellites.
  • PAGER — "Pagers" are wireless telecommunications devices that were widely used in the 80-es and could receive (and, optionally, send) text or voice messages.
  • UAN — "UAN is a number resource that allows a service or business with several terminating lines to be reached through a unique universal number. A UAN number shall be dialable from the entire Pakistan, based on the applicant’s proposed coverage without dialing the area code. UAN cannot be assigned to two separate business or mutually exclusive public services. Each service provider who allows UAN through its network shall offer a tariff, which is not more expensive than the normal tariff available for a similar non-UAN public service".
  • VOICEMAIL — "A voicemail access number is a telephone number provided by a voicemail service to allow subscribers to dial into their voicemail accounts and manage any currently saved messages. Typically, the number is used when a subscriber is away from home and wishes to check any voice messages currently stored on the service. Originally envisioned as part of the features associated with voicemail accounts offered with land line accounts, many mobile service providers today also supply their customers with a voicemail access number to use when checking messages from any phone other than the mobile or cellular unit associated with the account".

See an example illustrating different results when using /min vs /max vs /mobile

import parseMin from 'libphonenumber-js/min'
import parseMax from 'libphonenumber-js/max'
import parseMobile from 'libphonenumber-js/mobile'

// Singapore valid mobile number.

// The (default) "min" bundle doesn't contain any regexps for
// getting phone number type based on national number (for Singapore).
parseMin('+6584655555').getType() === undefined

// The "max" bundle contains regexps for
// getting phone number type based on national number
// for all possible phone number types.
parseMax('+6584655555').getType() === 'MOBILE'

// The "mobile" bundle contains regexps for
// getting phone number type based on national number
// for mobile phone numbers only.
parseMobile('+6584655555').getType() === 'MOBILE'

isNonGeographic(): boolean

Returns true if the number belongs to a "non-geographic numbering plan".

isEqual(phoneNumber: PhoneNumber): boolean

Compares two PhoneNumbers: returns true if they're equal, false otherwise.

isPossiblePhoneNumber(input: string, defaultCountry?: string | options?: object): boolean

Checks if input can be parsed as a "possible" phone number. A phone number is "possible" when it has valid length. The actual phone number digits aren't validated.

isPossiblePhoneNumber('8 (888) 888-88-88', 'RU') === true
isPossiblePhoneNumber('+12223333333') === true

For the description of the defaultCountry?: string | options?: object argument, see parsePhoneNumber() function description.

This function is just a shortcut for a two-step process of "strictly" parsing a phone number and then calling .isPossible().

isValidPhoneNumber(input: string, defaultCountry?: string | options?: object): boolean

Checks if input can be parsed as a "valid" phone number. A phone number is "valid" when it has valid length, and the actual phone number digits match the regular expressions for its country.

isValidPhoneNumber('8 (888) 888-88-88', 'RU') === false
isValidPhoneNumber('8 (800) 555-35-35', 'RU') === true
isValidPhoneNumber('+12223333333') === false
isValidPhoneNumber('+12133734253') === true

For the description of the defaultCountry?: string | options?: object argument, see parsePhoneNumber() function description.

This function is just a shortcut for a two-step process of "strictly" parsing a phone number and then calling .isValid().

See "Using phone number validation feature" for choosing between isPossible() and isValid().

isValidPhoneNumberForCountry(input: string, country: string): boolean

Same as isValidPhoneNumber() but with the "default country" argument being an "exact country" instead.

This function is not currently exported from this library. The reason is that its result would be too vague when false is returned — it could mean any of:

  • The input is not a valid phone number.
  • The input is a valid phone number but it belongs to another country.
  • The input is a phone number that belongs to the correct country but is not valid.

At least the second case should be handled separately from a "User Experience" point of view: if the user has input a valid phone number but for another country, they should be notified that "the country is incorrect" rather than that "the phone number is incorrect", otherwise it would be bad UX design.

But for those who'd still like to have such function, here's a possible implementation for it:

export default function isValidPhoneNumberForCountry(phoneNumberString, country) {
  const phoneNumber = parsePhoneNumber(phoneNumberString, {
    defaultCountry: country,
    // Demand that the entire input string must be a phone number.
    // Otherwise, it would "extract" a phone number from an input string.
    extract: false
  })
  if (!phoneNumber) {
    return false
  }
  if (phoneNumber.country !== country) {
    return false
  }
  return phoneNumber.isValid()
}

The same approach could be used to implement an isPossiblePhoneNumberForCountry() function.

validatePhoneNumberLength(input: string, defaultCountry?: string | options?: object): string?

Checks if input phone number length is valid. If it is, then nothing is returned. Otherwise, a rejection reason is returned.

Possible rejection reasons
  • NOT_A_NUMBER — When the supplied string is not a phone number. For example, when there are no digits: "abcde", "+".

  • INVALID_COUNTRY

    • When defaultCountry doesn't exist (or isn't supported by this library yet): parsePhoneNumber('(111) 222-3333', 'XX').
    • When parsing a non-international number without a defaultCountry: parsePhoneNumber('(111) 222-3333').
    • When an international number's country calling code doesn't exist: parsePhoneNumber('+9991112223333').
  • TOO_SHORT — When the number is too short. For example, just 1 or 2 digits: "1", "+12".

  • TOO_LONG — When the national (significant) number is too long (17 digits max) or when the string being parsed is too long (250 characters max).

  • INVALID_LENGTH — When the national (significant) number is neither too short, nor too long, but somewhere in between and its length is still invalid.

validatePhoneNumberLength('abcde') === 'NOT_A_NUMBER'
validatePhoneNumberLength('444 1 44') === 'INVALID_COUNTRY'
validatePhoneNumberLength('444 1 44', 'TR') === 'TOO_SHORT'
validatePhoneNumberLength('444 1 444', 'TR') === undefined // Length is valid.
validatePhoneNumberLength('444 1 4444', 'TR') === 'INVALID_LENGTH'
validatePhoneNumberLength('444 1 44444', 'TR') === 'INVALID_LENGTH'
validatePhoneNumberLength('444 1 444444', 'TR') === undefined // Length is valid.
validatePhoneNumberLength('444 1 4444444444', 'TR') === 'TOO_LONG'

For the description of the defaultCountry?: string | options?: object argument, see parsePhoneNumber() function description.

This function is just a more detailed version of isPossiblePhoneNumber() for those who've asked for a more specific rejection reason.

The phone number is parsed "strictly" from the input string.

class AsYouType(defaultCountry?: string | options?: object)

Creates a formatter for a partially entered phone number.

For the description of the defaultCountry?: string | options?: object argument, see parsePhoneNumber() function description.

The formatter instance has the following methods:

  • input(text: string) — Appends text to the input. Returns the formatted phone number.

  • reset() — Resets the input.

new AsYouType().input('+12133734') === '+1 213 373 4'
new AsYouType('US').input('2133734') === '(213) 373-4'

The formatter instance also provides the following getters:

  • getNumber(): PhoneNumber? — Returns the PhoneNumber. Will return undefined if no national (significant) number digits have been entered so far, or if no defaultCountry/defaultCallingCode has been set and the user enters a phone number not in international format.

  • getNumberValue(): string? — Returns the phone number in E.164 format. For example, for country "US" and input "(222) 333-4444" it will return "+12223334444". Will return undefined if no digits have been input, or when inputting a phone number in national format and no default country or default "country calling code" have been set.

  • getChars(): string — Returns the phone number characters entered by the user: digits and a + sign (if present). Returns an empty string if no phone number characters have been input.

  • getTemplate(): string — Returns the template used to format the phone number characters (digits and a + sign, if present), which are denoted by x-es. Returns an empty string if no phone number characters have been input.

// National phone number input example.

const asYouType = new AsYouType('US')

asYouType.input('2') === '2'
asYouType.getNumber().number === '+12'
asYouType.getChars() === '2'
asYouType.getTemplate() === 'x'

asYouType.input('1') === '21'
asYouType.getNumber().number === '+121'
asYouType.getChars() === '21'
asYouType.getTemplate() === 'xx'

asYouType.input('3') === '(213)'
asYouType.getNumber().number === '+1213'
asYouType.getChars() === '213'
asYouType.getTemplate() === '(xxx)'

asYouType.input('3734253') === '(213) 373-4253'
asYouType.getNumber().number === '+12133734253'
asYouType.getChars() === '2133734253'
asYouType.getTemplate() === '(xxx) xxx-xxxx'

// International phone number input example.

const asYouType = new AsYouType()
asYouType.input('+1-213-373-4253') === '+1 213 373 4253'
asYouType.getNumber().country === 'US'
asYouType.getNumber().number === '+12133734253'
asYouType.getChars() === '+12133734253'
asYouType.getTemplate() === 'xx xxx xxx xxxx'
  • isInternational(): boolean — Returns true if the phone number is being input in international format. In other words, returns true if and only if the parsed phone number starts with a "+".

  • getCallingCode(): string? — Returns the "country calling code" part of the phone number. Returns undefined if the number is not being input in international format, or if no valid "country calling code" has been entered. Supports "non-geographic" phone numbering plans: even though those aren't technically "countries", they have their own "country calling codes" too.

  • getCountry(): string? — Returns a two-letter country code of the phone number. Returns undefined for "non-geographic" phone numbering plans. Returns undefined if no phone number has been input yet.

  • isPossible(): boolean — Returns true if the phone number is "possible". Is just a shortcut for PhoneNumber.isPossible().

  • isValid(): boolean — Returns true if the phone number is "valid". Is just a shortcut for PhoneNumber.isValid().

Legacy API (before version 1.6.0)

For legacy API (before version 1.6.0) the formatter instance provides the following getters:

  • country: string? — Phone number country. Will return undefined if the country couldn't be derived from the number.

  • getNationalNumber(): string — Returns the national (significant) number part of the phone number.

  • getTemplate(): string? — Same as the current version of getTemplate() with the only difference that it returns undefined if no suitable format was found for the number being entered (or if no national (significant) number has been entered so far).

// National phone number input example.

const asYouType = new AsYouType('US')

asYouType.input('2') === '2'
asYouType.getNationalNumber() === '2'

asYouType.input('1') === '21'
asYouType.getNationalNumber() === '21'

asYouType.input('3') === '(213)'
asYouType.getNationalNumber() === '213'

asYouType.input('3734253') === '(213) 373-4253'
asYouType.getNationalNumber() === '2133734253'

// International phone number input example.

const asYouType = new AsYouType()
asYouType.input('+1-213-373-4253') === '+1 213 373 4253'
asYouType.country === 'US'
asYouType.getNationalNumber() === '2133734253'

"As You Type" formatter was created by Google as part of their Android OS and therefore only works for numerical keyboard input, i.e. it can only accept digits (and a + sign in the start of an international number). When used on desktops where a user can input all kinds of punctuation (spaces, dashes, parens, etc) it simply ignores everything except digits (and a + sign in the start of an international number).

Google's "As You Type" formatter does not support entering phone number extensions. If your project requires phone number extensions input then use a separate input field for that.

findPhoneNumbersInText(text: string, defaultCountry?: string | options?: object): object[]

Searches for phone numbers in text.

Available options:

  • defaultCountry: string
  • defaultCallingCode: string

For the description of defaultCountry or defaultCallingCode, see parsePhoneNumber() function description.

import { findPhoneNumbersInText } from 'libphonenumber-js'

findPhoneNumbersInText(`
  For tech support call +7 (800) 555-35-35 internationally
  or reach a local US branch at (213) 373-4253 ext. 1234.
`, 'US')

// Outputs:
//
// [{
//   number: PhoneNumber {
//     country: 'RU',
//     countryCallingCode: '7',
//     number: '+78005553535',
//     nationalNumber: '8005553535'
//   },
//   startsAt : 22,
//   endsAt   : 40
// }, {
//   number: PhoneNumber {
//     country: 'US',
//     countryCallingCode: '1',
//     number: '+12133734253',
//     nationalNumber: '2133734253',
//     ext: '1234'
//   },
//   startsAt : 86,
//   endsAt   : 110
// }]

(in previous versions, it was called findNumbers())

Legacy API (before version 1.6.0) example

import { findNumbers } from 'libphonenumber-js'

findNumbers(`
  For tech support call +7 (800) 555-35-35 internationally
  or reach a local US branch at (213) 373-4253 ext. 1234.
`, 'US')

// Outputs:
//
// [{
//   phone    : '8005553535',
//   country  : 'RU',
//   startsAt : 22,
//   endsAt   : 40
// },
// {
//   phone    : '2133734253',
//   country  : 'US',
//   ext      : '1234',
//   startsAt : 86,
//   endsAt   : 110
// }]

By default it processes the whole text and then outputs the phone numbers found. If the text is very big (say, a hundred thousand characters) then it might freeze the user interface for a couple of seconds. To avoid such lags one can employ "iterator" approach using searchPhoneNumbersInText() to perform the search asynchronously (e.g. using requestIdleCallback or requestAnimationFrame).

(in previous versions, it was called searchNumbers())

Asynchronous search example using searchPhoneNumbersInText()

ES6 iterator:

import { searchPhoneNumbersInText } from 'libphonenumber-js'

const text = `
  For tech support call +7 (800) 555-35-35 internationally
  or reach a local US branch at (213) 373-4253 ext. 1234.
`

async function() {
  for (const number of searchPhoneNumbersInText(text, 'US')) {
    console.log(number)
    await new Promise(resolve => setTimeout(resolve, 0))
  }
  console.log('Finished')
}

Java-style iterator (for those still not using ES6):

import { PhoneNumberMatcher } from 'libphonenumber-js'

const matcher = new PhoneNumberMatcher(`
  For tech support call +7 (800) 555-35-35 internationally
  or reach a local US branch at (213) 373-4253 ext. 1234.
`, {
  defaultCountry: 'US',
  v2: true
})

// Search cycle iteration.
const iteration = () => {
  if (matcher.hasNext()) {
    console.log(matcher.next())
    setTimeout(iteration, 0)
  } else {
    console.log('Finished')
  }
}

// Run the search.
iteration()

Although Google's javascript port doesn't have the findPhoneNumbersInText() functionality the Java and C++ ports do. I guess Google just doesn't need to crawl phone numbers on Node.js because they can afford to hire a Java/C++ developer to do that. Still, javascript nowadays is the most popular programming language given its simplicity and user-friendliness. The findPhoneNumbersInText() function provided is a port of Google's PhoneNumberMatcher.java into javascript.

getExampleNumber(country: string, examples: object): PhoneNumber

Returns an example phone number for a country. Returns an instance of PhoneNumber class. Will return undefined if country doesn't exist or isn't supported by this library.

import examples from 'libphonenumber-js/mobile/examples'
import { getExampleNumber } from 'libphonenumber-js'

const phoneNumber = getExampleNumber('RU', examples)

phoneNumber.formatNational() === '8 (912) 345-67-89'

isSupportedCountry(country: string): boolean

Checks if a country is supported by this library.

isSupportedCountry('RU') === true
isSupportedCountry('XX') === false

getCountries(): string[]

Returns a list of supported countries.

getCountries() === ["AC", "AD", ...]

getCountryCallingCode(country: string): string

Returns country calling code for a country. Will throw an error if country doesn't exist or isn't supported by this library.

getCountryCallingCode('RU') === '7'
getCountryCallingCode('IL') === '972'

getExtPrefix(country: string): string

Returns phone number extension prefix for a given country. If no custom ext prefix is defined for a country then the default " ext. " prefix is returned.

getExtPrefix('US') === ' ext. '
getExtPrefix('GB') === ' x'

parseDigits(text: string): string

Parses digits from string. Can be used for building a phone number extension input component (e.g. react-phone-number-input).

parseDigits('x123') === '123'
parseDigits('٤٤٢٣') === '4423'

parseIncompletePhoneNumber(text: string): string

Parses phone number characters (+ and digits). Can be used for building a phone number input component (e.g. react-phone-number-input).

parseIncompletePhoneNumber('8 (800) 555') === '8800555'
parseIncompletePhoneNumber('+7 800 555') === '+7800555'
parseIncompletePhoneNumber('+٤٤٢٣٢٣٢٣٤') === '+442323234'

parsePhoneNumberCharacter(nextCharacter, prevParsedCharacters, emitEvent?)

Parses next character of an input string while parsing phone number digits (including a +) from that string. Basically, it discards everything except + and digits, and + is only allowed at the start of a phone number.

This function is a low-level one that is currently only used in react-phone-number-input with input-format. Frankly speaking, that's the only reason why this function is exported. Other developers should just ignore it and use parseIncompletePhoneNumber() instead because it's much simpler.

// Suppose a user inputs a "+1 (213) 373-42-53" string
// and it starts parsing that string character-by-character.

parsePhoneNumberCharacter('+', undefined) === '+'
parsePhoneNumberCharacter('1', '+') === '1'
parsePhoneNumberCharacter(' ', '+1') === undefined
parsePhoneNumberCharacter('(', '+1') === undefined
parsePhoneNumberCharacter('2', '+1') === '2'
parsePhoneNumberCharacter('1', '+12') === '1'
parsePhoneNumberCharacter('3', '+121') === '3'
parsePhoneNumberCharacter(')', '+1213') === undefined
parsePhoneNumberCharacter(' ', '+1213') === undefined
parsePhoneNumberCharacter('3', '+1213') === '3'
parsePhoneNumberCharacter('7', '+12133') === '7'
parsePhoneNumberCharacter('3', '+121337') === '3'
parsePhoneNumberCharacter('-', '+121337') === undefined
parsePhoneNumberCharacter('4', '+1213373') === '4'
parsePhoneNumberCharacter('2', '+12133734') === '2'
parsePhoneNumberCharacter('-', '+12133734') === undefined
parsePhoneNumberCharacter('5', '+121337342') === '5'
parsePhoneNumberCharacter('3', '+1213373425') === '3'

So basically, it's the same as parseIncompletePhoneNumber() with the only difference that it operates at a character-by-character level rather than at a string-as-a-whole level.

The optional emitEvent argument is a function of (eventName: string) arguments. It will be called in a situation when the application should stop parsing the input string. Currently, the only situation when that could happen is when it encounters an "out-of-place" + character. For example, when parsing a "+1 (234) + 56-78" string it would emit an "end" event at the second + character so that the application would return "+1234" rather than "+12345678".

formatIncompletePhoneNumber(value: string, defaultCountry?: string | options?: object): string

Formats a possibly incomplete phone number.

While the usual parsePhoneNumber(string).format() function could only be used to format a complete phone number, this function could be used to format a possibly incomplete phone number.

The value argument should be a (possibly incomplete) phone number in E.164 format.

For the description of the defaultCountry?: string | options?: object argument, see parsePhoneNumber() function description.

This function is just an alias for new AsYouType(defaultCountry, metadata).input(value). It can be used for building a phone number input component (e.g. react-phone-number-input).

// National numbers, with second argument.
formatIncompletePhoneNumber('8800555', 'RU') === '8 (800) 555'
formatIncompletePhoneNumber('8800555', { defaultCountry: 'RU' }) === '8 (800) 555'
formatIncompletePhoneNumber('8800555', { defaultCallingCode: '7' }) === '8 (800) 555'

// International numbers, without second argument.
formatIncompletePhoneNumber('+7800555') === '+7 800 555'

Legacy API

Legacy API (before version 1.6.0): parse(), parseNumber(), format(), formatNumber(), isValidNumber(), getNumberType().

parseNumber(text, [defaultCountry], [options])

(previously called parse())

(legacy API)

Attempts to parse a phone number from text.

If defaultCountry is passed then it's gonna be the default country for parsing non-international phone numbers.

Returns { country, phone, ext } object where

If the phone number supplied isn't valid then an empty object {} is returned.

Examples
// Parses international numbers.
parseNumber('+1 213 373 4253') === { country: 'US', phone: '2133734253' }
parseNumber('Phone: +1-213-373-4253.') === { country: 'US', phone: '2133734253' }
parseNumber('+12133734253') === { country: 'US', phone: '2133734253' }

// Parses national numbers provided a default country.
parseNumber('Phone: (213) 373-4253.', 'US') === { country: 'US', phone: '2133734253' }

// Parses phone number extensions.
parseNumber('(213) 373-4253 ext. 123', 'US') === { country: 'US', phone: '2133734253', ext: '123' }

// Parses RFC 3966 phone number URIs.
parseNumber('tel:+78005553535;ext=123') === { country: 'RU', phone: '8005553535', ext: '123' }

If the phone number supplied isn't valid then an empty object {} is returned.

parseNumber('+1 111 111 1111') === {}
parseNumber('(111) 111-1111', 'US') === {}
parseNumber('abcdefg') === {}

Available options:

  • defaultCountry : string — Same as the defaultCountry argument.

  • extended : boolean — If set to true then parseNumber() will attempt to parse even a remotely hypothetical phone number even if it is considered "invalid".

{ extended: true } documentation and examples

The result of "extended" parsing is an object where

  • country is a country code.
  • phone is a national (significant) number.
  • ext is a phone number extension.
  • countryCallingCode is a country calling code.
  • carrierCodes are only used in Colombia and Brazil and only when dialing within those countries from a mobile phone to a fixed line number.
  • valid: boolean — whether it's a "valid" (real) phone number.
  • possible: boolean — a phone number is considered "possible" when it fits the phone number length rules for a given country. E.g. for US national (significant) number regexp is [2-9]\d{9} and possible national (significant) number length is 10 so a phone number (111) 111-1111 is not a "valid" number because it doesn't match the US national (significant) number regexp but it is a "possible" number because it's 10 digits long.
  • Some or all of these properties may be absent from the result object.
// If the number is valid.
parseNumber('Phone: (213) 373-4253.', 'US', { extended: true }) ===
{
  country: 'US',
  phone: '2133734253',
  ext: undefined,
  countryCallingCode: 1,
  carrierCode: undefined,
  valid: true,
  possible: true
}

// If the number is not "valid" but "possible".
parseNumber('(111) 111-1111', 'US', { extended: true }) ===
{
  country: 'US',
  phone: '1111111111',
  ext: undefined,
  countryCallingCode: 1,
  carrierCode: undefined,
  valid: false,
  possible: true
}

// If the number is not "valid" but "possible"
// and country can't be derived from it.
// (e.g. can't tell if it's a US number or a Canadian number)
parseNumber('+1 111 111 1111', { extended: true }) ===
{
  country: undefined,
  phone: '1111111111',
  ext: undefined,
  countryCallingCode: 1,
  carrierCode: undefined,
  valid: false,
  possible: true
}

// If the number is not "possible" (invalid length).
parseNumber('(213) 373', 'US', { extended: true }) ===
{
  country: 'US',
  phone: '213373',
  ext: undefined,
  countryCallingCode: 1,
  carrierCode: undefined,
  valid: false,
  possible: false
}

// In some cases if the number is extremely not "possible"
// then an empty object `{}` is returned.
//
// Too short (or too long) for any country's phone number.
parseNumber('1', 'US', { extended: true }) === {}
// Non-existent country calling code.
parseNumber('+210', { extended: true }) === {}
// No phone number found.
parseNumber('abcdefg', 'US', { extended: true }) === {}

The "extended" parsing mode is the default behaviour of the original Google's libphonenumber: it still returns parsed data even if the phone number being parsed is not considered valid (but is kinda "possible"). I guess this kind of behaviour is better for crawling websites for phone numbers because when mining "big data" it is better to extract all possible info rather than discard some pieces of it prematurely, e.g. when national (significant) number regexp for some country gets outdated which might very well happen because phone numbering plans are changing constantly around the world. Maybe after all it would make sense to make the "extended" parsing mode the default one in the next major version. I guess it would.

Also parses IDD-prefixed phone numbers

Sometimes users icorrectly input phone numbers in "out-of-country" dialing (IDD-prefixed) format instead of the proper international phone number format (the "+" notation). In such cases parseNumber() will attempt to parse such IDD-prefixed numbers if "default country" is provided:

// International format.
parseNumber('+61 2 3456 7890') === { country: 'AU', phone: '234567890' }
// IDD-prefixed format.
parseNumber('011 61 2 3456 7890', 'US') === { country: 'AU', phone: '234567890' }

formatNumber(number, format, [options])

(previously called format())

(legacy API)

Formats a number into a string according to a format.

Available formats and options are the same as for PhoneNumber.format(format).

The number argument must be either a result of parseNumber() function call (to strip national prefix) or an E.164 phone number string (e.g. +12133734253).

Examples
// Formats E.164 phone numbers.
formatNumber('+12133734253', 'NATIONAL') === '(213) 373-4253'
formatNumber('+12133734253', 'INTERNATIONAL') === '+1 213 373 4253'

// Formats E.164 phone numbers when
// they're not "valid" but still "possible".
formatNumber('+11111111111', 'NATIONAL') === '(111) 111-1111'
formatNumber('+11111111111', 'INTERNATIONAL') === '+1 111 111 1111'

// Formats E.164 phone numbers when
// they're not "valid" and not "possible" (invalid length).
formatNumber('+11111', 'NATIONAL') === '1111'
formatNumber('+11111', 'INTERNATIONAL') === '+1 1111'

// Formats a result of `parseNumber()` function call.
const parsedNumber = parseNumber('2133734253', 'US')
formatNumber(parsedNumber, 'NATIONAL') === '(213) 373-4253'
formatNumber(parsedNumber, 'INTERNATIONAL') === '+1 213 373 4253'

// Formats a result of `parseNumber()` function call in "extended" mode
// when it's not a "valid" number but is still a "possible" one.
const possibleNumber = parseNumber('+11111111111', { extended: true })
formatNumber(possibleNumber, 'NATIONAL') === '(111) 111-1111'
formatNumber(possibleNumber, 'INTERNATIONAL') === '+1 111 111 1111'

// Formats a result of `parseNumber()` function call in "extended" mode
// when it's neither a "valid" number nor a "possible" one (invalid length).
const possibleNumber = parseNumber('+11111', { extended: true })
formatNumber(possibleNumber, 'NATIONAL') === '1111'
formatNumber(possibleNumber, 'INTERNATIONAL') === '+1 1111'

// Formats phone number extensions.
formatNumber({ country: 'US', phone: '2133734253', ext: '123' }, 'NATIONAL') ===  '(213) 373-4253 ext. 123'

// When given an object not having `phone` property
// (e.g. a empty object `{}`) it will throw.
formatNumber({}) throws Error

getNumberType(number, [defaultCountry])

(legacy API)

See the description for PhoneNumber.getType().

The number argument can be either a result of the parseNumber() function call — { country, phone } — or a string (phone number digits only) possibly accompanied with the second defaultCountry argument.

Examples
getNumberType('+79160151539') === 'MOBILE'
getNumberType('9160151539', 'RU') === 'MOBILE'
getNumberType({ phone: '9160151539', country: 'RU' }) === 'MOBILE'

isValidNumber(number, [defaultCountry])

(legacy API)

Checks if a phone number is valid, the validation is more strict than parseNumber().

The number argument can be either a result of the parseNumber() function call — { country, phone } — or a string (phone number digits only) possibly accompanied with the second defaultCountry argument.

Examples
isValidNumber('+12133734253') === true
isValidNumber('+1213373') === false

isValidNumber('2133734253', 'US') === true
isValidNumber('21337', 'US') === false

isValidNumber({ phone: '2133734253', country: 'US' }) === true

The difference between using parseNumber() and isValidNumber()

The difference between using parseNumber() and isValidNumber() for phone number validation is that isValidNumber() also checks the precise regular expressions of possible phone numbers for a country. For example, for Germany parseNumber('123456', 'DE') would return { country: 'DE', phone: '123456' } because this phone number matches the general phone number rules for Germany (basic length check, etc). But, if the metadata is compiled with --extended (or relevant --types) flag (see Customizing metadata section of this document) then isValidNumber() is gonna use those precise regular expressions for extensive validation and isValid('123456', 'DE') will return false because the phone number 123456 doesn't actually exist in Germany.

This is how it is implemented in the original Google's libphonenumber: parseNumber() parses phone numbers and loosely validates them while isValidNumber() validates phone numbers precisely (provided the precise regular expressions are included in metadata).

The precise regular expressions aren't included in the default metadata because that would cause the default metadata to grow twice in its size: the complete ("full") metadata size is about 145 kilobytes while the reduced ("default") metadata size is about 77 kilobytes. Hence in the default configuration isValidNumber() performs absolutely the same "lite" validation as parseNumber(). For enabling extensive phone number validation the simplest way is to import functions from libphonenumber-js/custom module and supply them with libphonenumber-js/metadata.max.json. For generating custom metadata see the instructions provided in the Customizing metadata section of this document.

isValidNumberForRegion()

The optional defaultCountry argument is the default country, i.e. it does not restrict to just that country, e.g. in those cases where several countries share the same phone numbering rules (NANPA, Britain, etc). For example, even though the number 07624 369230 belongs to the Isle of Man ("IM" country code) calling isValidNumber('07624369230', 'GB') still returns true because the country is not restricted to GB, it's just that GB is the default one for the phone numbering rules. For restricting the country, see isValidNumberForRegion(), though restricting a country might not be a good idea.

// Even though '07624 369230' number belongs to the Isle of Man ("IM")
// the `defaultCountry` argument "GB" still works here because
// "GB" and "IM" both share the same phone numbering rules ("+44").
isValidNumber('07624369230', 'GB') === true
isValidNumber('07624369230', 'IM') === true

// Imposing country restrictions.
isValidNumberForRegion('07624369230', 'GB') === false
isValidNumberForRegion('07624369230', 'IM') === true

Using phone number validation feature

I personally don't use strict phone number validation in my projects. The rationale is that telephone numbering plans can and sometimes do change, meaning that PhoneNumber.isValid() function may one day become outdated on a website that isn't actively maintained anymore. Imagine a "promo-site" or a "personal website" being deployed once and then running for years without any maintenance, where a client may be unable to submit a simple "Contact Us" form just because this newly allocated pool of mobile phone numbers wasn't present in that old version of libphonenumber-js bundled in it.

Whenever there's a "business requirement" to validate a phone number that's being input by a user, I prefer using PhoneNumber.isPossible() instead of PhoneNumber.isValid(), so that it just validates the phone number length, and doesn't validate the actual phone number digits. But it doesn't mean that you shouldn't use PhoneNumber.isValid() — maybe in your case it would make sense.

React

If you’re trying to build a React component with this library, take a look at react-phone-number-input.

Bug reporting

This library is a simpler rewrite of Google's libphonenumber library. Basically, it mimicks Google's library behavior. Hence, as long as this library's demo page and Google's library demo page exhibit the same behavior, it's not considered a bug.

When reporting issues with:

  • Parsing
  • Validation
  • Formatting
  • "As You Type" formatting

one must provide two links:

Google's demo page outputs four sections:

  • "Parsing Result"
  • "Validation Results"
  • "Formatting Results"
  • "AsYouTypeFormatter Results"

Choose the relevant section of those four corresponding to the type of the bug you're reporting.

In a bug report:

  • First, describe the observed libphonenumber-js demo result (and provide a link to it).
  • Second, describe the observed Google's demo result (and provide a link to it).
  • The described observed result of Google's demo must be different from the described observed result of libphonenumber-js demo, otherwise it's not considered a bug. If you don't agree with Google's demo result then create an issue in Google's repo instead. If they fix it in their library, I'll port the fix to this library.

TypeScript

This library comes with TypeScript "typings". If you happen to find any bugs in those, create an issue.

CDN

One can use any npm CDN service, e.g. unpkg.com or jsdelivr.com

<script src="https://unpkg.com/libphonenumber-js@[version]/bundle/libphonenumber-[type].js"></script>

<script>
  alert(new libphonenumber.AsYouType('US').input('213-373-4253'))
</script>

where [version] is an npm package version range (for example, 1.x or ^1.7.6) and [type] is the bundle type: min, max or mobile.

Metadata

Metadata is generated from Google's PhoneNumberMetadata.xml by transforming XML into JSON and removing unnecessary fields. See metadata fields description.

Programmatic access

Metadata can be accessed programmatically by using the exported Metadata class.

First, create a Metadata class instance:

import { Metadata } from 'libphonenumber-js'

const metadata = new Metadata()

Then, select a "numbering plan" (a country):

metadata.selectNumberingPlan('US')

After that, the following methods of metadata.numberingPlan can be called:

Example:

import { Metadata } from 'libphonenumber-js'

const metadata = new Metadata()
metadata.selectNumberingPlan('US')

metadata.numberingPlan.leadingDigits() === undefined
metadata.numberingPlan.possibleLengths() === [10]
metadata.numberingPlan.IDDPrefix() === '011'
metadata.numberingPlan.defaultIDDPrefix() === undefined

Using with custom metadata:

import { Metadata } from 'libphonenumber-js/core'

import min from 'libphonenumber-js/min/metadata'
// import max from 'libphonenumber-js/max/metadata'
// import mobile from 'libphonenumber-js/mobile/metadata'

const metadata = new Metadata(min)

As one can see, the Metadata class is not documented much. Partially, that's because its usage is not necessarily encouraged, but it's still used, for example, in react-phone-number-input to get "leading digits" for a country, or to get maximum phone number length for a country. Stick to the methods documented above, don't call any other methods. If you think there's a need to call any other methods, create a discussion issue.

Customizing metadata

This library comes prepackaged with three types of metadata.

Sometimes, if only a specific set of countries is needed in a project, and a developer really wants to reduce the resulting bundle size, say, by 50 kilobytes (even when including all regular expressions for validating phone number digits and detecting phone number type), then they can generate such custom metadata and pass it as the last argument to this library's "core" functions.

See generate custom metadata instructions.

Then, use the generated metadata.custom.json file with the "core" functions.

Pass the metadata argument as the last one to the "core" functions.

In ES6 that would be:

import _parsePhoneNumber, {
  findPhoneNumbersInText as _findPhoneNumbersInText,
  AsYouType as _AsYouType
} from 'libphonenumber-js/core'

import metadata from 'libphonenumber-js/max/metadata'

function call(func, _arguments) {
  var args = Array.prototype.slice.call(_arguments)
  args.push(metadata)
  return func.apply(this, args)
}

export default function parsePhoneNumber() {
  return call(_parsePhoneNumber, arguments)
}

export function findPhoneNumbersInText() {
  return call(_findPhoneNumbersInText, arguments)
}

export function AsYouType(country) {
  return _AsYouType.call(this, country, metadata)
}
AsYouType.prototype = Object.create(_AsYouType.prototype, {})
AsYouType.prototype.constructor = AsYouType

And for Common.js environment that would be:

var core = require('libphonenumber-js/core')
var metadata = require('libphonenumber-js/max/metadata')

function call(func, _arguments) {
  var args = Array.prototype.slice.call(_arguments)
  args.push(metadata)
  return func.apply(this, args)
}

function parsePhoneNumber() {
  return call(core.default, arguments)
}

exports = module.exports = parsePhoneNumber
exports['default'] = parsePhoneNumber

exports.findPhoneNumbersInText = function findPhoneNumbersInText() {
  return call(core.findPhoneNumbersInText, arguments)
}

exports.AsYouType = function AsYouType(country) {
  return core.AsYouType.call(this, country, metadata)
}
exports.AsYouType.prototype = Object.create(core.AsYouType.prototype, {})
exports.AsYouType.prototype.constructor = exports.AsYouType

Legacy: How to use the generated metadata.custom.json file with the legacy "custom" functions.

Pass the metadata argument as the last one to the "custom" functions.

In ES6 that would be:

import {
  parseNumber,
  formatNumber,
  isValidNumber,
  getNumberType,
  AsYouType
} from 'libphonenumber-js/custom'

import metadata from 'libphonenumber-js/max/metadata'

parseNumber('+78005553535', metadata)
formatNumber({ phone: '8005553535', country: 'RU' }, metadata)
isValidNumber('+78005553535', metadata)
getNumberType('+78005553535', metadata)
new AsYouType('RU', metadata).input('+78005553535')

And for Common.js environment that would be:

var custom = require('libphonenumber-js/custom')
var metadata = require('libphonenumber-js/max/metadata')

exports.parseNumber = function parseNumber() {
  var parameters = Array.prototype.slice.call(arguments)
  parameters.push(metadata)
  return custom.parseNumber.apply(this, parameters)
}

exports.formatNumber = function formatNumber() {
  var parameters = Array.prototype.slice.call(arguments)
  parameters.push(metadata)
  return custom.formatNumber.apply(this, parameters)
}

exports.isValidNumber = function isValidNumber() {
  var parameters = Array.prototype.slice.call(arguments)
  parameters.push(metadata)
  return custom.isValidNumber.apply(this, parameters)
}

exports.getNumberType = function isValidNumber() {
  var parameters = Array.prototype.slice.call(arguments)
  parameters.push(metadata)
  return custom.getNumberType.apply(this, parameters)
}

exports.AsYouType = function AsYouType(country) {
  custom.AsYouType.call(this, country, metadata)
}

exports.AsYouType.prototype = Object.create(custom.AsYouType.prototype, {})
exports.AsYouType.prototype.constructor = exports.AsYouType

Metadata should be re-generated each time the project is being deployed because Google constantly updates their metadata.

Maintenance

Google periodically releases new metadata with the changes described in the release notes. Sometimes those are minor non-breaking updates, sometimes those are major-version breaking updates.

Metadata update process is automated through an "autoupdate" script: see autoupdate.cmd (Windows) or autoupdate.sh (Linux/macOS). The script detects changes to PhoneNumberMetadata.xml in Google libphonenumber's repo and if there are changes then it pulls the latest metadata, processes it, commits the changes to GitHub, builds a new version of the library and releases it to NPM. So this library's metadata is supposed to be up-to-date. I could set up this script to run automatically but on my Windows machine ssh-agent doesn't work properly so I run the "autoupdate" script manually from time to time.

Also Google sometimes (very rarely) updates their code:

The latest sync-up was on Mar 18th, 2024.

Contributing

After cloning this repo, ensure dependencies are installed by running:

npm install

This module is written in ES6 and uses Babel for ES5 transpilation. Widely consumable JavaScript can be produced by running:

npm run build

Once npm run build has run, you may import or require() directly from node.

After developing, the full test suite can be evaluated by running:

npm test

Test coverage must remain at 100%:

npm run test-coverage

When you're ready to test your new functionality on a real project, you can run

npm pack

It will build, test and then create a .tgz archive which you can then install in your project folder

npm install [module name with version].tar.gz

Tests

This component comes with a 100% code coverage.

To run tests:

npm test

To generate a code coverage report:

npm run test-coverage

The code coverage report can be viewed by opening ./coverage/lcov-report/index.html.

Advertisement

If you like this library then you might also like:

  • react-phone-number-input — A React component for phone number input.
  • javascript-time-ago — An international human-readable past or future date formatter. Example: "2 days ago".
  • react-time-ago — A React component for international human-readable formatting of past or future dates. Example: "2 days ago".
  • read-excel-file — A simple and easy-to-use *.xlsx file reader (client-side or server-side).
  • write-excel-file — A simple and easy-to-use *.xlsx file writer (client-side or server-side).
  • flexible-json-schema — A simple and easy-to-use *.json schema data validator / parser.
  • virtual-scroller — A universal implementation of a "virtual scroller" infinite list scrolling component: only renders the rows that fit the screen bounds.

License

Google's libphonenumber is licensed under Apache 2.

Apache 2 does not require a derivative work of the software, or modifications to the original, to be distributed using the same license. Hence, this library is licensed under MIT, which is compatible with Apache 2.

The Apache license is terminated if the user sues anyone over patent infringement related to the software covered by the license. This condition is added in order to prevent patent litigations.

libphonenumber-js's People

Contributors

asaarnak avatar audiolion avatar badaz avatar belar avatar breathe avatar bvluong avatar catamphetamine avatar chafel avatar estebanav avatar gertsallaerts avatar gsharishkumar avatar hbouhadji avatar ipoddubny avatar jackphilippi avatar jinhoso avatar justingrant avatar leonascimento avatar lucsky avatar msheakoski avatar othree avatar purecatamphetamine avatar richeterre avatar ronnewcomb avatar sebastien-cleany avatar skfd avatar skyuplam avatar take-cheeze avatar trysound avatar westcoastsuccess avatar wolfwalter avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libphonenumber-js's Issues

Issue with asYouType and invalid phone numbers

Hi there, I've been using this library in my project and it's been working great. Thanks for making it available.

There's however one issue with the asYouType functionality that I have not been able to work around.

If I enter a sequence of digits followed by a plus sign (e.g. 1234+) the formatter returns just the numbers (1234). Then any subsequent digit entered will result in an empty string (1234+5 => empty)

My expectation is that the moment the input starts looking like an invalid number, the formatter should just return the original input. At least this is how the dialpad on iPhone works.

Invalid phone number when it should be valid

Hello,

I was running tests with australian numbers when I found that "413071810" is not valid if there's no "0" before it i.e. "0413071810"

I verified that Google's Javascript demo does recognize "413071810" as a valid number for Australia(AU) https://rawgit.com/googlei18n/libphonenumber/master/javascript/i18n/phonenumbers/demo-compiled.html

In Australia is normal to use "04" or "4" for mobile numbers. Also Safari autofill feature adds Australian mobile numbers without the zero that's how I found this problem.

Some countries are missing

I was trying to use the getPhoneCode method for Bulgaria (country code 'BU') and the library have failed with an error breaking the page.

 error      TypeError: Cannot read property '0' of undefined
    at get_phone_code (eval at <anonymous> (), <anonymous>:31:25)
    at getPhoneCodeCustom (eval at <anonymous> (), <anonymous>:107:101)
    at Object.getPhoneCode [as a] (eval at <anonymous> (), <anonymous>:102:9)

I have noticed that the https://github.com/halt-hammerzeit/libphonenumber-js/blob/master/metadata.min.json does not include BU as a country.

I could go and regenerate the metadata file to get that country code from the Google library, but I think it would be nicer to have some kind of handling country codes that are not supported in a better way. Some examples are :

  1. Make the function return undefined
  2. Make the function throw an error with a message "BU is not a supported country"

The bundle folder for libphonenumber-js.min.js not created when running "npm run browser-build"

I've given it another try but the "bundle" folder is not created after running command: npm run browser-build
No error though. Just be sure, I'm trying to generate the standalone libphonenumber-js.min.js file.

Here a CMD extract:

C:\JS_LIB02\libphonenumber-js>npm run browser-build

[email protected] browser-build C:\JS_LIB02\libphonenumber-js
better-npm-run browser-build

running better-npm-run in C:\JS_LIB02\libphonenumber-js
Executing script: browser-build

to be executed: "npm run build-es6-modules"

[email protected] build-es6-modules C:\JS_LIB02\libphonenumber-js
better-npm-run build-es6-modules

running better-npm-run in C:\JS_LIB02\libphonenumber-js
Executing script: build-es6-modules

to be executed: "babel ./source --out-dir ./es6 --source-maps"
source\as you type.js -> es6\as you type.js
source\common.js -> es6\common.js
source\format.js -> es6\format.js
source\metadata.js -> es6\metadata.js
source\parse.js -> es6\parse.js
source\tools\compress.js -> es6\tools\compress.js
source\tools\download.js -> es6\tools\download.js
source\tools\generate.js -> es6\tools\generate.js
source\validate.js -> es6\validate.js

C:\JS_LIB02\libphonenumber-js>

npm metadata:update script broken

As per the instructions in the README to update the Metadata from Google's repo, I executed

$ npm run metadata:update

This downloaded the latest XML file but the script failed when it checked how many files had been modified. See here.

The problem is that the update.js script executes metadata:generate which regenerates all the metadata files including min, full, and mobile. So when update.js checks how many files have been modified, it fails because too many have been changed.

The way I see it, there's 2 ways to fix this depending on what the intent of the update.js script is.

  • If ALL the metadata files should be regenerated then update.js should be updated to expect at most 4 files to be changed

    • PhoneNumberMetadata.xml
    • metadata.full.json
    • metadata.min.json
    • metadata.mobile.json
  • If only the XML and min metadata files should be updated then update.js should execute metadata:generate:min instead.

I don't mind submitting a PR with either one of these changes, just let me know which one it should be.

bundle/browser build gives error `libphonenumber is not defined`

I'm trying to use this in the browser on codepen.io, but when I try to use the library with libphonenumber-js, it gives me an error Uncaught RferenceError: libphonenumber is not defined. It works if I instead do window['libphonenumber-js'].asYouType.

The name libphonenumber-js is a strange name to use in browser javascript. I get that it works well with es6 imports import {asYouType} from 'libphonenumber-js';; is there any way to support LibPhoneNumberJS in the browser build?

angular2 and SystemJS import

After installing through npm in my angular 2 app and updating my SystemJS config.ts to include

'libphonenumber-js': 'npm:angular-libphonenumber/index.es6.js'

and including
import { parse, format, asYouType } from 'libphonenumber-js'; in my @directive and @NgModule, I'm still getting "Cannot find module 'libphonenumber-js'"

Do I need to do anything else specific to install this into my ng2 app?

Make customized metadata work for TypeScript + Angular4 + WebPack2

Hi,

I'm using your library for my application which is built using TS+Angular4+WebPack2. I could use the library with default metadata.min.json without any issues. But, I see some issues while using a customized metadata of the library.

Details:

  1. I generated the metadata.min.json file using "libphonenumber-metadata": "libphonenumber-generate-metadata metadata.min.json --types mobile" and "npm run libphonenumber-metadata".
  2. I created a new TS file, metadata.ts. I have attached the file (as a .txt version).
  3. When I try to use asYouType like, this.inputPhoneNumber = new asYouTypeCustom('US').input(this.inputPhoneNumber);
    TypeScript compiler is throwing the error, property 'input' doesn't exist on type 'asYouType'.
  4. To avoid the error, I modified the line to, this.inputPhoneNumber = new asYouTypeCustom('US').input(this.inputPhoneNumber);
    It resolved the issue mentioned in the above step. But, I know that is not what is expected.
  5. Now, I see console errors saying metadata is not passed to asYouType(). This is happening is because the metadata that got imported from 'metadata.json' doesn't have any value and it is undefined.

To sum it up, I have two issues. One is 'input' isn't available on asYouType and 'metadata' variable doesn't have any data after importing from the JSON.

I'm not sure whether I'm using the customized version properly or the code doesn't support TypeScript.
Can you please help me out to resolve my issue?

Attached two files, metadata.txt and phone-number.txt.
metadata.txt
phone-number.txt

Thank you in advance.

npm browser-build fails

When I build using npm for browser, I get the following error log. I can send over npm-debug.log if needed.
I tried installing various version of node/npm version combinations (including the latest).

[email protected] browser-build \JS_LIB\libphonenumber-js
npm run build-es6-modules && WEBPACK_ENV=build webpack

[email protected] build-es6-modules \JS_LIB\libphonenumber-js
better-npm-run build-es6-modules

running better-npm-run in \JS_LIB\libphonenumber-js
Executing script: build-es6-modules

to be executed: "babel ./source --out-dir ./es6 --source-maps"
source\as you type.js -> es6\as you type.js
source\common.js -> es6\common.js
source\format.js -> es6\format.js
source\metadata.js -> es6\metadata.js
source\parse.js -> es6\parse.js
source\tools\compress.js -> es6\tools\compress.js
source\tools\download.js -> es6\tools\download.js
source\tools\generate.js -> es6\tools\generate.js
source\validate.js -> es6\validate.js
'WEBPACK_ENV' is not recognized as an internal or external command,
operable program or batch file.

npm ERR! Windows_NT 6.3.9600
npm ERR! argv "C:\Program Files\nodejs\node.exe" "AppData\Roaming\npm\node_modules\npm\bin\npm-cli.js" "run" "browser-build"
npm ERR! node v5.10.1
npm ERR! npm v3.8.3
npm ERR! code ELIFECYCLE
npm ERR! [email protected] browser-build: npm run build-es6-modules && WE BPACK_ENV=build webpack
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] browser-build script 'npm run bui
ld-es6-modules && WEBPACK_ENV=build webpack'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the libphonenumber-js pac
kage,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! npm run build-es6-modules && WEBPACK_ENV=build webpack
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs libphonenumber-js
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls libphonenumber-js
npm ERR! There is likely additional logging output above.

Unable to generate custom metadata with example script "scriptlibphonenumber-metadata"

Hey Nikolay

I followed the new docs for generating a set of custom metadata but the example script provided in the docs fails to execute with the following error: sh: libphonenumber-generate-metadata: command not found. This is the script I've included into the package.js: "libphonenumber-metadata": "libphonenumber-generate-metadata metadata.min.json --countries DE --extended",.

What works for me though is the following script: "libphonenumber-metadata": "node bin/update-metadata metadata.min.json --countries DE --extended",.

asYouType returning null

Repro steps:

console.log(new asYouType('US').input('12')

Expected Output:
(12 )

Actual Output:
(null) 2 -

invalid format Ghana phone numbers

numbers like this:
233111111111
it formats like:
233 233111111111

//test
import { format } from 'libphonenumber-js'

it('Ghana phone',()=>{
const phone = format('233111111111', 'GH', 'International')
expect(phone).toBe('+233111111111')
})

Error in installing dependencies

Facing issue while installing libphonenumber-js dependencies to update metadata.

me@:libphonenumber-js$ node -v
v6.9.4
me@:libphonenumber-js$ npm -v
3.10.10

Below is the error-

Executing script: build-commonjs-modules

to be executed: babel ./source --out-dir ./build --source-maps 
source/as you type.js -> build/as you type.js
source/common.js -> build/common.js
source/format.js -> build/format.js
source/metadata.js -> build/metadata.js
SyntaxError: source/parse.js: Unexpected token (216:14)
  214 |         if (!options)
  215 |         {
> 216 |                 options = { ...default_options }
      |                             ^
  217 |         }
  218 | 
  219 |         // Validate country codes

is valid with 0 prefix

First off, let me say i LOVE your library, it's so easy to use and works amazing well. Thank you a million times over.

Not sure what i am doing wrong but i want to know how to handle the use case when a number has a 0 in the national portion like so:

+33 0 6 12 34 56 78 === this validates as valid but it really is not and also it does not get formatted properly

the correct number is

+33 6 12 34 56 78 which this time gets returned properly as +33-6-12-34-56-78

with the 0 the format is not applied but funny enough in the as you type function it shows the number properly formatted with the 0 removed.

For now i found a bypass method wher i reconstruct the number like so and it works nicely but i figured i would give you a shout:

                                 var tempPhoneNumber = '+' + formatter.country_phone_code + parse(phoneNumber).phone

and then:

                                tempPhoneNumber = format(tempPhoneNumber, parse(tempPhoneNumber).country, 'International')
				
				var regEx = new RegExp(' ', 'g') //remove the space and replace with "-" dash
				tempPhoneNumber = tempPhoneNumber.replace(regEx, '-')

Add findNumbers functionality from libphonenumber

Hi,
we are currently using this awesome port for parsing and formatting phone numbers.
Is there a plan to also implement the findNumbers functionality from libphonenumber?

I can help with implementing if that's on the plan... 🍻

libphonenumber-metadata not so clear

{
"scripts": {
"libphonenumber-metadata": "libphonenumber-generate-metadata metadata.min.json --countries RU,DE --extended",
}
}

when we add the script to package.json and run the command as explained, there is an error it is not generating the json with extended data

Brazilian numbers not recognized

The brazilians numbers are not recognize, unless a zero is added in the beggining of the input.
In the demo page, if I put the number 11987654321 with country as BR, that number is not recognized. But if I add the zero in the beggining, the number is recognized and formatted as expected.

How to prevent entering next digit if the longest number is achieved?

Hello!
Could you please advise me how to prevent entering next digit if the longest number is achieved for the given country?
I can not rely on the validation result, for small length, it returns false too.
Maximum lengths for a country are different, so I can not just set it to 15.

Return also country_phone_code from parse

First of all, thanks for the nice library!

One small improvement came into my mind: why not return also country_phone_code from parse(), i.e. instead of:

let parse = require('libphonenumber-js').parse
parse('+358401234567')
// { country: 'FI', phone: '401234567' }
parse('0401234567', 'FI')
// { country: 'FI', phone: '401234567' }

we'd get this:

let parse = require('libphonenumber-js').parse
parse('+358401234567')
// { country: 'FI', phone: '401234567', country_phone_code: '358' }
parse('0401234567', 'FI')
// { country: 'FI', phone: '401234567', country_phone_code: '358' }

Ok, I am aware that you could do it with asYouType:

let asYouType = require('libphonenumber-js').asYouType
let formatter = new asYouType()
formatter.input('+358401234567')
// '+358 40 1234567'
formatter.country
// 'FI'
formatter.country_phone_code
// '358'
formatter.national_number
// '401234567'

but for me it would make sense to include the country_phone_code also to parse() result.

If you feel this would be a welcome addition to the library, I'm more than happy to provide a pull request that would provide this functionality!

Country names

do we get the country names along with the country codes?

Metadata loading fails

I'm trying to load the library like this: import { parse, format } from 'libphonenumber-js'; and gives me an error during build.

ERROR in ./~/libphonenumber-js/metadata.min.json
Module parse failed: ./node_modules/libphonenumber-js/metadata.min.json Unexpected token (1:34)
You may need an appropriate loader to handle this file type.

I'm using ES6+, babel and Vue 2 with Laravel as framework

Parse doesn't detect KZ country

At the demo page:
The number +7 702 211 1111
AsYouType detects KZ correctly
Parse doesn't detect any country
Format doesn't detect any country

Different output when parsing

Hello,

I tried to check the validity of +33169454850 like this:

var libphonenumber = window['libphonenumber-js'];
document.body.innerText = libphonenumber.isValidNumber('+33169454850');

demo

And got "false", but "true" when I try on the official project demo.

What did I miss?

Thank you!

Problems in IE 11

Hi,
first, thanks for developing on this great library ;).

I detected a problem in Internet Explorer 11:
I get the following error if my App starts:

Unhandled rejection Error: Nicht genügend Stackspeicher.
   at __symbol:iterator0.51182658601296831.set (http://localhost/HelpdeskApp/assets/vendor.js:83134:12)
   at __symbol:iterator0.51182658601296831.set (http://localhost/HelpdeskApp/assets/vendor.js:83134:12)
   at __symbol:iterator0.51182658601296831.set (http://localhost/HelpdeskApp/assets/vendor.js:83134:12)
   at __symbol:iterator0.51182658601296831.set (http://localhost/HelpdeskApp/assets/vendor.js:83134:12)
   at __symbol:iterator0.51182658601296831.set (http://localhost/HelpdeskApp/assets/vendor.js:83134:12)
   at __symbol:iterator0.51182658601296831.set (http://localhost/HelpdeskApp/assets/vendor.js:83134:12)
   at __symbol:iterator0.51182658601296831.set (http://localhost/HelpdeskApp/assets/vendor.js:83134:12)
   at __symbol:iterator0.51182658601296831.set (http://localhost/HelpdeskApp/assets/vendor.js:83134:12)
   at __symbol:iterator0.51182658601296831.set (http://localhost/HelpdeskApp/assets/vendor.js:83134:12)
   at __symbol:iterat

This only happens in IE, not in Chrome. I think is is a problem with the metadata.min.json which cannot be handled or loaded from IE. Maybe it's too big.

I use Webpack 1 for Bundling the application.

Thanks for your investigation.

Consider documenting required webpack configuration

libphonenumbers-js needs:

  • the JSON loader: {test: /\.json$/, loader: 'json'} in config.module.rules

  • '.json' in config.resolve.extensions (perhaps it would be easier to just reference the data file with the full name .min.json)

Note -- this is a webpack2 configuration.

UK National 03xxxxxxx landline not valid

Tried to run this number through the parser and it is supposedly invalid however the google libphonenumber demo says it's ok: 03300 881288. Just to confirm, it is a valid phone number :) Interestingly, replacing the 03 with +443 satisfies the parser.

Parse Options Issue

Your js version is fantastic so far, so thank you =) However, I'm running in to one issue where I'm trying to parse a phone number but don't want to force a country code. I'd like it to figure out based on what is typed. But when I create the options object and pass it in to parse, I get this error:

Uncaught TypeError: Cannot read property 'default' of undefined
at e (libphonenumber-js.min.js:1)
at new e (libphonenumber-js.min.js:4)

I've tried multiple ways to create an object with different values for your two fields:

var options = {};
options.restrict = '';
options.default = 'US';

Thanks, Mike

Proper usage for AsYouType formatter

Hello!

Thank you for this great module!

However, I'm trying to use AsYouType formatter in order to format user input in my Angular 2 application.

I'm creating an instance of asYouType with the input component and I can feed new numbers to it by listening to the keyup event of the input element: input.value = formatter.input(event.key); and it works great. But, when I press backspace it continues to render previous value, because it doesn't know about removed character. So, how do I tell it to actually remove one character?

The only workaround I've found so far is to create new instance of the formatter on each keyup event and to feed entire input value to it. It works flawlessly, but it's terrible from the design perspective and probably performance (creating a new instance of the object and calling a function on it is probably a serious overkill).

How do I use it correctly and at the same time achieve better design and performance?

Thanks!

Add a release

Hello,

If the lib is ready to use, could you release one?

Thank you

Cheers,

Issue with Reunion

Hello again,

i hope i am not doing anything wrong, but i see nothing for reunion in 262 country code, is the issue just on my side?

libphonenumber.isValidNumber not wirking as expected

libphonenumber.isValidNumber(mobile_number, country_code) returns true for invalid numbers as well.

For example, i enetered
country_code - DE
mobile number : 1755892292222222222
function returns true as a result, is there something wrong in the library?

The getNumberType function return undefined

I have generated full size metadata.json :

> libphonenumber-generate-metadata app/metadata.min.json --extended

Metadata path: /Users/chaofeis/beary/pensieve/app/metadata.min.json
Include extra validation regular expressions
========================================
=       Metadata has been updated      =
========================================

and I run below codes:

 node
> var lib = require('libphonenumber-js');
undefined
> lib.getNumberType('13453965555', 'CN');
undefined
> lib.getNumberType('13453965555', 'CN') === 'MOBILE';
false
> lib.getNumberType('13453965555', 'CN') === undefined;
true

npm browser-build fails

When I build using npm for browser, I get the following error log. I can send over npm-debug.log if needed.

> [email protected] browser-build /home/divick/work/external/libphonenumber-js
> WEBPACK_ENV=build webpack

/home/divick/work/external/libphonenumber-js/node_modules/webpack/lib/Compiler.js:324
					content = Buffer.from(content, "utf8");
					                 ^

TypeError: utf8 is not a function
    at Function.from (native)
    at Function.from (native)
    at Compiler.writeOut (/home/divick/work/external/libphonenumber-js/node_modules/webpack/lib/Compiler.js:324:23)
    at Compiler.<anonymous> (/home/divick/work/external/libphonenumber-js/node_modules/webpack/lib/Compiler.js:312:20)
    at /home/divick/work/external/libphonenumber-js/node_modules/webpack/node_modules/async/dist/async.js:3025:16
    at eachOfArrayLike (/home/divick/work/external/libphonenumber-js/node_modules/webpack/node_modules/async/dist/async.js:941:9)
    at eachOf (/home/divick/work/external/libphonenumber-js/node_modules/webpack/node_modules/async/dist/async.js:991:5)
    at Object.eachLimit (/home/divick/work/external/libphonenumber-js/node_modules/webpack/node_modules/async/dist/async.js:3089:3)
    at Compiler.emitFiles (/home/divick/work/external/libphonenumber-js/node_modules/webpack/lib/Compiler.js:301:20)
    at /home/divick/work/external/libphonenumber-js/node_modules/mkdirp/index.js:48:26
    at FSReqWrap.oncomplete (fs.js:82:15)

npm ERR! Linux 3.13.0-37-generic
npm ERR! argv "/home/divick/.nvm/versions/node/v5.0.0/bin/node" "/home/divick/.nvm/versions/node/v5.0.0/bin/npm" "run" "browser-build"
npm ERR! node v5.0.0
npm ERR! npm  v3.3.6
npm ERR! code ELIFECYCLE
npm ERR! [email protected] browser-build: `WEBPACK_ENV=build webpack`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] browser-build script 'WEBPACK_ENV=build webpack'.
npm ERR! This is most likely a problem with the libphonenumber-js package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     WEBPACK_ENV=build webpack
npm ERR! You can get their info via:
npm ERR!     npm owner ls libphonenumber-js
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /home/divick/work/external/libphonenumber-js/npm-debug.log

Local swedish mobile phone numbers breaks the as you type formatter

Whats wrong
Typing a local Swedish mobile phone number (with default country set to: SE) in the as you type formatter in the demo makes the caret move unexpectedly.

How to reproduce
Entering a valid local mobile phone number, for example the prefix 077 followed by 1234567. This leads to the number being formatted as 077-123 46 75. The 5 is in the end instead of after 4.

The caret seems to jump when the dash-character moves and the spacing changes as you type 5.

Expected behaviour
The number should be formatted as 077-123 45 67.

Failed running script liphonenumber-generate-metadata

Hi I'm trying to create a custom metadata but I get the following error:

`

root@ip-172-31-5-150:/home/ubuntu/libphonenumber-js# npm run-script libphonenumber-metadata

> [email protected] libphonenumber-metadata /home/ubuntu/libphonenumber-js
> libphonenumber-generate-metadata metadata.min.json --extended

sh: 1: libphonenumber-generate-metadata: not found

npm ERR! Linux 3.13.0-112-generic
npm ERR! argv "/usr/bin/nodejs" "/usr/bin/npm" "run-script" "libphonenumber-metadata"
npm ERR! node v7.8.0
npm ERR! npm  v4.2.0
npm ERR! file sh
npm ERR! code ELIFECYCLE
npm ERR! errno ENOENT
npm ERR! syscall spawn
npm ERR! [email protected] libphonenumber-metadata: `libphonenumber-generate-metadata metadata.min.json --extended`
npm ERR! spawn ENOENT
npm ERR!
npm ERR! Failed at the [email protected] libphonenumber-metadata script 'libphonenumber-generate-metadata metadata.min.json --extended'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the libphonenumber-js package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     libphonenumber-generate-metadata metadata.min.json --extended
npm ERR! You can get information on how to open an issue for this project with:
npm ERR!     npm bugs libphonenumber-js
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!     npm owner ls libphonenumber-js
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR!     /root/.npm/_logs/2017-03-29T23_04_03_471Z-debug.log
root@ip-172-31-5-150:/home/ubuntu/libphonenumber-js#`

metadata update error under node version >= 7.0.3

Hi,

Just caught an error while building custom metadata:

> [email protected] postinstall /Users/user/Documents/Projects/secret-frontend
> libphonenumber-generate-metadata ./app/js/utils/libs/libphonenumber-metadata.json --countries RU --extended

Metadata path: /Users/user/Documents/Projects/secret-frontend/app/js/utils/libs/libphonenumber-metadata.json
Included countries: [ 'RU' ]
Include extra validation regular expressions
/Users/user/Documents/Projects/secret-frontend/node_modules/libphonenumber-js/bin/update-metadata.js:43
download('https://raw.githubusercontent.com/googlei18n/libphonenumber/master/resources/PhoneNumberMetadata.xml')
^

TypeError: download is not a function
    at Object.<anonymous> (/Users/user/Documents/Projects/secret-frontend/node_modules/libphonenumber-js/bin/update-metadata.js:43:1)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.runMain (module.js:605:10)
    at run (bootstrap_node.js:420:7)
    at startup (bootstrap_node.js:139:9)
    at bootstrap_node.js:535:3

Fixed by adding .default to imports in bin/update-metadata:

var download = require('../build/tools/download').default
var generate = require('../build/tools/generate').default
var compress = require('../build/tools/compress').default

Command was called as:
"postinstall": "libphonenumber-generate-metadata ./app/js/utils/libs/libphonenumber-metadata.json --countries RU --extended"

Node:

10:secret-frontend user$ node -v
v7.3.0
10:secret-frontend user$ npm -v
4.0.5

Thank you for this lib very much!

Use a CDN

Hello,

It would be nice to be able to use libphonenumber through a CDN (like cdnjs).

What do you think?

Inconsistency between isValidNumber and the valid property of asYouType

Hey!

First of all thank you for providing this alternative to the official library provided by Google.

isValidNumber() returns true for the invalid german phone number '123456' while the valid property of asYouType returns false as expected/desired. isValidNumber() uses parse() internally which strips the national prefix.

If this behavior is desired then I believe it must be documented more clearly in the README.md.

Question: Is it possible to specify that you only want mobile numbers (without loading all other types via extend)?

Hi,

I'd like to only accept mobile numbers as input.
In the old libphonenumber code, I was checking through all the types, and only accepting the number if it was a mobile number. I could do the same with your library, but as you say, the resulting file size is considerably bigger if you want to support "number types".
My question is whether the library could be extended to to generate the metadata only for mobile number types, e.g. with flags as follows: --countries DE --number_types mobile
Then when parsing a number, and calling get_number_type, non-mobile numbers would report a type of "unknown" and valid mobile numbers would return type "mobile". I would assume there would be a size saving over using --extended option (which supports all phone number types).

If you have advice on how to achieve this, it would be greatly appreciated.

Thanks
Rob

asYouType incorrectly formats some NZ numbers

The as-you-type formatter could return incorrect values for inputs with less than 5 digits.

new asYouType("NZ").input("0212") returns 02-12, which is incorrect as there is no 02 area code in NZ. Should return 021 2.

new asYouType("NZ").input("02122") returns 021 22, which is correct

Whereas google's as-you-type formatter will correctly return 021 2.

See https://en.wikipedia.org/wiki/List_of_dialling_codes_in_New_Zealand

Edit: similar thing happens when inputting +64212; returns +64 2 12, when it should be +64 21 2

Some questions

Hi @halt-hammerzeit,
first, thank you that you are working on this library!!

I've some questions to you:

  • The files inside source/tools seems to be helper scripts and not part of the library at runtime, right?
  • This means that "bluebird", "minimist" and "xml2js" should be devDependencies?
  • Do you think, that there's a way that babel-runtime does not become a runtime dependency? (I use this lib in a typescript project without any dependencies to babel)
  • Is it possible to split the metadata.min.json to single json files for each supported language to reduce the bundle size in projects which use this library?

General:

  • bin/update-metadata.js and the contents of runnable seems to be helper scripts too?
  • There are different Promise implementations used (native in download.js, Bluebird in generate.js)

Thanks!!

getNumberType always return undefined for Indonesia Phone Number

Hi,
I try to check whether my input is an Indonesia Phone Number or not by using getNumberType function, but i always get "undefined" although I input my correct phone number,
Any idea or suggestion is really appreciated.

const numberType = getNumberType(value, 'ID');
  if( numberType !== 'MOBILE'){
    return errorMessage;
  }

Some GB numbers showing invalid

This is a number I stumbled across while testing, it's for the Park Plaza Westminster Bridge London hotel and it shows as invalid

isValidNumber('+44 844 415 6790', 'GB') == false

Loader Problem

screenshot 2017-01-10 17 53 57

I am just importing parse and asyoutype!
And this is the error I get while compiling!
I have added json-loader as suggested but still the problem persists!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.