import markdownItTaskLists from "@hackmd/markdown-it-task-lists"; import { fromHighlighter } from "@shikijs/markdown-it/core"; import MarkdownIt from "markdown-it"; import markdownItAnchor from "markdown-it-anchor"; import markdownItContainer from "markdown-it-container"; import markdownItTocDoneRight from "markdown-it-toc-done-right"; import { createHighlighterCore } from "shiki/core"; const highlighter = createHighlighterCore({ themes: [import("shiki/themes/rose-pine.mjs")], langs: [ import("shiki/langs/javascript.mjs"), import("shiki/langs/typescript.mjs"), import("shiki/langs/python.mjs"), import("shiki/langs/toml.mjs"), import("shiki/langs/rust.mjs"), import("shiki/langs/sql.mjs"), import("shiki/langs/json.mjs"), import("shiki/langs/html.mjs"), import("shiki/langs/css.mjs"), import("shiki/langs/scss.mjs"), import("shiki/langs/bash.mjs"), import("shiki/langs/shell.mjs"), import("shiki/langs/yaml.mjs"), ], loadWasm: import("shiki/wasm"), }); export const getMarkdownRenderer = async () => { const renderer = MarkdownIt({ html: true, linkify: true, }); const otherRenderer = MarkdownIt({ html: true, linkify: true, }); for (const ren of [renderer, otherRenderer]) { ren.use( // @ts-ignore fromHighlighter(await highlighter, { theme: "rose-pine", }), ); ren.use(markdownItAnchor, { permalink: markdownItAnchor.permalink.ariaHidden({ symbol: "", placement: "before", }), }); ren.use(markdownItTocDoneRight, { containerClass: "toc", level: [1, 2, 3, 4], listType: "ul", listClass: "toc-list", itemClass: "toc-item", linkClass: "toc-link", }); ren.use(markdownItTaskLists); ren.use(markdownItContainer, "spoiler"); } renderer.use((md) => { md.renderer.rules.html_block = (tokens, idx) => { // Modify figure tags if (tokens[idx]?.content.startsWith(" { // biome-ignore lint/style/noNonNullAssertion: const output = otherRenderer.renderer.rules.image!( tokens, idx, options, env, self, ); const imageUrl = (output.match(/src="([^"]+)"/) ?? [null, null])[1]; if (!imageUrl) { return output; } const newUrl = `/_ipx/w_800&f_webp/${imageUrl.replace(/^\//, "")}`; return output.replace(imageUrl, newUrl); }; }); return renderer; }; // Extract the FrontMatter header from raw markdown export const parseFrontMatter = (frontMatter: string): T | null => { const regex = /---\n([\s\S]+?)\n---/; const match = frontMatter.match(regex); if (!match) { return null; } const [, frontMatterString] = match; if (!frontMatterString) { return null; } const frontMatterObject = frontMatterString .split("\n") .map((line) => line.split(": ")) .reduce( (acc, [key, value]) => { if (!(key && value)) { return acc; } acc[key] = value; return acc; }, {} as Record, ); return frontMatterObject as T; }; export const stripFrontMatter = (markdown: string) => { // Also strip the --- --- around the front matter return markdown.replace(/---\n([\s\S]+?)\n---/, ""); };