You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
4.4 KiB

/**
* @author Titus Wormer
* @copyright 2015 Titus Wormer
* @license MIT
* @module remark:parse:tokenize:reference
* @fileoverview Tokenise a reference.
*/
'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 T_LINK = 'link';
var T_IMAGE = 'image';
var T_FOOTNOTE = 'footnote';
var REFERENCE_TYPE_SHORTCUT = 'shortcut';
var REFERENCE_TYPE_COLLAPSED = 'collapsed';
var REFERENCE_TYPE_FULL = 'full';
var C_CARET = '^';
var C_BACKSLASH = '\\';
var C_BRACKET_OPEN = '[';
var C_BRACKET_CLOSE = ']';
/* Tokenise a reference. */
function reference(eat, value, silent) {
var self = this;
var character = value.charAt(0);
var index = 0;
var length = value.length;
var subvalue = '';
var intro = '';
var type = T_LINK;
var referenceType = REFERENCE_TYPE_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 === '!') {
type = T_IMAGE;
intro = character;
character = value.charAt(++index);
}
if (character !== C_BRACKET_OPEN) {
return;
}
index++;
intro += character;
queue = '';
/* Check whether we’re eating a footnote. */
if (
self.options.footnotes &&
type === T_LINK &&
value.charAt(index) === C_CARET
) {
intro += C_CARET;
index++;
type = T_FOOTNOTE;
}
/* Eat the text. */
depth = 0;
while (index < length) {
character = value.charAt(index);
if (character === C_BRACKET_OPEN) {
bracketed = true;
depth++;
} else if (character === C_BRACKET_CLOSE) {
if (!depth) {
break;
}
depth--;
}
if (character === C_BACKSLASH) {
queue += C_BACKSLASH;
character = value.charAt(++index);
}
queue += character;
index++;
}
subvalue = queue;
content = queue;
character = value.charAt(index);
if (character !== C_BRACKET_CLOSE) {
return;
}
index++;
subvalue += character;
queue = '';
while (index < length) {
character = value.charAt(index);
if (!whitespace(character)) {
break;
}
queue += character;
index++;
}
character = value.charAt(index);
if (character === C_BRACKET_OPEN) {
identifier = '';
queue += character;
index++;
while (index < length) {
character = value.charAt(index);
if (character === C_BRACKET_OPEN || character === C_BRACKET_CLOSE) {
break;
}
if (character === C_BACKSLASH) {
identifier += C_BACKSLASH;
character = value.charAt(++index);
}
identifier += character;
index++;
}
character = value.charAt(index);
if (character === C_BRACKET_CLOSE) {
referenceType = identifier ? REFERENCE_TYPE_FULL : REFERENCE_TYPE_COLLAPSED;
queue += identifier + character;
index++;
} else {
identifier = '';
}
subvalue += queue;
queue = '';
} else {
if (!content) {
return;
}
identifier = content;
}
/* Brackets cannot be inside the identifier. */
if (referenceType !== REFERENCE_TYPE_FULL && bracketed) {
return;
}
/* Inline footnotes cannot have an identifier. */
if (type === T_FOOTNOTE && referenceType !== REFERENCE_TYPE_SHORTCUT) {
type = T_LINK;
intro = C_BRACKET_OPEN + C_CARET;
content = C_CARET + content;
}
subvalue = intro + subvalue;
if (type === T_LINK && self.inLink) {
return null;
}
/* istanbul ignore if - never used (yet) */
if (silent) {
return true;
}
if (type === T_FOOTNOTE && content.indexOf(' ') !== -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 === REFERENCE_TYPE_FULL ? identifier : content;
node = {
type: type + 'Reference',
identifier: normalize(identifier)
};
if (type === T_LINK || type === T_IMAGE) {
node.referenceType = referenceType;
}
if (type === T_LINK) {
exit = self.enterLink();
node.children = self.tokenizeInline(content, now);
exit();
} else if (type === T_IMAGE) {
node.alt = self.decode.raw(self.unescape(content), now) || null;
}
return eat(subvalue)(node);
}