123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- import {
- VALID_DIGITS,
- PLUS_CHARS,
- MIN_LENGTH_FOR_NSN,
- MAX_LENGTH_FOR_NSN
- } from './constants.js'
- import ParseError from './ParseError.js'
- import Metadata from './metadata.js'
- import isViablePhoneNumber, { isViablePhoneNumberStart } from './helpers/isViablePhoneNumber.js'
- import extractExtension from './helpers/extension/extractExtension.js'
- import parseIncompletePhoneNumber from './parseIncompletePhoneNumber.js'
- import getCountryCallingCode from './getCountryCallingCode.js'
- import { isPossibleNumber } from './isPossible.js'
- import PhoneNumber from './PhoneNumber.js'
- import matchesEntirely from './helpers/matchesEntirely.js'
- import extractCountryCallingCode from './helpers/extractCountryCallingCode.js'
- import extractNationalNumber from './helpers/extractNationalNumber.js'
- import stripIddPrefix from './helpers/stripIddPrefix.js'
- import getCountryByCallingCode from './helpers/getCountryByCallingCode.js'
- import extractFormattedPhoneNumberFromPossibleRfc3966NumberUri from './helpers/extractFormattedPhoneNumberFromPossibleRfc3966NumberUri.js'
- const MAX_INPUT_STRING_LENGTH = 250
- const PHONE_NUMBER_START_PATTERN = new RegExp('[' + PLUS_CHARS + VALID_DIGITS + ']')
- const AFTER_PHONE_NUMBER_END_PATTERN = new RegExp('[^' + VALID_DIGITS + '#' + ']+$')
- const USE_NON_GEOGRAPHIC_COUNTRY_CODE = false
- export default function parse(text, options, metadata) {
-
-
- options = options || {}
- metadata = new Metadata(metadata)
-
- if (options.defaultCountry && !metadata.hasCountry(options.defaultCountry)) {
- if (options.v2) {
- throw new ParseError('INVALID_COUNTRY')
- }
- throw new Error(`Unknown country: ${options.defaultCountry}`)
- }
-
- const { number: formattedPhoneNumber, ext, error } = parseInput(text, options.v2, options.extract)
-
- if (!formattedPhoneNumber) {
- if (options.v2) {
- if (error === 'TOO_SHORT') {
- throw new ParseError('TOO_SHORT')
- }
- throw new ParseError('NOT_A_NUMBER')
- }
- return {}
- }
- const {
- country,
- nationalNumber,
- countryCallingCode,
- countryCallingCodeSource,
- carrierCode
- } = parsePhoneNumber(
- formattedPhoneNumber,
- options.defaultCountry,
- options.defaultCallingCode,
- metadata
- )
- if (!metadata.hasSelectedNumberingPlan()) {
- if (options.v2) {
- throw new ParseError('INVALID_COUNTRY')
- }
- return {}
- }
-
- if (!nationalNumber || nationalNumber.length < MIN_LENGTH_FOR_NSN) {
-
-
- if (options.v2) {
- throw new ParseError('TOO_SHORT')
- }
-
- return {}
- }
-
-
-
-
-
-
-
-
-
- if (nationalNumber.length > MAX_LENGTH_FOR_NSN) {
- if (options.v2) {
- throw new ParseError('TOO_LONG')
- }
-
- return {}
- }
- if (options.v2) {
- const phoneNumber = new PhoneNumber(
- countryCallingCode,
- nationalNumber,
- metadata.metadata
- )
- if (country) {
- phoneNumber.country = country
- }
- if (carrierCode) {
- phoneNumber.carrierCode = carrierCode
- }
- if (ext) {
- phoneNumber.ext = ext
- }
- phoneNumber.__countryCallingCodeSource = countryCallingCodeSource
- return phoneNumber
- }
-
-
-
- const valid = (options.extended ? metadata.hasSelectedNumberingPlan() : country) ?
- matchesEntirely(nationalNumber, metadata.nationalNumberPattern()) :
- false
- if (!options.extended) {
- return valid ? result(country, nationalNumber, ext) : {}
- }
-
- return {
- country,
- countryCallingCode,
- carrierCode,
- valid,
- possible: valid ? true : (
- options.extended === true &&
- metadata.possibleLengths() &&
- isPossibleNumber(nationalNumber, metadata) ? true : false
- ),
- phone: nationalNumber,
- ext
- }
- }
- function extractFormattedPhoneNumber(text, extract, throwOnError) {
- if (!text) {
- return
- }
- if (text.length > MAX_INPUT_STRING_LENGTH) {
- if (throwOnError) {
- throw new ParseError('TOO_LONG')
- }
- return
- }
- if (extract === false) {
- return text
- }
-
- const startsAt = text.search(PHONE_NUMBER_START_PATTERN)
- if (startsAt < 0) {
- return
- }
- return text
-
- .slice(startsAt)
-
- .replace(AFTER_PHONE_NUMBER_END_PATTERN, '')
- }
- function parseInput(text, v2, extract) {
-
-
-
-
-
- let number = extractFormattedPhoneNumberFromPossibleRfc3966NumberUri(text, {
- extractFormattedPhoneNumber: (text) => extractFormattedPhoneNumber(text, extract, v2)
- })
-
- if (!number) {
- return {}
- }
- if (!isViablePhoneNumber(number)) {
- if (isViablePhoneNumberStart(number)) {
- return { error: 'TOO_SHORT' }
- }
- return {}
- }
-
-
- const withExtensionStripped = extractExtension(number)
- if (withExtensionStripped.ext) {
- return withExtensionStripped
- }
- return { number }
- }
- function result(country, nationalNumber, ext) {
- const result = {
- country,
- phone: nationalNumber
- }
- if (ext) {
- result.ext = ext
- }
- return result
- }
- function parsePhoneNumber(
- formattedPhoneNumber,
- defaultCountry,
- defaultCallingCode,
- metadata
- ) {
-
- let { countryCallingCodeSource, countryCallingCode, number } = extractCountryCallingCode(
- parseIncompletePhoneNumber(formattedPhoneNumber),
- defaultCountry,
- defaultCallingCode,
- metadata.metadata
- )
-
- let country
- if (countryCallingCode) {
- metadata.selectNumberingPlan(countryCallingCode)
- }
-
-
- else if (number && (defaultCountry || defaultCallingCode)) {
- metadata.selectNumberingPlan(defaultCountry, defaultCallingCode)
- if (defaultCountry) {
- country = defaultCountry
- } else {
-
- if (USE_NON_GEOGRAPHIC_COUNTRY_CODE) {
- if (metadata.isNonGeographicCallingCode(defaultCallingCode)) {
- country = '001'
- }
- }
- }
- countryCallingCode = defaultCallingCode || getCountryCallingCode(defaultCountry, metadata.metadata)
- }
- else return {}
- if (!number) {
- return {
- countryCallingCodeSource,
- countryCallingCode
- }
- }
- const {
- nationalNumber,
- carrierCode
- } = extractNationalNumber(
- parseIncompletePhoneNumber(number),
- metadata
- )
-
-
-
-
-
-
-
-
-
-
- const exactCountry = getCountryByCallingCode(countryCallingCode, {
- nationalNumber,
- defaultCountry,
- metadata
- })
- if (exactCountry) {
- country = exactCountry
-
- if (exactCountry === '001') {
-
-
-
- } else {
- metadata.country(country)
- }
- }
- return {
- country,
- countryCallingCode,
- countryCallingCodeSource,
- nationalNumber,
- carrierCode
- }
- }
|