import { compile } from '@mdx-js/mdx'; import { fromMarkdown } from 'mdast-util-from-markdown'; import { mdxFromMarkdown } from 'mdast-util-mdx'; import { mdxjs } from 'micromark-extension-mdxjs'; interface StreamChunk { type: 'text' | 'annotation' | 'html' | 'block-start' | 'block-end'; content: string; annotation?: { type: string; color?: string; multiline?: boolean; }; tag?: string; className?: string; } // 自定义插件:将文本内容转换为流式块 function remarkStreamChunks() { return (tree: any) => { const chunks: StreamChunk[] = []; function processNode(node: any) { try { if (node.type === 'heading') { // 处理标题 chunks.push({ type: 'block-start', content: '', tag: 'div', className: `text-${4-node.depth}xl font-bold mb-4` }); node.children?.forEach(processNode); chunks.push({ type: 'block-end', content: '', tag: 'div' }); } else if (node.type === 'paragraph') { // 处理段落 chunks.push({ type: 'block-start', content: '', tag: 'div', className: 'text-base mb-4' }); node.children?.forEach(processNode); chunks.push({ type: 'block-end', content: '', tag: 'div' }); } else if (node.type === 'mdxJsxTextElement' && node.name === 'Annot') { // 处理 Annot 注释 const annotType = node.attributes?.find((attr: any) => attr.name === 'type')?.value; const color = node.attributes?.find((attr: any) => attr.name === 'color')?.value; if (!annotType) { console.warn('Annot 标签缺少 type 属性'); return; } chunks.push({ type: 'annotation', content: node.children?.[0]?.value || '', annotation: { type: annotType, color: color, multiline: false }, tag: 'span' }); } else if (node.type === 'text') { // 处理普通文本 if (node.value?.trim()) { chunks.push({ type: 'text', content: node.value, tag: 'span' }); } } else if (node.type === 'list') { // 处理列表 chunks.push({ type: 'block-start', content: '', tag: 'ul', className: 'list-disc list-inside mb-4' }); node.children?.forEach(processNode); chunks.push({ type: 'block-end', content: '', tag: 'ul' }); } else if (node.type === 'listItem') { // 处理列表项 chunks.push({ type: 'block-start', content: '', tag: 'li', className: 'mb-2' }); node.children?.forEach(processNode); chunks.push({ type: 'block-end', content: '', tag: 'li' }); } else if (node.children) { // 递归处理其他节点 node.children.forEach(processNode); } } catch (error) { console.error('处理节点时出错:', error, '节点类型:', node.type); } } try { tree.children?.forEach(processNode); if (chunks.length === 0) { throw new Error('解析结果为空'); } return { chunks }; } catch (error) { console.error('处理 MDX 树时出错:', error); throw error; } }; } export async function parseMDXContent(content: string): Promise { try { if (!content || typeof content !== 'string') { throw new Error('无效的内容输入'); } console.log('开始处理 MDX 内容...'); // 使用 fromMarkdown 直接解析 MDX const tree = fromMarkdown(content, { extensions: [mdxjs()], mdastExtensions: [mdxFromMarkdown()] }); // 应用我们的自定义处理器 const chunks: StreamChunk[] = []; const processor = remarkStreamChunks(); const result = processor(tree); if (!result || !result.chunks || result.chunks.length === 0) { throw new Error('解析 MDX 内容失败:没有生成有效的块'); } console.log('MDX 处理完成,生成块数:', result.chunks.length); return result.chunks; } catch (error) { console.error('解析 MDX 内容时出错:', error); throw error; } } // 用于客户端渲染的编译函数 export async function compileMDX(source: string) { const compiled = await compile(source, { outputFormat: 'function-body', development: false, jsx: true, jsxImportSource: 'react' }); return String(compiled); }