How the Mermaid Import Parser Handles Grammar Types and Markdown Blocks
The Mermaid import parser in cathrynlavery/diagram-design detects file formats via extension, extracts fenced code blocks from Markdown, normalizes content by removing front-matter and directives, detects grammar types through lexical scanning, and routes each diagram to specialized parsers that produce a sanitized intermediate representation.
The parser is implemented in skills/diagram-design/scripts/mermaid_extract.py and serves as the entry point for converting Mermaid diagrams into a layout-agnostic intermediate representation (IR). It handles both standalone .mmd files and Markdown documents containing fenced Mermaid blocks, applying strict normalization before dispatching to grammar-specific parsers.
Detecting Source Formats and Markdown Blocks
The parser distinguishes between standalone Mermaid files and Markdown containers through extension-based detection in load_blocks() (source lines 221‑252).
Standalone Files vs. Markdown Containers
The parser accepts three input categories:
- Standalone Mermaid files: Extensions
.mmdor.mermaidtrigger single-block mode where the entire file content becomes oneSourceBlock(defined at lines 80‑84). - Markdown files: Extensions
.md,.markdown,.mkd, or.mdowntrigger line-by-line scanning for fenced blocks.
Fence Extraction Logic
For Markdown inputs, the parser applies a regular expression defined at lines 35‑42 to detect fences starting with ```mermaid or ~~~mermaid. Each matched region becomes a distinct SourceBlock with incremental indexing, allowing selective processing via the --diagram CLI flag.
Normalizing Content and Removing Artifacts
Before grammar detection, raw blocks undergo sanitation through _prepared_lines() (source lines 274‑301).
Pre-processing Pipeline
This function returns a list of (source_line, line_text) tuples after stripping:
- Front-matter: YAML blocks wrapped in
---that Mermaid treats as configuration directives. - Mermaid directives: Syntax like
%%{…}%%used for runtime configuration. - Comments: Lines starting with
%%followed by arbitrary text.
This normalization ensures that grammar detection operates on semantic content rather than metadata or styling instructions.
Grammar Type Detection and Routing
The parser identifies diagram types through lexical analysis in _kind_and_direction() (source lines 306‑322).
Supported Grammar Types
The scanner examines the first non-empty line of prepared content to classify the diagram:
flowchartorgraph: Kind is set to"flowchart"with direction extraction (TD,TB,LR,RL,BT).sequenceDiagram: Kind is"sequenceDiagram"with default left-to-right direction.stateDiagram-v2: Kind is"stateDiagram-v2"with default top-down direction.erDiagram: Kind is"erDiagram"with default top-down direction.
Unsupported Grammar Handling
If the detected token belongs to UNSUPPORTED_KINDS (including pie, mindmap, and other syntactically incompatible types), the parser aborts with a clear error message (source lines 37‑44).
Grammar-Specific Parsing Strategies
After type detection, parse_block() (source lines 447‑459) instantiates a Diagram object and dispatches to specialized parsers that populate Diagram.nodes, Diagram.edges, and ancillary structures.
Flowchart Parsing
_parse_flowchart() (source lines 672‑735) handles:
- Node definitions with shape classification
- Subgraph declarations
- Edge connections with style attributes
- Direction statements
- Discarded style directives (tracked but removed from IR)
Sequence Diagram Parsing
_parse_sequence() (source lines 742‑808) processes:
- Participant declarations
- Fragment blocks (
alt,opt,loop,par) - Note placements
- Message edges with activation indicators
State Diagram Parsing
_parse_state() (source lines 813‑855) extracts:
- Simple state nodes
- Composite state hierarchies
- Direction hints within state blocks
- Transition edges with event triggers
ER Diagram Parsing
_parse_er() (source lines 894‑943) parses:
- Entity declarations with field lists
- Relationship edges respecting cardinality syntax (
||--o{, etc.) - Attribute type annotations
Security Sanitization and Trust Boundaries
The parser enforces a strict trust boundary across all grammar types to prevent injection of non-semantic content.
Label Sanitization
clean_label() (source lines 87‑103) strips:
- Markdown styling syntax (italics, bold)
- HTML entities and tags
- Class attachments (
:::classsuffixes)
Non-Semantic Directive Removal
_discard_nonsemantic() (source lines 560‑668) counts and removes:
- Click handlers and JavaScript callbacks
- Style directives that affect rendering but not structure
- CSS class assignments
Command-Line Usage and Output Formats
The parser exposes three primary workflows via CLI:
Processing Standalone Mermaid Files
python3 skills/diagram-design/scripts/mermaid_extract.py \
examples/sample-flowchart.mmd \
--json
Extracting from Markdown with Multiple Diagrams
python3 skills/diagram-design/scripts/mermaid_extract.py \
docs/README.md \
--diagram all \
--max-rows 20
Generating Human-Readable Digests
python3 skills/diagram-design/scripts/mermaid_extract.py \
docs/README.md
The --diagram parameter accepts an integer index (for specific blocks) or all (for batch processing). Output formats include:
- JSON: Machine-readable IR via
to_json() - Markdown digest: Human summary via
digest()showing node counts, directions, and cycle detection
Summary
- The Mermaid import parser resides in
skills/diagram-design/scripts/mermaid_extract.pyand processes both.mmdfiles and Markdown documents. - Format detection occurs in
load_blocks(), using file extensions to determine whether to treat content as a single block or scan for fenced regions. - Content normalization via
_prepared_lines()removes front-matter, directives, and comments before grammar analysis. - Grammar detection in
_kind_and_direction()supportsflowchart,sequenceDiagram,stateDiagram-v2, anderDiagram, explicitly rejecting unsupported types likepieormindmap. - Specialized parsers handle each grammar type's unique syntax, building a normalized IR with sanitized labels and discard tracking.
- Security measures include
clean_label()for content scrubbing and_discard_nonsemantic()for removing executable directives.
Frequently Asked Questions
How does the parser distinguish between Markdown and standalone Mermaid files?
The parser examines file extensions in load_blocks(). Files ending in .mmd or .mermaid are treated as single raw blocks, while .md, .markdown, .mkd, or .mdown extensions trigger fenced-code-block scanning using regex patterns matching ```mermaid or ~~~mermaid delimiters.
What happens to unsupported diagram types like pie charts or mindmaps?
When _kind_and_direction() encounters a token listed in UNSUPPORTED_KINDS (such as pie or mindmap), the parser immediately aborts with a descriptive error. This prevents partial parsing of grammars that lack specialized handlers in the current implementation.
Can the parser handle multiple Mermaid diagrams in a single Markdown file?
Yes. The load_blocks() function extracts each fenced Mermaid region into separate SourceBlock instances with incremental indices. Users can process specific diagrams using --diagram N (where N is the block index) or process all diagrams using --diagram all.
How does the parser ensure extracted content is safe for further processing?
The parser applies clean_label() to strip Markdown formatting, HTML entities, and CSS class attachments from all labels. Additionally, _discard_nonsemantic() counts and removes click handlers, style directives, and other presentation-layer metadata that could execute code or affect layout calculations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →