feat: 实现 Pandoc DOCX 转换服务

This commit is contained in:
SkyJourney
2026-07-30 15:05:50 +08:00
parent fa159d916f
commit bf43433d38
32 changed files with 2908 additions and 61 deletions
@@ -10,7 +10,8 @@ import {
} from "@md-to-pdf/core";
import {
createDynamicReferenceDocx,
validateDynamicReferenceDocx
PandocRuntime,
validateGeneratedDocx
} from "@md-to-pdf/docx-engine";
import { unzipSync } from "fflate";
@@ -28,8 +29,19 @@ const themePath = path.join(
"gov-red-standard",
"theme.json"
);
const pandocExecutable =
process.env.MD_TO_PDF_PANDOC_PATH?.trim() || "pandoc";
const runtime = new PandocRuntime(
process.env.DOCX_PANDOC_PATH?.trim()
? { configuredPath: process.env.DOCX_PANDOC_PATH.trim() }
: {}
);
const runtimeResolution = await runtime.probe();
assert(
runtimeResolution.capability.status === "available",
runtimeResolution.capability.status === "available"
? ""
: runtimeResolution.capability.message
);
const pandocExecutable = await runtime.getExecutablePath();
const maximumBuffer = 128 * 1024 * 1024;
const decoder = new TextDecoder();
@@ -64,7 +76,7 @@ function countMatches(value, pattern) {
}
function inspectResult(content, expected) {
const validation = validateDynamicReferenceDocx(content);
const validation = validateGeneratedDocx(content);
const entries = unzipSync(content);
const documentXml = decoder.decode(entries["word/document.xml"]);
const stylesXml = decoder.decode(entries["word/styles.xml"]);
@@ -174,22 +186,13 @@ function createVariant(
};
}
const versionResult = runPandoc(["--version"]);
const detectedVersion =
versionResult.stdout
.split(/\r?\n/u)[0]
?.replace(/^pandoc\s+/u, "")
.trim() ?? "";
const detectedVersion = runtimeResolution.capability.detectedVersion;
assert(
detectedVersion === DOCX_PANDOC_VERSION,
`Pandoc 版本不匹配:期望 ${DOCX_PANDOC_VERSION},实际 ${detectedVersion || "未知"}`
);
const baselineResult = runPandoc(
["--print-default-data-file", "reference.docx"],
{ binary: true }
);
const baseline = new Uint8Array(baselineResult.stdout);
const baseline = await runtime.getDefaultReferenceDocx();
const theme = themeManifestSchema.parse(
JSON.parse(fs.readFileSync(themePath, "utf8"))
);