const esc = (s: string) => s.replace(/&/g, "&").replace(//g, ">"); function inline(s: string): string { return esc(s) .replace(/`([^`]+)`/g, (_, c) => `${c}`) .replace(/\*\*([^*]+)\*\*/g, "$1") .replace(/(^|[\s(])_([^_]+)_/g, "$1$2") .replace( /\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g, '$1', ); } export function renderMarkdown(src: string): string { const lines = src.replace(/\r\n/g, "\n").split("\n"); const out: string[] = []; let i = 0; while (i < lines.length) { const line = lines[i]; if (line.trim() === "") { i++; continue; } if (line.trim().startsWith("```")) { const buf: string[] = []; i++; while (i < lines.length && !lines[i].trim().startsWith("```")) { buf.push(esc(lines[i])); i++; } i++; out.push(`
${buf.join("\n")}
`); continue; } const h = line.match(/^(#{2,4})\s+(.*)$/); if (h) { const level = h[1].length; out.push(`${inline(h[2])}`); i++; continue; } if (/^\s*[-*]\s+/.test(line)) { const items: string[] = []; while (i < lines.length && /^\s*[-*]\s+/.test(lines[i])) { items.push(`
  • ${inline(lines[i].replace(/^\s*[-*]\s+/, ""))}
  • `); i++; } out.push(``); continue; } const para: string[] = []; while ( i < lines.length && lines[i].trim() !== "" && !lines[i].trim().startsWith("```") && !/^(#{2,4})\s+/.test(lines[i]) && !/^\s*[-*]\s+/.test(lines[i]) ) { para.push(lines[i]); i++; } out.push(`

    ${inline(para.join(" "))}

    `); } return out.join("\n"); }