Files
Agent-System/web/src/engine/blockToMarkdown.ts
T

111 lines
3.3 KiB
TypeScript

import { DocumentAST, DocumentBlock } from '../types/block';
import { cleanHeadingContent } from './autoNumber';
/**
* blockASTToMarkdown: 将 Block AST 树无损还原为整洁的标准 Markdown 文本
*/
export function blockASTToMarkdown(ast: DocumentAST): string {
const chunks: string[] = [];
function serializeBlock(block: DocumentBlock) {
switch (block.type) {
case 'heading': {
const level = Math.max(1, Math.min(6, block.level || 1));
const prefix = '#'.repeat(level);
const titleText = cleanHeadingContent(block.content);
const numPrefix = block.numbering ? `${block.numbering} ` : '';
chunks.push(`${prefix} ${numPrefix}${titleText}\n`);
break;
}
case 'paragraph': {
if (block.content) {
chunks.push(`${block.content}\n`);
}
break;
}
case 'list': {
const isOrdered = block.properties?.isOrdered ?? true;
const items =
block.properties?.listItems ||
block.content
.split('\n')
.map((line) => line.replace(/^\s*(\d+\.|[-*+])\s+/, '').trim())
.filter(Boolean);
const start = block.properties?.startNumber || 1;
items.forEach((item, idx) => {
const clean = item.trim();
if (!clean) return;
if (isOrdered) {
chunks.push(`${start + idx}. ${clean}\n`);
} else {
chunks.push(`- ${clean}\n`);
}
});
chunks.push('\n');
break;
}
case 'divider': {
chunks.push('---\n');
break;
}
case 'callout': {
const typeTag = block.properties?.calloutType === 'regulatory' ? '合规依据' : '提示';
chunks.push(`> **[${typeTag}]** ${block.content}\n`);
break;
}
case 'mermaid': {
chunks.push('```mermaid\n' + block.content.trim() + '\n```\n');
break;
}
case 'math': {
chunks.push('$$\n' + block.content.trim() + '\n$$\n');
break;
}
case 'table': {
const data = block.properties?.tableData;
if (data && data.length > 0) {
const colCount = Math.max(...data.map((r) => r.length));
const lines: string[] = [];
// 表头行
const header = data[0];
const headerCells = Array.from({ length: colCount }, (_, idx) => header[idx] || '');
lines.push('| ' + headerCells.join(' | ') + ' |');
// 分隔线
const sep = Array.from({ length: colCount }, () => '---');
lines.push('| ' + sep.join(' | ') + ' |');
// 数据行
for (let r = 1; r < data.length; r++) {
const row = data[r];
const rowCells = Array.from({ length: colCount }, (_, idx) => row[idx] || '');
lines.push('| ' + rowCells.join(' | ') + ' |');
}
chunks.push(lines.join('\n') + '\n');
}
break;
}
case 'document': {
if (block.children) {
for (const child of block.children) {
serializeBlock(child);
}
}
break;
}
default: {
if (block.content) {
chunks.push(`${block.content}\n`);
}
break;
}
}
}
serializeBlock(ast.rootBlock);
return chunks.join('\n').trim() + '\n';
}