react-markdown
Version:
Renders Markdown as React components
95 lines (79 loc) • 2.23 kB
JavaScript
;
/**
* Naive, simple plugin to match inline nodes without attributes
* This allows say <strong>foo</strong>, but not <strong class="very">foo</strong>
* For proper HTML support, you'll want a different plugin
**/
var visit = require('unist-util-visit');
var type = 'virtualHtml';
var selfClosingRe = /^<(area|base|br|col|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)\s*\/?>$/i;
var simpleTagRe = /^<(\/?)([a-z]+)\s*>$/;
module.exports = function (tree) {
var open;
var currentParent;
visit(tree, 'html', function (node, index, parent) {
if (currentParent !== parent) {
open = [];
currentParent = parent;
}
var selfClosing = getSelfClosing(node);
if (selfClosing) {
parent.children.splice(index, 1, {
type: type,
tag: selfClosing,
position: node.position
});
return true;
}
var current = getSimpleTag(node, parent);
if (!current) {
return true;
}
var matching = findAndPull(open, current.tag);
if (matching) {
parent.children.splice(index, 0, virtual(current, matching, parent));
} else if (!current.opening) {
open.push(current);
}
return true;
}, true // Iterate in reverse
);
return tree;
};
function findAndPull(open, matchingTag) {
var i = open.length;
while (i--) {
if (open[i].tag === matchingTag) {
return open.splice(i, 1)[0];
}
}
return false;
}
function getSimpleTag(node, parent) {
var match = node.value.match(simpleTagRe);
return match ? {
tag: match[2],
opening: !match[1],
node: node
} : false;
}
function getSelfClosing(node) {
var match = node.value.match(selfClosingRe);
return match ? match[1] : false;
}
function virtual(fromNode, toNode, parent) {
var fromIndex = parent.children.indexOf(fromNode.node);
var toIndex = parent.children.indexOf(toNode.node);
var extracted = parent.children.splice(fromIndex, toIndex - fromIndex + 1);
var children = extracted.slice(1, -1);
return {
type: type,
children: children,
tag: fromNode.tag,
position: {
start: fromNode.node.position.start,
end: toNode.node.position.end,
indent: []
}
};
}