Skip to content

fix(converter): preserve numbering.xml definitions on round-trip (SD-2911)#3231

Merged
luccas-harbour merged 2 commits into
mainfrom
tadeu/sd-2911-preserve-numbering-on-round-trip
May 14, 2026
Merged

fix(converter): preserve numbering.xml definitions on round-trip (SD-2911)#3231
luccas-harbour merged 2 commits into
mainfrom
tadeu/sd-2911-preserve-numbering-on-round-trip

Conversation

@tupizz
Copy link
Copy Markdown
Contributor

@tupizz tupizz commented May 11, 2026

Summary

  • #exportNumberingFile no longer filters numbering.xml by which numIds are referenced from the document body. Every <w:abstractNum> and <w:num> the importer captured is emitted on export.
  • Removes strip-orphaned-numbering.js + its unit tests; the inline write is now four lines.

Why

Customer fixture in SD-2911:

  • Active variant (one numId used in the body): <w:abstractNum> dropped from 8 → 1, <w:num> from 8 → 1. Live numbering definitions Word would otherwise expose in the Multilevel List dropdown were silently lost.
  • Tentative variant (no numId referenced): numbering.xml was effectively wiped (2 → 0 abstractNum, 1 → 0 num).

The filter was added by PR #2223 for the lists.delete document-api operation — when a user deletes a list, the dead definition should be cleaned up. But the filter ran on every export and had no way to tell "user just deleted in this session" from "definition was always unused in the source file" (Word's tentative numbering). Both reached it with no referencing paragraph and were treated identically. Word tolerates unused definitions, so the safe default on round-trip is to preserve everything.

Test plan

  • New integration test (sd-2911-numbering-roundtrip.test.js) round-trips both customer fixtures and asserts <w:abstractNum> / <w:num> counts and ids match the input exactly.
  • Full pnpm test for super-editor (12 695 / 12 708 pass — the 13 deletions are the removed strip-orphaned-numbering.test.js unit tests).
  • Live verification in the dev app: re-exported both fixtures, opened in Word.
    • Active: numbering.xml byte-identical to input after pretty-print (8 / 8 preserved).
    • Tentative: same — numbering.xml byte-identical (2 / 1 preserved).
  • No "Word found unreadable content" prompts on open.

Verified diffs on the customer fixtures

Variant input before fix after fix
active — <w:abstractNum> 8 1 8
active — <w:num> 8 1 8
tentative — <w:abstractNum> 2 0 2
tentative — <w:num> 1 0 1

What about the lists.delete flow that originally motivated the filter?

If lists.delete needs to remove the definition for the list it deletes, that should happen at the operation site — where the deletion intent is known — not as an opportunistic GC pass at every export. There's no existing test in the repo that gates this behavior end-to-end against the document-api; adding one is out of scope for this fix.

…2911)

#exportNumberingFile filtered out every w:num whose numId wasn't referenced
from the exported document parts (including headers, footers, and footnotes).
Word's tentative numbering, where a document carries definitions for lists
the user hasn't applied yet, was therefore silently wiped: the active-numbering
fixture lost 7 of 8 definitions and the tentative fixture lost them all.

The filter was introduced for the lists.delete document-api operation, but it
couldn't distinguish "user just deleted a list in this session" from
"definition was always unused in the source file" — both arrived at the export
with no referencing paragraph and both were dropped.

Word tolerates unused definitions, so the safe default on export is to emit
every abstractNum and num the importer captured. The strip-orphaned helper is
removed entirely; the inline write in #exportNumberingFile is now four lines.

Verified: both fixtures round-trip byte-identical (after pretty-print) at the
numbering.xml level. New integration test covers both the active and tentative
variants.
@tupizz tupizz requested a review from a team as a code owner May 11, 2026 15:14
@linear
Copy link
Copy Markdown

linear Bot commented May 11, 2026

SD-2911

@codecov-commenter
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@tupizz tupizz self-assigned this May 11, 2026
@caio-pizzol caio-pizzol self-assigned this May 13, 2026
Copy link
Copy Markdown
Contributor

@luccas-harbour luccas-harbour left a comment

Choose a reason for hiding this comment

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

hey! can you check this one?

- [P2] Avoid exporting fallback numbering for docs without numbering — packages/super-editor/src/editors/v1/core/super-converter/SuperConverter.js:1440-1442
When the input package has no `word/numbering.xml` (or an empty one), the importer still fills `this.numbering` from `baseNumbering` via `ensureElementsArray`; writing all `Object.values` here therefore exports SuperDoc's fallback numbering definitions even though the source document had none. Main previously emitted no definitions because no paragraphs referenced those fallback numIds, so plain documents now gain unused numbering definitions on round-trip. Track whether the numbering part came from the source, or filter only the fallback, before preserving everything.

…no refs (SD-2911)

The previous SD-2911 fix wrote `this.numbering`'s contents on every export.
The importer falls back to `baseNumbering` when the source had no
`word/numbering.xml`, so plain documents gained unused fallback definitions
on round-trip — the regression Luccas flagged.

Capture whether the source package shipped the numbering part before the
baseNumbering fallback runs, and short-circuit the write when both: source
had none AND no `w:numPr` reference exists in the exported body. Sourced
numbering (including tentative variants) still round-trips fully, and a
list created during the session still ships because the body now carries
`w:numPr`.

Editor.ts: the numbering part is now optional in the export bundle — same
shape as appXml / coreXml.

TDD
- 3 new failing integration tests on blank-doc.docx / Hello docx world.docx
  (no source numbering, no body refs).
- All 3 green after the fix.
- The 3 existing SD-2911 tests (active + tentative variants) still pass.

Verification: `pnpm --filter super-editor test --run`: 12 698 / 12 698 pass.
@tupizz
Copy link
Copy Markdown
Contributor Author

tupizz commented May 14, 2026

@luccas-harbour pushed `9e9e8b318`. The regression you flagged is fixed: plain documents no longer gain a `word/numbering.xml` on round-trip.

Fix shape

`SuperConverter.js::#exportNumberingFile` now captures source presence before `baseNumbering` is substituted, and returns early when both:

  • the source package didn't ship `word/numbering.xml`, AND
  • the exported body contains no `w:numPr` reference.

If the source had numbering (active or tentative), every definition still round-trips (SD-2911's original intent is preserved). If a user creates a list in the session, the body carries `w:numPr` and the numbering part is written normally.

`Editor.ts` was the only other place that assumed numbering.xml was always set on `convertedXml`; treating it as optional now mirrors the appXml / coreXml handling already in that block.

TDD

3 new integration tests against `blank-doc.docx` and `Hello docx world.docx` (both have no source numbering): `exportedNumberingEntry` was being emitted before the fix and is now absent. The 3 existing tests for the active + tentative SD-2911 fixtures still pass.

Verification

Layer Result
New plain-doc tests (3) red → green
Existing SD-2911 tests (3) preserved
Full `super-editor` suite ✅ 12 698 / 12 698

@tupizz tupizz requested a review from luccas-harbour May 14, 2026 18:43
Copy link
Copy Markdown
Contributor

@luccas-harbour luccas-harbour left a comment

Choose a reason for hiding this comment

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

LGTM

@luccas-harbour luccas-harbour merged commit b424684 into main May 14, 2026
68 checks passed
@luccas-harbour luccas-harbour deleted the tadeu/sd-2911-preserve-numbering-on-round-trip branch May 14, 2026 19:01
@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 14, 2026

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

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 14, 2026

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

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 14, 2026

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

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 14, 2026

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

The release is available on GitHub release

@superdoc-bot
Copy link
Copy Markdown
Contributor

superdoc-bot Bot commented May 14, 2026

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

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.

4 participants