mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-28 06:53:42 +08:00
docs/content/docs/limitations.mdx now holds the frontmatter, the headings, the anchor spans and one <include> line per partial. The text moves unchanged to docs/content/limitations/: one file per labeled bullet (<section>/<label>.mdx) and one per section's other text (<section>.mdx). Edits to different bullets no longer touch adjacent lines of one file. remarkDocsConventions splices the included partials into the page and joins the lists that consecutive bullet partials contribute, so the page, its Markdown twin and the search index render as before. The route tests read the page with its partials inlined. A page that includes partials takes its last-modified date, used by the sitemap, from the newest commit to the page or any of its partials. docs/scripts/limitations-partials.mjs joins the partials back into one file, splits a single-file page, and merges a branch's edits to the single-file page into the partials.
55 lines
2.0 KiB
TypeScript
55 lines
2.0 KiB
TypeScript
import type { List, Parent, Root, RootContent } from "mdast";
|
|
import { visit } from "unist-util-visit";
|
|
|
|
/** Preserve anchors published by the previous HeadingLink component. */
|
|
export function headingId(text: string): string {
|
|
return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim();
|
|
}
|
|
|
|
/** `<include>` replaces itself with the partial's root. Splice those roots
|
|
* into their parent, and join lists that consecutive partials contribute, so
|
|
* a page split into partials renders the same as the single file. */
|
|
function inlinePartials(tree: Root) {
|
|
visit(tree, (node) => {
|
|
if (!("children" in node)) return;
|
|
const parent = node as Parent;
|
|
const out: RootContent[] = [];
|
|
for (const child of parent.children as RootContent[]) {
|
|
if ((child as { type: string }).type !== "root") {
|
|
out.push(child);
|
|
continue;
|
|
}
|
|
for (const included of (child as unknown as Root).children) {
|
|
const previous = out[out.length - 1];
|
|
if (
|
|
included.type === "list" &&
|
|
previous?.type === "list" &&
|
|
(previous.data as { fromPartial?: boolean } | undefined)?.fromPartial &&
|
|
previous.ordered === included.ordered &&
|
|
previous.spread === included.spread
|
|
) {
|
|
previous.children.push(...included.children);
|
|
} else {
|
|
if (included.type === "list") (included as List).data = { ...included.data, fromPartial: true } as List["data"];
|
|
out.push(included);
|
|
}
|
|
}
|
|
}
|
|
parent.children = out as Parent["children"];
|
|
});
|
|
}
|
|
|
|
/** Keep the repository's language:filename fence syntax in the shared MDX pipeline. */
|
|
export function remarkDocsConventions() {
|
|
return (tree: Root) => {
|
|
inlinePartials(tree);
|
|
visit(tree, "code", (node) => {
|
|
const colon = node.lang?.indexOf(":") ?? -1;
|
|
if (colon < 0 || !node.lang) return;
|
|
const filename = node.lang.slice(colon + 1);
|
|
node.lang = node.lang.slice(0, colon);
|
|
if (filename) node.meta = `title=${JSON.stringify(filename)}`;
|
|
});
|
|
};
|
|
}
|