Files
MorphDoc/docs/V0.6.0_DESIGN.md
T

14 KiB
Raw Blame History

v0.6.0 DOCX 导出与 Markdown 工具栏设计

状态:阶段 1 架构已冻结;阶段 2 Pandoc 运行时与许可证方案已冻结。

1. 版本目标

v0.6.0 包含两个核心功能:

  1. 新增可由 Microsoft Word 和 WPS 正常打开、编辑、保存的 DOCX 导出;
  2. 将左侧原生文本框升级为 CodeMirror 6,并增加可扩展的基础 Markdown 工具栏。

本版本不改变现有 Markdown 渲染、连续预览、分页预览和 PDF 导出链路。 DOCX 是与 PDF 并列的新输出适配器,不以 HTML 转 Word 的方式复用 PDF 打印结果。

flowchart LR
    A["Markdown 与受限资源"] --> B["共享文档与资源服务"]
    B --> C["现有 HTML 渲染"]
    C --> D["连续与分页预览"]
    C --> E["Chromium PDF"]
    B --> F["DOCX 文档准备"]
    F --> G["媒体 PNG 渲染"]
    F --> H["动态 reference.docx"]
    G --> I["Pandoc DOCX"]
    H --> I
    I --> J["Word 与 WPS 可编辑文档"]

2. 发布门禁

DOCX 功能必须同时满足以下两条门禁,否则不能作为 v0.6.0 正式能力 发布。

2.1 纸张与样式门禁

导出的 DOCX 必须保留当前导出配置和主题中有明确 Word 语义的属性:

  • 纸张尺寸;
  • 横向或纵向;
  • 上、右、下、左页边距;
  • 页眉、页脚和基础页码;
  • 正文与标题的中西文字体、字号、颜色和字重;
  • 段落对齐、行距、段前、段后和首行缩进;
  • 标题 16
  • 引用、列表、任务列表、表格和代码块;
  • 图片、图片标题、Mermaid 和 ECharts
  • 链接、脚注和可转换为 OMML 的数学公式。

同一输入在固定 Pandoc 版本和相同配置下应生成结构稳定的 OOXML。DOCX 与 PDF 使用不同的排版引擎,不要求两者逐页分页完全一致。

2.2 可编辑性门禁

导出的文档必须:

  • 可由当前支持范围内的 Microsoft Word 和 WPS 无修复提示地打开;
  • 正文、标题、列表、表格、链接、脚注和公式保持原生 OOXML 结构;
  • 文本可选择、修改、复制和重新排版;
  • 图片可移动、缩放、删除和替换;
  • 在 Word 或 WPS 中编辑并保存后,可由另一应用再次打开;
  • 不以整页截图、整篇图片或 HTML altChunk 作为正文实现。

Mermaid 和 ECharts 在 DOCX 中是高分辨率 PNG,不是 Office 原生图表对象。 它们可以作为图片编辑,但不能在 Word 或 WPS 中修改图表数据。

3. “完整样式映射”的定义

CSS 和 WordprocessingML 不是等价排版模型。“完整样式映射”在本项目中 定义为:对项目声明支持的文档语义和可转换样式建立确定性映射,而不是 承诺转换任意浏览器 CSS。

3.1 必须映射

Markdown/主题语义 DOCX 目标
正文 Normal 或项目正文段落样式
标题 16 Word 原生标题层级
强调、粗体、删除线、行内代码 字符级 OOXML 属性或字符样式
引用 独立段落样式
有序、无序和任务列表 原生编号定义与段落编号
围栏代码块 代码段落样式、底纹、边框和等宽字体
表格 原生 Word 表格、单元格和表格样式
图片与图注 DrawingML 图片和图注段落样式
链接 原生超链接关系
脚注 原生脚注
数学公式 Pandoc 可转换时使用 OMML
分页控制 Word 段落分页属性

3.2 尽力映射

  • 简单边框、底纹、单元格内边距和表格表头样式;
  • 标题的段前、段后、与下段同页;
  • 图片最大宽度和图注对齐;
  • 内置主题中能够转换为 Word 属性的装饰;
  • 自定义主题中经安全解析后允许的字体、颜色和基础段落属性。

3.3 不承诺映射

  • CSS 伪元素、滤镜、阴影、渐变、动画和复杂背景;
  • 浏览器布局模型,如 Flex、Grid、绝对定位和复杂浮动;
  • Paged.js 分页结果和 Chromium 子像素布局;
  • 任意 CSS 选择器的层叠结果;
  • JavaScript 生成的交互行为;
  • PDF 专属打印缩放。

内置主题必须提供经过测试的 Word 样式映射。自定义主题采用受限的通用 映射;未来可以在主题清单中增加显式 DOCX 样式扩展,但不作为本阶段的 前置条件。

4. DOCX 技术路线

4.1 组件职责

packages/core/
  DOCX 请求、结果、能力和错误协议

packages/application/
  文档准备、资源解析、媒体处理和导出用例

packages/docx-engine/(计划新增)
  Pandoc 调用、动态 reference.docx、OOXML 与 DOCX 验证

apps/server/
  HTTP 适配、Pandoc 运行时和并发控制

apps/desktop/
  IPC 适配、内置 Pandoc 定位和原生另存为

apps/web/
  DOCX 导出交互、状态和错误展示

packages/docx-engine 不依赖 Fastify、Electron 或浏览器 UI。Server 和 Desktop 只提供平台运行时、传输与保存能力。

4.2 转换流程

  1. 校验 Markdown、主题和导出配置;
  2. 在每个请求的独立临时目录准备 Markdown 和资源;
  3. 将本地、远程和 Data URL 图片规范化为受控本地资源;
  4. 使用现有 Chromium/Electron 图表运行时将 Mermaid、ECharts 输出为 高分辨率 PNG
  5. 根据主题和导出配置生成动态 reference.docx
  6. 调用固定版本 Pandoc 生成 DOCX
  7. 检查 DOCX ZIP 和关键 OOXML 部件;
  8. 返回 DOCX Buffer,并在 finally 中清理临时目录。

不引入 Python。Node.js 负责业务编排、OOXML 修改、资源处理、进程控制和 安全边界;Pandoc 仅作为受控的独立转换器。

4.3 Pandoc 分发

  • 固定使用 Pandoc 3.9.0.2,不在构建时跟随 latest
  • 开发环境允许通过 DOCX_PANDOC_PATHPATH 使用相同版本;
  • Docker amd64 使用官方 Linux 静态发行包,安装到 /opt/pandoc/3.9.0.2/
  • Windows Desktop 将官方 ZIP 中的 pandoc.exe、许可证和版权文件放入 process.resourcesPath 下的固定资源目录;
  • 用户输入不得成为可执行路径或任意命令行参数;
  • 启动时或导出前校验精确版本,并通过 capability 状态报告不可用原因;
  • 发行时保留 GPL、版权声明和精确版本源码获取方式;
  • Pandoc 继续作为独立子进程,不链接或导入其程序代码。

官方文件、SHA-256、路径优先级、包体实测和许可证义务见 Pandoc 运行时与分发规范

4.4 动态 reference.docx

动态模板以固定 Pandoc 版本的默认 reference.docx 为基线,由 Node 修改必要 OOXML

  • word/document.xml 的节属性;
  • word/styles.xml 的段落与字符样式;
  • 页眉页脚部件及其关系;
  • 页码字段;
  • 字体、主题色和兼容性设置;
  • 文档元数据。

模板缓存键至少包含 Pandoc 版本、主题版本和影响 DOCX 的导出配置。缓存 不得跨越不兼容的主题或 Pandoc 版本。

4.5 媒体策略

  • 普通 PNG、JPEG 等兼容图片保持原格式或安全规范化;
  • SVG 默认转换为 PNG,不直接嵌入 DOCX;
  • Mermaid 和 ECharts 使用 PNG
  • PNG 按足够高的像素尺寸生成,DOCX 中使用纸张内容区对应的物理尺寸;
  • 保持纵横比,不得超出可用内容宽高;
  • 图表渲染必须等待字体、图片和图表资源完成;
  • 图表错误产生局部、可理解的导出错误,不输出损坏 DOCX。

5. Markdown 编辑器与工具栏

5.1 编辑器选型

左侧编辑器采用:

  • @uiw/react-codemirror
  • @codemirror/lang-markdown
  • CodeMirror 6 的状态、选区、事务、历史和快捷键扩展。

不引入带独立 Markdown 预览的完整编辑器,避免复制现有安全渲染和统一 预览链路。CodeMirror 只管理 Markdown 源文本,不负责生成最终预览 HTML。

5.2 命令扩展层

工具栏使用项目自有命令接口,不绑定第三方 Markdown 编辑器的私有插件 协议。命令至少包含:

interface MarkdownEditorCommand {
  id: string;
  group: "history" | "text" | "block" | "insert" | "document";
  label: string;
  shortcut?: string;
  isEnabled?: (context: EditorCommandContext) => boolean;
  execute: (context: EditorCommandContext) => void | Promise<void>;
  render?: (context: ToolbarRenderContext) => React.ReactNode;
}

该接口必须允许命令:

  • 读取和修改选区;
  • 执行单个可撤销事务;
  • 恢复光标和焦点;
  • 打开 React 弹窗或侧边面板;
  • 执行异步操作;
  • 根据编辑器或平台状态禁用;
  • 注册快捷键。

5.3 v0.6.0 基础命令

  • 撤销、重做;
  • 标题级别;
  • 加粗、斜体、删除线;
  • 行内代码、代码块;
  • 引用;
  • 有序列表、无序列表和任务列表;
  • 链接、图片;
  • 表格;
  • 分隔线。

Front Matter 表单工具和 ECharts YAML 工具不在 v0.6.0 实现,但必须 能够在后续版本中以命令和面板扩展接入,不再次更换编辑器。

5.4 兼容性要求

替换原生 textarea 后必须保持:

  • React 中的 Markdown 受控状态和防抖渲染;
  • Web 文件选择和下载;
  • Desktop 新建、打开、保存、另存为及文件关联;
  • 外部文件变化检测;
  • 多窗口和同文件单例;
  • 编辑区折叠与恢复焦点;
  • 编辑区和预览区滚动同步;
  • Windows 与 macOS 常用快捷键语义;
  • 中文输入法组合输入;
  • 大文档编辑性能。

外部文件加载不得污染用户的撤销历史;工具栏的一次操作应形成一次清晰 的撤销步骤。

6. API、安全与运行约束

6.1 API 与 IPC

  • Web 提供单独的 DOCX 导出接口;
  • Desktop 提供最小权限 DOCX IPC
  • 两端复用相同应用用例和 DOCX 引擎;
  • 响应使用正确的 DOCX MIME 类型和安全 UTF-8 文件名;
  • DOCX 状态不得污染 PDF 精确预览缓存。

6.2 安全

  • 每次导出使用独立临时目录,并在所有退出路径清理;
  • 继续阻止路径穿越、符号链接越界、内网资源访问和任意本地文件读取;
  • 对输入大小、资源数量、图片像素、总资源大小、执行时间和并发设置上限;
  • Pandoc 只接收程序构造的参数数组,不经过 Shell;
  • 不允许 Markdown 注入 Pandoc 参数、Lua Filter 路径或可执行文件路径;
  • Pandoc 子进程超时后必须终止,应用退出时不得遗留子进程;
  • 输出必须通过 ZIP 和关键 OOXML 部件检查后才能返回。

6.3 隐私

DOCX 沿用当前无历史数据库原则。Markdown、图片、中间 PNG、动态模板和 最终 DOCX 只存在于当前请求或桌面保存流程中。

6.4 当前项目许可与内部发行

  • 当前仓库采用公司内部专属许可证,包元数据标记为 UNLICENSED
  • 公司内部可以共享源码,并分发 Web/Docker、Desktop、ZIP 和测试产物;
  • 未经书面许可,不向公司外部或公开网络分发项目源码与二进制;
  • 用户文档和导出结果不因使用本软件而自动受项目许可证约束;
  • 三套 Typora 复制主题只允许随公司内部发行物分发;
  • Apache License 2.0 是未来公开 GitHub 时的候选许可证,不在当前阶段 自动授予;
  • 公开前必须重新审查第三方依赖、主题、字体、Pandoc 源码义务及 Git 历史。

根许可证和第三方边界分别见仓库根目录 LICENSETHIRD_PARTY_NOTICES.md

7. 验收矩阵

7.1 文档内容

综合样例必须覆盖:

  • 中英文正文和多级标题;
  • 强调、删除线、行内代码和链接;
  • 有序、无序、嵌套和任务列表;
  • 引用、代码块、长表格和分页边界;
  • 脚注与 KaTeX 数学公式;
  • 本地图片、受限远程图片和图片标题;
  • Mermaid
  • 当前支持的全部 ECharts 系列;
  • Front Matter 公文、报告和标书结构;
  • 页眉、页脚、页码及多页文档。

7.2 配置组合

至少验证:

  • A4 纵向;
  • A4 横向;
  • Letter 纵向;
  • 两组不同的四边页边距;
  • 两套字体和颜色差异明显的内置主题;
  • 普通文档主题和正式公文主题。

7.3 应用互操作

每个发布候选至少完成:

  1. Word 打开、编辑、保存,WPS 再打开;
  2. WPS 打开、编辑、保存,Word 再打开;
  3. 修改正文、标题、列表、表格和图片;
  4. 确认无修复提示、内容丢失或整体图片化;
  5. 对关键页面进行渲染截图和视觉检查。

自动检查至少验证:

  • DOCX ZIP 完整;
  • 页面和页边距属性;
  • 样式定义;
  • 图片关系;
  • 页眉页脚和页码字段;
  • 原生编号、表格、链接、脚注和 OMML;
  • 不存在正文 altChunk

7.4 回归

  • 现有 Web、Docker 和 Desktop PDF 导出不得回退;
  • 连续预览、快速预览和精确预览不得回退;
  • Mermaid、ECharts 和图片安全边界保持不变;
  • 完整通过 npm testnpm run typechecknpm run buildgit diff --check

8. 分阶段提交约定

v0.6.0 按以下阶段推进:

  1. 架构与验收边界;
  2. Pandoc 分发、许可证与运行时;
  3. DOCX 共享模型与导出协议;
  4. CodeMirror 6 与基础工具栏;
  5. DOCX 资源预处理;
  6. 动态 reference.docx
  7. Pandoc DOCX 转换服务;
  8. Web 与 Desktop 导出交互;
  9. 自动化测试与 Word/WPS 验收;
  10. 体积、文档和正式发布。

每个阶段遵循:

  1. 完成当前阶段实现与验证;
  2. 汇报结果并等待用户验收;
  3. 验收后创建一个独立提交;
  4. 再确认是否进入下一阶段。

阶段提交不得混入无关修改,也不得通过重置或清理覆盖用户工作区内容。

9. 已知限制

  • DOCX 与 PDF 不保证分页完全相同;
  • 图表不是 Office 原生可编辑图表;
  • 任意浏览器 CSS 无法无损映射为 WordprocessingML
  • 自定义主题首版只转换受支持属性;
  • 字体能否显示取决于目标系统安装字体或后续是否实现字体嵌入;
  • Word 与 WPS 对复杂分页和字体替换可能存在细微差异。

这些限制不降低两条发布门禁:受支持的纸张与样式必须稳定映射,文档主体 必须保持 Word/WPS 可编辑。