diff --git a/plug-api/lib/markdown.ts b/plug-api/lib/markdown.ts new file mode 100644 index 00000000..dea82841 --- /dev/null +++ b/plug-api/lib/markdown.ts @@ -0,0 +1,135 @@ +import { findNodeOfType, ParseTree, renderToText } from "$sb/lib/tree.ts"; + +export function stripMarkdown( + tree: ParseTree, +): string { + if (tree.type?.endsWith("Mark") || tree.type?.endsWith("Delimiter")) { + return ""; + } + + const stripArray = (arr: ParseTree[]) => arr.map(stripMarkdown).join(""); + + switch (tree.type) { + case "Document": + case "Emphasis": + case "Highlight": + case "Strikethrough": + case "InlineCode": + case "StrongEmphasis": + case "Superscript": + case "Subscript": + case "Paragraph": + case "ATXHeading1": + case "ATXHeading2": + case "ATXHeading3": + case "ATXHeading4": + case "ATXHeading5": + case "ATXHeading6": + case "Blockquote": + case "BulletList": + case "OrderedList": + case "ListItem": + case "Table": + case "TableHeader": + case "TableCell": + case "TableRow": + case "Task": + case "HTMLTag": { + return stripArray(tree.children!); + } + + case "FencedCode": + case "CodeBlock": { + tree.children = tree.children!.filter((c) => c.type); + return stripArray(tree.children!); + } + + case "Link": { + const linkTextChildren = tree.children!.slice(1, -4); + return stripArray(linkTextChildren); + } + + case "Image": { + const altTextNode = findNodeOfType(tree, "WikiLinkAlias") || + tree.children![1]; + let altText = altTextNode && altTextNode.type !== "LinkMark" + ? renderToText(altTextNode) + : ""; + + const dimReg = /\d*[^\|\s]*?[xX]\d*[^\|\s]*/.exec(altText); + if (dimReg) { + altText = altText.replace(dimReg[0], "").replace("|", ""); + } + + return altText; + } + + case "WikiLink": { + const aliasNode = findNodeOfType(tree, "WikiLinkAlias"); + + let linkText; + if (aliasNode) { + linkText = aliasNode.children![0].text!; + } else { + const ref = findNodeOfType(tree, "WikiLinkPage")!.children![0].text!; + linkText = ref.split("/").pop()!; + } + + return linkText; + } + + case "NakedURL": { + const url = tree.children![0].text!; + return url; + } + + case "CommandLink": { + const aliasNode = findNodeOfType(tree, "CommandLinkAlias"); + + let command; + if (aliasNode) { + command = aliasNode.children![0].text!; + } else { + command = tree.children![1].children![0].text!; + } + + return command; + } + + case "TaskState": { + return tree.children![1].text!; + } + + case "Escape": { + return tree.children![0].text!.slice(1); + } + + case "CodeText": + case "Entity": { + return tree.children![0].text!; + } + + case "TemplateDirective": + case "DeadlineDate": { + return renderToText(tree); + } + + case "CodeInfo": + case "CommentBlock": + case "FrontMatter": + case "Hashtag": + case "HardBreak": + case "HorizontalRule": + case "NamedAnchor": + case "Attribute": { + return ""; + } + + case undefined: + return tree.text!; + + default: + console.log("Unknown tree type: ", tree.type); + return ""; + } +} diff --git a/plugs/index/toc.ts b/plugs/index/toc.ts index d8bdd5ba..83292ea6 100644 --- a/plugs/index/toc.ts +++ b/plugs/index/toc.ts @@ -1,6 +1,7 @@ import { editor, markdown, YAML } from "$sb/syscalls.ts"; -import { CodeWidgetContent } from "../../plug-api/types.ts"; -import { renderToText, traverseTree } from "$sb/lib/tree.ts"; +import { CodeWidgetContent } from "$sb/types.ts"; +import { stripMarkdown } from "$sb/lib/markdown.ts"; +import { traverseTree } from "$sb/lib/tree.ts"; type Header = { name: string; @@ -31,7 +32,11 @@ export async function widget( traverseTree(tree, (n) => { if (n.type?.startsWith("ATXHeading")) { headers.push({ - name: n.children!.slice(1).map(renderToText).join("").trim(), + name: n.children! + .slice(1) + .map(stripMarkdown) + .join("") + .trim(), pos: n.from!, level: +n.type[n.type.length - 1], });