Skip to content

feat!: migrate DocumentPackage onto schema 3's fused content + pages shape - #611

Merged
Mearman merged 2 commits into
mainfrom
feat/unified-document-package
Aug 17, 2026
Merged

feat!: migrate DocumentPackage onto schema 3's fused content + pages shape#611
Mearman merged 2 commits into
mainfrom
feat/unified-document-package

Conversation

@Mearman

@Mearman Mearman commented Aug 17, 2026

Copy link
Copy Markdown
Member

Closes #569

Migrates the package onto document-schema.js 3's fused DocumentPackage: { formatVersion: 2, content, pages }, with every content leaf carrying its own rendered positions as frames — the second, independent LayoutDocument half correlated back by sourcePath strings is gone from the package surface.

Dependency set (one PR because splitting them leaves the tree unable to typecheck — markdown-codec 1.4.2 pins schema ^2.7.17, which dual-copies against schema ^3): document-schema.js@^3.2.0, ooxml.js@^2.16.0, odf.js@^3.0.1, markdown-codec@^2.0.0. pdf-codec was already on schema 3.

What changed

  • The four layout engines (convertWordprocessingToLayout, convertPresentationToLayout, convertSpreadsheetToLayout, convertDrawingToLayout) stamp every placement they compute onto the corresponding content node's own frames array, in place — one frame per rendered fragment on a run, the cell box on a table/sheet cell, the emitted item's box on an image, vector, or shape — and return the package's pages array alongside the internal LayoutDocument, which remains pdf-codec's writePdf contract. convertDrawingToLayout now returns { document, pages } like its three siblings.
  • The four reconstructors attach frames from the exact LayoutItems each reconstructed node was clustered from, so every PDF-to-X conversion's content carries genuine positions too. sourcePath survives as traceability only.
  • onDocument / ConversionResult.package surface the unified package: pages + frame-stamped content for toPdf/fromPdf hops, content-only (no pages, no frames) for bridges. odfToPdf reports its single A4 page.
  • buildDocumentBytes(pkg, 'pdf') rebuilds the pdf-codec view from the package's own frames + pages (layoutDocumentFromPackage, exported) — a mechanical inverse walking the content tree and emitting LayoutItems from each node's recorded placements, with drawing vectors re-emitted through the layout engine's own conversion so geometry cannot drift. Two honest limits, documented in the README: a run's frames carry positions, not the wrap decisions that distributed its text across them, so a wrapped run re-renders once, whole, at its first recorded placement; and no font registry or positioned formula survives a bare package (same as before the fusion).
  • Examples regenerated (GENERATE_EXAMPLES=1): document-package.json now shows formatVersion 2 + pages + frame-stamped runs; the six content examples carry formatVersion 3. README's DocumentPackage documentation, the snapshot gotcha, and the sourcePath note updated.

Breaking (semantic-release should cut 2.0.0): package formatVersion 1 → 2, layout gone, buildDocumentBytes(pkg, 'pdf') throws /has no pages/ for bridge dumps instead of /has no layout/, convertDrawingToLayout return shape widened, markdown content carries headingLevel on heading paragraphs.

Generated by Claude Code

…f in DocumentPackage

Bump document-schema.js to ^3.2.0, ooxml.js to ^2.16.0, odf.js to ^3.0.1
and markdown-codec to ^2.0.0 in the same change: holding markdown-codec
1.4.2 (schema ^2) alongside schema ^3 installs two schema copies and
fails typecheck, so the bumps and the code migration cannot land apart.

The four layout engines stamp every placement they compute onto the
corresponding content node's own frames array -- one frame per rendered
fragment on a run, the cell box on a cell, the emitted item's box on an
image, vector or shape -- and return the package's pages array alongside
the internal LayoutDocument, which remains pdf-codec's writePdf
contract. buildDocumentBytes('pdf') rebuilds that LayoutDocument from
the package's own frames and pages (layoutDocumentFromPackage) instead
of reading a layout half the schema no longer carries; a run's frames
carry positions, not wrap decisions, so a wrapped run re-renders once at
its first recorded placement.

BREAKING CHANGE: DocumentPackage is document-schema.js 3's fused shape
({ formatVersion: 2, content, pages }); onDocument and
ConversionResult.package no longer report a layout,
buildDocumentBytes(pkg, 'pdf') throws for a package with no pages and
rebuilds from frames otherwise, convertDrawingToLayout returns
{ document, pages } rather than a bare LayoutDocument, and content read
by markdown-codec 2.0.0 carries headingLevel on heading paragraphs.
… content nodes

The four reconstructors stamp every node they build with frames taken
from the exact LayoutItems it was clustered from -- each recovered run
carries its source item's box, each paragraph the bounding box of its
line, each lattice-recovered cell and table its measured grid box, each
recovered vector the PDF-space box of the item it came from -- so
PDF-to-X conversions surface genuine positions in the same unified
package shape the layout engines produce. sourcePath survives on
recovered items as traceability only.
@github-code-quality

Copy link
Copy Markdown

Code Coverage Overview

Languages: TypeScript

TypeScript / unit

The overall coverage in commit e9ed390 in the feat/unified-documen... branch remains at 91%, unchanged from commit 9572c51 in the main branch.

Show a code coverage summary of the most impacted files.
File main 9572c51 feat/unified-documen... e9ed390 +/-
src/convert/from-package.ts 90% 72% -18%
src/layout/engine.ts 95% 93% -2%
src/layout/shared.ts 97% 96% -1%
src/convert/composition.ts 93% 93% 0%
src/layout/reconstruct.ts 99% 99% 0%
src/layout/slides.ts 99% 99% 0%
src/layout/sheets.ts 98% 98% 0%
src/layout/drawing.ts 100% 100% 0%
src/layout/text-layout.ts 90% 92% +2%

@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 2.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Populate the unified DocumentPackage shape once document-schema.js defines it

1 participant