extractFormattedPhoneNumberFromPossibleRfc3966NumberUri.js 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. import extractPhoneContext, {
  2. isPhoneContextValid,
  3. PLUS_SIGN,
  4. RFC3966_PREFIX_,
  5. RFC3966_PHONE_CONTEXT_,
  6. RFC3966_ISDN_SUBADDRESS_
  7. } from './extractPhoneContext.js'
  8. import ParseError from '../ParseError.js'
  9. /**
  10. * @param {string} numberToParse
  11. * @param {string} nationalNumber
  12. * @return {}
  13. */
  14. export default function extractFormattedPhoneNumberFromPossibleRfc3966NumberUri(numberToParse, {
  15. extractFormattedPhoneNumber
  16. }) {
  17. const phoneContext = extractPhoneContext(numberToParse)
  18. if (!isPhoneContextValid(phoneContext)) {
  19. throw new ParseError('NOT_A_NUMBER')
  20. }
  21. let phoneNumberString
  22. if (phoneContext === null) {
  23. // Extract a possible number from the string passed in.
  24. // (this strips leading characters that could not be the start of a phone number)
  25. phoneNumberString = extractFormattedPhoneNumber(numberToParse) || ''
  26. } else {
  27. phoneNumberString = ''
  28. // If the phone context contains a phone number prefix, we need to capture
  29. // it, whereas domains will be ignored.
  30. if (phoneContext.charAt(0) === PLUS_SIGN) {
  31. phoneNumberString += phoneContext
  32. }
  33. // Now append everything between the "tel:" prefix and the phone-context.
  34. // This should include the national number, an optional extension or
  35. // isdn-subaddress component. Note we also handle the case when "tel:" is
  36. // missing, as we have seen in some of the phone number inputs.
  37. // In that case, we append everything from the beginning.
  38. const indexOfRfc3966Prefix = numberToParse.indexOf(RFC3966_PREFIX_)
  39. let indexOfNationalNumber
  40. // RFC 3966 "tel:" prefix is preset at this stage because
  41. // `isPhoneContextValid()` requires it to be present.
  42. /* istanbul ignore else */
  43. if (indexOfRfc3966Prefix >= 0) {
  44. indexOfNationalNumber = indexOfRfc3966Prefix + RFC3966_PREFIX_.length
  45. } else {
  46. indexOfNationalNumber = 0
  47. }
  48. const indexOfPhoneContext = numberToParse.indexOf(RFC3966_PHONE_CONTEXT_)
  49. phoneNumberString += numberToParse.substring(indexOfNationalNumber, indexOfPhoneContext)
  50. }
  51. // Delete the isdn-subaddress and everything after it if it is present.
  52. // Note extension won't appear at the same time with isdn-subaddress
  53. // according to paragraph 5.3 of the RFC3966 spec.
  54. const indexOfIsdn = phoneNumberString.indexOf(RFC3966_ISDN_SUBADDRESS_)
  55. if (indexOfIsdn > 0) {
  56. phoneNumberString = phoneNumberString.substring(0, indexOfIsdn)
  57. }
  58. // If both phone context and isdn-subaddress are absent but other
  59. // parameters are present, the parameters are left in nationalNumber.
  60. // This is because we are concerned about deleting content from a potential
  61. // number string when there is no strong evidence that the number is
  62. // actually written in RFC3966.
  63. if (phoneNumberString !== '') {
  64. return phoneNumberString
  65. }
  66. }