@brendonovich/kobalte__solidbase
Version:
Fully featured, fully customisable static site generation for SolidStart
83 lines (70 loc) • 1.84 kB
text/typescript
import { fromJs } from "esast-util-from-js";
import type { PhrasingContent } from "mdast";
import { findAndReplace } from "mdast-util-find-and-replace";
import { toString as nodeToString } from "mdast-util-to-string";
import { type Options, toc } from "mdast-util-toc";
interface ParagraphNode {
type: "paragraph";
url: string;
children: [
{
type: "link";
url: string;
children: [{ type: "text"; value: string }];
},
];
}
interface ListItemNode {
type: "listItem";
children: [
ParagraphNode,
{ type: "list"; children: Array<ListItemNode> } | undefined,
];
}
interface TOCTree {
title: string;
href: string;
children: Array<TOCTree>;
}
function mapNode(node: ListItemNode): TOCTree {
return {
title: nodeToString(node.children[0].children[0].children),
href: node.children[0].children[0].url,
children: (node.children[1]?.children ?? []).map(mapNode),
};
}
export const SolidBaseTOC = "$$SolidBase_TOC";
export type TOCOptions = {
minDepth?: Options["minDepth"];
maxDepth?: Options["maxDepth"];
};
export function remarkTOC(opts?: TOCOptions) {
return (tree: any) => {
const map = toc(tree, {
ordered: true,
minDepth: opts?.minDepth ?? 1,
maxDepth: opts?.maxDepth ?? 4,
parents: (a) => a.type === "root" || a.type === "mdxJsxFlowElement",
}).map as PhrasingContent | undefined;
let value: string;
if (!map) {
value = "undefined";
} else {
map.data ??= {};
map.data.hProperties ??= {};
map.data.hProperties["data-toc"] = "";
findAndReplace(tree, [["[[toc]]", () => map]]);
// @ts-ignore: not sure what the correct type is
value = JSON.stringify(map.children.map(mapNode));
}
tree.children.unshift({
type: "mdxjsEsm",
value: "",
data: {
estree: fromJs(`const ${SolidBaseTOC} = ${value};`, {
module: true,
}),
},
});
};
}