import { ReplyDocumentIR, ReplyNode, ReplyInline } from '../../types/replyExport'; /** * 将 Reply Document IR 序列化为规范化 GFM Markdown */ export function serializeMarkdown(ir: ReplyDocumentIR): string { return ir.nodes.map(renderNodeToMarkdown).join('\n\n'); } function renderNodeToMarkdown(node: ReplyNode): string { switch (node.type) { case 'heading': { const hashes = '#'.repeat(node.level); return `${hashes} ${node.children.map(renderInlineToMarkdown).join('')}`; } case 'paragraph': { return node.children.map(renderInlineToMarkdown).join(''); } case 'list': { return node.items .map((item, idx) => { const prefix = node.ordered ? `${idx + 1}. ` : '- '; return `${prefix}${item.map(renderInlineToMarkdown).join('')}`; }) .join('\n'); } case 'table': { const headerLine = `| ${node.header.map((c) => c.map(renderInlineToMarkdown).join('')).join(' | ')} |`; const sepLine = `| ${node.header.map(() => '---').join(' | ')} |`; const rowLines = node.rows.map( (row) => `| ${row.map((c) => c.map(renderInlineToMarkdown).join('')).join(' | ')} |` ); return [headerLine, sepLine, ...rowLines].join('\n'); } case 'blockquote': { const inner = node.children.map(renderNodeToMarkdown).join('\n\n'); return inner .split('\n') .map((l) => `> ${l}`) .join('\n'); } case 'code': { const lang = node.language || ''; return `\`\`\`${lang}\n${node.value}\n\`\`\``; } case 'math': { if (node.display) { return `$$\n${node.latex}\n$$`; } return `$${node.latex}$`; } case 'mermaid': { return `\`\`\`mermaid\n${node.source}\n\`\`\``; } case 'divider': { return '---'; } default: return ''; } } function renderInlineToMarkdown(inline: ReplyInline): string { switch (inline.type) { case 'text': { let val = inline.value; if (inline.bold) val = `**${val}**`; if (inline.italic) val = `*${val}*`; if (inline.strike) val = `~~${val}~~`; return val; } case 'code': return `\`${inline.value}\``; case 'math': return `$${inline.latex}$`; case 'link': { const text = inline.children.map(renderInlineToMarkdown).join(''); return `[${text}](${inline.href})`; } case 'hardBreak': return '\n'; default: return ''; } }