123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- 'use strict'
- var whitespace = require('is-whitespace-character')
- var locate = require('../locate/link')
- module.exports = link
- link.locator = locate
- var lineFeed = '\n'
- var exclamationMark = '!'
- var quotationMark = '"'
- var apostrophe = "'"
- var leftParenthesis = '('
- var rightParenthesis = ')'
- var lessThan = '<'
- var greaterThan = '>'
- var leftSquareBracket = '['
- var backslash = '\\'
- var rightSquareBracket = ']'
- var graveAccent = '`'
- function link(eat, value, silent) {
- var self = this
- var subvalue = ''
- var index = 0
- var character = value.charAt(0)
- var pedantic = self.options.pedantic
- var commonmark = self.options.commonmark
- var gfm = self.options.gfm
- var closed
- var count
- var opening
- var beforeURL
- var beforeTitle
- var subqueue
- var hasMarker
- var isImage
- var content
- var marker
- var length
- var title
- var depth
- var queue
- var url
- var now
- var exit
- var node
- // Detect whether this is an image.
- if (character === exclamationMark) {
- isImage = true
- subvalue = character
- character = value.charAt(++index)
- }
- // Eat the opening.
- if (character !== leftSquareBracket) {
- return
- }
- // Exit when this is a link and we’re already inside a link.
- if (!isImage && self.inLink) {
- return
- }
- subvalue += character
- queue = ''
- index++
- // Eat the content.
- length = value.length
- now = eat.now()
- depth = 0
- now.column += index
- now.offset += index
- while (index < length) {
- character = value.charAt(index)
- subqueue = character
- if (character === graveAccent) {
- // Inline-code in link content.
- count = 1
- while (value.charAt(index + 1) === graveAccent) {
- subqueue += character
- index++
- count++
- }
- if (!opening) {
- opening = count
- } else if (count >= opening) {
- opening = 0
- }
- } else if (character === backslash) {
- // Allow brackets to be escaped.
- index++
- subqueue += value.charAt(index)
- } else if ((!opening || gfm) && character === leftSquareBracket) {
- // In GFM mode, brackets in code still count. In all other modes,
- // they don’t.
- depth++
- } else if ((!opening || gfm) && character === rightSquareBracket) {
- if (depth) {
- depth--
- } else {
- if (value.charAt(index + 1) !== leftParenthesis) {
- return
- }
- subqueue += leftParenthesis
- closed = true
- index++
- break
- }
- }
- queue += subqueue
- subqueue = ''
- index++
- }
- // Eat the content closing.
- if (!closed) {
- return
- }
- content = queue
- subvalue += queue + subqueue
- index++
- // Eat white-space.
- while (index < length) {
- character = value.charAt(index)
- if (!whitespace(character)) {
- break
- }
- subvalue += character
- index++
- }
- // Eat the URL.
- character = value.charAt(index)
- queue = ''
- beforeURL = subvalue
- if (character === lessThan) {
- index++
- beforeURL += lessThan
- while (index < length) {
- character = value.charAt(index)
- if (character === greaterThan) {
- break
- }
- if (commonmark && character === lineFeed) {
- return
- }
- queue += character
- index++
- }
- if (value.charAt(index) !== greaterThan) {
- return
- }
- subvalue += lessThan + queue + greaterThan
- url = queue
- index++
- } else {
- character = null
- subqueue = ''
- while (index < length) {
- character = value.charAt(index)
- if (
- subqueue &&
- (character === quotationMark ||
- character === apostrophe ||
- (commonmark && character === leftParenthesis))
- ) {
- break
- }
- if (whitespace(character)) {
- if (!pedantic) {
- break
- }
- subqueue += character
- } else {
- if (character === leftParenthesis) {
- depth++
- } else if (character === rightParenthesis) {
- if (depth === 0) {
- break
- }
- depth--
- }
- queue += subqueue
- subqueue = ''
- if (character === backslash) {
- queue += backslash
- character = value.charAt(++index)
- }
- queue += character
- }
- index++
- }
- subvalue += queue
- url = queue
- index = subvalue.length
- }
- // Eat white-space.
- queue = ''
- while (index < length) {
- character = value.charAt(index)
- if (!whitespace(character)) {
- break
- }
- queue += character
- index++
- }
- character = value.charAt(index)
- subvalue += queue
- // Eat the title.
- if (
- queue &&
- (character === quotationMark ||
- character === apostrophe ||
- (commonmark && character === leftParenthesis))
- ) {
- index++
- subvalue += character
- queue = ''
- marker = character === leftParenthesis ? rightParenthesis : character
- beforeTitle = subvalue
- // In commonmark-mode, things are pretty easy: the marker cannot occur
- // inside the title. Non-commonmark does, however, support nested
- // delimiters.
- if (commonmark) {
- while (index < length) {
- character = value.charAt(index)
- if (character === marker) {
- break
- }
- if (character === backslash) {
- queue += backslash
- character = value.charAt(++index)
- }
- index++
- queue += character
- }
- character = value.charAt(index)
- if (character !== marker) {
- return
- }
- title = queue
- subvalue += queue + character
- index++
- while (index < length) {
- character = value.charAt(index)
- if (!whitespace(character)) {
- break
- }
- subvalue += character
- index++
- }
- } else {
- subqueue = ''
- while (index < length) {
- character = value.charAt(index)
- if (character === marker) {
- if (hasMarker) {
- queue += marker + subqueue
- subqueue = ''
- }
- hasMarker = true
- } else if (!hasMarker) {
- queue += character
- } else if (character === rightParenthesis) {
- subvalue += queue + marker + subqueue
- title = queue
- break
- } else if (whitespace(character)) {
- subqueue += character
- } else {
- queue += marker + subqueue + character
- subqueue = ''
- hasMarker = false
- }
- index++
- }
- }
- }
- if (value.charAt(index) !== rightParenthesis) {
- return
- }
- /* istanbul ignore if - never used (yet) */
- if (silent) {
- return true
- }
- subvalue += rightParenthesis
- url = self.decode.raw(self.unescape(url), eat(beforeURL).test().end, {
- nonTerminated: false
- })
- if (title) {
- beforeTitle = eat(beforeTitle).test().end
- title = self.decode.raw(self.unescape(title), beforeTitle)
- }
- node = {
- type: isImage ? 'image' : 'link',
- title: title || null,
- url: url
- }
- if (isImage) {
- node.alt = self.decode.raw(self.unescape(content), now) || null
- } else {
- exit = self.enterLink()
- node.children = self.tokenizeInline(content, now)
- exit()
- }
- return eat(subvalue)(node)
- }
|