image.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. // Process ![image](<src> "title")
  2. 'use strict';
  3. var normalizeReference = require('../common/utils').normalizeReference;
  4. var isSpace = require('../common/utils').isSpace;
  5. module.exports = function image(state, silent) {
  6. var attrs,
  7. code,
  8. content,
  9. label,
  10. labelEnd,
  11. labelStart,
  12. pos,
  13. ref,
  14. res,
  15. title,
  16. token,
  17. tokens,
  18. start,
  19. href = '',
  20. oldPos = state.pos,
  21. max = state.posMax;
  22. if (state.src.charCodeAt(state.pos) !== 0x21/* ! */) { return false; }
  23. if (state.src.charCodeAt(state.pos + 1) !== 0x5B/* [ */) { return false; }
  24. labelStart = state.pos + 2;
  25. labelEnd = state.md.helpers.parseLinkLabel(state, state.pos + 1, false);
  26. // parser failed to find ']', so it's not a valid link
  27. if (labelEnd < 0) { return false; }
  28. pos = labelEnd + 1;
  29. if (pos < max && state.src.charCodeAt(pos) === 0x28/* ( */) {
  30. //
  31. // Inline link
  32. //
  33. // [link]( <href> "title" )
  34. // ^^ skipping these spaces
  35. pos++;
  36. for (; pos < max; pos++) {
  37. code = state.src.charCodeAt(pos);
  38. if (!isSpace(code) && code !== 0x0A) { break; }
  39. }
  40. if (pos >= max) { return false; }
  41. // [link]( <href> "title" )
  42. // ^^^^^^ parsing link destination
  43. start = pos;
  44. res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);
  45. if (res.ok) {
  46. href = state.md.normalizeLink(res.str);
  47. if (state.md.validateLink(href)) {
  48. pos = res.pos;
  49. } else {
  50. href = '';
  51. }
  52. }
  53. // [link]( <href> "title" )
  54. // ^^ skipping these spaces
  55. start = pos;
  56. for (; pos < max; pos++) {
  57. code = state.src.charCodeAt(pos);
  58. if (!isSpace(code) && code !== 0x0A) { break; }
  59. }
  60. // [link]( <href> "title" )
  61. // ^^^^^^^ parsing link title
  62. res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);
  63. if (pos < max && start !== pos && res.ok) {
  64. title = res.str;
  65. pos = res.pos;
  66. // [link]( <href> "title" )
  67. // ^^ skipping these spaces
  68. for (; pos < max; pos++) {
  69. code = state.src.charCodeAt(pos);
  70. if (!isSpace(code) && code !== 0x0A) { break; }
  71. }
  72. } else {
  73. title = '';
  74. }
  75. if (pos >= max || state.src.charCodeAt(pos) !== 0x29/* ) */) {
  76. state.pos = oldPos;
  77. return false;
  78. }
  79. pos++;
  80. } else {
  81. //
  82. // Link reference
  83. //
  84. if (typeof state.env.references === 'undefined') { return false; }
  85. if (pos < max && state.src.charCodeAt(pos) === 0x5B/* [ */) {
  86. start = pos + 1;
  87. pos = state.md.helpers.parseLinkLabel(state, pos);
  88. if (pos >= 0) {
  89. label = state.src.slice(start, pos++);
  90. } else {
  91. pos = labelEnd + 1;
  92. }
  93. } else {
  94. pos = labelEnd + 1;
  95. }
  96. // covers label === '' and label === undefined
  97. // (collapsed reference link and shortcut reference link respectively)
  98. if (!label) { label = state.src.slice(labelStart, labelEnd); }
  99. ref = state.env.references[normalizeReference(label)];
  100. if (!ref) {
  101. state.pos = oldPos;
  102. return false;
  103. }
  104. href = ref.href;
  105. title = ref.title;
  106. }
  107. //
  108. // We found the end of the link, and know for a fact it's a valid link;
  109. // so all that's left to do is to call tokenizer.
  110. //
  111. if (!silent) {
  112. content = state.src.slice(labelStart, labelEnd);
  113. state.md.inline.parse(
  114. content,
  115. state.md,
  116. state.env,
  117. tokens = []
  118. );
  119. token = state.push('image', 'img', 0);
  120. token.attrs = attrs = [ [ 'src', href ], [ 'alt', '' ] ];
  121. token.children = tokens;
  122. token.content = content;
  123. if (title) {
  124. attrs.push([ 'title', title ]);
  125. }
  126. }
  127. state.pos = pos;
  128. state.posMax = max;
  129. return true;
  130. };