Compare commits
4
Commits
v0.6.2
..
7533226366
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7533226366 | ||
|
|
c4df499680 | ||
|
|
effeca7ca8 | ||
|
|
55614fafed |
@@ -13,34 +13,28 @@
|
||||
|
||||
## 2. 会话启动检查
|
||||
|
||||
新会话、上下文压缩后或对当前目录不确定时,在执行其他 Shell 命令前先运行:
|
||||
|
||||
```powershell
|
||||
Get-Location
|
||||
```
|
||||
|
||||
确认目录为:
|
||||
新会话、上下文压缩后或对当前目录不确定时,在执行其他 Shell 命令前先确认仓库根目录。不得假设固定绝对路径或盘符——协作环境可能是 Windows、macOS 或 Linux,克隆位置因机器而异。可用如下只读方式确认(按当前 Shell 语法改写等价命令):
|
||||
|
||||
```text
|
||||
C:\Projects\md-to-pdf
|
||||
git rev-parse --show-toplevel
|
||||
```
|
||||
|
||||
随后依次执行只读检查:
|
||||
|
||||
```powershell
|
||||
```text
|
||||
git status --short
|
||||
git log --oneline -5
|
||||
Get-Content -LiteralPath 'docs\PROGRESS.md' -Encoding UTF8
|
||||
读取 docs/PROGRESS.md(显式使用 UTF-8 编码)
|
||||
```
|
||||
|
||||
当前工作区可能包含用户或上一个会话留下的未提交修改。禁止使用 `git reset --hard`、`git checkout --`、`git clean` 等方式丢弃修改,除非用户明确要求。
|
||||
|
||||
## 3. Shell 与文件操作
|
||||
|
||||
- 当前默认 Shell 为 PowerShell,使用 PowerShell 语法。
|
||||
- 不假设固定 Shell 类型(PowerShell、bash、zsh 等均可能);命令语法跟随当前会话实际使用的 Shell,禁止把某一种 Shell 的专属语法当作硬性要求写入产物、脚本或文档。
|
||||
- 不要通过绝对路径 `cd` 前缀拼接命令;工具支持时优先使用 `workdir`。
|
||||
- 子目录操作使用相对路径或直接设置 `workdir`。
|
||||
- PowerShell 读取、写入、追加或替换文本时显式指定 UTF-8 编码。
|
||||
- 读取、写入、追加或替换文本文件时显式指定 UTF-8 编码。
|
||||
- 本地文件修改优先使用补丁工具,避免使用不透明的大段覆盖命令。
|
||||
- 不执行破坏性删除;如确需删除,先确认精确目标并向用户说明。
|
||||
|
||||
@@ -150,19 +144,19 @@ docs/ 进度、架构和部署文档
|
||||
|
||||
安装依赖:
|
||||
|
||||
```powershell
|
||||
```text
|
||||
npm install
|
||||
```
|
||||
|
||||
本地开发:
|
||||
|
||||
```powershell
|
||||
```text
|
||||
npm run dev
|
||||
```
|
||||
|
||||
完整验证:
|
||||
|
||||
```powershell
|
||||
```text
|
||||
npm test
|
||||
npm run typecheck
|
||||
npm run build
|
||||
|
||||
+286
@@ -0,0 +1,286 @@
|
||||
# 变更日志
|
||||
|
||||
本文档记录 MorphDoc(原 Markdown PDF 导出器)的重要版本变更。
|
||||
|
||||
格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循
|
||||
[Semantic Versioning](https://semver.org/lang/zh-CN/)。发布时以对应版本章节作为
|
||||
Gitea Release 页面正文的基础;构建产物、校验和及详细验收记录可继续写入
|
||||
`docs/releases/v<version>.md`。
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### 变更
|
||||
|
||||
- 暂无。
|
||||
|
||||
## [0.6.4] - 2026-08-26
|
||||
|
||||
### 新增
|
||||
|
||||
- 桌面端新增 macOS 打包能力:`electron-builder` 增加独立 `mac` 配置块,产出
|
||||
`dmg`,按 arm64、x64 分别单独构建,不产出 universal 包(内置完整
|
||||
Chromium/Electron 与固定版本 Pandoc,合并双架构会让单包体积翻倍)。
|
||||
- Pandoc 运行时清单新增 `darwin/arm64`、`darwin/x64` 两个官方发行项及独立
|
||||
许可证文件来源(macOS 官方 zip 本身不随附许可证文本);桌面 Pandoc 候选
|
||||
路径与 `prepare-pandoc-runtime.mjs` 均已泛化为按 `--platform`/`--arch`
|
||||
参数选取目标,不再只认 Windows x64。
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复 `apps/desktop/scripts/prepare-pandoc-runtime.mjs` 解压内置 Pandoc 时
|
||||
未保留 Unix 可执行权限位的问题(`unzipSync` 不保留压缩包内的权限信息),
|
||||
macOS/Linux 上解压出的二进制此前无法直接执行。
|
||||
- 修复根 `package.json` 中 `build:web-runtime`、`dev`、`desktop:dev` 三个
|
||||
脚本的构建顺序错误:`@md-to-pdf/application` 依赖
|
||||
`@md-to-pdf/preview-engine`,但被排在其构建之前,在没有历史 `dist/`
|
||||
残留的全新环境(如全新克隆 + 全新 `npm install`)中会导致类型解析失败。
|
||||
- 修正 `AGENTS.md` 中硬编码的 Windows 绝对路径与强制 PowerShell 语法,改为
|
||||
按当前 Shell 与仓库实际位置自适应。
|
||||
- 修正测试用例 `packages/docx-engine/tests/pandoc-runtime.test.ts` 中硬编码
|
||||
反斜杠路径分隔符的断言,避免该测试仅能在 Windows 宿主上通过。
|
||||
|
||||
### 验证
|
||||
|
||||
- `docx-engine` 包 15 个测试文件、93 项测试通过;类型检查通过。
|
||||
- 本机 macOS(Apple Silicon)实测:`npm run package:mac:arm64` 全链路成功,
|
||||
内置 darwin-arm64 版 Pandoc 3.9.0.2 完成下载、哈希校验与真实 DOCX 冒烟
|
||||
转换;未打包应用(`--dir`)可正常启动,主进程/渲染进程/GPU 进程/网络
|
||||
服务进程均稳定运行,AppleScript 可正常触发退出。实际截图确认窗口、
|
||||
macOS 原生菜单栏、Markdown 编辑器工具栏、中文字体与实时预览(标题、
|
||||
任务列表、表格、行内公式、引用块)均渲染正常。
|
||||
- 补跑跳过真实语料依赖的全部工作区测试与全项目类型检查、生产构建均
|
||||
通过;`test:docx-real-world-corpus` 与 `test:docx-release-gate-suites`
|
||||
依赖 Git 忽略的真实客户文档语料(`tmp/`),本机没有该目录,这两步
|
||||
在当前环境下无法验证,留待接入真实语料的机器上执行。
|
||||
|
||||
### 兼容与部署
|
||||
|
||||
- 本版本仅完成开发基础设施与验证,未构建正式发行文件:没有产出真实签名
|
||||
的 dmg、没有重新构建 Windows 安装包,也没有重新构建 Docker 镜像;正式
|
||||
macOS 发行产物、Windows/Docker 同步验证留待后续门禁阶段完成后一并发布。
|
||||
|
||||
## [0.6.2] - 2026-08-26
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复真实长文档中表格分页后的列宽、偏移和行样式丢失,冻结逻辑表格列轨并将
|
||||
打印几何稳定传递到 Paged.js 分片。
|
||||
- 修复 Markdown 表格中 `<br>` 变体、连续换行、实体和行内代码的 DOCX 翻译,
|
||||
避免换行逃逸到目标单元格段落之外。
|
||||
- 修复全 JSON 围栏缩进、表格末行对齐、代码高亮和行内代码连续性。
|
||||
- 改进 PDF 文本流排序和数值范围归一化,减少窄字符重叠、跨视觉行破折号及重复
|
||||
表头映射造成的视觉比较误报。
|
||||
|
||||
### 验证
|
||||
|
||||
- 合成基线与长庆真实文档两套严格门禁为 `280/280`,M4N 复杂表格文档为
|
||||
`140/140`。
|
||||
- 健康数据长文档残余误报为 `6/115`(`5.22%`),均核查为重复表头自动对齐或
|
||||
取样错配,基础设施错误为 0。
|
||||
- 全项目测试、类型检查、生产构建、正式 Docker、内置字体 NSIS/ZIP 和离线发行
|
||||
归集通过。
|
||||
|
||||
### 发行与兼容性
|
||||
|
||||
- Desktop 安装器、免安装 ZIP 与 Docker 镜像统一为 0.6.2。
|
||||
- Docker 继续内置固定 Chromium、Pandoc 3.9.0.2 和受校验字体包;Desktop
|
||||
继续直接内置 Serif、Sans、Mono 字体,无需安装系统字体。
|
||||
- Windows 安装器尚未进行 Authenticode 签名,仅适用于公司内部发布。
|
||||
|
||||
## [0.6.1] - 2026-08-04
|
||||
|
||||
### 修复
|
||||
|
||||
- 重构通用 CSS 到 WordprocessingML 翻译链,统一字体、字号、行距、段距、缩进、
|
||||
边框、底纹、表格、引用和代码样式。
|
||||
- 修复字体实际嵌入、中文标点字距、精确行距、打印媒体环境和 Markdown 行内代码
|
||||
连续性问题。
|
||||
|
||||
### 验证
|
||||
|
||||
- 建立 14 套主题 × 两个方向 × 五组页边距的 140 场景视觉矩阵,`140/140`
|
||||
全部通过。
|
||||
- 四套独立封面执行 Chromium、Word、WPS 整页严格门禁,正文执行与物理分页无关
|
||||
的语义块门禁。
|
||||
- 源码服务、Docker Web API 和实际安装 Desktop 三条生产 DOCX 导出链通过。
|
||||
|
||||
### 发行与兼容性
|
||||
|
||||
- Serif、Sans、Mono 三套字体直接内置于 Desktop 安装器和免安装 ZIP,不再发布
|
||||
独立字体安装器或字体 ZIP。
|
||||
- Docker 内置固定 Chromium、Pandoc 3.9.0.2 和三套正式字体包。
|
||||
|
||||
## [0.6.0] - 2026-08-02
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增原生可编辑 DOCX 导出,支持 Microsoft Word 与 WPS,并保留纸张、页边距、
|
||||
字体、段落、标题、代码块、表格、媒体、封面、页眉页脚和页码配置。
|
||||
- 建立通用主题到 DOCX 样式翻译引擎,覆盖 14 套内置主题。
|
||||
- 新增可扩展 Markdown 工具栏,支持标题、强调、代码、引用、列表、任务列表、
|
||||
分隔线及 M×N 表格。
|
||||
- PDF 与 DOCX 统一收口至“导出”菜单,并提供生成进度提示。
|
||||
|
||||
### 变更
|
||||
|
||||
- 产品更名为“墨呈”,英文名 MorphDoc,并保留原 NSIS 安装身份以支持覆盖升级。
|
||||
- Desktop 内置固定 Pandoc 3.9.0.2;Docker 内置 Chromium、Pandoc 和正式字体,
|
||||
支持完全离线部署。
|
||||
- 正式字体资产改由 Git LFS 管理,发行产物统一归集到 `release/v<version>/`。
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复精确预览放大后的右侧留白、保存与导出默认路径、Desktop DOCX 媒体捕获
|
||||
超时及品牌迁移后的安装目录问题。
|
||||
|
||||
## [0.5.1] - 2026-07-29
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增 4 套红头、3 套正式文档和 3 套标书主题,内置主题总数增至 14 套。
|
||||
- 支持主题推荐页边距、页面装饰、页眉页脚、页码和结构化公文、报告及标书
|
||||
Front Matter。
|
||||
- 内置 Fandol 中文字体、两份教程和 14 份主题示例。
|
||||
- Desktop 增加新建、保存、另存为快捷键和未保存确认;另存为后跟随新路径。
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复红头标题居中、正式文档字体、代码块长内容越界和大型代码块跨页留白。
|
||||
- Docker Web 镜像补齐 `samples` 目录。
|
||||
|
||||
### 兼容性
|
||||
|
||||
- 未声明主题推荐设置的主题继续使用原有 16mm 默认页边距。
|
||||
|
||||
## [0.5.0] - 2026-07-28
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增共享 Preview Engine,统一 Web 连续预览、快速分页、Playwright PDF 与
|
||||
Electron PDF 渲染链路。
|
||||
- 新增连续预览和修改位置之后的增量分页,支持稳定前缀复用。
|
||||
- Desktop 支持多窗口、同文件单例、本地路径与 Markdown 链接,以及聚焦时检测
|
||||
外部文件变化。
|
||||
- Web 统一处理文档锚点和 HTTP/HTTPS 外链。
|
||||
|
||||
### 变更
|
||||
|
||||
- 内置主题统一为 Typora Github、Typora Pixyll、Typora whitey 和 Typora Clean。
|
||||
- Windows 安装包统一使用 NSIS,并提供免安装 ZIP。
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复连续预览双滚动条、ECharts 尺寸、PDF 本地链接、围栏代码块样式和发行包
|
||||
复用陈旧 Web 构建产物的问题。
|
||||
|
||||
## [0.4.5] - 2026-07-28
|
||||
|
||||
### 新增
|
||||
|
||||
- Web 与 Desktop 支持新建和保存 Markdown;Desktop 增加 `.md`、`.markdown`
|
||||
文件关联、单实例系统打开、自定义主题目录和窗口状态恢复。
|
||||
- 新文档可按一级标题或首行生成合法文件名,并直接导出 PDF。
|
||||
|
||||
### 变更
|
||||
|
||||
- 图片、Mermaid 和 ECharts 改为按文档顺序串行执行媒体分页回填,每个媒体元素
|
||||
至多重排一次,并保持标题原尺寸。
|
||||
- Web 取消本地素材目录入口。
|
||||
|
||||
## [0.4.4] - 2026-07-27
|
||||
|
||||
### 变更
|
||||
|
||||
- Desktop 发行包仅保留简体中文和英文语言资源,显著缩减目录版、安装包和 ZIP
|
||||
体积,同时保留 Chromium 图形与软件渲染后备组件。
|
||||
|
||||
## [0.4.3] - 2026-07-27
|
||||
|
||||
### 变更
|
||||
|
||||
- Windows Desktop 从 Squirrel 迁移到标准 NSIS 安装向导,支持安装范围和安装目录
|
||||
选择。
|
||||
- 安装包改用英文、无空格、包含版本与平台的文件名,并继续提供免安装 ZIP。
|
||||
|
||||
## [0.4.2] - 2026-07-27
|
||||
|
||||
### 变更
|
||||
|
||||
- 移除 Windows Desktop 原生应用菜单栏,使应用内容直接位于系统标题栏下方。
|
||||
- 此版本仅更新 Desktop,Web 与 Docker Compose 继续保持 0.4.1。
|
||||
|
||||
## [0.4.1] - 2026-07-27
|
||||
|
||||
### 新增
|
||||
|
||||
- 支持 Web 素材目录、Desktop 同目录资源和受限公网图片下载。
|
||||
- 支持图片标题、图片整块分页以及超高图片在单页内容区内自适应缩放。
|
||||
|
||||
### 修复
|
||||
|
||||
- 修复本地与网络图片的资源解析、自然尺寸解码和 PDF 分页边界问题。
|
||||
|
||||
## [0.4.0] - 2026-07-27
|
||||
|
||||
### 新增
|
||||
|
||||
- 首次发布 Electron Windows Desktop,复用与 Web 相同的渲染和 PDF 核心。
|
||||
- 支持桌面 Markdown 文件选择、原生保存和离线 PDF 导出。
|
||||
|
||||
### 修复
|
||||
|
||||
- 固定桌面端英文可执行文件名,避免中文名称影响安装和自动化链路。
|
||||
|
||||
## [0.3.1] - 2026-07-27
|
||||
|
||||
### 新增
|
||||
|
||||
- 扩展 ECharts 第二阶段图表协议和示例覆盖,完善更多系列、坐标轴及组合图表。
|
||||
|
||||
## [0.3.0] - 2026-07-27
|
||||
|
||||
### 新增
|
||||
|
||||
- 新增 ECharts YAML 围栏、安全校验、浏览器 SVG 渲染和 PDF 输出。
|
||||
- 增强编辑区折叠、页码导航和快速预览外层滚动交互。
|
||||
|
||||
### 修复
|
||||
|
||||
- ECharts 媒体块参与统一不可跨页处理,避免图表被分页裁断。
|
||||
|
||||
## [0.2.0] - 2026-07-27
|
||||
|
||||
### 新增
|
||||
|
||||
- 完善 Mermaid 配置、安全渲染、资源等待和预览缩放。
|
||||
- 增强长文档分页、滚动同步和预览/PDF 边界处理。
|
||||
|
||||
### 变更
|
||||
|
||||
- 收敛 Web 预览和 Chromium PDF 的共享渲染抽象,减少链路分叉。
|
||||
|
||||
## [0.1.0] - 2026-07-26
|
||||
|
||||
### 新增
|
||||
|
||||
- 实现 Markdown 安全渲染核心、网页实时预览、本地主题兼容和导出设置。
|
||||
- 支持真实分页预览、固定 Chromium PDF 导出和 PDF 精确预览。
|
||||
- 支持长文档分页、页码导航、滚动同步以及 AIO Docker 容器部署。
|
||||
|
||||
[Unreleased]: https://gitea.rk-health.com/yixiong/MorphDoc/compare/v0.6.4...main
|
||||
[0.6.4]: https://gitea.rk-health.com/yixiong/MorphDoc/releases/tag/v0.6.4
|
||||
[0.6.2]: https://gitea.rk-health.com/yixiong/MorphDoc/releases/tag/v0.6.2
|
||||
[0.6.1]: https://gitea.rk-health.com/yixiong/MorphDoc/releases/tag/v0.6.1
|
||||
[0.6.0]: https://gitea.rk-health.com/yixiong/MorphDoc/releases/tag/v0.6.0
|
||||
[0.5.1]: https://gitea.rk-health.com/yixiong/MorphDoc/releases/tag/v0.5.1
|
||||
[0.5.0]: https://gitea.rk-health.com/yixiong/MorphDoc/releases/tag/v0.5.0
|
||||
[0.4.5]: https://gitea.rk-health.com/yixiong/MorphDoc/src/tag/v0.4.5
|
||||
[0.4.4]: https://gitea.rk-health.com/yixiong/MorphDoc/releases/tag/v0.4.4
|
||||
[0.4.3]: https://gitea.rk-health.com/yixiong/MorphDoc/releases/tag/v0.4.3
|
||||
[0.4.2]: https://gitea.rk-health.com/yixiong/MorphDoc/src/tag/v0.4.2
|
||||
[0.4.1]: https://gitea.rk-health.com/yixiong/MorphDoc/src/tag/v0.4.1
|
||||
[0.4.0]: https://gitea.rk-health.com/yixiong/MorphDoc/src/tag/v0.4.0
|
||||
[0.3.1]: https://gitea.rk-health.com/yixiong/MorphDoc/src/tag/v0.3.1
|
||||
[0.3.0]: https://gitea.rk-health.com/yixiong/MorphDoc/src/tag/v0.3.0
|
||||
[0.2.0]: https://gitea.rk-health.com/yixiong/MorphDoc/src/tag/v0.2.0
|
||||
[0.1.0]: https://gitea.rk-health.com/yixiong/MorphDoc/src/tag/v0.1.0
|
||||
@@ -57,8 +57,8 @@ npm run verify:pandoc-runtime -w @md-to-pdf/desktop
|
||||
```
|
||||
|
||||
版本化目录包、NSIS `Setup.exe` 和 ZIP 输出到
|
||||
`apps/desktop/out/v0.6.2/`。该目录被 Git 忽略。公司内部分发以
|
||||
`MorphDoc-0.6.2-x86_64-Setup.exe` 为正式安装包,ZIP 作为免安装
|
||||
`apps/desktop/out/v0.6.4/`。该目录被 Git 忽略。公司内部分发以
|
||||
`MorphDoc-0.6.4-x86_64-Setup.exe` 为正式安装包,ZIP 作为免安装
|
||||
辅助包;当前未配置代码签名,Windows 首次运行可能显示“未知发布者”
|
||||
提示。
|
||||
|
||||
|
||||
@@ -9,9 +9,25 @@ const windowsIcon = path.resolve(
|
||||
__dirname,
|
||||
"../../logos/desktop/windows/app.ico"
|
||||
);
|
||||
const macIcon = path.resolve(
|
||||
__dirname,
|
||||
"../../logos/desktop/macos/app.icns"
|
||||
);
|
||||
const nsisInclude = process.env.MD_TO_PDF_NSIS_INCLUDE?.trim() ||
|
||||
"build/installer.nsh";
|
||||
|
||||
// macOS 每次只构建一个架构的 dmg(arm64 或 x64),不产出 universal 包——
|
||||
// 项目内置完整 Chromium/Electron 运行时和固定版本 Pandoc,合并双架构会让单个
|
||||
// 安装包体积翻倍。目标架构通过环境变量显式声明,用于挑选对应的内置 Pandoc
|
||||
// 资源目录;不依赖 electron-builder 的 `${arch}` 路径宏(该宏在 extraResources
|
||||
// 场景下有已知的可靠性问题)。
|
||||
const macTargetArch = process.env.MD_TO_PDF_MAC_TARGET_ARCH?.trim() || "";
|
||||
if (macTargetArch && macTargetArch !== "arm64" && macTargetArch !== "x64") {
|
||||
throw new Error(
|
||||
`未知 macOS 目标架构:${macTargetArch}(仅支持 arm64 或 x64)`
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
appId: brand.appId,
|
||||
productName: brand.englishName,
|
||||
@@ -46,22 +62,12 @@ module.exports = {
|
||||
to: "font-packs",
|
||||
filter: ["**/*"]
|
||||
},
|
||||
{
|
||||
from: `.runtime/pandoc/${pandocRuntime.version}/windows-x86_64`,
|
||||
to: `pandoc/${pandocRuntime.version}/windows-x86_64`,
|
||||
filter: [
|
||||
"pandoc.exe",
|
||||
"COPYING.rtf",
|
||||
"COPYRIGHT.txt",
|
||||
"runtime-manifest.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
from: windowsIcon,
|
||||
to: "app.ico"
|
||||
},
|
||||
{
|
||||
from: "../../logos/desktop/macos/app.icns",
|
||||
from: macIcon,
|
||||
to: "app.icns"
|
||||
}
|
||||
],
|
||||
@@ -78,7 +84,19 @@ module.exports = {
|
||||
],
|
||||
icon: windowsIcon,
|
||||
executableName: brand.executableName,
|
||||
artifactName: `${brand.artifactPrefix}-${version}-x86_64.\${ext}`
|
||||
artifactName: `${brand.artifactPrefix}-${version}-x86_64.\${ext}`,
|
||||
extraResources: [
|
||||
{
|
||||
from: `.runtime/pandoc/${pandocRuntime.version}/windows-x86_64`,
|
||||
to: `pandoc/${pandocRuntime.version}/windows-x86_64`,
|
||||
filter: [
|
||||
"pandoc.exe",
|
||||
"COPYING.rtf",
|
||||
"COPYRIGHT.txt",
|
||||
"runtime-manifest.json"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
nsis: {
|
||||
oneClick: false,
|
||||
@@ -94,5 +112,36 @@ module.exports = {
|
||||
installerLanguages: ["zh_CN"],
|
||||
include: nsisInclude,
|
||||
artifactName: `${brand.artifactPrefix}-${version}-x86_64-Setup.\${ext}`
|
||||
},
|
||||
mac: {
|
||||
category: "public.app-category.productivity",
|
||||
icon: macIcon,
|
||||
executableName: brand.executableName,
|
||||
// 项目当前没有 Apple Developer 证书,显式声明不签名,与 Windows 侧
|
||||
// 一贯记录在案的"未签名"状态保持一致;后续如需公证再补齐。
|
||||
identity: null,
|
||||
target: [
|
||||
{
|
||||
target: "dmg"
|
||||
}
|
||||
],
|
||||
extraResources: macTargetArch
|
||||
? [
|
||||
{
|
||||
from: `.runtime/pandoc/${pandocRuntime.version}/darwin-${macTargetArch}`,
|
||||
to: `pandoc/${pandocRuntime.version}/darwin-${macTargetArch}`,
|
||||
filter: [
|
||||
"pandoc",
|
||||
"COPYING.md",
|
||||
"COPYRIGHT",
|
||||
"runtime-manifest.json"
|
||||
]
|
||||
}
|
||||
]
|
||||
: []
|
||||
},
|
||||
dmg: {
|
||||
title: brand.displayName,
|
||||
artifactName: `${brand.artifactPrefix}-${version}-\${arch}.\${ext}`
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@md-to-pdf/desktop",
|
||||
"version": "0.6.2",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"productName": "MorphDoc",
|
||||
"description": "墨呈桌面端:面向结构化 Markdown 的主题化文档创作与发布工具",
|
||||
@@ -11,13 +11,20 @@
|
||||
"build": "npm run clean && npm run build:main && npm run build:preload",
|
||||
"build:embedded-web": "npm --prefix ../.. run build:web-runtime",
|
||||
"prepare:pandoc": "node scripts/prepare-pandoc-runtime.mjs",
|
||||
"prepare:pandoc:mac-arm64": "node scripts/prepare-pandoc-runtime.mjs --platform=darwin --arch=arm64",
|
||||
"prepare:pandoc:mac-x64": "node scripts/prepare-pandoc-runtime.mjs --platform=darwin --arch=x64",
|
||||
"verify:pandoc-runtime": "node scripts/prepare-pandoc-runtime.mjs --check",
|
||||
"build:main": "node scripts/build-main.mjs",
|
||||
"build:preload": "esbuild src/app-preload.ts src/pdf-preload.ts --bundle --platform=node --format=cjs --external:electron --outdir=dist --out-extension:.js=.cjs",
|
||||
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
||||
"dev": "npm run build && wait-on http://localhost:5173 && electron dist/main.js --web-url=http://localhost:5173",
|
||||
"package": "npm run build:embedded-web && npm run prepare:pandoc && npm run build && electron-builder --dir --config electron-builder.config.cjs --x64",
|
||||
"package:mac:arm64": "npm run build:embedded-web && npm run prepare:pandoc:mac-arm64 && npm run build && MD_TO_PDF_MAC_TARGET_ARCH=arm64 electron-builder --dir --config electron-builder.config.cjs --mac --arm64",
|
||||
"package:mac:x64": "npm run build:embedded-web && npm run prepare:pandoc:mac-x64 && npm run build && MD_TO_PDF_MAC_TARGET_ARCH=x64 electron-builder --dir --config electron-builder.config.cjs --mac --x64",
|
||||
"make": "npm run build:embedded-web && npm run prepare:pandoc && npm run build && electron-builder --win nsis zip --config electron-builder.config.cjs --x64",
|
||||
"make:mac:arm64": "npm run build:embedded-web && npm run prepare:pandoc:mac-arm64 && npm run build && MD_TO_PDF_MAC_TARGET_ARCH=arm64 electron-builder --mac dmg --config electron-builder.config.cjs --arm64",
|
||||
"make:mac:x64": "npm run build:embedded-web && npm run prepare:pandoc:mac-x64 && npm run build && MD_TO_PDF_MAC_TARGET_ARCH=x64 electron-builder --mac dmg --config electron-builder.config.cjs --x64",
|
||||
"make:mac": "npm run make:mac:arm64 && npm run make:mac:x64",
|
||||
"test": "vitest run",
|
||||
"typecheck": "tsc -p tsconfig.json --noEmit --pretty false",
|
||||
"verify:docx-theme-styles": "electron scripts/verify-docx-theme-styles.cjs"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import {
|
||||
access,
|
||||
chmod,
|
||||
mkdir,
|
||||
readFile,
|
||||
rename,
|
||||
@@ -43,14 +44,38 @@ async function fileExists(filePath) {
|
||||
}
|
||||
}
|
||||
|
||||
async function readRuntimeManifest() {
|
||||
function platformDirectoryName(platform, architecture) {
|
||||
if (platform === "win32" && architecture === "x64") {
|
||||
return "windows-x86_64";
|
||||
}
|
||||
if (platform === "darwin" && (architecture === "arm64" || architecture === "x64")) {
|
||||
return `darwin-${architecture}`;
|
||||
}
|
||||
throw new Error(`不支持的 Pandoc 桌面内置目标:${platform}/${architecture}`);
|
||||
}
|
||||
|
||||
/** 归档下载得到的、需要从压缩包内部提取的文件名(不含通过 licenseSource 单独下载的许可证文件)。 */
|
||||
function archiveRequiredNames(artifact) {
|
||||
const licenseSource = artifact.licenseSource ?? {};
|
||||
return [
|
||||
normalizedBaseName(artifact.executableRelativePath),
|
||||
...artifact.licenseFiles
|
||||
.filter((fileName) => !licenseSource[fileName])
|
||||
.map(normalizedBaseName)
|
||||
];
|
||||
}
|
||||
|
||||
async function readRuntimeManifest({ platform, architecture }) {
|
||||
const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
||||
const artifact = manifest.artifacts?.find(
|
||||
(candidate) =>
|
||||
candidate.platform === "win32" && candidate.architecture === "x64"
|
||||
candidate.platform === platform && candidate.architecture === architecture
|
||||
);
|
||||
if (!artifact || artifact.archiveType !== "zip") {
|
||||
throw new Error("Pandoc 清单缺少 Windows x64 ZIP 发行项");
|
||||
if (!artifact) {
|
||||
throw new Error(`Pandoc 清单缺少 ${platform}/${architecture} 发行项`);
|
||||
}
|
||||
if (artifact.archiveType !== "zip") {
|
||||
throw new Error(`Pandoc 清单要求 ${platform}/${architecture} 为 ZIP 发行项`);
|
||||
}
|
||||
const requiredNames = [
|
||||
normalizedBaseName(artifact.executableRelativePath),
|
||||
@@ -92,6 +117,33 @@ async function downloadArchive(downloadUrl, destination) {
|
||||
return content;
|
||||
}
|
||||
|
||||
async function downloadLicenseSourceFile(downloadUrl) {
|
||||
const response = await fetch(downloadUrl, {
|
||||
redirect: "follow",
|
||||
signal: AbortSignal.timeout(downloadTimeoutMs)
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Pandoc 许可证文件下载失败:HTTP ${response.status}`);
|
||||
}
|
||||
const content = new Uint8Array(await response.arrayBuffer());
|
||||
if (content.byteLength > maximumExtractedBytes) {
|
||||
throw new Error("Pandoc 许可证文件超过允许的下载大小");
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 部分平台(如 macOS)的官方归档不随附许可证文件,需要按清单声明的
|
||||
* 独立来源单独下载;返回的文件与归档内提取的文件合并后一并校验哈希。
|
||||
*/
|
||||
async function loadLicenseSourceFiles(artifact) {
|
||||
const files = new Map();
|
||||
for (const [fileName, source] of Object.entries(artifact.licenseSource ?? {})) {
|
||||
files.set(fileName, await downloadLicenseSourceFile(source.downloadUrl));
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
async function loadVerifiedArchive(artifact, archivePath) {
|
||||
if (await fileExists(archivePath)) {
|
||||
const cached = new Uint8Array(await readFile(archivePath));
|
||||
@@ -122,10 +174,7 @@ async function loadVerifiedArchive(artifact, archivePath) {
|
||||
}
|
||||
|
||||
function extractRequiredFiles(archive, artifact) {
|
||||
const requiredNames = new Set([
|
||||
normalizedBaseName(artifact.executableRelativePath),
|
||||
...artifact.licenseFiles.map(normalizedBaseName)
|
||||
]);
|
||||
const requiredNames = new Set(archiveRequiredNames(artifact));
|
||||
let selectedBytes = 0;
|
||||
const entries = unzipSync(archive, {
|
||||
filter(file) {
|
||||
@@ -253,9 +302,13 @@ async function verifyPreparedRuntime(targetDirectory, manifest, artifact) {
|
||||
}
|
||||
}
|
||||
|
||||
async function preparePandocRuntime({ checkOnly = false } = {}) {
|
||||
const { manifest, artifact } = await readRuntimeManifest();
|
||||
const platformDirectory = "windows-x86_64";
|
||||
async function preparePandocRuntime({
|
||||
checkOnly = false,
|
||||
platform = process.platform,
|
||||
architecture = process.arch
|
||||
} = {}) {
|
||||
const { manifest, artifact } = await readRuntimeManifest({ platform, architecture });
|
||||
const platformDirectory = platformDirectoryName(platform, architecture);
|
||||
const runtimeRoot = path.join(desktopRoot, ".runtime", "pandoc");
|
||||
const targetDirectory = path.join(
|
||||
runtimeRoot,
|
||||
@@ -278,7 +331,10 @@ async function preparePandocRuntime({ checkOnly = false } = {}) {
|
||||
}
|
||||
const archivePath = path.join(downloadDirectory, archiveName);
|
||||
const archive = await loadVerifiedArchive(artifact, archivePath);
|
||||
const files = extractRequiredFiles(archive, artifact);
|
||||
const files = new Map([
|
||||
...extractRequiredFiles(archive, artifact),
|
||||
...await loadLicenseSourceFiles(artifact)
|
||||
]);
|
||||
const temporaryDirectory = path.join(
|
||||
runtimeRoot,
|
||||
manifest.version,
|
||||
@@ -308,6 +364,10 @@ async function preparePandocRuntime({ checkOnly = false } = {}) {
|
||||
temporaryDirectory,
|
||||
normalizedBaseName(artifact.executableRelativePath)
|
||||
);
|
||||
if (platform !== "win32") {
|
||||
// unzipSync 不保留压缩包内的可执行权限位,POSIX 平台需要手动补上。
|
||||
await chmod(executablePath, 0o755);
|
||||
}
|
||||
verifyPandocVersion(executablePath, manifest.version);
|
||||
await smokeTestPandoc(executablePath);
|
||||
await writeFile(
|
||||
@@ -315,8 +375,8 @@ async function preparePandocRuntime({ checkOnly = false } = {}) {
|
||||
`${JSON.stringify(
|
||||
{
|
||||
version: manifest.version,
|
||||
platform: "win32",
|
||||
architecture: "x64",
|
||||
platform,
|
||||
architecture,
|
||||
license: manifest.license,
|
||||
projectUrl: manifest.projectUrl,
|
||||
sourceArchiveUrl: manifest.sourceArchiveUrl,
|
||||
@@ -338,17 +398,25 @@ async function preparePandocRuntime({ checkOnly = false } = {}) {
|
||||
return targetDirectory;
|
||||
}
|
||||
|
||||
function readCliFlag(name) {
|
||||
const prefix = `--${name}=`;
|
||||
const match = process.argv.find((argument) => argument.startsWith(prefix));
|
||||
return match ? match.slice(prefix.length) : undefined;
|
||||
}
|
||||
|
||||
const isDirectInvocation =
|
||||
process.argv[1] &&
|
||||
path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
|
||||
|
||||
if (isDirectInvocation) {
|
||||
preparePandocRuntime({ checkOnly: process.argv.includes("--check") }).catch(
|
||||
(error) => {
|
||||
console.error(error instanceof Error ? error.message : error);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
);
|
||||
preparePandocRuntime({
|
||||
checkOnly: process.argv.includes("--check"),
|
||||
platform: readCliFlag("platform") ?? process.platform,
|
||||
architecture: readCliFlag("arch") ?? process.arch
|
||||
}).catch((error) => {
|
||||
console.error(error instanceof Error ? error.message : error);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { mkdtemp, realpath, rm, writeFile } from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
@@ -18,7 +18,11 @@ describe("桌面 Markdown 文件参数", () => {
|
||||
expect(isMarkdownFilePath("C:\\docs\\说明.txt")).toBe(false);
|
||||
});
|
||||
|
||||
it("从启动参数中提取绝对 Markdown 路径", () => {
|
||||
// findMarkdownFileArgument 依赖 Node 的 path 模块识别绝对路径,其行为
|
||||
// 随宿主 OS 而定:Windows 风格盘符路径只有在 Windows 宿主上才会被
|
||||
// 识别为绝对路径,这与真实部署一致(Windows 安装包只会在 Windows 上
|
||||
// 收到 Windows 风格的启动参数),因此该用例仅在 Windows 宿主上有意义。
|
||||
it.runIf(process.platform === "win32")("从启动参数中提取绝对 Markdown 路径", () => {
|
||||
expect(
|
||||
findMarkdownFileArgument(
|
||||
[
|
||||
@@ -83,15 +87,19 @@ describe("桌面 Markdown 文件参数", () => {
|
||||
const filePath = path.join(directory, "快照.md");
|
||||
try {
|
||||
await writeFile(filePath, "# 第一版", "utf8");
|
||||
// readMarkdownFileSnapshot 内部会 realpath 解析符号链接(例如 macOS
|
||||
// 的 /var -> /private/var),返回的是规范化路径,因此断言也需要对
|
||||
// 同一路径做 realpath,而不是直接比较 mkdtemp 拼接出的原始路径。
|
||||
const canonicalFilePath = await realpath(filePath);
|
||||
const snapshot = await readMarkdownFileSnapshot(filePath, 100);
|
||||
|
||||
expect(snapshot.document).toEqual({
|
||||
markdown: "# 第一版",
|
||||
fileName: "快照.md"
|
||||
});
|
||||
expect(snapshot.filePath).toBe(filePath);
|
||||
expect(snapshot.filePath).toBe(canonicalFilePath);
|
||||
expect(snapshot.documentKey).toBe(
|
||||
createMarkdownDocumentKey(filePath)
|
||||
createMarkdownDocumentKey(canonicalFilePath)
|
||||
);
|
||||
expect(snapshot.contentHash).toBe(
|
||||
createMarkdownContentHash("# 第一版")
|
||||
|
||||
@@ -44,8 +44,8 @@ describe("桌面发行构建链", () => {
|
||||
"@md-to-pdf/markdown-echarts",
|
||||
"@md-to-pdf/core",
|
||||
"@md-to-pdf/renderer",
|
||||
"@md-to-pdf/application",
|
||||
"@md-to-pdf/preview-engine",
|
||||
"@md-to-pdf/application",
|
||||
"@md-to-pdf/web"
|
||||
];
|
||||
|
||||
@@ -160,7 +160,7 @@ describe("桌面发行构建链", () => {
|
||||
artifactPrefix: "MorphDoc"
|
||||
});
|
||||
expect(desktopManifest).toMatchObject({
|
||||
version: "0.6.2",
|
||||
version: "0.6.4",
|
||||
productName: "MorphDoc"
|
||||
});
|
||||
expect(builderConfig).toContain("appId: brand.appId");
|
||||
|
||||
@@ -10,7 +10,7 @@ const app = buildApp({
|
||||
? {
|
||||
fontPacks: {
|
||||
roots: [fontPackRoot],
|
||||
appVersion: process.env.APP_VERSION ?? "0.6.2"
|
||||
appVersion: process.env.APP_VERSION ?? "0.6.4"
|
||||
}
|
||||
}
|
||||
: {})
|
||||
|
||||
@@ -14,7 +14,7 @@ function readProjectFile(relativePath: string) {
|
||||
return readFileSync(`${projectRoot}/${relativePath}`, "utf8");
|
||||
}
|
||||
|
||||
describe("Docker v0.6.2 部署契约", () => {
|
||||
describe("Docker v0.6.4 部署契约", () => {
|
||||
it("完整构建并复制 DOCX 运行时工作区和 Lua Filter", () => {
|
||||
const dockerfile = readProjectFile("deploy/Dockerfile");
|
||||
const workspaces = [
|
||||
@@ -82,7 +82,7 @@ describe("Docker v0.6.2 部署契约", () => {
|
||||
);
|
||||
expect(dockerfile).toContain("FONT_PACK_ROOT=/app/.local/font-packs");
|
||||
expect(compose).toContain(
|
||||
'APP_VERSION: "${MD_TO_PDF_APP_VERSION:-0.6.2}"'
|
||||
'APP_VERSION: "${MD_TO_PDF_APP_VERSION:-0.6.4}"'
|
||||
);
|
||||
expect(dockerignore.split(/\r?\n/u)).toContain(".local");
|
||||
expect(dockerignore).toContain("!output/font-packs/root/**");
|
||||
|
||||
@@ -10,8 +10,8 @@ const webRoot = fileURLToPath(new URL("../", import.meta.url));
|
||||
|
||||
describe("应用版本", () => {
|
||||
it("从统一构建版本生成标题徽标", () => {
|
||||
expect(APP_VERSION).toBe("0.6.2");
|
||||
expect(APP_VERSION_LABEL).toBe("v0.6.2");
|
||||
expect(APP_VERSION).toBe("0.6.4");
|
||||
expect(APP_VERSION_LABEL).toBe("v0.6.4");
|
||||
});
|
||||
|
||||
it("允许浏览器加载同源 Web Manifest", () => {
|
||||
|
||||
+6
-6
@@ -38,7 +38,7 @@ docker compose -f deploy\compose.yaml down
|
||||
可以直接指定版本化镜像名称构建:
|
||||
|
||||
```powershell
|
||||
$env:MD_TO_PDF_IMAGE = 'yixiong/md-to-pdf:v0.6.2'
|
||||
$env:MD_TO_PDF_IMAGE = 'yixiong/md-to-pdf:v0.6.4'
|
||||
docker compose -f deploy\compose.yaml build
|
||||
```
|
||||
|
||||
@@ -48,13 +48,13 @@ docker compose -f deploy\compose.yaml build
|
||||
已经保留同版本系列的已验证镜像,可在内网或软件源较慢时复用其运行层:
|
||||
|
||||
```powershell
|
||||
$env:MD_TO_PDF_IMAGE = 'yixiong/md-to-pdf:v0.6.2'
|
||||
$env:MD_TO_PDF_IMAGE = 'yixiong/md-to-pdf:v0.6.4'
|
||||
$env:MD_TO_PDF_RUNTIME_BASE_IMAGE = 'yixiong/md-to-pdf:v0.6.0'
|
||||
$env:MD_TO_PDF_REUSE_PLAYWRIGHT_RUNTIME = '1'
|
||||
docker compose -f deploy\compose.yaml build
|
||||
```
|
||||
|
||||
复用模式会校验基础镜像中存在 Chromium,再覆盖 v0.6.2 应用代码和生产
|
||||
复用模式会校验基础镜像中存在 Chromium,再覆盖 v0.6.4 应用代码和生产
|
||||
依赖。正式跨机器构建仍建议使用默认完整路径。
|
||||
|
||||
## 主题挂载
|
||||
@@ -76,7 +76,7 @@ docker compose -f deploy\compose.yaml up -d
|
||||
|
||||
## 内置字体包
|
||||
|
||||
v0.6.2 的发行镜像固定将受校验字体包内置到
|
||||
v0.6.4 的发行镜像固定将受校验字体包内置到
|
||||
`/app/.local/font-packs`。Compose 不挂载宿主机字体目录,因此部署端
|
||||
无需额外复制字体,Preview、PDF 和 DOCX 可以离线使用同一套原生资产。
|
||||
|
||||
@@ -104,7 +104,7 @@ docker compose -f deploy\compose.yaml up -d
|
||||
发布前执行真实内置字体门禁:
|
||||
|
||||
```powershell
|
||||
$env:MD_TO_PDF_IMAGE = 'yixiong/md-to-pdf:v0.6.2'
|
||||
$env:MD_TO_PDF_IMAGE = 'yixiong/md-to-pdf:v0.6.4'
|
||||
npm run verify:docker-font-pack
|
||||
```
|
||||
|
||||
@@ -122,7 +122,7 @@ npm run verify:docker-font-pack
|
||||
| `MD_TO_PDF_REUSE_PLAYWRIGHT_RUNTIME` | `0` | 是否复用基础镜像中的 Chromium |
|
||||
| `MD_TO_PDF_PORT` | `8080` | 宿主机监听端口 |
|
||||
| `MD_TO_PDF_THEME_DIR` | `../.local/themes` | 宿主机主题目录 |
|
||||
| `MD_TO_PDF_APP_VERSION` | `0.6.2` | 字体包兼容性判断使用的应用版本 |
|
||||
| `MD_TO_PDF_APP_VERSION` | `0.6.4` | 字体包兼容性判断使用的应用版本 |
|
||||
| `PDF_CONCURRENCY` | `1` | 同时执行的 PDF 任务数 |
|
||||
| `PDF_MAX_QUEUE` | `4` | 等待队列上限 |
|
||||
| `PDF_TIMEOUT_MS` | `120000` | 单次 PDF 生成超时 |
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ services:
|
||||
PDF_CONCURRENCY: "${PDF_CONCURRENCY:-1}"
|
||||
PDF_MAX_QUEUE: "${PDF_MAX_QUEUE:-4}"
|
||||
PDF_TIMEOUT_MS: "${PDF_TIMEOUT_MS:-120000}"
|
||||
APP_VERSION: "${MD_TO_PDF_APP_VERSION:-0.6.2}"
|
||||
APP_VERSION: "${MD_TO_PDF_APP_VERSION:-0.6.4}"
|
||||
FONT_PACK_ROOT: /app/.local/font-packs
|
||||
volumes:
|
||||
- "${MD_TO_PDF_THEME_DIR:-../.local/themes}:/app/.local/themes:ro"
|
||||
|
||||
@@ -175,7 +175,7 @@ const environment = {
|
||||
...buildEnvironment,
|
||||
MD_TO_PDF_PORT: String(port),
|
||||
MD_TO_PDF_THEME_DIR: themeRoot,
|
||||
MD_TO_PDF_APP_VERSION: "0.6.2"
|
||||
MD_TO_PDF_APP_VERSION: "0.6.4"
|
||||
};
|
||||
const compose = [
|
||||
"compose",
|
||||
|
||||
@@ -2,6 +2,34 @@
|
||||
|
||||
最后更新:2026-08-26
|
||||
|
||||
## v0.6.4 环境自适应与 macOS 打包
|
||||
|
||||
- `AGENTS.md` 不再硬编码 Windows 绝对路径与强制 PowerShell 语法;会话启动检查改为
|
||||
动态确认仓库根目录,命令语法跟随当前会话实际 Shell。
|
||||
- 新增 macOS 桌面打包能力:`electron-builder` 增加独立 `mac` 配置块,产出 `dmg`,
|
||||
按 arm64、x64 分别单独构建、不产出 universal 包;Pandoc 运行时清单新增
|
||||
`darwin/arm64`、`darwin/x64` 两个官方发行项(含独立许可证文件来源,因为 macOS
|
||||
官方 zip 本身不随附许可证文本),`prepare-pandoc-runtime.mjs` 与桌面 Pandoc
|
||||
候选路径均已泛化为按 `--platform`/`--arch` 参数选取目标。
|
||||
- 顺手发现并修复两个此前从未在 macOS 全新环境下暴露过的真实 bug:
|
||||
解压内置 Pandoc 时未保留 Unix 可执行权限位(`unzipSync` 不保留压缩包内权限,
|
||||
已补 `chmod 0o755`);根 `package.json` 的 `build:web-runtime`/`dev`/`desktop:dev`
|
||||
把 `@md-to-pdf/application` 排在其依赖的 `@md-to-pdf/preview-engine` 之前构建,
|
||||
在没有历史 `dist/` 残留的全新环境中会导致类型解析失败,已调整构建顺序。
|
||||
- 本机 macOS(Apple Silicon)实测:`npm run package:mac:arm64` 全链路成功,内置
|
||||
darwin-arm64 版 Pandoc 3.9.0.2 完成下载、哈希校验与真实 DOCX 冒烟转换;未打包
|
||||
应用(`--dir`)可正常启动,主/渲染/GPU/网络服务进程均稳定运行,可正常退出。
|
||||
实际截图确认窗口、macOS 原生菜单栏、编辑器工具栏、中文字体与实时预览(标题、
|
||||
任务列表、表格、行内公式、引用块)均渲染正常。
|
||||
- 跳过依赖真实语料的 `test:docx-real-world-corpus`、`test:docx-release-gate-suites`
|
||||
后,其余全部工作区测试、全项目类型检查和生产构建均通过;这两步依赖 Git 忽略、
|
||||
需从可信来源单独提供的真实客户文档(`tmp/`),本机没有该目录,留待接入真实
|
||||
语料的机器上执行。
|
||||
- 本版本仅完成开发基础设施与验证,未构建正式发行文件:没有产出真实签名的
|
||||
dmg、没有重新构建 Windows 安装包,也没有重新构建 Docker 镜像;下一步是统一
|
||||
DOCX 发布门禁的产出目录规范(版本号动态化,不再写死)并新增清理脚本,随后
|
||||
评估四套 140 门禁矩阵的并行执行策略。
|
||||
|
||||
## v0.6.2 DOCX 发布门禁结论
|
||||
|
||||
- 原整批 560 已停用,有效门禁由四套相互独立的 140 组成,未启动、恢复或重建旧 560 流程。
|
||||
|
||||
+15
-1
@@ -1,5 +1,16 @@
|
||||
# 发版规则
|
||||
|
||||
## 变更日志与发布说明
|
||||
|
||||
根目录 [`CHANGELOG.md`](../CHANGELOG.md) 是版本变更摘要的单一事实来源。
|
||||
每项面向用户或部署方的重要新增、修复、行为变化和兼容性变化应先记录在
|
||||
`Unreleased`;冻结版本时将相关内容移动到带发布日期的版本章节。
|
||||
|
||||
Gitea Release 页面正文应以 `CHANGELOG.md` 对应版本章节为基础生成,可按发布
|
||||
场景补充下载提示,但不得与变更日志中的功能、兼容性和验证结论冲突。
|
||||
`docs/releases/v<version>.md` 用于保存更详细的发布门禁、验证结论和内部发行说明,
|
||||
不单独维护另一份相互矛盾的版本摘要。
|
||||
|
||||
## 唯一产物目录
|
||||
|
||||
所有正式分发文件必须统一归集到仓库根目录下的:
|
||||
@@ -54,7 +65,8 @@ TTF、OTF、WOFF 和 WOFF2 必须由 Git LFS 跟踪。新增或升级字体前
|
||||
1. 完成全量测试、类型检查、生产构建和视觉门禁。
|
||||
2. 构建字体直接内置的 Desktop 安装包和便携 ZIP。
|
||||
3. 构建并验证版本化 Docker 镜像。
|
||||
4. 准备 `docs/releases/v<version>.md`。
|
||||
4. 将 `CHANGELOG.md` 中本版本变更从 `Unreleased` 冻结为带日期的版本章节,
|
||||
并以该章节为基础准备 `docs/releases/v<version>.md` 与 Gitea Release 正文。
|
||||
5. 执行:
|
||||
|
||||
```powershell
|
||||
@@ -65,6 +77,8 @@ TTF、OTF、WOFF 和 WOFF2 必须由 Git LFS 跟踪。新增或升级字体前
|
||||
7. 创建内容完整的 `release:` 提交。
|
||||
8. 重新生成 release 清单,确保 `gitCommit` 指向该发布提交。
|
||||
9. 创建 annotated `v<version>` 标签,标签说明与发布提交正文一致。
|
||||
10. 发布 Gitea Release,正文以 `CHANGELOG.md` 对应版本章节为基础,并附上
|
||||
本轮正式分发文件。
|
||||
|
||||
安装器公开分发前应完成 Authenticode 签名;未签名产物只能按内部发布风险
|
||||
规则分发。
|
||||
|
||||
Generated
+17
-70
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "md-to-pdf",
|
||||
"version": "0.6.2",
|
||||
"version": "0.6.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "md-to-pdf",
|
||||
"version": "0.6.2",
|
||||
"version": "0.6.4",
|
||||
"license": "UNLICENSED",
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"apps/desktop": {
|
||||
"name": "@md-to-pdf/desktop",
|
||||
"version": "0.6.2",
|
||||
"version": "0.6.4",
|
||||
"devDependencies": {
|
||||
"@md-to-pdf/application": "0.4.1",
|
||||
"@md-to-pdf/docx-engine": "0.1.0",
|
||||
@@ -626,7 +626,6 @@
|
||||
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.29.7",
|
||||
"@babel/generator": "^7.29.7",
|
||||
@@ -1056,7 +1055,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.43.7.tgz",
|
||||
"integrity": "sha512-FZsExxkoxnAN+d9TgqXLg5g4A1oQwzX9WlkOT5i2PKkcW7xx3Bmu0vs90g6fo9Mpdsb/l96dnAraQ8932aO4/g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@codemirror/state": "^6.7.0",
|
||||
"crelt": "^1.0.6",
|
||||
@@ -1310,6 +1308,7 @@
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cross-dirname": "^0.1.0",
|
||||
"debug": "^4.3.4",
|
||||
@@ -1331,6 +1330,7 @@
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
@@ -2019,18 +2019,6 @@
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/source-map": {
|
||||
"version": "0.3.11",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
|
||||
"integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||
@@ -3500,7 +3488,6 @@
|
||||
"integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.2.2"
|
||||
}
|
||||
@@ -3771,20 +3758,6 @@
|
||||
"integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.17.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz",
|
||||
"integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
@@ -4441,7 +4414,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.10.44",
|
||||
"caniuse-lite": "^1.0.30001806",
|
||||
@@ -4910,7 +4882,8 @@
|
||||
"integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.6",
|
||||
@@ -4952,7 +4925,6 @@
|
||||
"resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.34.0.tgz",
|
||||
"integrity": "sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
@@ -5375,7 +5347,6 @@
|
||||
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
|
||||
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
@@ -5921,6 +5892,7 @@
|
||||
"integrity": "sha512-Jc19XPV9y9+2bAdZPkXuVNGNIEFBq9poHC61l8Kv6FdK7DRG3+Ic0rerC0DXOaeHNz8yW0fg/JnF8GQROOF5MA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"app-builder-lib": "26.15.3",
|
||||
"builder-util": "26.15.3",
|
||||
@@ -5934,6 +5906,7 @@
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@electron/asar": "^3.2.1",
|
||||
"debug": "^4.1.1",
|
||||
@@ -5954,6 +5927,7 @@
|
||||
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"jsonfile": "^4.0.0",
|
||||
@@ -5969,6 +5943,7 @@
|
||||
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
@@ -5979,6 +5954,7 @@
|
||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
@@ -7470,7 +7446,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "^4.5.0",
|
||||
@@ -7554,7 +7529,6 @@
|
||||
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.16.0.tgz",
|
||||
"integrity": "sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^7.1.2",
|
||||
"@iconify/utils": "^3.0.2",
|
||||
@@ -8076,7 +8050,6 @@
|
||||
"integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -8262,6 +8235,7 @@
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"commander": "^9.4.0"
|
||||
},
|
||||
@@ -8279,6 +8253,7 @@
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^12.20.0 || >=14"
|
||||
}
|
||||
@@ -8423,7 +8398,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz",
|
||||
"integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -8433,7 +8407,6 @@
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz",
|
||||
"integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"scheduler": "^0.27.0"
|
||||
},
|
||||
@@ -9155,6 +9128,7 @@
|
||||
"integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"mkdirp": "^0.5.1",
|
||||
"rimraf": "~2.6.2"
|
||||
@@ -9180,6 +9154,7 @@
|
||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.6"
|
||||
},
|
||||
@@ -9194,6 +9169,7 @@
|
||||
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"glob": "^7.1.3"
|
||||
},
|
||||
@@ -9201,34 +9177,6 @@
|
||||
"rimraf": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.49.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.49.0.tgz",
|
||||
"integrity": "sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
"acorn": "^8.15.0",
|
||||
"commander": "^2.20.0",
|
||||
"source-map-support": "~0.5.20"
|
||||
},
|
||||
"bin": {
|
||||
"terser": "bin/terser"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/terser/node_modules/commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/thread-stream": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.2.0.tgz",
|
||||
@@ -9541,7 +9489,6 @@
|
||||
"integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.27.0 || ^0.28.0",
|
||||
"fdir": "^6.5.0",
|
||||
|
||||
+10
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "md-to-pdf",
|
||||
"version": "0.6.2",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"license": "UNLICENSED",
|
||||
"description": "面向结构化 Markdown 的主题化文档创作与发布工具",
|
||||
@@ -10,8 +10,8 @@
|
||||
],
|
||||
"scripts": {
|
||||
"build": "npm run build:web-runtime && npm run build -w @md-to-pdf/font-pack-builder && npm run build -w @md-to-pdf/server && npm run build -w @md-to-pdf/desktop",
|
||||
"build:web-runtime": "npm run build -w @md-to-pdf/markdown-echarts && npm run build -w @md-to-pdf/core && npm run build -w @md-to-pdf/semantic-document && npm run build -w @md-to-pdf/docx-theme-engine && npm run build -w @md-to-pdf/font-pack-registry && npm run build -w @md-to-pdf/docx-engine && npm run build -w @md-to-pdf/renderer && npm run build -w @md-to-pdf/application && npm run build -w @md-to-pdf/preview-engine && npm run build -w @md-to-pdf/web",
|
||||
"dev": "npm run build -w @md-to-pdf/markdown-echarts && npm run build -w @md-to-pdf/core && npm run build -w @md-to-pdf/semantic-document && npm run build -w @md-to-pdf/docx-theme-engine && npm run build -w @md-to-pdf/font-pack-registry && npm run build -w @md-to-pdf/docx-engine && npm run build -w @md-to-pdf/renderer && npm run build -w @md-to-pdf/application && npm run build -w @md-to-pdf/preview-engine && concurrently -k -n markdown-echarts,core,semantic-document,docx-theme-engine,font-pack-registry,docx-engine,renderer,application,preview-engine,server,web \"npm:dev:markdown-echarts\" \"npm:dev:core\" \"npm:dev:semantic-document\" \"npm:dev:docx-theme-engine\" \"npm:dev:font-pack-registry\" \"npm:dev:docx-engine\" \"npm:dev:renderer\" \"npm:dev:application\" \"npm:dev:preview-engine\" \"npm:dev:server\" \"npm:dev:web\"",
|
||||
"build:web-runtime": "npm run build -w @md-to-pdf/markdown-echarts && npm run build -w @md-to-pdf/core && npm run build -w @md-to-pdf/semantic-document && npm run build -w @md-to-pdf/docx-theme-engine && npm run build -w @md-to-pdf/font-pack-registry && npm run build -w @md-to-pdf/docx-engine && npm run build -w @md-to-pdf/renderer && npm run build -w @md-to-pdf/preview-engine && npm run build -w @md-to-pdf/application && npm run build -w @md-to-pdf/web",
|
||||
"dev": "npm run build -w @md-to-pdf/markdown-echarts && npm run build -w @md-to-pdf/core && npm run build -w @md-to-pdf/semantic-document && npm run build -w @md-to-pdf/docx-theme-engine && npm run build -w @md-to-pdf/font-pack-registry && npm run build -w @md-to-pdf/docx-engine && npm run build -w @md-to-pdf/renderer && npm run build -w @md-to-pdf/preview-engine && npm run build -w @md-to-pdf/application && concurrently -k -n markdown-echarts,core,semantic-document,docx-theme-engine,font-pack-registry,docx-engine,renderer,application,preview-engine,server,web \"npm:dev:markdown-echarts\" \"npm:dev:core\" \"npm:dev:semantic-document\" \"npm:dev:docx-theme-engine\" \"npm:dev:font-pack-registry\" \"npm:dev:docx-engine\" \"npm:dev:renderer\" \"npm:dev:application\" \"npm:dev:preview-engine\" \"npm:dev:server\" \"npm:dev:web\"",
|
||||
"dev:markdown-echarts": "npm run dev -w @md-to-pdf/markdown-echarts",
|
||||
"dev:core": "npm run dev -w @md-to-pdf/core",
|
||||
"dev:semantic-document": "npm run dev -w @md-to-pdf/semantic-document",
|
||||
@@ -24,12 +24,17 @@
|
||||
"dev:server": "npm run dev -w @md-to-pdf/server",
|
||||
"dev:web": "npm run dev -w @md-to-pdf/web",
|
||||
"dev:desktop": "npm run dev -w @md-to-pdf/desktop",
|
||||
"desktop:dev": "npm run build -w @md-to-pdf/markdown-echarts && npm run build -w @md-to-pdf/core && npm run build -w @md-to-pdf/semantic-document && npm run build -w @md-to-pdf/font-pack-registry && npm run build -w @md-to-pdf/docx-engine && npm run build -w @md-to-pdf/renderer && npm run build -w @md-to-pdf/application && npm run build -w @md-to-pdf/preview-engine && concurrently -k -n web,desktop \"npm:dev:web\" \"npm:dev:desktop\"",
|
||||
"desktop:dev": "npm run build -w @md-to-pdf/markdown-echarts && npm run build -w @md-to-pdf/core && npm run build -w @md-to-pdf/semantic-document && npm run build -w @md-to-pdf/font-pack-registry && npm run build -w @md-to-pdf/docx-engine && npm run build -w @md-to-pdf/renderer && npm run build -w @md-to-pdf/preview-engine && npm run build -w @md-to-pdf/application && concurrently -k -n web,desktop \"npm:dev:web\" \"npm:dev:desktop\"",
|
||||
"desktop:package": "npm run build:font-pack && npm run package -w @md-to-pdf/desktop",
|
||||
"desktop:package:mac:arm64": "npm run build:font-pack && npm run package:mac:arm64 -w @md-to-pdf/desktop",
|
||||
"desktop:package:mac:x64": "npm run build:font-pack && npm run package:mac:x64 -w @md-to-pdf/desktop",
|
||||
"build:font-pack": "npm run build -w @md-to-pdf/core && npm run build -w @md-to-pdf/docx-theme-engine && npm run build -w @md-to-pdf/font-pack-registry && npm run build -w @md-to-pdf/docx-engine && npm run build -w @md-to-pdf/font-pack-builder && node scripts/build-font-packs.mjs",
|
||||
"verify:font-pack": "npm run build:font-pack",
|
||||
"verify:docker-font-pack": "npm run verify:font-pack && npm run build:web-runtime && npm run build -w @md-to-pdf/server && node deploy/verify-font-pack-compose.mjs",
|
||||
"desktop:make": "npm run build:font-pack && node scripts/build-desktop-release.mjs",
|
||||
"desktop:make:mac:arm64": "npm run build:font-pack && npm run make:mac:arm64 -w @md-to-pdf/desktop",
|
||||
"desktop:make:mac:x64": "npm run build:font-pack && npm run make:mac:x64 -w @md-to-pdf/desktop",
|
||||
"desktop:make:mac": "npm run desktop:make:mac:arm64 && npm run desktop:make:mac:x64",
|
||||
"release:stage": "node scripts/stage-release.mjs",
|
||||
"test:release-stage": "node --test scripts/stage-release.test.mjs",
|
||||
"test:docx-layout-visual-matrix-cases": "node --test scripts/docx-layout-visual-matrix-cases.test.mjs",
|
||||
@@ -49,6 +54,7 @@
|
||||
"verify:docx-layout-visual-matrix": "npm run test:docx-layout-visual-matrix-cases && npm run verify:font-pack && npm run build:web-runtime && npm run build -w @md-to-pdf/document-visual-diff && npm run build -w @md-to-pdf/server && node scripts/verify-docx-layout-visual-matrix.mjs",
|
||||
"verify:docx-release-gate-suite": "npm run test:docx-layout-visual-matrix-cases && npm run test:docx-real-world-corpus && npm run test:docx-release-gate-suites && npm run verify:font-pack && npm run build:web-runtime && npm run build -w @md-to-pdf/document-visual-diff && npm run build -w @md-to-pdf/server && node scripts/verify-docx-release-gate-suite.mjs",
|
||||
"verify:docx-release-gate-560": "npm run verify:docx-release-gate-suite",
|
||||
"clean:docx-gate-output": "node scripts/clean-docx-gate-output.mjs",
|
||||
"test": "npm run test:release-stage && npm run test:docx-layout-visual-matrix-cases && npm run test:docx-real-world-corpus && npm run test:docx-release-gate-suites && npm run test -w @md-to-pdf/markdown-echarts && npm run test -w @md-to-pdf/core && npm run build -w @md-to-pdf/core && npm run test -w @md-to-pdf/semantic-document && npm run build -w @md-to-pdf/semantic-document && npm run test -w @md-to-pdf/docx-theme-engine && npm run test -w @md-to-pdf/document-visual-diff && npm run test -w @md-to-pdf/font-pack-registry && npm run build -w @md-to-pdf/font-pack-registry && npm run test -w @md-to-pdf/docx-engine && npm run build -w @md-to-pdf/docx-engine && npm run test -w @md-to-pdf/font-pack-builder && npm run test -w @md-to-pdf/renderer && npm run test -w @md-to-pdf/application && npm run build -w @md-to-pdf/application && npm run test -w @md-to-pdf/preview-engine && npm run build -w @md-to-pdf/preview-engine && npm run test -w @md-to-pdf/web && npm run test -w @md-to-pdf/server && npm run test -w @md-to-pdf/desktop",
|
||||
"typecheck": "npm run typecheck -w @md-to-pdf/markdown-echarts && npm run build -w @md-to-pdf/markdown-echarts && npm run typecheck -w @md-to-pdf/core && npm run build -w @md-to-pdf/core && npm run typecheck -w @md-to-pdf/semantic-document && npm run build -w @md-to-pdf/semantic-document && npm run typecheck -w @md-to-pdf/docx-theme-engine && npm run build -w @md-to-pdf/docx-theme-engine && npm run typecheck -w @md-to-pdf/document-visual-diff && npm run typecheck -w @md-to-pdf/font-pack-registry && npm run typecheck -w @md-to-pdf/docx-engine && npm run build -w @md-to-pdf/docx-engine && npm run typecheck -w @md-to-pdf/font-pack-builder && npm run typecheck -w @md-to-pdf/renderer && npm run build -w @md-to-pdf/renderer && npm run typecheck -w @md-to-pdf/application && npm run build -w @md-to-pdf/application && npm run typecheck -w @md-to-pdf/preview-engine && npm run build -w @md-to-pdf/preview-engine && npm run typecheck -w @md-to-pdf/web && npm run typecheck -w @md-to-pdf/server && npm run typecheck -w @md-to-pdf/desktop"
|
||||
},
|
||||
|
||||
@@ -2,13 +2,18 @@ import { DOCX_PANDOC_VERSION } from "@md-to-pdf/core";
|
||||
import runtimeManifest from "./pandoc-runtime.json" with { type: "json" };
|
||||
|
||||
export interface PandocRuntimeArtifact {
|
||||
platform: "win32" | "linux";
|
||||
architecture: "x64";
|
||||
platform: "win32" | "linux" | "darwin";
|
||||
architecture: "x64" | "arm64";
|
||||
archiveType: "zip" | "tar.gz";
|
||||
downloadUrl: string;
|
||||
sha256: string;
|
||||
executableRelativePath: string;
|
||||
licenseFiles: readonly string[];
|
||||
/**
|
||||
* 部分平台的官方归档不随附许可证文件(如 macOS zip),需要单独声明
|
||||
* 每个许可证文件的独立下载来源;缺省时许可证文件从归档内部提取。
|
||||
*/
|
||||
licenseSource?: Readonly<Record<string, { downloadUrl: string }>>;
|
||||
files?: Readonly<
|
||||
Record<string, { bytes: number; sha256: string }>
|
||||
>;
|
||||
|
||||
@@ -35,6 +35,68 @@
|
||||
"sha256": "A69ABFABABDA8A56969A254B09F9553A7BE89DDEC00D4E0FE9FD585D71A67508",
|
||||
"executableRelativePath": "bin/pandoc",
|
||||
"licenseFiles": ["COPYING.md", "COPYRIGHT"]
|
||||
},
|
||||
{
|
||||
"platform": "darwin",
|
||||
"architecture": "arm64",
|
||||
"archiveType": "zip",
|
||||
"downloadUrl": "https://github.com/jgm/pandoc/releases/download/3.9.0.2/pandoc-3.9.0.2-arm64-macOS.zip",
|
||||
"sha256": "6E9ECA844076BCBB599BBEEBBBA78A70F93B5307782B85C2C272872812C88875",
|
||||
"executableRelativePath": "pandoc-3.9.0.2-arm64/bin/pandoc",
|
||||
"licenseFiles": ["COPYING.md", "COPYRIGHT"],
|
||||
"licenseSource": {
|
||||
"COPYING.md": {
|
||||
"downloadUrl": "https://raw.githubusercontent.com/jgm/pandoc/3.9.0.2/COPYING.md"
|
||||
},
|
||||
"COPYRIGHT": {
|
||||
"downloadUrl": "https://raw.githubusercontent.com/jgm/pandoc/3.9.0.2/COPYRIGHT"
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"pandoc": {
|
||||
"bytes": 187727808,
|
||||
"sha256": "901A9D2B3D1484E008CBCE7A11739E8C9C22161C4A4222589ED2C53C96B8A55E"
|
||||
},
|
||||
"COPYING.md": {
|
||||
"bytes": 17787,
|
||||
"sha256": "9D56CAC92294E206AF026A5502BEE0FED77200B08B51EC28AA63C9EFDA4DCFDD"
|
||||
},
|
||||
"COPYRIGHT": {
|
||||
"bytes": 9598,
|
||||
"sha256": "842E33EF01625E93F85BEBB8BAC83AA570186B7AA77A09971257CC29F8F60740"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"platform": "darwin",
|
||||
"architecture": "x64",
|
||||
"archiveType": "zip",
|
||||
"downloadUrl": "https://github.com/jgm/pandoc/releases/download/3.9.0.2/pandoc-3.9.0.2-x86_64-macOS.zip",
|
||||
"sha256": "B9FBCEABCCBC8F34AC021A50483FC32F8160568D0B4B2C22D81BB29E3054FD82",
|
||||
"executableRelativePath": "pandoc-3.9.0.2-x86_64/bin/pandoc",
|
||||
"licenseFiles": ["COPYING.md", "COPYRIGHT"],
|
||||
"licenseSource": {
|
||||
"COPYING.md": {
|
||||
"downloadUrl": "https://raw.githubusercontent.com/jgm/pandoc/3.9.0.2/COPYING.md"
|
||||
},
|
||||
"COPYRIGHT": {
|
||||
"downloadUrl": "https://raw.githubusercontent.com/jgm/pandoc/3.9.0.2/COPYRIGHT"
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"pandoc": {
|
||||
"bytes": 119823904,
|
||||
"sha256": "539A4D539386E62EA7DBD6F0B7C0F76DFADAA78D57E47472849B1C878F8A0A6B"
|
||||
},
|
||||
"COPYING.md": {
|
||||
"bytes": 17787,
|
||||
"sha256": "9D56CAC92294E206AF026A5502BEE0FED77200B08B51EC28AA63C9EFDA4DCFDD"
|
||||
},
|
||||
"COPYRIGHT": {
|
||||
"bytes": 9598,
|
||||
"sha256": "842E33EF01625E93F85BEBB8BAC83AA570186B7AA77A09971257CC29F8F60740"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -140,6 +140,22 @@ function createCandidates(options: PandocRuntimeOptions) {
|
||||
exclusive: false
|
||||
});
|
||||
}
|
||||
if (
|
||||
platform === "darwin" &&
|
||||
(architecture === "arm64" || architecture === "x64") &&
|
||||
options.desktopResourcesPath
|
||||
) {
|
||||
candidates.push({
|
||||
executablePath: path.join(
|
||||
options.desktopResourcesPath,
|
||||
"pandoc",
|
||||
DOCX_PANDOC_VERSION,
|
||||
`darwin-${architecture}`,
|
||||
"pandoc"
|
||||
),
|
||||
exclusive: false
|
||||
});
|
||||
}
|
||||
if (platform === "linux" && architecture === "x64") {
|
||||
candidates.push({
|
||||
executablePath: `/opt/pandoc/${DOCX_PANDOC_VERSION}/bin/pandoc`,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import path from "node:path";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { zipSync } from "fflate";
|
||||
import {
|
||||
@@ -118,7 +119,34 @@ describe("Pandoc 运行时探测", () => {
|
||||
executablePath: "pandoc.exe"
|
||||
});
|
||||
expect(runner.mock.calls[0]?.[0]).toContain(
|
||||
`pandoc\\${DOCX_PANDOC_VERSION}\\windows-x86_64\\pandoc.exe`
|
||||
path.join("pandoc", DOCX_PANDOC_VERSION, "windows-x86_64", "pandoc.exe")
|
||||
);
|
||||
});
|
||||
|
||||
it("macOS 内置路径不存在时回退到 PATH", async () => {
|
||||
const runner = vi
|
||||
.fn<PandocProcessRunner>()
|
||||
.mockResolvedValueOnce(
|
||||
processResult({
|
||||
outcome: "not-found",
|
||||
exitCode: null,
|
||||
stdout: new Uint8Array()
|
||||
})
|
||||
)
|
||||
.mockResolvedValueOnce(processResult());
|
||||
const resolution = await probePandocRuntime({
|
||||
platform: "darwin",
|
||||
architecture: "arm64",
|
||||
desktopResourcesPath: "/Applications/MorphDoc.app/Contents/Resources",
|
||||
environment: {},
|
||||
runner
|
||||
});
|
||||
expect(resolution).toMatchObject({
|
||||
capability: { status: "available" },
|
||||
executablePath: "pandoc"
|
||||
});
|
||||
expect(runner.mock.calls[0]?.[0]).toContain(
|
||||
path.join("pandoc", DOCX_PANDOC_VERSION, "darwin-arm64", "pandoc")
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const bundlePath = join(repositoryRoot, "font-packs", "bundle.json");
|
||||
const bundle = JSON.parse(await readFile(bundlePath, "utf8"));
|
||||
const outputRoot = join(repositoryRoot, "output", "font-packs", "root");
|
||||
const appVersion = process.env.npm_package_version || "0.6.2";
|
||||
const appVersion = process.env.npm_package_version || "0.6.4";
|
||||
|
||||
if (
|
||||
bundle.schemaVersion !== 1 ||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
const repositoryDirectory = path.resolve(import.meta.dirname, "..");
|
||||
const outputDirectory = path.join(repositoryDirectory, "output");
|
||||
|
||||
const targets = [path.join(outputDirectory, "docx-release-gate")];
|
||||
|
||||
if (fs.existsSync(outputDirectory)) {
|
||||
for (const entry of fs.readdirSync(outputDirectory, { withFileTypes: true })) {
|
||||
if (entry.isDirectory() && /^docx-release-gate-v/u.test(entry.name)) {
|
||||
targets.push(path.join(outputDirectory, entry.name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let removedCount = 0;
|
||||
for (const target of targets) {
|
||||
if (fs.existsSync(target)) {
|
||||
fs.rmSync(target, { recursive: true, force: true });
|
||||
process.stdout.write(`已删除:${path.relative(repositoryDirectory, target)}\n`);
|
||||
removedCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (removedCount === 0) {
|
||||
process.stdout.write("没有找到需要清理的门禁产出目录。\n");
|
||||
}
|
||||
@@ -16,10 +16,13 @@ import {
|
||||
const execFileAsync = promisify(execFile);
|
||||
const repositoryDirectory = path.resolve(import.meta.dirname, "..");
|
||||
const matrixScript = path.join(repositoryDirectory, "scripts", "verify-docx-layout-visual-matrix.mjs");
|
||||
const repositoryVersion = JSON.parse(
|
||||
fs.readFileSync(path.join(repositoryDirectory, "package.json"), "utf8")
|
||||
).version;
|
||||
const outputRoot = path.resolve(
|
||||
repositoryDirectory,
|
||||
process.env.MD_TO_PDF_RELEASE_GATE_OUTPUT_DIR?.trim() ||
|
||||
"output/docx-release-gate-v0.6.2"
|
||||
path.join("output", "docx-release-gate", `v${repositoryVersion}`)
|
||||
);
|
||||
const requestedSuiteId = process.env.MD_TO_PDF_RELEASE_GATE_SUITE?.trim() || "next";
|
||||
const selectedCaseId = process.env.MD_TO_PDF_RELEASE_GATE_CASE?.trim() || undefined;
|
||||
|
||||
Reference in New Issue
Block a user