98 lines
2.3 KiB
JavaScript
98 lines
2.3 KiB
JavaScript
/**
|
|
* @author Titus Wormer
|
|
* @copyright 2015 Titus Wormer
|
|
* @license MIT
|
|
* @module mdast:toc
|
|
* @fileoverview Generate a Table of Contents (TOC) from a given Markdown file.
|
|
*/
|
|
|
|
/* Expose. */
|
|
module.exports = search;
|
|
|
|
/* Dependencies */
|
|
var toString = require('mdast-util-to-string');
|
|
var visit = require('unist-util-visit');
|
|
var slugs = require('github-slugger')();
|
|
var isClosingHeading = require('./is-closing-heading');
|
|
var isOpeningHeading = require('./is-opening-heading');
|
|
|
|
/* Constants. */
|
|
var HEADING = 'heading';
|
|
|
|
/**
|
|
* Search a node for a location.
|
|
*
|
|
* @param {Node} root - Parent to search in.
|
|
* @param {RegExp} expression - Heading-content to search
|
|
* for.
|
|
* @param {number} maxDepth - Maximum-depth to include.
|
|
* @return {Object} - Results.
|
|
*/
|
|
function search(root, expression, maxDepth) {
|
|
var length = root.children.length;
|
|
var depth = null;
|
|
var lookingForToc = expression !== null;
|
|
var map = [];
|
|
var headingIndex;
|
|
var closingIndex;
|
|
|
|
if (!lookingForToc) {
|
|
headingIndex = -1;
|
|
}
|
|
|
|
slugs.reset();
|
|
|
|
/*
|
|
* Visit all headings in `root`.
|
|
* We `slug` all headings (to account for duplicates),
|
|
* but only create a TOC from top-level headings.
|
|
*/
|
|
|
|
visit(root, HEADING, function(child, index, parent) {
|
|
var value = toString(child);
|
|
var id =
|
|
child.data && child.data.hProperties && child.data.hProperties.id;
|
|
id = slugs.slug(id || value);
|
|
|
|
if (parent !== root) {
|
|
return;
|
|
}
|
|
|
|
if (lookingForToc) {
|
|
if (isClosingHeading(child, depth)) {
|
|
closingIndex = index;
|
|
lookingForToc = false;
|
|
}
|
|
|
|
if (isOpeningHeading(child, depth, expression)) {
|
|
headingIndex = index + 1;
|
|
depth = child.depth;
|
|
}
|
|
}
|
|
|
|
if (!lookingForToc && value && child.depth <= maxDepth) {
|
|
map.push({
|
|
depth: child.depth,
|
|
value: value,
|
|
id: id
|
|
});
|
|
}
|
|
});
|
|
|
|
if (headingIndex && !closingIndex) {
|
|
closingIndex = length + 1;
|
|
}
|
|
|
|
if (headingIndex === undefined) {
|
|
headingIndex = -1;
|
|
closingIndex = -1;
|
|
map = [];
|
|
}
|
|
|
|
return {
|
|
index: headingIndex,
|
|
endIndex: closingIndex,
|
|
map: map
|
|
};
|
|
}
|