release: 发布 v0.6.2 DOCX 真实文档修复

新增能力:将 DOCX 发布验收拆分为四套独立 140,支持真实语料冻结、指纹复用、失败与基础设施错误独立统计,并为表格换行、全 JSON 围栏、代码连续性和长文档分页建立通用门禁。

问题修复:冻结 Paged.js 分片前的逻辑表格列轨并传递打印几何,统一 Markdown 表格换行、代码、段落与 OOXML 翻译;改进 PDF 文本流排序、语义块映射、颜色与栅格比较,消除窄字符重叠和跨行范围符号误报。

兼容与部署:版本统一为 0.6.2;正式 Docker 镜像内置固定 Chromium、Pandoc 3.9.0.2 和 Serif/Sans/Mono 字体;Desktop NSIS 与 ZIP 继续直接内置字体,无需系统字体安装。

验证结果:合成基线与长庆严格 280/280,M4N 140/140;健康数据残余误报 6/115(5.22%),均核查为重复表头自动对齐/取样误报且基础设施错误为 0。全项目测试、类型检查、生产构建和 git diff --check 通过;正式 Docker、NSIS、ZIP、离线镜像、部署包、清单及 SHA-256 均已生成并校验。
This commit is contained in:
SkyJourney
2026-08-26 10:50:20 +08:00
parent 01b06abc2c
commit 64445322eb
75 changed files with 9255 additions and 298 deletions
@@ -3,6 +3,7 @@ const CHUNK_CLASS = "md-code-pagination-chunk";
const CHUNK_POSITION_ATTRIBUTE = "data-code-pagination-position";
const LINE_GROUP_CLASS = "md-code-line-group";
const LINE_CLASS = "md-code-line";
const LINE_INDENT_CLASS = "md-code-line-indent";
function splitNodeIntoLines(node: Node): Node[][] {
const documentRef = node.ownerDocument;
@@ -47,6 +48,56 @@ function lineHasContent(nodes: Node[]) {
return nodes.some((node) => (node.textContent ?? "").length > 0);
}
function stabilizeLeadingWhitespace(
documentRef: Document,
nodes: Node[]
) {
let indent = "";
let index = 0;
for (; index < nodes.length; index += 1) {
const node = nodes[index];
if (!node || node.nodeType !== node.TEXT_NODE) {
break;
}
const value = node.textContent ?? "";
const match = value.match(/^[\t ]+/u);
if (!match) {
if (value.length === 0) {
continue;
}
break;
}
indent += match[0];
const remainder = value.slice(match[0].length);
if (remainder) {
node.textContent = remainder;
break;
}
}
if (!indent) {
return nodes;
}
const indentElement = documentRef.createElement("span");
indentElement.className = LINE_INDENT_CLASS;
let columns = 0;
for (const character of indent) {
columns = character === "\t"
? columns + (4 - columns % 4)
: columns + 1;
}
indentElement.dataset.codeIndentColumns = String(columns);
indentElement.style.width = `${columns}ch`;
indentElement.textContent = indent;
return [
indentElement,
...nodes.slice(index).filter(
(node) =>
node.nodeType !== node.TEXT_NODE ||
(node.textContent ?? "").length > 0
)
];
}
function createLineGroups(
documentRef: Document,
lines: Node[][]
@@ -68,7 +119,12 @@ function createLineGroups(
) {
const line = documentRef.createElement("span");
line.className = LINE_CLASS;
line.append(...(lines[lineIndex] ?? []));
line.append(
...stabilizeLeadingWhitespace(
documentRef,
lines[lineIndex] ?? []
)
);
group.append(line);
}