# How Importing Diagrams from Mermaid Syntax Works in Diagram-Design: The 7-Stage Pipeline

> Discover how diagram-design imports Mermaid syntax through a 7-stage pipeline. Learn how it validates, extracts, normalizes, and renders diagrams without JavaScript execution.

- Repository: [Cathryn Lavery/diagram-design](https://github.com/cathrynlavery/diagram-design)
- Tags: how-to-guide
- Published: 2026-08-19

---

**Importing diagrams from Mermaid syntax in diagram-design is a deterministic, seven-stage pipeline that validates input, extracts fenced blocks via [`mermaid_extract.py`](https://github.com/cathrynlavery/diagram-design/blob/main/mermaid_extract.py), normalizes nodes and edges into a safe intermediate representation, and renders editorial templates without executing JavaScript or preserving the original Mermaid layout.**

The `cathrynlavery/diagram-design` repository provides a deterministic toolchain for converting Mermaid source files into editorial-quality diagrams, as advertised in [`skills/diagram-design/SKILL.md`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/SKILL.md). Importing diagrams from Mermaid syntax relies on a custom parser—[`skills/diagram-design/scripts/mermaid_extract.py`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/scripts/mermaid_extract.py)—rather than the official Mermaid renderer, ensuring that every diagram is sanitized, normalized, and rebuilt from scratch.

## Stage 1: Locate and Validate Input

The process begins with the `import-mermaid` command defined in [`commands/import-mermaid.md`](https://github.com/cathrynlavery/diagram-design/blob/main/commands/import-mermaid.md). It verifies that the supplied file exists and carries a supported suffix: `.mmd`, `.mermaid`, or a Markdown file containing fenced `mermaid` blocks. If multiple Mermaid blocks exist and the user omits the `--diagram` flag, the command lists available blocks and prompts for a selection.

## Stage 2: Extract Blocks via [`mermaid_extract.py`](https://github.com/cathrynlavery/diagram-design/blob/main/mermaid_extract.py)

The command invokes the core extractor script, **[`mermaid_extract.py`](https://github.com/cathrynlavery/diagram-design/blob/main/mermaid_extract.py)** ([`skills/diagram-design/scripts/mermaid_extract.py`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/scripts/mermaid_extract.py)), as a subprocess. As shown in [`scripts/verify-mermaid-import.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/verify-mermaid-import.py), the extractor reads the file, pulls out fenced `mermaid` blocks, or treats the entire file as a single block for pure `.mmd`/`.mermaid` sources. This script forms the primary trust boundary: it never evaluates JavaScript, follows URLs, or renders the original layout.

## Stage 3: Parse and Normalize the Grammar

Inside [`mermaid_extract.py`](https://github.com/cathrynlavery/diagram-design/blob/main/mermaid_extract.py), the raw text is tokenized and converted into a **`Diagram`** object. The parser respects the four grammars listed in **`SUPPORTED_KINDS`** (flowchart, sequenceDiagram, stateDiagram-v2, erDiagram). During this phase the extractor:

- Strips front-matter and Mermaid directives (`%%{…}%%`).
- Normalizes node shapes using **`classify_shape()`**, which consults the **`SHAPE_FOR_DELIMITERS`** table to map delimiter pairs to canonical shapes.
- Normalizes edge operators, arrowheads, and styles through **`_operator_style()`**.
- Sanitizes labels with **`clean_label()`**, treating all content as inert plain text.
- Discards non-semantic directives such as style overrides and click handlers, incrementing `diagram.discarded` for auditing.

## Stage 4: Build the Intermediate Representation (IR)

After parsing, the extractor constructs an intermediate representation consisting of:

- **Nodes** — a `Node` dataclass carrying id, label, shape, parent, depth, and related metadata.
- **Edges** — an `Edge` dataclass with source, target, label, style, arrowhead, and bidirectional or undirected flags.
- **Metadata** — fragments, notes, and discarded counts.

The **`analyze()`** function then aggregates statistics such as cycle detection, hub-node identification, and budget warnings. These metrics drive later rendering decisions in the pipeline.

## Stage 5: Emit JSON or Markdown Digest

The user controls output serialization through flags. If **`--json`** is passed, the tool serializes the full IR via **`to_json()`**. Otherwise, it produces a human-readable Markdown digest via **`digest()`**, which surfaces diagram metadata, node and edge tables, and any budget warnings. This digest acts as the bridge between extraction and rendering.

## Stage 6: Select an Editorial Rendering Template

The `import-mermaid` command consumes the digest (or JSON) and selects one of the editorial templates stored in `skills/diagram-design/assets/`. The available templates include **[`template-light.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-light.html)**, **[`template-dark.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-dark.html)**, and **[`template-full.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-full.html)**. Each template implements the “four dials” described in [`references/import-mermaid.md`](https://github.com/cathrynlavery/diagram-design/blob/main/references/import-mermaid.md) and [`references/output-spec.md`](https://github.com/cathrynlavery/diagram-design/blob/main/references/output-spec.md): format, size, detail, and audience.

## Stage 7: Render and Deliver the Final Asset

The selected template is populated with the normalized node and edge data. Rendering is **layout-free**—the original Mermaid layout is intentionally ignored—and produces the requested output format: `html`, `svg`, `png`, or `html+png`. The result is written to the path specified by **`--output`**, and the command prints a summary of the four dials alongside a “fidelity ledger” documenting what was merged, collapsed, or dropped during import.

## Security Controls and Resource Limits

Because Mermaid source is treated as untrusted, the extractor enforces strict hard caps to prevent denial-of-service:

- **`MAX_SOURCE_BYTES`** — 4 MiB maximum source size.
- **`MAX_NODES`** — 2,000 nodes per diagram.
- **`MAX_EDGES`** — 5,000 edges per diagram.

Violations trigger a controlled exit with code 2. Additionally, image URLs and click handlers are never fetched or executed; they are stripped and counted only in `diagram.discarded`.

## Extending the Parser for New Diagram Types

Adding support for a new Mermaid grammar requires only two changes in [`mermaid_extract.py`](https://github.com/cathrynlavery/diagram-design/blob/main/mermaid_extract.py):

1. Append the grammar name to **`SUPPORTED_KINDS`**.
2. Implement a corresponding **`_parse_<kind>()`** function that returns normalized nodes and edges.

This modular design keeps the import pipeline maintainable as the Mermaid ecosystem evolves.

## Automated Pipeline Verification

The repository includes [`scripts/verify-mermaid-import.py`](https://github.com/cathrynlavery/diagram-design/blob/main/scripts/verify-mermaid-import.py) to guarantee correctness. This script runs an extensive suite that validates extraction logic, shape and edge vocabularies, front-matter handling, error paths, and documentation wiring. It also verifies the exact subprocess call used to invoke [`mermaid_extract.py`](https://github.com/cathrynlavery/diagram-design/blob/main/mermaid_extract.py), ensuring the command layer and parser remain synchronized.

## Practical Import Examples

Import a simple flowchart and capture the JSON IR:

```bash

# 1️⃣ Import a simple flowchart and get a JSON IR

$ diagram-design import-mermaid path/to/flowchart.mmd --json > flow.json

```

Import a Markdown file containing multiple Mermaid blocks, selecting the second block and exporting as SVG:

```bash

# 2️⃣ Import a Markdown file with multiple Mermaid blocks, choosing block 2

$ diagram-design import-mermaid docs/readme.md --diagram 2 --format svg --size doc-wide

```

Programmatically invoke the extractor from Python:

```python
>>> from pathlib import Path
>>> import json, subprocess, sys
>>> def extract(file):
...     proc = subprocess.run([sys.executable,
...                           "skills/diagram-design/scripts/mermaid_extract.py",
...                           str(file), "--json"], capture_output=True, text=True)
...     return json.loads(proc.stdout)
>>> ir = extract(Path("sample.mmd"))
>>> ir["diagrams"][0]["analysis"]["has_cycle"]
False

```

## Summary

- Importing diagrams from Mermaid syntax in diagram-design follows a strict seven-stage pipeline from file validation to final render.
- The core parser, [`skills/diagram-design/scripts/mermaid_extract.py`](https://github.com/cathrynlavery/diagram-design/blob/main/skills/diagram-design/scripts/mermaid_extract.py), tokenizes input into a safe `Diagram` object without executing JavaScript.
- Normalization functions such as `classify_shape()`, `_operator_style()`, and `clean_label()` standardize nodes, edges, and labels before IR construction.
- Hard resource limits (`MAX_SOURCE_BYTES`, `MAX_NODES`, `MAX_EDGES`) protect the pipeline from malformed or malicious input.
- Output is produced through editorial templates ([`template-light.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-light.html), [`template-dark.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-dark.html), [`template-full.html`](https://github.com/cathrynlavery/diagram-design/blob/main/template-full.html)) that ignore the original Mermaid layout.
- Extensibility is built in: new grammars require only an entry in `SUPPORTED_KINDS` and a matching `_parse_<kind>()` implementation.

## Frequently Asked Questions

### What file formats does the diagram-design importer accept?

The `import-mermaid` command accepts files ending in `.mmd`, `.mermaid`, or standard Markdown documents that contain fenced `mermaid` code blocks. If a Markdown file holds multiple blocks and you omit the `--diagram` flag, the tool lists the blocks and asks you to choose one.

### Does the importer preserve the original Mermaid layout?

No. According to the diagram-design source code, the pipeline is intentionally **layout-free**; it discards the original Mermaid positioning and rebuilds the diagram using normalized node and edge data inserted into editorial templates.

### How does the tool handle potentially malicious Mermaid input?

The extractor runs inside a strict trust boundary. It never evaluates JavaScript, follows URLs, or renders the original Mermaid layout. Labels are sanitized through `clean_label()` and treated as inert plain text. Hard caps on source size (`MAX_SOURCE_BYTES` = 4 MiB), node count (`MAX_NODES` = 2000), and edge count (`MAX_EDGES` = 5000) prevent denial-of-service, with violations returning exit code 2.

### Can I add support for additional Mermaid diagram types?

Yes. As implemented in cathrynlavery/diagram-design, you only need to add the grammar name to `SUPPORTED_KINDS` and implement a corresponding `_parse_<kind>()` function inside [`mermaid_extract.py`](https://github.com/cathrynlavery/diagram-design/blob/main/mermaid_extract.py). The existing pipeline will automatically route matching diagrams through your new parser.