mermaid-compile
Syntax-check every ```mermaid block across markdown files. Runs
mmdc (the official Mermaid CLI) inside a transient podman
container — no local Node install, no global package pollution.
Prereqs
- Python ≥ 3.9
- Podman (rootless works fine)
- Network reachable to Docker Hub for the first
docker.io/minlag/mermaid-clipull
Install
git clone https://git.timemachine.center/Timemachine/mermaid-compile.git
cd mermaid-compile
chmod +x check-mermaid.py
Optionally symlink onto $PATH:
ln -s "$PWD/check-mermaid.py" ~/.local/bin/check-mermaid
Usage
# Walk current dir
./check-mermaid.py
# Specific path(s)
./check-mermaid.py docs/ README.md
# Skip the upfront podman pull (faster reruns)
./check-mermaid.py --no-pull docs/
# Override the image
./check-mermaid.py --image my-mirror.example.com/mermaid-cli:1.2.3 docs/
Exit code:
0— every block parsed1— at least one parse failure2— environment problem (no podman, etc.)
Suitable for make check-docs, pre-commit hooks, CI.
Output
✓ docs/architecture.md:4
✓ docs/architecture.md:111
✗ docs/auth-flow.md:6
1 of 3 block(s) FAILED:
=== docs/auth-flow.md:6 ===
Error: Parse error on line 3:
...D A --> B A -> C invalid edge
---------------------^
Expecting 'SEMI', 'NEWLINE', 'EOF', 'AMP', ..., got 'MINUS'
The reported line is the line of the offending statement within the
Mermaid block (1 = the first line after the opening ```mermaid).
The script prints the markdown file's line of the fence + 1 as the
block start, so jumping with Ctrl+G in most editors lands you on the
diagram body.
Why mmdc and not a pure parser?
Mermaid's grammar is implemented in JavaScript (Jison). The simplest trustworthy way to validate is to invoke the same renderer the docs viewer will use. mmdc renders to SVG (which forces a full parse + layout); we ignore the SVG and only consume the exit code.
docker.io/minlag/mermaid-cli packages Node + Puppeteer + Chromium
already, so no host-side runtime needed. ~250 MB pull, one-time.
Common parse errors and fixes
flowchart node labels
Wrap the label in "..." whenever the text contains any of [, ],
(, ), {, }, $, ". The parser treats those as
shape-delimiters mid-token.
| Wrong | Right |
|---|---|
Box[/portal · waker (waking)/] |
Box[/"portal · waker (waking)"/] |
Box[build []liteRoute] |
Box["build []liteRoute"] |
Box[Templates ${VAR}] |
Box["Templates ${VAR}"] |
Cond{state == "x"?} |
Cond{"state == 'x' ?"} |
sequence-diagram messages
Cannot contain ; — Mermaid reads Foo->>Bar: a; b as a partial
statement and misidentifies the next line. Replace with then or
,, or use the HTML entity #59;.
| Wrong | Right |
|---|---|
A->>A: mu.Lock(); set flag |
A->>A: mu.Lock then set flag |
A->>A: x=true; y=false |
A->>A: x=true, y=false |
License
MIT. See LICENSE.