import Prism from "prismjs";
import "prismjs/components/prism-lua.js";
import "prismjs/components/prism-markdown.js";
import { escape as escapeHtml } from "@std/html";
import { mangle } from "marked-mangle";
import GitHubSlugger from "github-slugger";
import * as Marked from "marked";
const slugger = new GitHubSlugger();
Marked.marked.use(mangle());
const ADMISSION_REG = /^\[(info|warn|tip)\]:\s/;
export interface MarkdownHeading {
id: string;
html: string;
}
class DefaultRenderer extends Marked.Renderer {
headings: MarkdownHeading[] = [];
override text(
token: Marked.Tokens.Text | Marked.Tokens.Escape | Marked.Tokens.Tag,
): string {
if (
token.type === "text" && "tokens" in token && token.tokens !== undefined
) {
return this.parser.parseInline(token.tokens);
}
// Smartypants typography enhancement
return token.text
.replaceAll("...", "…")
.replaceAll("--", "—")
.replaceAll("---", "–")
.replaceAll(/(\w)'(\w)/g, "$1’$2")
.replaceAll(/s'/g, "s’")
.replaceAll("'", "’")
.replaceAll(/["](.*?)["]/g, "“$1”")
.replaceAll(/"(.*?)"/g, "“$1”")
.replaceAll(/['](.*?)[']/g, "‘$1’");
}
override heading({
tokens,
depth,
raw,
}: Marked.Tokens.Heading): string {
const slug = slugger.slug(raw);
const text = this.parser.parseInline(tokens);
this.headings.push({ id: slug, html: text });
return `
${escapeHtml(text)}
`;
} else {
const html = Prism.highlight(text, grammar, lang);
out +=
`${html}
`;
}
out += `\n${icon}${ label[type] }${Marked.parser(tokens)}\n`; } return `
\n${Marked.parser(tokens)}\n`; } } export interface MarkdownHeading { id: string; html: string; } export interface MarkdownOptions { inline?: boolean; } export function renderMarkdown( input: string, opts: MarkdownOptions = {}, ): { headings: MarkdownHeading[]; html: string } { const renderer = new DefaultRenderer(); const markedOpts: Marked.MarkedOptions = { gfm: true, renderer, }; const html = opts.inline ? Marked.parseInline(input, markedOpts) as string : Marked.parse(input, markedOpts) as string; return { headings: renderer.headings, html }; }