auto-link.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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 C_LT = '<';
  9. var C_GT = '>';
  10. var C_AT_SIGN = '@';
  11. var C_SLASH = '/';
  12. var MAILTO = 'mailto:';
  13. var MAILTO_LENGTH = MAILTO.length;
  14. /* Tokenise a link. */
  15. function autoLink(eat, value, silent) {
  16. var self;
  17. var subvalue;
  18. var length;
  19. var index;
  20. var queue;
  21. var character;
  22. var hasAtCharacter;
  23. var link;
  24. var now;
  25. var content;
  26. var tokenizers;
  27. var exit;
  28. if (value.charAt(0) !== C_LT) {
  29. return;
  30. }
  31. self = this;
  32. subvalue = '';
  33. length = value.length;
  34. index = 0;
  35. queue = '';
  36. hasAtCharacter = false;
  37. link = '';
  38. index++;
  39. subvalue = C_LT;
  40. while (index < length) {
  41. character = value.charAt(index);
  42. if (
  43. whitespace(character) ||
  44. character === C_GT ||
  45. character === C_AT_SIGN ||
  46. (character === ':' && value.charAt(index + 1) === C_SLASH)
  47. ) {
  48. break;
  49. }
  50. queue += character;
  51. index++;
  52. }
  53. if (!queue) {
  54. return;
  55. }
  56. link += queue;
  57. queue = '';
  58. character = value.charAt(index);
  59. link += character;
  60. index++;
  61. if (character === C_AT_SIGN) {
  62. hasAtCharacter = true;
  63. } else {
  64. if (
  65. character !== ':' ||
  66. value.charAt(index + 1) !== C_SLASH
  67. ) {
  68. return;
  69. }
  70. link += C_SLASH;
  71. index++;
  72. }
  73. while (index < length) {
  74. character = value.charAt(index);
  75. if (whitespace(character) || character === C_GT) {
  76. break;
  77. }
  78. queue += character;
  79. index++;
  80. }
  81. character = value.charAt(index);
  82. if (!queue || character !== C_GT) {
  83. return;
  84. }
  85. /* istanbul ignore if - never used (yet) */
  86. if (silent) {
  87. return true;
  88. }
  89. link += queue;
  90. content = link;
  91. subvalue += link + character;
  92. now = eat.now();
  93. now.column++;
  94. now.offset++;
  95. if (hasAtCharacter) {
  96. if (link.slice(0, MAILTO_LENGTH).toLowerCase() === MAILTO) {
  97. content = content.substr(MAILTO_LENGTH);
  98. now.column += MAILTO_LENGTH;
  99. now.offset += MAILTO_LENGTH;
  100. } else {
  101. link = MAILTO + link;
  102. }
  103. }
  104. /* Temporarily remove all tokenizers except text in autolinks. */
  105. tokenizers = self.inlineTokenizers;
  106. self.inlineTokenizers = {text: tokenizers.text};
  107. exit = self.enterLink();
  108. content = self.tokenizeInline(content, now);
  109. self.inlineTokenizers = tokenizers;
  110. exit();
  111. return eat(subvalue)({
  112. type: 'link',
  113. title: null,
  114. url: decode(link, {nonTerminated: false}),
  115. children: content
  116. });
  117. }