mmdflux 1.0.0

Render Mermaid diagrams as Unicode text, ASCII, SVG, and MMDS JSON.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
# mmdflux

Render Mermaid diagrams as Unicode text, ASCII, or SVG. Includes a structured JSON interchange format (MMDS) for tooling integration.

## Installation

```bash
cargo install mmdflux
```

Or build from source:

```bash
git clone https://github.com/kevinswiber/mmdflux
cd mmdflux
cargo build --release
```

## Releasing

GitHub Actions now handles CI and binary distribution:

- `CI` workflow runs lint, tests, and cross-platform build checks on pushes/PRs.
- `Release` workflow builds release binaries and uploads them to GitHub Releases.

To publish a release from a tag:

```bash
git tag v1.0.0
git push origin v1.0.0
```

The release workflow publishes these artifacts:

- Linux x64 (`x86_64-unknown-linux-gnu`)
- macOS x64 (`x86_64-apple-darwin`)
- macOS arm64 (`aarch64-apple-darwin`)
- Windows x64 (`x86_64-pc-windows-msvc`)
- `checksums.txt` (SHA256)

## CLI Usage

```bash
# Parse a Mermaid file
mmdflux diagram.mmd

# Read from stdin
echo -e 'graph LR\nA-->B' | mmdflux

# Multi-line input with heredoc
mmdflux <<EOF
graph TD
    A --> B
    B --> C
EOF

# Write to a file
mmdflux diagram.mmd -o output.txt

# Debug mode: show detected diagram type
mmdflux --debug diagram.mmd

# Lint mode: validate input and report diagnostics
mmdflux --lint diagram.mmd

# Show node IDs alongside labels
mmdflux --show-ids diagram.mmd

# ASCII output
mmdflux --format ascii diagram.mmd

# SVG output
mmdflux --format svg diagram.mmd -o diagram.svg

# SVG output with scale factor
mmdflux --format svg --svg-scale 1.5 diagram.mmd -o diagram.svg
```

Note: SVG output is currently supported only for flowcharts; other diagram types return an error.

## Examples

See the [gallery](docs/gallery.md) for rendered fixtures.

### Simple Flow (LR)

Input:
```
graph LR
    A[Start] --> B[Process] --> C[End]
```

Output:
```
┌───────┐     ┌─────────┐     ┌─────┐
│ Start │────►│ Process │────►│ End │
└───────┘     └─────────┘     └─────┘
```

### Decision Flow (TD)

Input:
```
graph TD
    A[Start] --> B{Decision}
    B -->|Yes| C[Accept]
    B -->|No| D[Reject]
```

Output:
```
          ┌───────┐
          │ Start │
          └───────┘
        ┌──────────┐
        < Decision >
        └──────────┘
     ┌───┘        └────┐
     │                 │
    Yes               No
     │                 │
     ▼                 ▼
┌────────┐        ┌────────┐
│ Accept │        │ Reject │
└────────┘        └────────┘
```

### Cycle Flow

Input:
```
graph TD
    A[Start] --> B[Process]
    B --> C[End]
    C --> A
```

Output:
```
      ┌───────┐
      │ Start │
      └───────┘
     ┌─┘     ▲
     │       └┐
     ▼        │
┌─────────┐   │
│ Process │   │
└─────────┘   │
     │        │
     └──┐     │
        ▼   ┌─┘
       ┌─────┐
       │ End │
       └─────┘
```

### Subgraph Flow

Input:
```
graph TD
    subgraph sg1[Process]
        A[Start] --> B[Middle]
    end
    B --> C[End]
```

Output:
```
┌── Process ───┐
│   ┌───────┐  │
│   │ Start │  │
│   └───────┘  │
│       │      │
│       │      │
│       ▼      │
│  ┌────────┐  │
│  │ Middle │  │
│  └────────┘  │
└───────┼──────┘
     ┌─────┐
     │ End │
     └─────┘
```

### Nested Subgraphs (LR)

Input:
```
graph LR
    subgraph outer[Outer]
        subgraph left[Left]
            A --> B
        end
        subgraph right[Right]
            C --> D
        end
    end
    B --> C
```

Output:
```
┌───────────────────── Outer ──────────────────────┐
│                                                  │
│    ┌──── Left ────┐         ┌──── Right ─────┐   │
│    │              │         │                │   │
│    │┌───┐    ┌───┐│         │ ┌───┐    ┌───┐ │   │
│    ││ A │───►│ B │┼─────────┼►│ C │───►│ D │ │   │
│    │└───┘    └───┘│         │ └───┘    └───┘ │   │
│    │              │         │                │   │
│    └──────────────┘         └────────────────┘   │
│                                                  │
└──────────────────────────────────────────────────┘
```

### HTTP Request Flow

Input:
```
graph TD
    Client[Client] -->|HTTP Request| Server[Server]
    Server --> Auth{Authenticated?}
    Auth -->|Yes| Process[Process Request]
    Auth -->|No| Reject[401 Unauthorized]
    Process --> Response[Send Response]
    Reject --> Response
    Response -->|HTTP Response| Client
```

Output:
```
                         ┌────────┐
                         │ Client │◄────────┐
                         └────────┘         │
                     ┌────┘                 │
                     │                      │
               HTTP Request                 │
                     │                      │
                     ▼                      │
                ┌────────┐                  │
                │ Server │                  │
                └────────┘                  │
                     │                      │
                     │                      │
                     │                      │
                     │                      │
                     ▼                HTTP Response
            ┌────────────────┐              │
            < Authenticated? >              │
            └────────────────┘              │
         ┌───┘              └────┐          │
         │                       │          │
         │                       │          │
        Yes                     No          │
         │                       │          │
         ▼                       ▼          │
┌─────────────────┐       ┌──────────────────┐
│ Process Request │       │ 401 Unauthorized │
└─────────────────┘       └──────────────────┘
         │                       │          │
         │                       │          │
         │                       │          │
         └────────────────┐      └──────┐   │
                          ▼             ▼   │
                         ┌───────────────┐  │
                         │ Send Response │──┘
                         └───────────────┘
```

### ASCII Mode

Use `--format ascii` for ASCII-only output (no Unicode box-drawing):

```bash
echo 'graph LR\nA-->B-->C' | mmdflux --format ascii
```

```
+---+    +---+    +---+
| A |--->| B |--->| C |
+---+    +---+    +---+
```

## Supported Syntax

### Directions

- `TD` / `TB` - Top to Bottom
- `BT` - Bottom to Top
- `LR` - Left to Right
- `RL` - Right to Left

### Node Shapes

| Syntax          | Shape                   |
| --------------- | ----------------------- |
| `A`             | Rectangle (default)     |
| `A[text]`       | Rectangle with label    |
| `A(text)`       | Rounded rectangle       |
| `A([text])`     | Stadium                 |
| `A[[text]]`     | Subroutine              |
| `A[(text)]`     | Cylinder                |
| `A{text}`       | Diamond                 |
| `A{{text}}`     | Hexagon                 |
| `A((text))`     | Circle                  |
| `A(((text)))`   | Double circle           |
| `A>text]`       | Asymmetric (flag)       |
| `A[/text\]`     | Trapezoid               |
| `A[\text/]`     | Inverse trapezoid       |
| `@{shape: ...}` | Extended shape notation |

### Edge Types

| Syntax         | Description             |
| -------------- | ----------------------- |
| `-->`          | Solid arrow             |
| `-->\|label\|` | Solid arrow with label  |
| `---`          | Open line (no arrow)    |
| `-.->`         | Dotted arrow            |
| `==>`          | Thick arrow             |
| `~~~`          | Invisible (layout only) |
| `--x`          | Cross arrow             |
| `--o`          | Circle arrow            |
| `<-->`         | Bidirectional arrow     |

### Chains and Groups

```
graph LR
    %% Chain: connects A to B to C
    A --> B --> C

    %% Ampersand: connects X and Y to Z
    X & Y --> Z
```

### Subgraphs

```
graph TD
    subgraph id[Title]
        direction LR
        A --> B
    end
```

Subgraphs group nodes inside a bordered box with an optional title.
Nested subgraphs, cross-boundary edges, direction overrides, and
edges to/from subgraph IDs are supported.

### Comments

Lines starting with `%%` are treated as comments.

## JSON Output (MMDS)

mmdflux produces structured JSON using the MMDS (Machine-Mediated Diagram Specification) format, designed for machine consumption in LLM pipelines, adapter libraries, and agentic workflows.

```bash
# Layout level (default): node geometry + edge topology, no edge paths
mmdflux --format mmds diagram.mmd

# Routed level: includes edge paths, bounds, and routing metadata
mmdflux --format mmds --geometry-level routed diagram.mmd

# Reduce edge path detail (useful for token-conscious LLM consumers)
mmdflux --format mmds --geometry-level routed --path-detail simplified diagram.mmd
mmdflux --format mmds --geometry-level routed --path-detail endpoints diagram.mmd
```

The `--path-detail` option controls how many waypoints are emitted on edge paths:

| Value        | Waypoints kept                  |
| ------------ | ------------------------------- |
| `full`       | All routed waypoints (default)  |
| `simplified` | Start, midpoint, and end only   |
| `endpoints`  | Start and end only              |

This applies to both MMDS and SVG output. Text/ASCII output ignores this setting.

MMDS output is supported for flowchart and class diagrams (`--format json` remains an alias). The output includes a top-level `defaults` block and omits per-node/per-edge fields when they match those defaults. See [`docs/mmds.md`](docs/mmds.md) for the full specification and [`docs/mmds.schema.json`](docs/mmds.schema.json) for the JSON Schema. Adapter examples for React Flow, Cytoscape.js, and D3 are in [`examples/mmds/`](examples/mmds/).

For subgraph-as-endpoint parity, MMDS edges may include optional `from_subgraph` / `to_subgraph` intent metadata. Producers should emit these when available; consumers should tolerate payloads where they are absent and fall back to `source`/`target` node semantics.

MMDS input detection is wired in the registry path, and hydration enforces a strict-core/permissive-extensions validation contract (see [MMDS input validation contract](docs/mmds.md#mmds-input-validation-contract)).

Render support for MMDS input is geometry-level aware:
- `layout` payloads support `text`, `ascii`, `svg`, and `mmds/json`.
- `routed` (positioned) payloads support `svg` and `mmds/json`; `text`/`ascii` are intentionally rejected with guidance to use SVG.

MMDS governance fields are `profiles` and namespaced `extensions`. The initial profile vocabulary is `mmds-core-v1`, `mmdflux-svg-v1`, and `mmdflux-text-v1`. Canonical profile payload examples are:
- [`examples/mmds/profile-mmdflux-svg-v1.json`]examples/mmds/profile-mmdflux-svg-v1.json
- [`examples/mmds/profile-mmdflux-text-v1.json`]examples/mmds/profile-mmdflux-text-v1.json

See [`docs/mmds.md`](docs/mmds.md) for the full capability matrix and detailed accepted/rejected/tolerated MMDS input behavior.

### MMDS -> Mermaid Generation (Library)

For graph-family payloads, mmdflux can generate canonical Mermaid from MMDS:

```rust
use mmdflux::generate_mermaid_from_mmds_str;

let mmds_json = std::fs::read_to_string("diagram.mmds.json").unwrap();
let mermaid = generate_mermaid_from_mmds_str(&mmds_json).unwrap();
println!("{mermaid}");
```

Generation is deterministic (stable ordering, escaping policy, trailing newline) and intended for semantic roundtrip workflows. See [MMDS -> Mermaid generation contract](docs/mmds.md#mmds---mermaid-generation-contract) for the full policy and caveats.

### MMDS -> Mermaid Generation (CLI)

Convert MMDS JSON back to Mermaid syntax using `--format mermaid`:

```bash
# Convert MMDS file to Mermaid
mmdflux --format mermaid diagram.mmds.json

# Roundtrip: Mermaid -> MMDS -> Mermaid
mmdflux --format mmds diagram.mmd | mmdflux --format mermaid
```

This is useful for editing diagrams in MMDS-native tools, then exporting back to Mermaid for use with other renderers.

## Library Usage

```rust
use mmdflux::{parse_flowchart, build_diagram};

fn main() {
    let input = r#"graph LR
A[Hello] --> B[World]
"#;

    // Parse Mermaid syntax into AST
    let flowchart = parse_flowchart(input).unwrap();

    // Build graph structure
    let diagram = build_diagram(&flowchart);

    println!("Direction: {:?}", diagram.direction);
    println!("Nodes: {}", diagram.nodes.len());
    println!("Edges: {}", diagram.edges.len());

    // Access nodes by ID
    if let Some(node) = diagram.nodes.get("A") {
        println!("Node A: {} ({:?})", node.label, node.shape);
    }

    // Iterate edges
    for edge in &diagram.edges {
        println!("{} -> {}", edge.from, edge.to);
    }
}
```

### Types

```rust
use mmdflux::{Diagram, Direction, Node, Shape, Edge};
use mmdflux::graph::{Stroke, Arrow};

// Direction: TopDown, BottomTop, LeftRight, RightLeft
// Shape: Rectangle, Round, Stadium, Subroutine, Cylinder, Diamond, Hexagon, ...
// Stroke: Solid, Dotted, Thick, Invisible
// Arrow: Normal, None, Cross, Circle
```

## Roadmap

- [x] Flowchart parsing (`graph` / `flowchart`)
- [x] Text rendering (Unicode and ASCII, TD/BT/LR/RL layouts)
- [x] SVG rendering
- [x] Subgraph support (nesting, direction overrides, edges to subgraph IDs)
- [ ] Sequence diagrams
- [x] Class diagrams
- [ ] State diagrams
- [ ] Entity Relationship diagrams

## License

MIT