Skip to content

fix(html): do not crash ConvertToHtml when DocumentSettingsPart is missing#264

Merged
JSv4 merged 14 commits into
JSv4:mainfrom
arthrod:fix/html-missing-document-settings-part
Jul 12, 2026
Merged

fix(html): do not crash ConvertToHtml when DocumentSettingsPart is missing#264
JSv4 merged 14 commits into
JSv4:mainfrom
arthrod:fix/html-missing-document-settings-part

Conversation

@arthrod

@arthrod arthrod commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • CalculateSpanWidthForTabs no longer assumes MainDocumentPart.DocumentSettingsPart is always present. Missing word/settings.xml is legal OOXML (Word opens those packages without repair); the converter previously threw ArgumentNullException("part") via GetXDocument and aborted conversion.
  • When settings (or w:defaultTabStop) are absent, keep the existing default of 720 twips.
  • Read w:defaultTabStop as a direct child of w:settings (not a full Descendants walk).
  • Remove the throwaway invent-if-missing DocumentSettingsPart path in AddFormattingParts now that conversion tolerates a missing part.
  • Normalize dotnet.boot.js asset integrityhash in scripts/build-wasm.sh so the .NET 10 loader applies SRI.
  • Regression tests: HCO057HCO061 (no settings / custom tab stop / empty settings / RenderBlockHtml).

Surfaced while scoring Docxodus on a large minimal-OOXML corpus: this single null path was the dominant convert failure for packages without settings.

Behaviour

Package shape Before After
settings + w:defaultTabStop OK unchanged
settings, no defaultTabStop 720 unchanged
no settings.xml crash 720, HTML produced

Test plan

  • dotnet test --filter FullyQualifiedName~HCO05 / HCO06 (includes HCO056–HCO061)
  • CI green
  • After merge: rebuild/publish WASM so npm docxodus consumers get the engine fix (JS + WASM must ship as a matched pair)

opencode-agent Bot and others added 8 commits July 10, 2026 17:21
…ssing

OOXML does not require word/settings.xml. CalculateSpanWidthForTabs called
DocumentSettingsPart.GetXDocument() unconditionally, so packages with only
document + styles threw ArgumentNullException("part") before any HTML.

Treat settings as optional and keep the existing 720-twip default tab stop.
Add HCO057 regression coverage for a no-settings package.
Drop redundant MainDocumentPart null-conditional (already non-null in
ConvertToHtml), read w:defaultTabStop as a direct child of w:settings,
and remove the throwaway DocumentSettingsPart invent-if-missing path in
AddFormattingParts now that ConvertToHtml tolerates a missing part.
AddFormattingParts no longer synthesizes a dummy DocumentSettingsPart;
update the RenderBlockHtml regression comment to match.
dotnet.js applies fetch integrity from asset.hash; some SDK builds emit
integrity instead. Rename at publish so SRI is not silently skipped.
@arthrod

arthrod commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author
vendor version datetime benchmark mean median n_docs
docxodus 6.4.0 2026-07-09T15:58:38.145555+00:00 accepted_changes 68.9994 77.1882 164
docxodus 6.4.0 2026-07-10T00:12:10.214778+00:00 roundtrip 92.2445 100 198
docxodus 6.4.0 2026-07-09T15:48:47.581159+00:00 script_redlines 58.7425 55.0306 205
docxodus 6.4.0 2026-07-09T17:19:51.161639+00:00 visual_accepted_changes 62.3235 62.7622 152
docxodus 6.4.0 2026-07-09T16:57:22.200205+00:00 visual_redlines 60.9207 61.2232 145
docxodus 6.4.0-local.1 2026-07-10T20:58:07.916380+00:00 visual_rendering 56.5017 49.7216 190
docxodus 7.0.0 2026-07-10T21:37:40.839901+00:00 accepted_changes 70.1963 74.9182 164
docxodus 7.0.0 2026-07-10T21:37:40.839901+00:00 roundtrip 97.4281 100 166
docxodus 7.0.0 2026-07-10T21:37:40.839901+00:00 script_redlines 58.7507 55.0306 205
docxodus 7.0.0 2026-07-10T21:37:40.839901+00:00 visual_redlines 58.7507 55.0306 205
docxodus 7.0.0 2026-07-10T21:55:37.514080+00:00 visual_rendering 56.5017 49.7216 190

opencode-agent Bot added 3 commits July 10, 2026 18:12
Extract DefaultTabStopTwips const and GetSettingsXDocumentOrDefault
helper; reuse in both CalculateSpanWidthForTabs and GetDocumentDefaultLanguage.
Conflict-resolved to keep the .Root?.Element() optimization.
…harness (PR #5)

Type-mania recipe: annotate docx_scalpel session.py __exit__, enums.py
_missing_ return type, and all LibreOffice diff-harness scripts (lo_batch,
lo_bookmark_check, lo_comment_check, lo_compare, lo_footnote_check,
lo_headerfooter_check).
#6)

Type-mania recipe: annotate npm session.ts predicate functions with
boolean return types; use TYPE_CHECKING guard for TracebackType import
in docx_scalpel session.py (avoids runtime import under PEP 563).
@arthrod

arthrod commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Here the full results: https://github.com/jandira-tech/neurotic_docx_bench

opencode-agent Bot added 2 commits July 10, 2026 19:14
Stop tracking macOS Finder metadata (.DS_Store) across the repo and
prevent future commits from re-adding them.
@JSv4

JSv4 commented Jul 11, 2026

Copy link
Copy Markdown
Owner

Thanks! This looks great. Will review a little further but good find. The HTML converter has not been my focus, but it's handy and great fix!

@JSv4 JSv4 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Added a changelog entry but looks great. Thank you

@JSv4
JSv4 merged commit f11bd6d into JSv4:main Jul 12, 2026
7 of 8 checks passed
JSv4 added a commit that referenced this pull request Jul 12, 2026
…ssing (#266)

word/styles.xml is optional in OOXML (Word opens a document-only package
without repair), but FormattingAssembler.AssembleFormatting dereferenced
StyleDefinitionsPart unconditionally at many sites - and it runs before
the settings fix from #264 - so a package with only word/document.xml
still threw ArgumentNullException("part") before producing any HTML.

Ensure the styles part exists at the AssembleFormatting entry via a new
shared StyleFactory.EnsureStylesPart find-or-create helper (extracted
from the two identical synthesize sites already in StyleFactory), so
every style lookup falls through to built-in defaults; this covers the
full-document, RenderBlockHtml, and session-render paths in one place.

Regression coverage: HCO062 (programmatic document-only package), HCO063
(in-repo RPR-FivePageTestDoc.docx document-only fixture), HCO064
(RenderBlockHtml on a styles-less source).

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants