@mdit-vue/plugin-toc
Version:
A markdown-it plugin to generate table-of-contents that compatible with Vue.js
95 lines (91 loc) • 3.34 kB
JavaScript
import { htmlEscape, resolveHeadersFromTokens, slugify } from "@mdit-vue/shared";
//#region src/create-render-headers.ts
const createRenderHeaders = ({ listTag, listClass, itemClass, linkTag, linkClass }) => {
const listTagString = htmlEscape(listTag);
const listClassString = listClass ? ` class="${htmlEscape(listClass)}"` : "";
const itemTagString = "li";
const itemClassString = itemClass ? ` class="${htmlEscape(itemClass)}"` : "";
const linkTagString = htmlEscape(linkTag);
const linkClassString = linkClass ? ` class="${htmlEscape(linkClass)}"` : "";
const linkTo = (link) => linkTag === "router-link" ? ` to="${link}"` : ` href="${link}"`;
const renderHeaders = (headers) => `\
<${listTagString}${listClassString}>\
${headers.map((header) => `\
<${itemTagString}${itemClassString}>\
<${linkTagString}${linkClassString}${linkTo(header.link)}>\
${header.title}\
</${linkTagString}>\
${header.children.length > 0 ? renderHeaders(header.children) : ""}\
</${itemTagString}>\
`).join("")}\
</${listTagString}>`;
return renderHeaders;
};
//#endregion
//#region src/create-toc-block-rule.ts
/**
* Forked and modified from markdown-it-toc-done-right
*
* - remove the `inlineOptions` support
* - use markdown-it default renderer to render token whenever possible
*
* @see https://github.com/nagaozen/markdown-it-toc-done-right
*/
const createTocBlockRule = ({ pattern, containerTag, containerClass }) => (state, startLine, endLine, silent) => {
if (state.sCount[startLine] - state.blkIndent >= 4) return false;
const pos = state.bMarks[startLine] + state.tShift[startLine];
const max = state.eMarks[startLine];
const lineFirstToken = state.src.slice(pos, max).split(" ")[0];
if (!pattern.test(lineFirstToken)) return false;
if (silent) return true;
state.line = startLine + 1;
const tokenOpen = state.push("toc_open", containerTag, 1);
tokenOpen.markup = "";
tokenOpen.map = [startLine, state.line];
if (containerClass) tokenOpen.attrSet("class", containerClass);
const tokenBody = state.push("toc_body", "", 0);
tokenBody.markup = lineFirstToken;
tokenBody.map = [startLine, state.line];
tokenBody.hidden = true;
const tokenClose = state.push("toc_close", containerTag, -1);
tokenClose.markup = "";
tokenBody.map = [startLine, state.line];
return true;
};
//#endregion
//#region src/toc-plugin.ts
/**
* Generate table of contents
*
* Forked and modified from markdown-it-toc-done-right:
*
* @see https://github.com/nagaozen/markdown-it-toc-done-right
*/
const tocPlugin = (md, { pattern = /^\[\[toc\]\]$/i, slugify: slugify$1 = slugify, format, level = [2, 3], shouldAllowNested = false, containerTag = "nav", containerClass = "table-of-contents", listTag = "ul", listClass = "", itemClass = "", linkTag = "a", linkClass = "" } = {}) => {
md.block.ruler.before("heading", "toc", createTocBlockRule({
pattern,
containerTag,
containerClass
}), { alt: [
"paragraph",
"reference",
"blockquote"
] });
const renderHeaders = createRenderHeaders({
listTag,
listClass,
itemClass,
linkTag,
linkClass
});
md.renderer.rules.toc_body = (tokens) => renderHeaders(resolveHeadersFromTokens(tokens, {
level,
shouldAllowHtml: true,
shouldAllowNested,
shouldEscapeText: true,
slugify: slugify$1,
format
}));
};
//#endregion
export { createRenderHeaders, createTocBlockRule, tocPlugin };