All checks were successful
continuous-integration/drone/push Build is passing
49 lines
1.2 KiB
JavaScript
49 lines
1.2 KiB
JavaScript
const JSDOM = require("jsdom").JSDOM;
|
|
|
|
function generateToC(html) {
|
|
const dom = JSDOM.fragment(html);
|
|
|
|
const headings = Array.from(dom.querySelectorAll("h1, h2, h3, h4, h5, h6"))
|
|
// Filter headings with ids
|
|
.filter((el) => el && el.id)
|
|
// {id: string, content: string|null, depth: number}
|
|
.map((el) => ({
|
|
id: el.id,
|
|
content: el.textContent,
|
|
depth: Number(el.nodeName.replace("H", "")), // H1 -> 1
|
|
}));
|
|
|
|
let pos = 0;
|
|
function genToC(arr, lastDepth) {
|
|
const stack = [];
|
|
while (pos < arr.length) {
|
|
const { depth, id, content } = arr[pos];
|
|
|
|
if (depth < lastDepth) {
|
|
// unwind
|
|
pos -= 1;
|
|
break;
|
|
} else if (depth > lastDepth) {
|
|
// nested ToC
|
|
stack.push(stack.pop() + genToC(arr, depth));
|
|
} else {
|
|
// same depth
|
|
stack.push(`<a href="#${id}">${content}</a>`);
|
|
}
|
|
|
|
pos += 1;
|
|
}
|
|
|
|
return "<ul>" + stack.map((s) => `<li>${s}</li>`).join("") + "</ul>";
|
|
}
|
|
|
|
return genToC(headings, 1);
|
|
}
|
|
|
|
exports.after_post_render = function (data) {
|
|
data.content = data.content.replace("<!-- toc -->", () =>
|
|
generateToC(data.content)
|
|
);
|
|
return data;
|
|
};
|