Files

123 lines
3.3 KiB
TypeScript

import { readdirSync, readFileSync, statSync } from "node:fs";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
import { bench, describe } from "vitest";
import { lezerToParseTree } from "../../client/markdown_parser/parse_tree.ts";
import {
extendedMarkdownLanguage,
parseMarkdown,
} from "../../client/markdown_parser/parser.ts";
import {
addParentPointers,
cloneTree,
collectNodesMatching,
collectNodesOfType,
findNodeOfType,
type ParseTree,
removeParentPointers,
renderToText,
replaceNodesMatching,
traverseTree,
} from "./tree.ts";
// --- Load all docs markdown files ---
const __dirname = fileURLToPath(new URL(".", import.meta.url));
const docsDir = join(__dirname, "../../docs");
type PageData = {
name: string;
text: string;
};
function loadMarkdownFiles(dir: string, base = ""): PageData[] {
const pages: PageData[] = [];
for (const entry of readdirSync(dir)) {
const fullPath = join(dir, entry);
const relativePath = base ? `${base}/${entry}` : entry;
const stat = statSync(fullPath);
if (stat.isDirectory()) {
pages.push(...loadMarkdownFiles(fullPath, relativePath));
} else if (entry.endsWith(".md")) {
pages.push({
name: relativePath.replace(/\.md$/, ""),
text: readFileSync(fullPath, "utf-8"),
});
}
}
return pages;
}
const pages = loadMarkdownFiles(docsDir);
// Pre-parse trees for tree-operation benchmarks
const parsedTrees: ParseTree[] = pages.map((p) => parseMarkdown(p.text));
describe("Tree API Benchmarks", () => {
bench("lezerToParseTree (all pages)", () => {
for (const p of pages) {
// Remove \r like parse() does, then run lezer + conversion
const text = p.text.replaceAll("\r", "");
const lezerTree = extendedMarkdownLanguage.parser.parse(text);
lezerToParseTree(text, lezerTree.topNode);
}
});
bench("addParentPointers (all pages)", () => {
for (const tree of parsedTrees) {
addParentPointers(tree);
}
});
bench("removeParentPointers (all pages)", () => {
// First add them so we can remove them
for (const tree of parsedTrees) {
addParentPointers(tree);
}
for (const tree of parsedTrees) {
removeParentPointers(tree);
}
});
bench("collectNodesOfType (all pages, 'WikiLink')", () => {
for (const tree of parsedTrees) {
collectNodesOfType(tree, "WikiLink");
}
});
bench("collectNodesMatching (all pages, ATXHeading*)", () => {
for (const tree of parsedTrees) {
collectNodesMatching(tree, (n) => !!n.type?.startsWith("ATXHeading"));
}
});
bench("findNodeOfType (all pages, 'FrontMatter')", () => {
for (const tree of parsedTrees) {
findNodeOfType(tree, "FrontMatter");
}
});
bench("traverseTree (all pages, full walk)", () => {
for (const tree of parsedTrees) {
traverseTree(tree, (_n) => false);
}
});
bench("replaceNodesMatching (all pages, no-op)", () => {
for (const tree of parsedTrees) {
replaceNodesMatching(tree, (_n) => undefined);
}
});
bench("renderToText (all pages)", () => {
for (const tree of parsedTrees) {
renderToText(tree);
}
});
bench("cloneTree (all pages)", () => {
for (const tree of parsedTrees) {
cloneTree(tree);
}
});
});