mirror of https://github.com/lukechilds/node.git
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
220 lines
4.4 KiB
8 years ago
|
/**
|
||
|
* @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);
|
||
|
}
|