Skip to content

Add multi-format exports and PowerPoint fidelity modes - #6

Merged
LJAYi merged 7 commits into
mainfrom
agent/diagram-platform-foundation
Jul 22, 2026
Merged

LJAYi merged 7 commits into
mainfrom
agent/diagram-platform-foundation

Conversation

@LJAYi

@LJAYi LJAYi commented Jul 22, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • introduce a target-neutral Diagram IR with Mermaid FlowDB/SVG source mapping
  • add tiered PowerPoint export modes: smart, faithful, and exact
  • add forward-only normalized SVG, draw.io, and JSON Canvas exporters
  • share capability diagnostics across SDK, CLI, web, and generated compatibility docs

Scope

This PR establishes the forward-export foundation for mmd2pptx. The browser-based visual layout workbench is tracked separately in Draft PR #7. Reverse conversion remains deferred.

Export fidelity

This work also aligns live preview and forward exports across Mermaid curve defaults, vector zoom, dash styles, draw.io, PowerPoint, and Illustrator-compatible SVG output.

Testing

  • full TypeScript checks and unit tests
  • Web Playwright coverage
  • compatibility document generation check
  • PPTX package validation

Summary by CodeRabbit

  • New Features
    • Export to PPTX, normalized SVG, draw.io, and JSON Canvas, including PPTX smart/faithful/exact modes.
    • Web app adds format/mode-aware export readiness, Flowchart semantics extraction, and an .mmd picker (with size-limit error handling).
    • CLI now supports --format plus PPTX --mode and background color validation.
  • Documentation
    • Updated SDK/CLI docs, forward-only conversion guidance, and added detailed compatibility/capability matrices.
  • Bug Fixes
    • Improved diagnostics, safer exact-mode SVG embedding, and more reliable export preflights/fallbacks and stroke/connectivity handling.
  • Tests / CI
    • Expanded e2e/exporter suites; CI runs compatibility checks and PPTX compatibility verification.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Changes

Forward conversion platform

Layer / File(s) Summary
IR, SVG parsing, and Mermaid semantics
packages/core/src/diagram-ir/*, packages/core/src/parse-svg.ts, packages/core/src/source-mapping/*, packages/core/src/types.ts
Adds canonical path geometry, richer Diagram IR metadata, SVG style and transform handling, and FlowDB semantic extraction and merging.
Exporter contracts and serializers
packages/core/src/export-contract.ts, packages/core/src/exporters/*, packages/core/src/stroke-style.ts
Adds shared exporter contracts, capability registries, deterministic SVG, draw.io, and JSON Canvas outputs with diagnostics, validation, and consistent stroke normalization.
Routing and PPTX conversion modes
packages/core/src/routing/*, packages/core/src/pptx.ts, packages/core/src/pptx-connector-patch.ts
Adds collision-aware routing, PPTX smart/faithful/exact handling, native connector patching, SVG embedding, and expanded validation.
CLI, web workflow, and compatibility validation
packages/cli/src/*, apps/web/src/*, scripts/*, docs/*, .github/workflows/ci.yml
Adds format and mode selection to CLI and web flows, updates API and project documentation, generates compatibility data, and checks it in CI.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • LJAYi/mmd2pptx#5: Both PRs modify the web SVG viewer’s viewport and pan/zoom behavior.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the PR’s main scope: building the Stage 1 and Stage 2 forward export foundation.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/diagram-platform-foundation

Comment @coderabbitai help to get the list of available commands.

@LJAYi LJAYi changed the title Build the forward diagram platform foundation Build the forward-only diagram platform foundation Jul 22, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
packages/core/src/layout/apply.ts (1)

358-359: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Avoid spreading points into Math.max.
expandCanvas collects every coordinate from groups, nodes, edges, and labels into points. For large diagrams, Math.max(...points.map(...)) can hit the engine argument limit and throw. A reduce keeps the same result without that risk.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/layout/apply.ts` around lines 358 - 359, Update the width
and height calculations in expandCanvas to aggregate coordinate values with
reduce rather than spreading mapped points into Math.max. Preserve the existing
maximum-coordinate results for both x and y while avoiding large argument lists.
apps/web/src/layout/editor.ts (1)

995-999: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Hoist the key array out of the .some() predicate.

[...this.nodeHandles.keys()][index] reconstructs the full key array on every iteration, making this O(n²) with per-iteration allocations. notify() runs on every mutation/selection, so this is worth hoisting once.

♻️ Suggested change
-        (this.sidecar.groups ?? []).some(({ id }) => id.startsWith("layout-group-")) ||
-        this.zOrder.some((key, index) => key !== [...this.nodeHandles.keys()][index]),
+        (this.sidecar.groups ?? []).some(({ id }) => id.startsWith("layout-group-")) ||
+        (() => {
+          const order = [...this.nodeHandles.keys()];
+          return this.zOrder.some((key, index) => key !== order[index]);
+        })(),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/layout/editor.ts` around lines 995 - 999, Update the
hasOverrides calculation in notify() to materialize this.nodeHandles.keys() once
before the zOrder.some() predicate, then compare each key against that reused
array. Preserve the existing ordering comparison and other override checks
unchanged.
packages/core/src/routing/orthogonal.ts (1)

117-143: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

Open list is fully re-sorted on every pop — replace with a binary heap.

open.sort(compareSearchNodes) followed by open.shift() on each iteration makes the search ~O(V²·log V). With maxSearchBudget defaulting to 20_000 and this running synchronously on the main thread (via routeSelectedEdge in the web editor), a dense diagram can visibly stall the UI. A binary min-heap keyed on compareSearchNodes gives O(log n) push/pop and preserves the deterministic ordering.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/routing/orthogonal.ts` around lines 117 - 143, The search
loop’s open list currently re-sorts and shifts on every iteration, causing
inefficient O(V²·log V) behavior. Replace the open-list operations in the
routing search with a binary min-heap ordered by compareSearchNodes, using heap
push and pop while preserving the existing deterministic comparator ordering and
search behavior.
packages/core/src/exporters/svg.ts (1)

336-341: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move imports to the top of the file.

Type imports for DiagramExporter, DiagramExportOptions, ConversionDiagnostic, and DiagramIR are declared at the very bottom of the file, after all the code that uses them (e.g. Lines 19, 25, 129). ES module import hoisting makes this compile, but it's inconsistent with the rest of the codebase's module layout and can trip lint rules that enforce imports-at-top (e.g. import/first).

♻️ Proposed fix
+import type {
+  DiagramExporter,
+  DiagramExportOptions,
+} from "../export-contract.js";
+import type { ConversionDiagnostic, DiagramIR } from "../types.js";
 import type {
   ExportBounds,
   ExportDiagram,
   ...
 } from "./model.js";
 import { assertUniqueIds, number, stableId, styleColor, styleFontFamily, xml } from "./xml.js";
 import {
   exporterFailure,
   exporterResult,
   unsupportedMermaidDiagramResult,
 } from "./result.js";
-import type {
-  DiagramExporter,
-  DiagramExportOptions,
-} from "../export-contract.js";
-import type { ConversionDiagnostic, DiagramIR } from "../types.js";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/exporters/svg.ts` around lines 336 - 341, Move the type
imports for DiagramExporter, DiagramExportOptions, ConversionDiagnostic, and
DiagramIR from the bottom of the SVG exporter module to the top-level import
section, before executable code and other declarations. Keep the existing import
paths and type-only semantics unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli/src/run.ts`:
- Around line 149-156: Update pathsReferToSameFile to compare both resolved
paths’ stat().dev and stat().ino values, detecting hard-link aliases as well as
symlinks before writing. Preserve the false result when the output path does not
exist, and add a regression test covering an output hard-linked to the input.

In `@packages/core/test/core.test.ts`:
- Line 493: Update the XML assertion in the relevant test to check for the
compact self-closing DrawingML form "<a:close/>" instead of "<a:close />". Apply
the same correction to the corresponding assertion in the edge-capability test.

---

Nitpick comments:
In `@apps/web/src/layout/editor.ts`:
- Around line 995-999: Update the hasOverrides calculation in notify() to
materialize this.nodeHandles.keys() once before the zOrder.some() predicate,
then compare each key against that reused array. Preserve the existing ordering
comparison and other override checks unchanged.

In `@packages/core/src/exporters/svg.ts`:
- Around line 336-341: Move the type imports for DiagramExporter,
DiagramExportOptions, ConversionDiagnostic, and DiagramIR from the bottom of the
SVG exporter module to the top-level import section, before executable code and
other declarations. Keep the existing import paths and type-only semantics
unchanged.

In `@packages/core/src/layout/apply.ts`:
- Around line 358-359: Update the width and height calculations in expandCanvas
to aggregate coordinate values with reduce rather than spreading mapped points
into Math.max. Preserve the existing maximum-coordinate results for both x and y
while avoiding large argument lists.

In `@packages/core/src/routing/orthogonal.ts`:
- Around line 117-143: The search loop’s open list currently re-sorts and shifts
on every iteration, causing inefficient O(V²·log V) behavior. Replace the
open-list operations in the routing search with a binary min-heap ordered by
compareSearchNodes, using heap push and pop while preserving the existing
deterministic comparator ordering and search behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ef4beebd-b7b7-4ce9-9119-fd05d4fb4748

📥 Commits

Reviewing files that changed from the base of the PR and between 141cabb and dff1c3b.

⛔ Files ignored due to path filters (4)
  • packages/core/test/fixtures/faithful-edges.svg is excluded by !**/*.svg
  • packages/core/test/fixtures/mermaid-11-renderer-prefix.svg is excluded by !**/*.svg
  • packages/core/test/fixtures/mermaid-11-synthetic-semantics.svg is excluded by !**/*.svg
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (83)
  • .github/workflows/ci.yml
  • README.md
  • apps/web/package.json
  • apps/web/src/layout/arrange.ts
  • apps/web/src/layout/editor.ts
  • apps/web/src/layout/history.ts
  • apps/web/src/layout/index.ts
  • apps/web/src/main.ts
  • apps/web/src/styles.css
  • apps/web/src/svg-viewer.ts
  • apps/web/tests/e2e/layout-editor.spec.ts
  • apps/web/tests/e2e/workbench.spec.ts
  • apps/web/tests/layout/arrange.test.ts
  • apps/web/tests/layout/history.test.ts
  • docs/adr/0001-forward-only-unified-ir.md
  • docs/architecture.md
  • docs/compatibility.md
  • docs/edge-capability.md
  • docs/openapi.yaml
  • docs/roadmap.md
  • package.json
  • packages/cli/README.md
  • packages/cli/src/arguments.test.ts
  • packages/cli/src/arguments.ts
  • packages/cli/src/index.ts
  • packages/cli/src/openapi-consistency.test.ts
  • packages/cli/src/run.test.ts
  • packages/cli/src/run.ts
  • packages/core/README.md
  • packages/core/src/diagram-ir/classify.ts
  • packages/core/src/diagram-ir/index.ts
  • packages/core/src/diagram-ir/path.ts
  • packages/core/src/diagram-ir/types.ts
  • packages/core/src/export-contract.ts
  • packages/core/src/exporters/capabilities.ts
  • packages/core/src/exporters/drawio.ts
  • packages/core/src/exporters/index.ts
  • packages/core/src/exporters/json-canvas.ts
  • packages/core/src/exporters/model.ts
  • packages/core/src/exporters/result.ts
  • packages/core/src/exporters/svg.ts
  • packages/core/src/exporters/xml.ts
  • packages/core/src/index.ts
  • packages/core/src/layout/apply.ts
  • packages/core/src/layout/identity.ts
  • packages/core/src/layout/index.ts
  • packages/core/src/layout/reconcile.ts
  • packages/core/src/layout/sidecar.ts
  • packages/core/src/layout/types.ts
  • packages/core/src/parse-svg.ts
  • packages/core/src/pptx-connector-patch.ts
  • packages/core/src/pptx.ts
  • packages/core/src/routing/collisions.ts
  • packages/core/src/routing/index.ts
  • packages/core/src/routing/orthogonal.ts
  • packages/core/src/routing/types.ts
  • packages/core/src/source-mapping/extract.ts
  • packages/core/src/source-mapping/index.ts
  • packages/core/src/source-mapping/merge.ts
  • packages/core/src/source-mapping/types.ts
  • packages/core/src/types.ts
  • packages/core/test/collisions.test.ts
  • packages/core/test/core.test.ts
  • packages/core/test/diagram-ir.test.ts
  • packages/core/test/exporters/contract.test.ts
  • packages/core/test/exporters/corpus.test.ts
  • packages/core/test/exporters/exporters.test.ts
  • packages/core/test/exporters/json-canvas.test.ts
  • packages/core/test/exporters/quality.test.ts
  • packages/core/test/exporters/semantic-fidelity.test.ts
  • packages/core/test/fixtures/forward-export-corpus.ts
  • packages/core/test/fixtures/pptx-edge-capability.ts
  • packages/core/test/layout.test.ts
  • packages/core/test/pptx-connector-patch.test.ts
  • packages/core/test/pptx-edge-capability.test.ts
  • packages/core/test/pptx-groups-z-order.test.ts
  • packages/core/test/pptx-package-integrity.test.ts
  • packages/core/test/pptx-preflight.test.ts
  • packages/core/test/public-api.test.ts
  • packages/core/test/routing.test.ts
  • packages/core/test/source-mapping.test.ts
  • scripts/generate-compatibility.mjs
  • scripts/verify-pptx-compatibility.mjs

Comment thread packages/cli/src/run.ts
Comment thread packages/core/test/core.test.ts Outdated
@LJAYi LJAYi changed the title Build the forward-only diagram platform foundation Build Stage 1 and Stage 2 forward export foundation Jul 22, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/main.ts`:
- Line 478: Apply the current layout sidecar to parsed.data before every IR
consumer so layout edits reach diagnostics and exported output. Update
apps/web/src/main.ts lines 478-478 before PPTX/exporter preflight and lines
611-611 before diagramToPptxBlob or forward exporters; both sites should use the
same sidecar-application flow rather than passing raw parsed.data.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 403827f5-48bf-44f3-aa57-8148f833fb7f

📥 Commits

Reviewing files that changed from the base of the PR and between 04ff4f7 and 56b7fd2.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (10)
  • README.md
  • apps/web/package.json
  • apps/web/src/main.ts
  • apps/web/src/styles.css
  • docs/adr/0001-forward-only-unified-ir.md
  • docs/architecture.md
  • docs/roadmap.md
  • packages/core/README.md
  • packages/core/src/index.ts
  • packages/core/test/public-api.test.ts
💤 Files with no reviewable changes (4)
  • apps/web/src/styles.css
  • packages/core/test/public-api.test.ts
  • packages/core/README.md
  • packages/core/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/architecture.md
  • README.md

Comment thread apps/web/src/main.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/stroke-style.ts`:
- Around line 4-30: Update nonZeroDashArray to validate every dash entry before
returning the custom array: any negative or non-finite value must produce
undefined so callers treat the pattern as solid. Ensure effectiveDashKind and
svgDashArray therefore never classify or serialize invalid dash arrays, while
preserving valid custom arrays and existing empty/all-zero behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9ed9f953-9b3d-4b2b-a032-72f20a0bc06d

📥 Commits

Reviewing files that changed from the base of the PR and between 56b7fd2 and 9e069aa.

📒 Files selected for processing (12)
  • apps/web/src/main.ts
  • apps/web/src/styles.css
  • apps/web/src/svg-viewer.ts
  • apps/web/tests/e2e/workbench.spec.ts
  • packages/core/src/exporters/drawio.ts
  • packages/core/src/exporters/svg.ts
  • packages/core/src/exporters/xml.ts
  • packages/core/src/parse-svg.ts
  • packages/core/src/pptx.ts
  • packages/core/src/stroke-style.ts
  • packages/core/test/exporters/exporters.test.ts
  • packages/core/test/exporters/stroke-consistency.test.ts
💤 Files with no reviewable changes (1)
  • apps/web/src/styles.css
🚧 Files skipped from review as they are similar to previous changes (8)
  • packages/core/test/exporters/exporters.test.ts
  • packages/core/src/exporters/xml.ts
  • apps/web/tests/e2e/workbench.spec.ts
  • packages/core/src/exporters/svg.ts
  • packages/core/src/pptx.ts
  • packages/core/src/exporters/drawio.ts
  • apps/web/src/main.ts
  • packages/core/src/parse-svg.ts

Comment thread packages/core/src/stroke-style.ts
@LJAYi

LJAYi commented Jul 22, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@LJAYi
LJAYi marked this pull request as ready for review July 22, 2026 13:24
@LJAYi
LJAYi merged commit d87d3f7 into main Jul 22, 2026
2 checks passed
@LJAYi LJAYi changed the title Build Stage 1 and Stage 2 forward export foundation Add multi-format exports and PowerPoint fidelity modes Jul 22, 2026
@LJAYi
LJAYi deleted the agent/diagram-platform-foundation branch July 23, 2026 05:48
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.

1 participant