| 'use strict' |
| |
| var whitespace = require('is-whitespace-character') |
| var locate = require('../locate/link') |
| var normalize = require('../util/normalize') |
| |
| module.exports = reference |
| reference.locator = locate |
| |
| var link = 'link' |
| var image = 'image' |
| var footnote = 'footnote' |
| var shortcut = 'shortcut' |
| var collapsed = 'collapsed' |
| var full = 'full' |
| var space = ' ' |
| var exclamationMark = '!' |
| var leftSquareBracket = '[' |
| var backslash = '\\' |
| var rightSquareBracket = ']' |
| var caret = '^' |
| |
| function reference(eat, value, silent) { |
| var self = this |
| var commonmark = self.options.commonmark |
| var character = value.charAt(0) |
| var index = 0 |
| var length = value.length |
| var subvalue = '' |
| var intro = '' |
| var type = link |
| var referenceType = shortcut |
| var content |
| var identifier |
| var now |
| var node |
| var exit |
| var queue |
| var bracketed |
| var depth |
| |
| // Check whether we’re eating an image. |
| if (character === exclamationMark) { |
| type = image |
| intro = character |
| character = value.charAt(++index) |
| } |
| |
| if (character !== leftSquareBracket) { |
| return |
| } |
| |
| index++ |
| intro += character |
| queue = '' |
| |
| // Check whether we’re eating a footnote. |
| if (self.options.footnotes && value.charAt(index) === caret) { |
| // Exit if `![^` is found, so the `!` will be seen as text after this, |
| // and we’ll enter this function again when `[^` is found. |
| if (type === image) { |
| return |
| } |
| |
| intro += caret |
| index++ |
| type = footnote |
| } |
| |
| // Eat the text. |
| depth = 0 |
| |
| while (index < length) { |
| character = value.charAt(index) |
| |
| if (character === leftSquareBracket) { |
| bracketed = true |
| depth++ |
| } else if (character === rightSquareBracket) { |
| if (!depth) { |
| break |
| } |
| |
| depth-- |
| } |
| |
| if (character === backslash) { |
| queue += backslash |
| character = value.charAt(++index) |
| } |
| |
| queue += character |
| index++ |
| } |
| |
| subvalue = queue |
| content = queue |
| character = value.charAt(index) |
| |
| if (character !== rightSquareBracket) { |
| return |
| } |
| |
| index++ |
| subvalue += character |
| queue = '' |
| |
| if (!commonmark) { |
| // The original markdown syntax definition explicitly allows for whitespace |
| // between the link text and link label; commonmark departs from this, in |
| // part to improve support for shortcut reference links |
| while (index < length) { |
| character = value.charAt(index) |
| |
| if (!whitespace(character)) { |
| break |
| } |
| |
| queue += character |
| index++ |
| } |
| } |
| |
| character = value.charAt(index) |
| |
| // Inline footnotes cannot have an identifier. |
| if (type !== footnote && character === leftSquareBracket) { |
| identifier = '' |
| queue += character |
| index++ |
| |
| while (index < length) { |
| character = value.charAt(index) |
| |
| if (character === leftSquareBracket || character === rightSquareBracket) { |
| break |
| } |
| |
| if (character === backslash) { |
| identifier += backslash |
| character = value.charAt(++index) |
| } |
| |
| identifier += character |
| index++ |
| } |
| |
| character = value.charAt(index) |
| |
| if (character === rightSquareBracket) { |
| referenceType = identifier ? full : collapsed |
| queue += identifier + character |
| index++ |
| } else { |
| identifier = '' |
| } |
| |
| subvalue += queue |
| queue = '' |
| } else { |
| if (!content) { |
| return |
| } |
| |
| identifier = content |
| } |
| |
| // Brackets cannot be inside the identifier. |
| if (referenceType !== full && bracketed) { |
| return |
| } |
| |
| subvalue = intro + subvalue |
| |
| if (type === link && self.inLink) { |
| return null |
| } |
| |
| /* istanbul ignore if - never used (yet) */ |
| if (silent) { |
| return true |
| } |
| |
| if (type === footnote && content.indexOf(space) !== -1) { |
| return eat(subvalue)({ |
| type: footnote, |
| children: this.tokenizeInline(content, eat.now()) |
| }) |
| } |
| |
| now = eat.now() |
| now.column += intro.length |
| now.offset += intro.length |
| identifier = referenceType === full ? identifier : content |
| |
| node = { |
| type: type + 'Reference', |
| identifier: normalize(identifier), |
| label: identifier |
| } |
| |
| if (type === link || type === image) { |
| node.referenceType = referenceType |
| } |
| |
| if (type === link) { |
| exit = self.enterLink() |
| node.children = self.tokenizeInline(content, now) |
| exit() |
| } else if (type === image) { |
| node.alt = self.decode.raw(self.unescape(content), now) || null |
| } |
| |
| return eat(subvalue)(node) |
| } |