auto-link.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. 'use strict'
  2. var whitespace = require('is-whitespace-character')
  3. var decode = require('parse-entities')
  4. var locate = require('../locate/tag')
  5. module.exports = autoLink
  6. autoLink.locator = locate
  7. autoLink.notInLink = true
  8. var lessThan = '<'
  9. var greaterThan = '>'
  10. var atSign = '@'
  11. var slash = '/'
  12. var mailto = 'mailto:'
  13. var mailtoLength = mailto.length
  14. function autoLink(eat, value, silent) {
  15. var self = this
  16. var subvalue = ''
  17. var length = value.length
  18. var index = 0
  19. var queue = ''
  20. var hasAtCharacter = false
  21. var link = ''
  22. var character
  23. var now
  24. var content
  25. var tokenizers
  26. var exit
  27. if (value.charAt(0) !== lessThan) {
  28. return
  29. }
  30. index++
  31. subvalue = lessThan
  32. while (index < length) {
  33. character = value.charAt(index)
  34. if (
  35. whitespace(character) ||
  36. character === greaterThan ||
  37. character === atSign ||
  38. (character === ':' && value.charAt(index + 1) === slash)
  39. ) {
  40. break
  41. }
  42. queue += character
  43. index++
  44. }
  45. if (!queue) {
  46. return
  47. }
  48. link += queue
  49. queue = ''
  50. character = value.charAt(index)
  51. link += character
  52. index++
  53. if (character === atSign) {
  54. hasAtCharacter = true
  55. } else {
  56. if (character !== ':' || value.charAt(index + 1) !== slash) {
  57. return
  58. }
  59. link += slash
  60. index++
  61. }
  62. while (index < length) {
  63. character = value.charAt(index)
  64. if (whitespace(character) || character === greaterThan) {
  65. break
  66. }
  67. queue += character
  68. index++
  69. }
  70. character = value.charAt(index)
  71. if (!queue || character !== greaterThan) {
  72. return
  73. }
  74. /* istanbul ignore if - never used (yet) */
  75. if (silent) {
  76. return true
  77. }
  78. link += queue
  79. content = link
  80. subvalue += link + character
  81. now = eat.now()
  82. now.column++
  83. now.offset++
  84. if (hasAtCharacter) {
  85. if (link.slice(0, mailtoLength).toLowerCase() === mailto) {
  86. content = content.slice(mailtoLength)
  87. now.column += mailtoLength
  88. now.offset += mailtoLength
  89. } else {
  90. link = mailto + link
  91. }
  92. }
  93. // Temporarily remove all tokenizers except text in autolinks.
  94. tokenizers = self.inlineTokenizers
  95. self.inlineTokenizers = {text: tokenizers.text}
  96. exit = self.enterLink()
  97. content = self.tokenizeInline(content, now)
  98. self.inlineTokenizers = tokenizers
  99. exit()
  100. return eat(subvalue)({
  101. type: 'link',
  102. title: null,
  103. url: decode(link, {nonTerminated: false}),
  104. children: content
  105. })
  106. }