Add docx-to-markdown reverse conversion (Tier-2)#16
Merged
Conversation
Add convertDocxToMarkdown(), converting Word documents to clean GitHub- flavored Markdown via pandoc's `--from docx --to gfm`, with an explicit `--track-changes` mode and reuse of the existing Markdown postprocessor hook. Because the acceptance criterion for this feature is that unmappable content is never silently dropped, the conversion also produces a DocxImportReport surfacing anything pandoc discards during import: comments, tracked changes and moves, text boxes, headers/footers, footnote-scoped revisions, SmartArt, charts, embedded media, OLE objects, and altChunk references. The main document part is resolved by reading `_rels/.rels` rather than assuming the conventional `word/document.xml` path, so documents with non-standard part layouts are still handled correctly. The docx archive reader is hardened against hostile input: per-part size caps, a total-bytes budget, an entry-count cap, and a header/footer-count cap, plus CRC-32 verification of every inspected part. PandocError has moved from src/pandoc.ts to a new src/errors.ts module and is re-exported from there, so the public API surface is unchanged. fflate has moved from devDependencies to dependencies, since archive inspection now happens at runtime rather than only in tests. Closes #6
This was referenced Jul 26, 2026
The aggregate-budget test deflated ~572MB of fixture data and took ~4.2s against vitest's 5s default, sitting at 84% of the timeout and flaking as "Test timed out in 5000ms" on the Node 20.x CI job under any slightly slower runner. This was a slow fixture, not a code defect. Both heavy fixtures now derive their size from the constants they probe (DOCX_MAX_PART_BYTES, DOCX_MAX_TOTAL_BYTES, etc.) via a shared createRepetitiveXmlPart helper, so each uses the minimum data needed to trip its limit (572MB -> 135MB). They also compress at level 1 instead of 9 since the archive is discarded immediately, and the two legitimately slow tests get explicit 30s timeouts instead of relying on the default. The aggregate-budget test now asserts all four preconditions that matter for it to prove anything (per-part under cap, part count under the header/footer cap, entry count under the archive cap, aggregate over budget), where it previously asserted only two. Suite runtime drops from 6.7s to 4.0s. No assertions were weakened.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
convertDocxToMarkdown(), converting Word documents to clean GitHub-flavored Markdown via pandoc, with aDocxImportReportthat surfaces content pandoc silently drops.PandocErrorinto its own module and shiftfflateto a runtime dependency.Changes
Docx-to-Markdown Conversion
convertDocxToMarkdown()runs pandoc--from docx --to gfmwith an explicit--track-changesmode, reusing the existing Markdown postprocessor hook.DocxImportReportsurfaces content pandoc drops silently during import — comments, tracked changes and moves, text boxes, headers/footers, footnote-scoped revisions, SmartArt, charts, embedded media, OLE objects, andaltChunkreferences — so unmappable items are never silently dropped._rels/.relsrather than assumed to beword/document.xml.Refactoring
PandocErrormoved out ofsrc/pandoc.tsinto a new module and re-exported, so the public API surface is unchanged.Dependencies
fflatemoved from devDependencies to dependencies, since archive inspection now runs at runtime.Tests
convertDocxToMarkdown(),DocxImportReport, part resolution, and archive-reader bounds/CRC checks.Documentation
Test plan
pnpm check(biome + tsc + 224 vitest tests + build) passesCloses #6