Mermaid
If a diagram already exists as Mermaid, diago draws it as it is:
diago render diagram.mmd > diagram.svgdiago render -format text diagram.mmdEvery verb reads Mermaid: render, check, both arguments of diff and -previous recognize a
.mmd or .mermaid file, or a body whose first meaningful line is a Mermaid header, and translate it before
anything else. diago import writes the translated JSON spec to stdout, for a diagram you want to
keep editing in diago’s own terms: it gives you ids to keep and fields to set.
diago import diagram.mmd > spec.jsondiago import < diagram.mmd | diago checkThe dialect is read from the header. Three are supported: flowchart (or graph),
sequenceDiagram and classDiagram.
What is reported and what fails
Section titled “What is reported and what fails”The importer does not guess silently. A construct diago cannot carry is translated to its nearest
form and reported on stderr, one line each, as warning: import line <n>: <message>, and the
import still succeeds. A statement with no meaning in diago fails with
diago <verb>: line <n>: <message> and exit 1, as does an input that is not Mermaid. The three
sources below import with nothing on stderr.
Flowcharts
Section titled “Flowcharts”flowchart LR client(Client) --> gateway[API Gateway] subgraph backend [Backend] gateway -->|route| orders[Orders] orders -->|save| db[(Postgres)] end orders -.->|notify| mail{Send mail?} mail ==>|yes| smtp[SMTP Relay]{ "type": "flow", "direction": "RIGHT", "nodes": [ {"id": "client", "label": "Client", "shape": "rounded"}, {"id": "gateway", "label": "API Gateway"}, {"id": "orders", "label": "Orders"}, {"id": "db", "label": "Postgres", "shape": "cylinder"}, {"id": "mail", "label": "Send mail?", "shape": "diamond"}, {"id": "smtp", "label": "SMTP Relay"} ], "edges": [ {"from": "client", "to": "gateway"}, {"from": "gateway", "to": "orders", "label": "route"}, {"from": "orders", "to": "db", "label": "save"}, {"from": "orders", "to": "mail", "label": "notify", "style": "dotted"}, {"from": "mail", "to": "smtp", "label": "yes", "style": "thick"} ], "groups": [{"id": "backend", "label": "Backend", "contains": ["gateway", "orders", "db"]}]}

Bracket shapes become shapes, -.-> a dotted edge and ==> a thick one, and a subgraph a group.
An edge keeps the id Mermaid writes before its arrow (A e1@--> B), and a diff matches edges by
it: give one to every edge before you start diffing versions. Without one, an edge is matched by
its two ends, and a labeled edge warns edge-without-id in a diff.
| Supported | |
|---|---|
| Header | graph or flowchart with TD, TB, LR, BT or RL |
| Nodes | every bracket form |
| Edges | -->, ---, -.->, -.-, ==>, === and <-->, with |label| or -- label -->; a trailing ; |
| Edge ids | e1@ before any arrow; on an & fan-out, the edge from the last source to the first target takes it, as in Mermaid |
| Shorthand | & fan-out and chains |
| Groups | nested subgraph … end; a title: frontmatter |
| Approximated, and reported | Becomes |
|---|---|
| stadium | rounded |
| subroutine | rect |
| doublecircle | circle |
| trapezoid | parallelogram |
| a fourth level of subgraphs | flattened into its third-level ancestor |
an edge’s properties, e1@{ animate: true } |
dropped: diago draws no edge animation or curve |
| an edge id already used | kept by its first edge; the later edge has none |
Rejected, with a line number: classDef, class, style, linkStyle, click, accTitle,
accDescr, direction, and an edge whose endpoint is a subgraph.
Sequence diagrams
Section titled “Sequence diagrams”sequenceDiagram participant U as User participant A as App participant D as Database U->>A: place order A->>D: check stock D-->>A: in stock alt in stock A->>D: reserve items else out of stock A-->>U: sorry end A-->>U: confirmation{ "type": "sequence", "actors": [ {"id": "U", "label": "User"}, {"id": "A", "label": "App"}, {"id": "D", "label": "Database"} ], "interactions": [ {"from": "U", "to": "A", "label": "place order"}, {"from": "A", "to": "D", "label": "check stock"}, {"from": "D", "to": "A", "label": "in stock", "style": "dashed"}, {"from": "A", "to": "D", "label": "reserve items"}, {"from": "A", "to": "U", "label": "sorry", "style": "dashed"}, {"from": "A", "to": "U", "label": "confirmation", "style": "dashed"} ], "fragments": [ { "type": "alt", "over": ["U", "A", "D"], "sections": [ {"label": "in stock", "start": 3, "end": 3}, {"label": "out of stock", "start": 4, "end": 4} ] } ]}

alt and else become one fragment with a section for each branch, over the range of messages it
holds. Declared participants keep their as alias as the label.
| Supported | |
|---|---|
| Participants | participant and actor, with as; implicit declaration on first use |
| Messages | ->>, -->>, -) and --) |
| Blocks | loop, opt, alt with else, par with and, and break, nested, as fragments over ranges of messages |
| Approximated, and reported | Becomes |
|---|---|
actor |
an ordinary participant |
+ and - marks, activate, deactivate |
ignored: the engine computes the activation bars |
a Note |
folded into the label of the nearest message before it in the block, and dropped when there is none |
| an empty branch or block | dropped |
Rejected, with a line number: critical, autonumber, create, destroy, rect, box, link,
links, properties, details, and lost-message arrows (-x).
Class diagrams
Section titled “Class diagrams”classDiagram direction LR class Animal { <<abstract>> +String name +eat() void* } class Dog { +bark() void } class Owner { +String name } Animal <|-- Dog Owner "1" --> "*" Dog : owns{ "type": "class", "direction": "RIGHT", "classes": [ { "id": "Animal", "stereotype": "abstract", "attributes": [{"visibility": "+", "text": "String name"}], "methods": [{"visibility": "+", "text": "eat() void", "abstract": true}] }, {"id": "Dog", "methods": [{"visibility": "+", "text": "bark() void"}]}, {"id": "Owner", "attributes": [{"visibility": "+", "text": "String name"}]} ], "relations": [ {"from": "Dog", "to": "Animal", "kind": "inheritance"}, { "from": "Owner", "to": "Dog", "kind": "association", "label": "owns", "from_card": "1", "to_card": "*", "directed": true } ]}

Every relation operator imports with its cardinalities and label. The JSON is written with from
as the subtype, implementer, owner or dependent, whichever way the Mermaid arrow pointed. A Mermaid
relation has no id: import the diagram and add ids to its relations before you start diffing
versions, since a diff warns edge-without-id for each relation without one.
| Supported | |
|---|---|
| Classes | class X~T~ { … } blocks and bare declarations, with generics |
| Stereotypes | <<stereotype>> inside a block or on its own line |
| Members | X : +member inline, visibility prefixes, a * (abstract) or $ (static) suffix |
| Relations | all twelve operators, with cardinalities and labels |
| Layout | direction TB, LR, BT or RL |
Rejected, with a line number: <-->, ()--, note, namespace, cssClass and click. Nothing
in the class dialect is approximated.
After an import, run diago check -strict on the JSON. The importer keeps what Mermaid says, so
it can bring a diagram that parses fine but reads badly, and the advisories
say where.