blob: ee72e6638e04ccc820665f69b8202987b88f7500 [file] [log] [blame]
'use strict'
var decode = require('parse-entities')
var whitespace = require('is-whitespace-character')
var locate = require('../locate/url')
module.exports = url
url.locator = locate
url.notInLink = true
var quotationMark = '"'
var apostrophe = "'"
var leftParenthesis = '('
var rightParenthesis = ')'
var comma = ','
var dot = '.'
var colon = ':'
var semicolon = ';'
var lessThan = '<'
var atSign = '@'
var leftSquareBracket = '['
var rightSquareBracket = ']'
var http = 'http://'
var https = 'https://'
var mailto = 'mailto:'
var protocols = [http, https, mailto]
var protocolsLength = protocols.length
function url(eat, value, silent) {
var self = this
var subvalue
var content
var character
var index
var position
var protocol
var match
var length
var queue
var parenCount
var nextCharacter
var tokenizers
var exit
if (!self.options.gfm) {
return
}
subvalue = ''
index = -1
while (++index < protocolsLength) {
protocol = protocols[index]
match = value.slice(0, protocol.length)
if (match.toLowerCase() === protocol) {
subvalue = match
break
}
}
if (!subvalue) {
return
}
index = subvalue.length
length = value.length
queue = ''
parenCount = 0
while (index < length) {
character = value.charAt(index)
if (whitespace(character) || character === lessThan) {
break
}
if (
character === dot ||
character === comma ||
character === colon ||
character === semicolon ||
character === quotationMark ||
character === apostrophe ||
character === rightParenthesis ||
character === rightSquareBracket
) {
nextCharacter = value.charAt(index + 1)
if (!nextCharacter || whitespace(nextCharacter)) {
break
}
}
if (character === leftParenthesis || character === leftSquareBracket) {
parenCount++
}
if (character === rightParenthesis || character === rightSquareBracket) {
parenCount--
if (parenCount < 0) {
break
}
}
queue += character
index++
}
if (!queue) {
return
}
subvalue += queue
content = subvalue
if (protocol === mailto) {
position = queue.indexOf(atSign)
if (position === -1 || position === length - 1) {
return
}
content = content.substr(mailto.length)
}
/* istanbul ignore if - never used (yet) */
if (silent) {
return true
}
exit = self.enterLink()
// Temporarily remove all tokenizers except text in url.
tokenizers = self.inlineTokenizers
self.inlineTokenizers = {text: tokenizers.text}
content = self.tokenizeInline(content, eat.now())
self.inlineTokenizers = tokenizers
exit()
return eat(subvalue)({
type: 'link',
title: null,
url: decode(subvalue, {nonTerminated: false}),
children: content
})
}