import { marked } from "marked"; import { markedHighlight } from "marked-highlight"; import hljs from "highlight.js/lib/common"; marked.use( markedHighlight({ langPrefix: "hljs language-", highlight(code, lang) { if (lang && hljs.getLanguage(lang)) { return hljs.highlight(code, { language: lang }).value; } return hljs.highlightAuto(code).value; }, }), ); /** * Preprocesses markdown content to support extended image size syntax: * * ![alt](url =WIDTHxHEIGHT) * ![alt](url "title" =WIDTHxHEIGHT) * * WIDTH and HEIGHT are pixel values or percentages (e.g. 50%). * Either can be omitted: * =200x → width 200 only * =x150 → height 150 only * * The syntax is transformed into a plain tag before passing to marked * because CommonMark terminates the link destination at whitespace, making it * impossible for marked to see the size spec otherwise. */ export function preprocessMarkdown(content) { if (!content) return content; return content.replace(/!\[([^\]]*)\]\(([^\s)"]+)(?:\s+"([^"]*)")?\s+=(\d*%?)[xX](\d*%?)\)/gi, (_, alt, url, title, w, h) => { const safeAlt = alt.replace(/"/g, """); let attrs = `src="${url}" alt="${safeAlt}"`; if (title) attrs += ` title="${title.replace(/"/g, """)}"`; if (w) attrs += ` width="${w}"`; if (h) attrs += ` height="${h}"`; return ``; }); } export function renderMarkdown(content) { return marked.parse(preprocessMarkdown(content || ""), { gfm: true }); }