fix(docx): read the comments part and render comments as notes (#191)

RA
4d ago
+58-0

Summary

Word's review layer — word/comments.xml, its relationship, and the w:commentRangeStart / w:commentRangeEnd / w:commentReference anchors — is read and rendered as notes instead of being dropped without a trace. Fixes #191.

What changed

  • src/package/relationships.rs: a rel_type::COMMENTS constant, so the comments relationship is locatable the same way FOOTNOTES and ENDNOTES are.
  • src/formats/docx/mod.rs: the comments part loads through the existing table-driven note loader, as (comments_part, "comments", "comment", "c", NoteKind::Comment); typed_part_path's comments.xml fallback covers producers that omit the relationship. The comment's paragraphs parse with the part's own relationships, exactly like a footnote's.
  • src/formats/docx/content.rs: a "commentReference" arm in walk_run_content pushes the note reference c<id> where the comment is anchored; commentRangeStart/End stay ignored as range boundaries (they carry no content, and the commented text between them renders as normal runs).
  • src/model/mod.rs: NoteKind::Comment describes the new source.
  • Regression test comments_load_as_notes_and_render: a docx with a comment range around one word plus word/comments.xml parses into a NoteRef("c1") inline and a NoteKind::Comment note, and the Markdown keeps the anchored text and renders [^1]: This section needs a citation.

The renderer is already note-kind-agnostic: a comment renders as a Markdown footnote definition in first-reference order, which is how a comment layer survives in Markdown.

Verification

No cargo toolchain was available where I prepared this, so no cargo run is claimed. What I did verify:

  • Static trace on HEAD e7178e0: grep '"sym"\|"commentReference"' src/ finds nothing; rel_type has no comments entry; the note loader in docx/mod.rs iterates only footnotes and endnotes; Inline::NoteRef and the note renderer (render/markdown/mod.rs: numbering by first reference, [^n]: definitions) handle any NoteKind without consulting it.
  • Every added code path mirrors an existing one line for line: FOOTNOTES→COMMENTS, the loader table row, and the commentReference arm beside footnoteReference/endnoteReference in the same match.
  • The test's fixture follows the module's existing docx_parts helper and namespace constants; its assertions were walked by hand against the loader's logic (id c1, prefix c, one comment, first-reference number 1).