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(`${content}`); } pos += 1; } return ""; } return genToC(headings, 1); } exports.after_post_render = function (data) { data.content = data.content.replace("", () => generateToC(data.content) ); return data; };