| import katex from "katex"; |
| import { marked } from "marked"; |
|
|
| marked.setOptions({ |
| breaks: true, |
| gfm: true, |
| }); |
|
|
| function replaceAll(value: string, entries: Array<{ token: string; replacement: string }>) { |
| let next = value; |
| for (const entry of entries) { |
| next = next.replaceAll(entry.token, entry.replacement); |
| } |
| return next; |
| } |
|
|
| export function renderAdminMarkdown(markdown: string): string { |
| const codeBlocks: Array<{ token: string; replacement: string }> = []; |
| const mathTokens: Array<{ token: string; replacement: string }> = []; |
| let next = markdown || ""; |
|
|
| next = next.replace(/```[\s\S]*?```/g, (block) => { |
| const token = `@@CODE_BLOCK_${codeBlocks.length}@@`; |
| codeBlocks.push({ token, replacement: block }); |
| return token; |
| }); |
|
|
| next = next.replace(/\$\$([\s\S]+?)\$\$/g, (_match, expression: string) => { |
| const token = `@@BLOCK_MATH_${mathTokens.length}@@`; |
| mathTokens.push({ |
| token, |
| replacement: katex.renderToString(expression.trim(), { |
| displayMode: true, |
| throwOnError: false, |
| strict: "ignore", |
| }), |
| }); |
| return `\n\n${token}\n\n`; |
| }); |
|
|
| next = next.replace(/(?<!\\)\$([^$\n]+?)(?<!\\)\$/g, (_match, expression: string) => { |
| const token = `@@INLINE_MATH_${mathTokens.length}@@`; |
| mathTokens.push({ |
| token, |
| replacement: katex.renderToString(expression.trim(), { |
| displayMode: false, |
| throwOnError: false, |
| strict: "ignore", |
| }), |
| }); |
| return token; |
| }); |
|
|
| next = replaceAll(next, codeBlocks); |
| const html = marked.parse(next) as string; |
| return replaceAll(html, mathTokens); |
| }
|
|
|