Skip to content

fix(comments): one anchor pair per comment id, regardless of paragraph crossings#3028

Merged
caio-pizzol merged 3 commits into
mainfrom
caio/fix-multi-paragraph-comment-range-export
Apr 30, 2026
Merged

fix(comments): one anchor pair per comment id, regardless of paragraph crossings#3028
caio-pizzol merged 3 commits into
mainfrom
caio/fix-multi-paragraph-comment-range-export

Conversation

@caio-pizzol
Copy link
Copy Markdown
Contributor

@caio-pizzol caio-pizzol commented Apr 30, 2026

Resolving a comment whose mark spans more than one paragraph was emitting N pairs of commentRangeStart / commentRangeEnd / commentReference markers all sharing the same w:id. The exported DOCX read fine in Word but is non-conformant per ECMA-376 §17.13.4 (the id attribute uniquely identifies an annotation; one start, one end, one reference per id), and Word would silently merge or render duplicates inconsistently.

Verified against a Word-authored fixture (multi-paragraph comment): Word emits one pair, with the paragraph close sitting inside the range. The fix collapses the segment list returned by getCommentMarkSegmentsById into one envelope range; all segments share the same commentId by construction, so they all belong to the same logical annotation.

Trigger: only multi-paragraph or discontinuous comments. Single-paragraph comments were always correct.

Verified:

  • 164/164 comment-extension tests pass; 12087/12087 super-editor tests pass.
  • Spec-derived suite added: single, multi (2/3 paragraphs), discontinuous, side-by-side, overlapping nested.
  • Runtime end-to-end against the BYO-UI demo: pre-fix SuperDoc(11).docx had id=3 with 2/2/2 markers; post-fix SuperDoc(12).docx has 1/1/1 for every id.

…h crossings

Resolving a comment whose mark spans more than one paragraph emitted
N range pairs for an N-paragraph comment, producing a non-conformant
DOCX with multiple `commentRangeStart` / `commentRangeEnd` /
`commentReference` markers sharing the same `w:id`.

Per ECMA-376 §17.13.4.3, §17.13.4.4, §17.13.4.5, `w:id` is the unique
identifier for an annotation: each annotation produces exactly one
start, one end, and one reference marker. Verified against Word
output for a comment that spans a paragraph break: Word emits one
pair, with the paragraph close sitting inside the range.

`getCommentMarkRangesById` previously merged adjacent segments via
`seg.from <= active.to`, which fails across paragraph boundaries
because PM positions skip the close+open delta of the structural
node. All segments returned by `getCommentMarkSegmentsById` belong
to the same logical annotation by id (a single `commentMark`
applied across the selection); collapse them into one envelope
range covering the full extent.

Tests: spec-derived suite for single-paragraph, multi-paragraph,
three-paragraph, discontinuous, side-by-side, and overlapping
nested cases (resolveCommentById emission), plus the canonical
plugin-level regression test for the multi-paragraph case.

Verified: 164/164 comment tests pass; 12087/12087 super-editor
tests pass; runtime end-to-end against the BYO-UI demo
(SuperDoc(11).docx → buggy: id=3 had 2/2/2 markers; SuperDoc(12).docx
post-fix: id=3 has 1/1/1 markers).
@caio-pizzol caio-pizzol requested a review from a team as a code owner April 30, 2026 16:45
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e404a9f6b3

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/super-editor/src/editors/v1/extensions/comment/comments-helpers.js Outdated
@codecov-commenter
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…view feedback)

The first iteration of this fix collapsed every segment carrying the
same `commentId` into one envelope range. That handles the
multi-paragraph case (the SuperDoc(8) bug) but expands the range
scope when PM legitimately stores two non-adjacent regions for the
same id — most commonly when a user copy-pastes a commented region.
The CommentMark has no `transformPasted` hook, so PM preserves the
mark attrs verbatim across paste. Both copies share the same
`commentId`, but the user's intent is two annotations on two
regions, not one annotation covering everything between them.

Distinguish the two cases by walking the doc between consecutive
segments: `doc.textBetween(prev.to, seg.from, '', '')` returns the
concatenated text of every text leaf in the gap, with empty block
separators so paragraph close+open contributes nothing. Empty
result → structural boundary only → merge (paragraph-crossing).
Non-empty result → real uncommented gap → keep ranges separate.

Two range pairs with the same id is still non-conformant per spec
(`w:id` should be unique per annotation), and remapping to fresh
ids on resolve is the proper long-term fix. Filed as a follow-up.
For now, preserving per-region scope is strictly better than
collapsing it.

Adds the disjoint regression test and tightens the assertions so
it pins the layout, not just marker counts.
Pins the full pipeline (resolveCommentById → prepareCommentsForExport
→ comment-range translator → word/document.xml) at the export
boundary. Builds a multi-segment TextTarget anchored across two
paragraph blocks, posts the comment, resolves it, exports to DOCX,
and asserts every comment id appears exactly once for each marker
type (commentRangeStart / commentRangeEnd / commentReference).

Verified the test catches the regression: against the pre-fix
getCommentMarkRangesById it fails with 2/2/2 markers for the
multi-paragraph id; against the fix it returns 1/1/1. 3/3 browsers
green (chromium / firefox / webkit).
@caio-pizzol caio-pizzol merged commit 45c0532 into main Apr 30, 2026
60 checks passed
@caio-pizzol caio-pizzol deleted the caio/fix-multi-paragraph-comment-range-export branch April 30, 2026 18:48
@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented Apr 30, 2026

🎉 This PR is included in @superdoc-dev/mcp v0.3.0-next.21

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented Apr 30, 2026

🎉 This PR is included in vscode-ext v2.3.0-next.66

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented Apr 30, 2026

🎉 This PR is included in @superdoc-dev/react v1.2.0-next.64

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented Apr 30, 2026

🎉 This PR is included in superdoc v1.30.0-next.23

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented Apr 30, 2026

🎉 This PR is included in superdoc-cli v0.8.0-next.39

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 1, 2026

🎉 This PR is included in superdoc-cli v0.8.0

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 1, 2026

🎉 This PR is included in superdoc-sdk v1.8.0

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 1, 2026

🎉 This PR is included in @superdoc-dev/mcp v0.3.0

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 1, 2026

🎉 This PR is included in superdoc v1.31.0

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 5, 2026

🎉 This PR is included in vscode-ext v2.3.0

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 7, 2026

🎉 This PR is included in @superdoc-dev/react v1.3.0

The release is available on GitHub release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants