Skip to content

Releases: ls-open/md-to-word

2.4.2

Choose a tag to compare

@ls-open ls-open released this 23 Oct 17:24

2.4.2

修复

  • 题名以 ?/!/./: 结尾时多补了一个句点:APA 在标题后写
    <group suffix=".">,citeproc-py 不会像 citeproc-js 那样把重复的标点合并掉,
    What Aspects Are Automated? 于是成了 Automated?.。现在终止标点后面不再补句点;
    合并同样看得穿标签与右引号——APA 的斜体书名(<i>What Now?</i>)与 Chicago/MLA
    的引号题名(“What Aspects Are Automated?”)后面那个句点也一并吃掉。

说明

  • 题名冒号后的首词大小写由数据决定:CSL 的 sentence 转换只处理第一个词的首字母,
    citeproc-js 也会保留 .bib 里的小写。要 APA 的「冒号后大写」,把 .bib 写成
    vehicles: A dual-path 即可,Zotero 与本工具都一致。

2.4.1

Choose a tag to compare

@ls-open ls-open released this 23 Oct 17:05

2.4.1

四份 demo 在本机 Word 里渲染成 PDF 逐页核对后修的三处问题。

修复

  • 文献表排序:同姓作者撞成一个排序键,顺序掉到年份上——Li, C. (2023) 会排到
    Li, M. (2021) 后面。现在按样式声明的键序、升降序与名字形态排:APA 收首字母
    (同首字母落到年份),Chicago/MLA 比全名;MLA 同作者按题名(它没有日期键),
    Elsevier Harvard 的年份是降序。判据取自 citeproc-js 对同一组条目的输出。
  • 相邻两张表被 Word 并成一张:</w:tbl><w:tbl> 在 Word 里就是一张表,第二张的表头、
    题注与独立编号跟着错位,而且不报错。现在两张表之间垫一个 1 磅空段落。
  • 无编号的独立公式按行内样式排(分式缩小、求和上下限跑到右侧):段落里只放公式后
    Word 按显示样式排。有编号的公式与制表位同段,仍是行内样式——这是 Word 的规矩,已写进
    references/design.md。
  • 「图片宽度超过版心」的提醒不再自称「不报错、也没有警告」。

说明

  • 数字制样式(GB/T 7714、Nature 等)不声明 <sort>,仍按引用顺序,未受影响。

2.4.0 —— PDF 图、引文消歧与静默错误的修复

Choose a tag to compare

@ls-open ls-open released this 23 Oct 16:27

2.4.0 —— PDF 图、引文消歧,以及一批「退出码 0 却已经错了」的修复

这一版来自三路独立审计(引文一致性、稿件链路、文档)加一轮 CSL 官方用例对标。

图片

  • 可以直接引用 PDF:![](fig.pdf){width=13cm},导出时按声明宽度的 300 dpi 栅格化;多页取第 1 页并提醒;加密或损坏的文件在预检拦下;Word 放不下的格式(.svg/.webp/.eps)同样在预检拦下并给出改法
  • 超宽图按版心钳制(此前手册承诺钳制,实际会溢出页面被裁)
  • 图片替代文字写进 docPr/@descr
  • 渲染在临时目录进行,用完即删;同一份 PDF 每次导出字节一致

引文(CSL)

  • 补全 CSL 的三条消歧:同姓不同人补首字母 (D. Zhang et al., 2024)、同首作者不同合作者补名字 (Bai, Sun, et al., 2024)、分不开时加年份后缀 (Kim & Park, 2020a)
  • collapse:year 与 year-suffix-ranged 两种折叠((Kim & Park, 2019, 2020a)、(Green 2020a–c))
  • 定位符:[@a, p. 33]、[@a, 33]、[@a, chap. 3]、[@a, 3, 7]、叙述式 @a [p. 33] 都成立,标签按 CSL 变量传下去
  • 页码区间展开(33-5 → 33–35)、引用级 <sort>、上标数字制的连续编号合并
  • 姓名与字段映射:团体作者 {{WHO}}、Jr. 后缀、van 前缀、translator / series / note / 页数、month、学位论文 genre、arXiv eprint
  • 手册新增「CSL 排版差异」七条,写清引文引擎已知的排版出入

稿件契约

  • 2*3*4、a*b*c、价格 $5 到 $10 不再被误判成强调/公式;带括号的链接不再截断
  • 脚注:补 w:footnoteRef(此前正文有号、注文无号)、脚注里的行内格式与链接
  • 有序列表各自编号(此前两个独立列表在 Word 里连续编成 3./4.);嵌套层起始号生效
  • 表格:单元格内的换行与转义、行尾竖线缺失的拦截、表头重复只在声明时生效
  • 新门禁:缺定义的脚注、未独立成行的图片、重复的公式标签、%% 缺空格、分节参数写错
  • YAML 未知键出提醒(toc:、geometry: 这类此前静默忽略)
  • 公式:cases 落成可伸缩定界符 m:d,aligned/split 落成 m:eqArr,不再产出空 run
  • 多行公式不再被误报「折行段落」;标题尾部闭合井号按 CommonMark 去掉

其他

  • 依赖新增 pypdfium2>=4.30(PDF 图栅格化,各平台轮子)
  • 文档全面清理:依赖数与 --json 键名已对齐实现,删掉 %20、fig-prefix、「缺 --citeproc」等过时说法

验证

  • 871 个测试通过;sdist 与 wheel 均通过 twine check
  • 干净 venv 从 PyPI 安装后跑通:消歧、年份后缀、页码、PDF 图均正常

2.3.2 — 未配对的星号不再阻断导出

Choose a tag to compare

@ls-open ls-open released this 23 Oct 14:45

修复

  • 显著性星号被误判为未闭合加粗:** 的闭合检查原来只数出现次数,.181***、0.052** 这类显著性标记在正文和表格里都会被拦下,整份稿件导不出来。加粗的判据只有一条——前后各一对星号;凑不成对的星号是普通字符,成品里原样输出,不再阻断。$…$ 与 $$…$$ 未闭合仍然拦截。

文档

  • 入门文档注明包内 guide.md 与技能入口 SKILL.md 同文,读其一即可;--contract 不再引导重读。
  • 手册与技能清单同步删去「跨行加粗」这一条不支持写法。

779 个测试通过。

2.3.1

Choose a tag to compare

@ls-open ls-open released this 23 Oct 05:16

补上一版在公式上的两个缺陷。

修复

  • \begin{aligned} 不再崩溃。 这是 AI 生成多行公式最常见的写法,转换器会把 & 对齐符漏成 <mi>&</mi>,产出非法 XML,用户拿到的是 lxml 的 traceback。现在按 split 处理,落成带对齐的两行矩阵。
  • 花括号不配对不再静默丢内容。 $$ \frac{a}{b $$ 这类写法转换器不报错,只把分子分母结构丢掉,渲染成 ab。新增阻断门禁 [公式括号不配对],按行提示补 }。
  • MathML 解析失败改用一句带公式片段的报错,不再抛 lxml 的 traceback。

文档

  • 手册补多行公式用 cases / matrix / split;@eq-x 的前缀由引擎自动添加(写「见 @eq-x」,不要写「见式 @eq-x」)。
  • README 的公式条目写明:原生 OMML 对象,可在 Word 中继续编辑,不是图片、不是字面文本。
  • 报错速查补「公式少了字符或结构不对」一行。

完整变更:git log v2.3.0..v2.3.1

2.3.0

Choose a tag to compare

@ls-open ls-open released this 23 Oct 05:04

这一版把「写法」和「门禁」两处长期含混的地方定清,并删掉了一批没有实际意义的兼容。

新增写法:段内换行

同一段落内需要换行(地址、诗句、长标题)时,在行尾写一个 \ 或两个空格,写出为 <w:br/>:

地址:北京市海淀区\
某路 1 号\
邮编 100000

不写标记时每一行仍是独立段落——短段落序列是正常写法,各自可以挂 %% 样式。

门禁

  • 三类写法从「原样印出」改为阻断:==高亮==、[文字]{.类名}(.underline 除外)、\(…\) 行内公式。
  • 折行段落仍为提醒,但同类合并成一条并列出全部行号(最多 8 个),不再一稿刷几十行。
  • 提醒现在进入 --json 的 messages,程序不必解析 stderr。
  • 成功导出末尾的提醒收成一句:「导出完成。版面效果仍须在 Word 中人工核验。」

一处行为变更

不带 -r 时只认稿件同目录的 format.txt,不再猜「旁边那个唯一的 .txt」。旁边另有 .txt 时输出一行提醒点名;原「多个 .txt 无法判定」的退出码 1 取消。

清理

  • template/generator.py 自带的 35 条样式表删掉,改从 spec/constants.py 引入;反查中文名不再依赖字典插入顺序。
  • 反推要求文件的逻辑原本写了两次(main() 与 extract_spec_from_docx()),合并为一份并加测试钉住。
  • config.get_csl_dir() 与 word_pdf._render_script() 中无调用方的分支删除。

文档

技能与手册只保留 agent 需要的内容:删除安装、运行时、源码检出、「requirements.txt 不是要求文件」等对人类读者的说明。references/design.md 新增 §4「为什么是 AI 原生」,把这一轮的判断写下来:文档先于参数、确定性优于宽容、可机读优先、不为不存在的人工操作做优化。

完整变更:git log v2.2.1..v2.3.0

2.2.1 — Python 下限改为 3.10;修 3.9 上 import 即崩

Choose a tag to compare

@ls-open ls-open released this 22 Oct 17:05

2.2.1

Python 下限改为 3.10。

2.x 从来没有在 3.9 上真正跑通过:inspector、extractor、generator、skill_utils 四个模块的函数注解写了 Path | str(PEP 604),而 3.9 里注解是定义时求值的,一 import 就抛 TypeError: unsupported operand type(s) for |。CI 的 3.9 任务一直在红,只是没人看。

这次不选择"补上 3.9 支持",理由:

  • 硬依赖 latex2mathml 自 3.79 起要求 >=3.10。留 3.9 意味着 pip 会退到 3.78.1——那正是公式解析的上游,测的和装的不一致。
  • Python 3.9 已于 2025-10 停止维护,3.10 也已于 2026-10 停止维护。
  • 承诺一条从未交付、也不再有上游修复的路径,不如把话说对。

变更

  • requires-python → >=3.10;分类器去掉 3.9、补 3.13。
  • CI 矩阵改为 ubuntu 3.10 / 3.12 与 macOS 3.12——下限本身进入测试。
  • 四个模块补 from __future__ import annotations(注解延迟求值,顺带省掉 import 时的求值开销)。
  • 移除专为 3.9 写的兼容守卫测试,职责交给 CI 的下限任务。

顺带修掉的

  • --pdf 在 pip 安装下不可用(渲染脚本原先只在仓库目录里找得到)——已随 2.2.0 修好,本次一并覆盖。
  • -t 传非 .docx、-o 传目录、输出目录只读这三类错误不再甩 traceback。
  • md-to-word init --preset 写错 不再抛 KeyError。
  • 退出码 2(参数用法错误)写进契约;无参数运行时打印简明帮助。

验证:729 测试通过;scripts/acceptance.sh 在干净 venv 装 wheel 跑通全部入口。

2.2.0 — 通用定位、init/--guide/--json、修 --pdf 安装后不可用

Choose a tag to compare

@ls-open ls-open released this 22 Oct 16:42

2.2.0

定位:从「学术排版工具」改为通用的 Markdown → Word 编译器(学位论文、期刊投稿、技术报告、公文、说明书同一套写法)。包描述、关键词、受众分类、README 同步。

新增

  • md-to-word init:在当前目录写一份完整预设的 format.txt 和一份能直接导出的 hello.md,第一次导出不必从空白开始。
  • md-to-word --guide:打印入门文档(流程、门禁判据、边界)。它是仓库根 SKILL.md 的正文,只装 pip 包的人从这里读,两份由测试保证一字不差。
  • --json:stdout 输出一行 JSON(ok、returncode、input、output、pdf、lang、messages、errors),键名固定;进度与报错仍走 stderr。给脚本与 Agent 用,不必解析会随语种变化的措辞。
  • 包内 guide.md、render_via_word.sh 随 wheel 发布;[project.urls] 补全主页、文档、仓库、issues。

修复

  • --pdf 在 pip 安装下不可用:渲染脚本原来只在仓库里找得到,装好的包永远按「跳过」返回 3。脚本改为包内资源,仓库 scripts/ 那份只做转发。
  • -t 传非 .docx(如 PDF)抛 BadZipFile traceback → 改为一句说明。
  • -o 传目录抛 IsADirectoryError traceback → 改为「输出路径是一个目录」。
  • 输出目录只读、磁盘已满等写入失败抛 PermissionError traceback → 改为「写出失败」并列出常见原因。
  • md-to-word init --preset 写错 抛 KeyError → 改为「未找到预设」。
  • init 生成的样例把正文折成两行,第一次导出就报「折行段落」→ 改为一行一段,零告警。

契约

  • 退出码补上 2(参数用法错误),0/1/2/3 在 SKILL.md、guide.md、两份手册里与代码一致,由测试核对。
  • 无参数运行时打印简明帮助(描述 + 三条示例 + 去哪读全部),不再只是 argparse 的报错。
  • SKILL.md 新增「版本契约」:命令与开关、退出码、JSON 键名、稿件契约、要求文件词法为冻结面;消息措辞、包内布局、版本号可变。

文档

  • README 中英重写:一句定位 → 产物图 → 安装 → 30 秒 → 样例 → 能力 → 常用写法 → 与其他方案的区别 → 另两个入口 → 环境 → 模板反推 → 上游 → 许可。英文版示例用英文词表,首图换成英文样例页。
  • 四份样例的 .docx/.pdf/page-*.png 按当前源码重出;英文样例补齐产物。
  • 手册:format.txt 命名统一(requirements.txt 只指依赖);获取要求文件由三种改四种。

验证:729 测试通过;scripts/acceptance.sh 在干净 venv 里装 wheel 跑通全部入口(含 --pdf);四份样例与源码逐字节一致。

v2.1.0 — 英文完整可用

Choose a tag to compare

@ls-open ls-open released this 22 Oct 15:10

PyPI:pip install md-to-word-docx(命令仍是 md-to-word)。

这一版做了什么

英文用户补齐到可用。之前的版本只有界面文案是英文的:英文稿件被门禁拦下时,报错细节是中文,提示里还让他改写成「摘要/关键词/表题」;模板必填项诊断、对账报告、公式/文献异常同样是中文。现在全部双语,语言跟着稿件语种走(不是跟着界面设置):

  • 348 条消息进同一张双语表(门禁 116、对账 91、模板 54、流水线 24、模板反推 23、CLI 17、写出器 15、公式 4、文献 3、标记 1)
  • 英文提示里的样式名举例给英文正典名,Table: … / Table Header: … 这类示例由测试保证真的能被解析器解析
  • 使用手册出英文版 manual_en.md,md-to-word --contract --lang en 指向它;两份手册由测试盯着必须覆盖同一批样式名、短代码、YAML 键与 CSL 清单

默认预设跟着稿件语种走。此前不给 -r 时一律用 zh-academic:英文稿会被排成「首行缩进两字符 + 宋体 fallback」,文档能打开、样式都在,只是每段都被顶了两个字符——我们的英文样例一直是这种状态。现在中文稿 zh-academic,其他 en-nature,并在输出里说明用了哪一份。

修的真问题

  • md-to-word-template 在 2.0.1 上是坏的:两处 from generate_template import … 是旧脚本名,每次运行都以 ModuleNotFoundError 崩掉。已修,并补了端到端测试
  • 残缺公式(如 \frac{1})会抛 ValueError,穿过异常处理变成 traceback;现在收成「写不出来」的正常报错
  • 英文稿写 %% References Title References 时,文献列表生成成功却被警告「没写文献区标题」,而提示让他补的正是那一行——死循环,已修
  • 输出目录不存在时不再抛 FileNotFoundError,而是一句话说明
  • 传非 .docx 给 md-to-word-template 不再甩 BadZipFile

兼容性

同一份稿件与要求文件,2.0.1 与 2.1.0 的产物逐字节相同(三份样例的 sha1 一致)——这一版只改消息语言与几个错误路径,不改排版。

697 个测试通过。

v2.0.1 — 首个 PyPI 版本

Choose a tag to compare

@ls-open ls-open released this 22 Oct 14:05

PyPI:pip install md-to-word-docx(命令仍是 md-to-word;PyPI 上 md-to-word 因与既有项目过于相似被拒)。

这一版是什么

断代式重写:写出器全部自己实现,不再依赖 Pandoc / Quarto 或任何外部二进制。同一份稿件与要求文件,任何时候重跑都产出逐字节一致的 .docx(zip 时间戳固定)。

主要能力

  • 声明式排版:requirements.txt 一行一种样式,与稿件一起进 Git
  • 原生 OMML 公式(居中、编号靠右、按章编号)、交叉引用 @eq-x
  • 三线表、跨页重复表头、题注与图同页
  • .bib + CSL:内置 29 份样式,自带 CSL 自动规范化
  • 三道质量门禁:导前预检、导后防丢数、与要求文件逐条对账
  • 包内 manual.md 随版本走;md-to-word --contract 给出契约速查与手册路径

早期版本说明

2.0.0 的包元数据里 README 仍写着旧包名 md-to-word,文件在 PyPI 上不可覆盖,故以 2.0.1 修正;两者代码相同。