import { describe, expect, it } from "vitest"; import { extractMarkdownImageSources, MarkdownDocumentParseError, renderMarkdown } from "../src/render-markdown.js"; describe("renderMarkdown", () => { it("将 GFM Alert 渲染为与 Pandoc 一致的独立标题引用块", () => { const result = renderMarkdown( "> [!CAUTION]\n> **关键约束**:必须执行。", ); expect(result.bodyHtml).toContain( '
', ); expect(result.bodyHtml).toContain( 'Caution
\n关键约束:必须执行。
', ); expect(result.bodyHtml).not.toContain("[!CAUTION]"); }); it("为含行内代码的普通段落标记分页保护类", () => { const result = renderMarkdown("段落前 `inline_code` 段落后"); expect(result.articleHtml).toContain( '段落前
', ); }); it("向下游暴露已剥离文首 Front Matter 的正文 Markdown", () => { const rendered = renderMarkdown( "---\ntitle: 测试标题\n---\n# 正文\n\n---\n\n后续内容" ); expect(rendered.markdownBody).toBe( "# 正文\n\n---\n\n后续内容" ); expect(rendered.metadata.title).toBe("测试标题"); }); it("渲染常用 Markdown 扩展并识别能力", () => { const result = renderMarkdown(` # 示例文档 | 名称 | 状态 | | --- | --- | | PDF | 可用 | - [x] 已完成 - [ ] 待处理 \`\`\`ts const answer = 42; \`\`\` 脚注引用[^note]。 [^note]: 脚注正文。 `); expect(result.articleHtml).toContain('id="write"'); expect(result.bodyHtml).toContain("inline_code段落后"); expect(result.bodyHtml).toContain("md-task-list-item"); expect(result.bodyHtml).toContain("hljs-keyword"); expect(result.bodyHtml).toContain("footnote"); expect(result.metadata.title).toBe("示例文档"); expect(result.semanticDocument).toEqual({ schemaVersion: 1, titlePolicy: { metadataTitle: "suppress", firstBodyHeading: "keep" }, regions: [] }); expect(result.features).toEqual( expect.arrayContaining(["code", "table", "task-list", "footnote"]) ); }); it("为围栏代码块输出 Typora 主题兼容容器", () => { const result = renderMarkdown(` \`\`\` 无语言代码块 \`\`\` \`\`\`ts const answer = 42; \`\`\` `); expect(result.bodyHtml).toContain( '
' ); expect(result.bodyHtml).toContain( '无语言代码块\n' ); expect(result.bodyHtml).toContain("hljs-keyword"); }); it("保留 Markdown 表格的列对齐语义", () => { const result = renderMarkdown(` | 左对齐 | 居中 | 右对齐 | | :--- | :---: | ---: | | A | B | C | `); expect(result.bodyHtml).toContain('左对齐 '); expect(result.bodyHtml).toContain('居中 '); expect(result.bodyHtml).toContain('右对齐 '); expect(result.bodyHtml).toContain('A '); expect(result.bodyHtml).toContain('B '); expect(result.bodyHtml).toContain('C '); }); it("只在 GFM 表格单元格内解释无属性 br 换行", () => { const result = renderMarkdown(` | 场景 | 内容 | | --- | --- | | 标准 | 第一行
第二行
第三行
第四行 | 正文中的
、
和
保持文本。 | 转义与代码 | 内容 | | --- | --- | | 转义 | \\
与 <br> | | 代码 | \`
\` | | 属性 |
| \`\`\`html
\`\`\` `); expect(result.bodyHtml).toContain( "第一行
第二行
第三行
第四行" ); expect(result.bodyHtml).toContain( "正文中的 <br>、<br/> 和 <br /> 保持文本" ); expect(result.bodyHtml).toContain("<br> 与 <br>"); expect(result.bodyHtml).toContain("<br>"); expect(result.bodyHtml).toContain("<br class=\"unsafe\">"); expect(result.bodyHtml).toContain( '' ); }); it("读取并规范化 Front Matter 元数据", () => { const result = renderMarkdown(`--- title: 项目报告 author: 张三 subject: 技术方案 keywords: - Markdown - PDF lang: zh-CN --- # 不作为标题 `); expect(result.metadata).toEqual({ title: "项目报告", author: "张三", subject: "技术方案", keywords: ["Markdown", "PDF"], language: "zh-CN" }); }); it("使用稳定错误类型报告无效 Front Matter", () => { expect(() => renderMarkdown(`--- title: [未闭合 --- # 文档 `) ).toThrow(MarkdownDocumentParseError); }); it("生成政企公文的语义化版头、落款和版记", () => { const result = renderMarkdown(`--- title: 关于推进示范项目建设的通知 document: profile: official issuer: 示例市人民政府办公室 number: 示例办发〔2026〕12号 secrecy: 内部 urgency: 加急 signatory: 张三 date: 2026年7月29日 copyTo: 市发展改革委, 市财政局 printingOffice: 示例市人民政府办公室 --- ## 工作要求 正文内容。 `); expect(result.metadata.document).toEqual({ profile: "official", issuer: "示例市人民政府办公室", number: "示例办发〔2026〕12号", secrecy: "内部", urgency: "加急", signatory: "张三", date: "2026年7月29日", copyTo: ["市发展改革委", "市财政局"], printingOffice: "示例市人民政府办公室" }); expect(result.articleHtml).toContain( 'data-document-profile="official"' ); expect(result.articleHtml).toContain( '' ); expect(result.articleHtml).toContain( ' 关于推进示范项目建设的通知
' ); expect(result.articleHtml).toContain( '' ); expect(result.articleHtml).toContain( '