189 lines
3.6 KiB
JavaScript
189 lines
3.6 KiB
JavaScript
'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 shortcut = 'shortcut'
|
||
var collapsed = 'collapsed'
|
||
var full = 'full'
|
||
var exclamationMark = '!'
|
||
var leftSquareBracket = '['
|
||
var backslash = '\\'
|
||
var rightSquareBracket = ']'
|
||
|
||
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 = ''
|
||
|
||
// 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)
|
||
|
||
if (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
|
||
}
|
||
|
||
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,
|
||
referenceType: referenceType
|
||
}
|
||
|
||
if (type === link) {
|
||
exit = self.enterLink()
|
||
node.children = self.tokenizeInline(content, now)
|
||
exit()
|
||
} else {
|
||
node.alt = self.decode.raw(self.unescape(content), now) || null
|
||
}
|
||
|
||
return eat(subvalue)(node)
|
||
}
|