* Remove pinning of eslint-plugin-markdown An issue affecting Node.js source has been fixed in eslint-plugin-markdown so we don't need to pin it to beta-4 anymore. Refs: https://github.com/eslint/eslint-plugin-markdown/issues/69 * Update eslint-plugin-markdown up to 1.0.0-beta.7 * Fix docs for eslint-plugin-markdown@1.0.0-beta.7 PR-URL: https://github.com/nodejs/node/pull/14047 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Yuta Hiroto <hello@about-hiroppy.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
219 lines
4.4 KiB
JavaScript
219 lines
4.4 KiB
JavaScript
/**
|
||
* @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);
|
||
}
|