/** * Markdown 渲染器配置 — 基于 marked 库 */ import { marked as markedLib, Renderer } from 'marked'; import { sanitize } from './sanitizer.js'; // 自定义渲染器:链接安全检查 const renderer = new Renderer(); const SAFE_SCHEMES = new Set(['http:', 'https:', 'mailto:', 'tel:', 'ftp:', 'ftps:', 'xmpp:']); renderer.link = function ({ href, text, tokens }) { try { const protocol = new URL(href, 'https://placeholder').protocol; if (!SAFE_SCHEMES.has(protocol)) { return `${text}`; } } catch { /* 允许相对路径 */ } return `${text}`; }; renderer.image = function ({ href, text }) { try { const protocol = new URL(href, 'https://placeholder').protocol; if (!SAFE_SCHEMES.has(protocol)) { return `${text || '图片'}`; } } catch { /* 允许相对路径 */ } return `${text || ''}`; }; // 配置 marked markedLib.use({ renderer, gfm: true, breaks: true, }); /** * 解析 Markdown 并净化 HTML 输出 */ export function marked(md: string): string { if (!md) return ''; const raw = markedLib.parse(md) as string; return sanitize(raw); }