import { QuartzTransformerPlugin } from "../types" import { Root } from "mdast" import { visit } from "unist-util-visit" import { toString } from "mdast-util-to-string" import { slug as slugAnchor } from 'github-slugger' export interface Options { maxDepth: 1 | 2 | 3 | 4 | 5 | 6, minEntries: 1, showByDefault: boolean } const defaultOptions: Options = { maxDepth: 3, minEntries: 1, showByDefault: true, } interface TocEntry { depth: number, text: string, slug: string } export const TableOfContents: QuartzTransformerPlugin | undefined> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "TableOfContents", markdownPlugins() { return [() => { return async (tree: Root, file) => { const display = file.data.frontmatter?.enableToc ?? opts.showByDefault if (display) { const toc: TocEntry[] = [] let highestDepth: number = opts.maxDepth visit(tree, 'heading', (node) => { if (node.depth <= opts.maxDepth) { const text = toString(node) highestDepth = Math.min(highestDepth, node.depth) toc.push({ depth: node.depth, text, slug: slugAnchor(text) }) } }) if (toc.length > opts.minEntries) { file.data.toc = toc.map(entry => ({ ...entry, depth: entry.depth - highestDepth })) } } } }] }, htmlPlugins() { return [] } } } declare module 'vfile' { interface DataMap { toc: TocEntry[] } }