Skip to content

feat(mermaid): layered flowchart layout, state/class/ER diagrams, better Gantt, mindmaps - #26

Merged
borghei merged 9 commits into
mainfrom
feat/mermaid-layout
Oct 1, 2026
Merged

borghei merged 9 commits into
mainfrom
feat/mermaid-layout

Conversation

@borghei

@borghei borghei commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Summary

Flowcharts used to print as a list of edges, repeating shared nodes and ignoring direction; state, class and ER diagrams printed as raw source.

  • Flowcharts get a layered layout: each node is drawn once, edges are routed with corners and arrowheads, labels sit on their edges, and TD, BT, LR and RL are honoured. Node shapes, link kinds, chains, & groups and subgraphs parse.
  • State diagrams, class diagrams (three-part boxes, relationship glyphs, cardinalities) and ER diagrams (attribute rows, cardinalities as text) use the same engine.
  • Gantt charts have a scaled time axis and distinct bars for done, active, planned and milestone tasks.
  • Mindmaps draw as a tree. Unsupported diagram types show their source in a titled box instead of bare text.

Limits

  • Above 200 nodes, 400 edges or 200 subgraphs a diagram falls back to the edge list. A diagram that cannot fit tries narrower labels, then top-down, then the list. No line exceeds the available width.
  • Diagrams with back edges get busy; subgraph frames are dropped when members interleave.
  • The sequence renderer is unchanged.

Testing

Exact-output tests, property checks over a 30-diagram corpus (width, each label once, determinism, ASCII-only in ASCII mode), timing-bounded hostile inputs, and an escape-byte test across all diagram types. Two plain snapshots changed deliberately (flowcharts and the Gantt chart). fmt, clippy and the full suite (506 tests) pass locally after merging current main.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UVcvmQrSXd2eyt32g4ko19

Flowcharts were printed as a list of edges, so a node with several edges
appeared once per edge and LR was ignored. They are now parsed fully
(shapes, every link kind, labels, chains, & groups, subgraphs, comments,
style lines, quoted labels, <br>, entities) and laid out Sugiyama-style
on a character grid: cycle breaking, longest-path ranks, dummy nodes,
barycenter crossing reduction with subgraph members kept together,
isotonic-regression coordinates, orthogonal routing with shared fan-in
and fan-out tracks, edge labels as nodes of their own, and arrowheads.

Each node is drawn once, with a shape-specific outline; TD/TB/BT/LR/RL
are honoured; subgraphs get a titled frame when their members stay
together, otherwise their membership is listed under the diagram.
Diagrams that do not fit narrow their labels, then LR falls back to top
down, then to a compact list; over 200 nodes or 400 edges the list is
used directly. Output never exceeds the width.

The mermaid module becomes a directory (canvas, engine, graph model,
flowchart parser, text helpers, tests) with a fixture corpus under
tests/fixtures/mermaid. Snapshots with flowcharts change accordingly.
stateDiagram and stateDiagram-v2 printed as raw source. States,
transitions with labels, 'state "…" as id', 'id : description',
composite states (as titled frames, with their own [*]), <<choice>>,
<<fork>> and <<join>>, direction and notes are parsed into the graph
model and drawn by the flowchart engine: [*] is ● as a source and ◉ as
a target, choice a ◇, fork/join a bar. Transitions to a composite land
on its start state and leave from its end state. Notes are listed under
the diagram.
classDiagram printed as raw source. Classes (bodies, 'Name : member'
lines, generics as <T>, <<annotations>>, ["labels"]), namespaces (as
frames), notes and every relationship form (<|--, *--, o--, -->, --,
..>, ..|>, .., two-way, with labels and "1"/"*" cardinalities) are
parsed into the graph model. Each class is a box split into name,
attributes and methods; relationship ends carry △ (inheritance,
realization), ◆ (composition), ◇ (aggregation) or an arrowhead, dotted
for the .. forms, and a legend line names the kinds used.
erDiagram printed as raw source. Entities (with attribute blocks and
["aliases"]) and relationships (||, |o, }o, }| ends, -- and .. lines,
labels) are parsed into the graph model. Each entity is a box with a
row per attribute ('type name PK,FK'); each relationship is a labelled
edge whose label carries the cardinality of the end nearest it (1,
0..1, 0..*, 1..*), dotted when non-identifying.
The Gantt renderer printed task names with bars whose length came from
the name, not the schedule. It now parses title, dateFormat (dates with
optional times, HH:mm, Unix timestamps), sections, ids, explicit start
and end dates, durations (ms s m h d w M y), 'after' and 'until'
dependencies and the done/active/crit/milestone tags, and draws a time
axis scaled to the width with ticks at round intervals, a section header
per section and one bar per task: █ done, ▓ active, ░ planned, ◆
milestone, critical tasks in the warning colour. Task names sit in a
left column. Work is linear in the number of tasks (3000-task test).

Snapshot: the Product Roadmap chart in diagrams.md.
Diagram types that are not drawn (journey, gitGraph, timeline,
quadrantChart, sankey, C4, requirementDiagram, xychart, block, packet,
kanban, architecture, …) were printed as bare text under a generic
header. They now show their source, hard-wrapped to the width, in a box
titled 'mermaid: <type> (not rendered)'. Mindmaps are drawn as an
indentation tree with ├─ └─ branches (shapes, icons and classes
stripped, deep trees capped at half the width).

Sequence diagrams and pie charts keep their output at the usual width;
when narrower, pie bars shrink and over-wide lines wrap behind the left
border, so no diagram line exceeds the width (ASCII mode included). A
'pie title …' first line now sets the title.
Subgraph membership for edges that name a subgraph was computed per
cluster per node (quadratic in thousands of subgraphs); it is now one
pass. Diagrams with more than 200 subgraphs are listed rather than laid
out, mindmap prefixes stop growing instead of being re-truncated per
node, and the list form indexes outgoing edges instead of scanning them
per node. The list form is left-aligned and now shows each edge's
markers, line style and cardinalities (◁── for inheritance, ┄┄ for
dotted, '1 ──buys── *▶').
@borghei
borghei merged commit 446815d into main Oct 1, 2026
8 checks passed
@borghei
borghei deleted the feat/mermaid-layout branch October 1, 2026 16:24
@borghei borghei mentioned this pull request Oct 1, 2026
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