fix(style-engine): keep list marker visible when paragraph-mark is vanished (SD-3269)#3465
Open
tupizz wants to merge 4 commits into
Open
fix(style-engine): keep list marker visible when paragraph-mark is vanished (SD-3269)#3465tupizz wants to merge 4 commits into
tupizz wants to merge 4 commits into
Conversation
…nished (SD-3269) ECMA-376 §17.3.2.36/§17.3.2.41 scope `w:vanish` and `w:specVanish` on the paragraph-mark rPr (`w:pPr/w:rPr`) to the paragraph-mark glyph (¶) only; the spec explicitly says they may be ignored on any other run. SuperDoc was cascading them into the auto-generated list marker's run properties, so the renderer dropped "Section 2.01" / "Section 1.01" markers on numbered Heading2 paragraphs whose paragraph-mark was marked hidden. Strip `vanish`/`specVanish` from the inline rPr when resolving the list marker (`isListNumber=true`). Vanish on the numbering definition's own rPr still flows through, so authors can still hide a marker the documented way. Adds two regression tests covering both directions: paragraph-mark vanish must not leak into the marker, numbering-definition vanish must still apply.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
VladaHarbour
approved these changes
May 23, 2026
When the paragraph-mark rPr carries `w:vanish`/`w:specVanish`, the cascade fix from the prior commit prevents that vanish from leaking into the auto-generated list marker. Word's actual behaviour, however, is to hide the marker when the *first inline run* of the paragraph is vanished — even if the rest of the paragraph is visible. Headings authored with a leading hidden seed run rely on that to suppress the section number. Detect a vanished first run on the PM paragraph node and force `markerRun.vanish` accordingly. Vanish from the numbering definition itself still applies through the resolveRunProperties cascade and is unaffected. Adds two regression tests: marker hidden when the first run carries vanish, marker visible when it does not.
…SD-3269)" This reverts commit 0c74e58.
…D-3269) ECMA-376 §17.3.2.36 specifies that when `w:specVanish` sits on the paragraph-mark rPr, "a paragraph mark shall never be used to break the end of a paragraph for display". Word implements this as a visual fuse: the next paragraph flows on the same line, the successor's auto numbering marker disappears, and numbering counters still advance per OOXML paragraph (so subsequent items skip a counter slot). Common in legal templates that keep a numbered heading structurally intact for TOC/cross-references but render the body inline. SuperDoc was emitting each paragraph as its own block, ignoring the fuse semantics. This commit: - Adds `specVanish?: boolean` on `ParagraphAttrs`. - Sets the flag in `computeParagraphAttrs` when the resolved pPr/rPr or the raw paragraph rPr declares `specVanish`. - Adds `mergeSpecVanishParagraphs` as a pm-adapter post-process: when a paragraph carries the flag, the next paragraph's runs are appended into its block; the successor block is dropped, taking its marker with it. Chains of consecutive specVanish paragraphs collapse left-to-right. Verified against the SD-3269 fixtures (HVY Asset Purchase Agreement + Missy's PURCHASE PRICE 3.docx). SuperDoc's `pdftotext`-equivalent now matches Word's PDF export — Heading2 + body merge into one paragraph, absorbed Heading3 markers disappear, and the next standalone item picks up the correct counter (`(a)` then `(c)`, matching Word). Adds three integration tests covering: single fuse, chained fuse, trailing specVanish with no successor.
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.
Demo
Summary
Numbered Heading2 paragraphs in SD-3269 lost their auto-generated marker (e.g.
Section 2.01) on render. Root cause:w:vanish/w:specVanishon the paragraph-mark rPr (w:pPr/w:rPr) was leaking into the list marker's resolved run properties, and the renderer drops markers whenmarker.run.vanishis true.Per ECMA-376 §17.3.2.36 / §17.3.2.41 those properties are scoped to the paragraph-mark glyph (¶); the spec explicitly says "if this element is applied to any other run, it can be ignored." Word renders the section number because the marker's formatting comes from the numbering definition's rPr, not the paragraph-mark rPr.
Fix
packages/layout-engine/style-engine/src/ooxml/index.ts— inresolveRunProperties, whenisListNumber=true, stripvanishandspecVanishfrom the inline rPr before composing the cascade. Vanish set on the numbering definition's ownw:lvl/w:rPrstill wins, so authors can still hide a marker the documented way.Why this seam
CLAUDE.md"Style Resolution Boundary"); a fix inpm-adapteror the painter would silo the rule.renderer.ts:3328resolvedMarker.vanishand:3553marker.run.vanish).w:vanishlegitimately hides actual text content.Tests
Two regression tests in
packages/layout-engine/pm-adapter/src/attributes/paragraph.test.ts:vanish/specVanishmust not leak into the marker run — fails onmain, passes after the fix.vanishis still honoured for the marker — positive control to prevent over-stripping.All pm-adapter (1840), style-engine (142), and layout-engine (652) unit tests pass.
Test plan
pnpm --filter @superdoc/style-engine testpnpm --filter @superdoc/pm-adapter testpnpm --filter @superdoc/layout-engine testpnpm dev, confirmSection 1.01 Assets Purchased.,Section 2.01 Purchase Price., etc. now renderpnpm test:layout) before mergeLinear
Closes SD-3269