Skip to main content

Crate mmdflux

Crate mmdflux 

Source
Expand description

mmdflux — Mermaid diagrams to text, SVG, and MMDS

mmdflux parses Mermaid diagram syntax and renders it as Unicode/ASCII text, SVG, or structured JSON (MMDS). Supported diagram types: flowchart, class, state, and sequence.

§High-Level API

Most consumers only need the facade functions and two config types:

Use render_diagram when you have text input. It auto-detects Mermaid source vs MMDS JSON because both represent the same abstract diagram. Use materialize_diagram when you want the typed mmds::Document, and use render_document when you already have one, such as after views::project. For document-level workflows, use commands::apply to mutate a document, mmds::diff::diff_documents to compare two snapshots, and views::project to produce a read-side view.

use mmdflux::{OutputFormat, RenderConfig, render_diagram};

let input = "graph TD\n    A[Collect] --> B[Render]";

// Render as Unicode text
let text = render_diagram(input, OutputFormat::Text, &RenderConfig::default()).unwrap();
println!("{text}");

// Render as SVG
let svg = render_diagram(input, OutputFormat::Svg, &RenderConfig::default()).unwrap();
assert!(svg.contains("<svg"));

// Render as MMDS JSON (structured interchange format)
let json = render_diagram(input, OutputFormat::Mmds, &RenderConfig::default()).unwrap();
assert!(json.contains("\"diagram_type\""));

// MMDS JSON is also accepted as text input.
let replayed = render_diagram(&json, OutputFormat::Text, &RenderConfig::default()).unwrap();
assert!(!replayed.trim().is_empty());

§Customizing output

Use RenderConfig to control layout direction, engine selection, edge routing, padding, color mode, and more:

use mmdflux::{OutputFormat, RenderConfig, render_diagram};
use mmdflux::LayoutConfig;
use mmdflux::format::RoutingStyle;

let config = RenderConfig {
    routing_style: Some(RoutingStyle::Direct),
    padding: Some(2),
    layout: LayoutConfig {
        rank_sep: 30.0,
        ..LayoutConfig::default()
    },
    ..RenderConfig::default()
};

let output = render_diagram("graph LR\n    A-->B-->C", OutputFormat::Text, &config).unwrap();
println!("{output}");

§Validation

validate_diagram returns structured JSON diagnostics suitable for editor integrations and CI pipelines:

use mmdflux::validate_diagram;

let result = validate_diagram("graph TD\n    A-->B");
let json: serde_json::Value = serde_json::from_str(&result).unwrap();
assert_eq!(json["valid"], true);

§Low-Level API

For adapters, tooling, or workflows that need explicit control over the detect → parse → payload → render pipeline, the low-level API provides:

use mmdflux::builtins::default_registry;
use mmdflux::payload::Diagram;

let input = "graph TD\n    A[Draft] --> B[Published]";
let registry = default_registry();

// Detect diagram type
let resolved = registry.resolve(input).expect("should detect diagram type");
println!("detected: {} ({:?})", resolved.diagram_id(), resolved.family());

// Parse and build payload
let instance = registry.create(resolved.diagram_id()).unwrap();
let payload = instance
    .parse(input).unwrap()
    .into_payload().unwrap();

// Inspect the payload
match payload {
    Diagram::Flowchart(graph) => {
        println!("flowchart with {} nodes", graph.nodes.len());
    }
    Diagram::Class(graph) => {
        println!("class diagram with {} nodes", graph.nodes.len());
    }
    Diagram::State(graph) => {
        println!("state diagram with {} nodes", graph.nodes.len());
    }
    Diagram::Sequence(seq) => {
        println!("sequence with {} participants", seq.participants.len());
    }
}

§MMDS interchange

MMDS is mmdflux’s structured JSON format for diagram geometry. Use the mmds module to parse MMDS input, hydrate it to a graph::Graph, or regenerate Mermaid source. To render MMDS input to text/SVG, pass it to render_diagram which auto-detects MMDS:

use mmdflux::mmds::{from_str, generate_mermaid_from_str};

let mmds_json = r#"{
  "version": 1,
  "profiles": ["mmds-core-v1"],
  "defaults": {
    "node": { "shape": "rectangle" },
    "edge": { "stroke": "solid", "arrow_start": "none", "arrow_end": "normal", "minlen": 1 }
  },
  "geometry_level": "layout",
  "metadata": {
    "diagram_type": "flowchart",
    "direction": "TD",
    "bounds": { "width": 100.0, "height": 80.0 }
  },
  "nodes": [
    { "id": "A", "label": "Start", "position": { "x": 50.0, "y": 20.0 },
      "size": { "width": 50.0, "height": 20.0 } },
    { "id": "B", "label": "End", "position": { "x": 50.0, "y": 60.0 },
      "size": { "width": 50.0, "height": 20.0 } }
  ],
  "edges": [{ "id": "e0", "source": "A", "target": "B" }]
}"#;

// Hydrate to graph IR
let graph = from_str(mmds_json).unwrap();
assert_eq!(graph.nodes.len(), 2);

// Regenerate Mermaid source
let mermaid = generate_mermaid_from_str(mmds_json).unwrap();
assert!(mermaid.contains("flowchart TD"));

§Commands and Model Events

Public MMDS commands mutate a document and emit model events that describe the accepted state transition:

use mmdflux::commands::{Command, apply};
use mmdflux::graph::Shape;
use mmdflux::mmds::Subject;
use mmdflux::mmds::events::ModelEventKind;
use mmdflux::{RenderConfig, materialize_diagram};

let mut document = materialize_diagram(
    "graph TD\n    A[Gateway] --> B[Billing]",
    &RenderConfig::default(),
)?;

let model_events = apply(
    &Command::AddNode {
        id: "C".to_string(),
        label: "Auth".to_string(),
        shape: Shape::Rectangle,
        parent: None,
    },
    &mut document,
)?;

assert!(model_events.iter().any(|event| {
    event.kind == ModelEventKind::NodeAdded
        && matches!(&event.subject, Subject::Node(id) if id == "C")
}));
assert!(document.nodes.iter().any(|node| node.id == "C"));

§Snapshot Diffs

mmds::diff::diff_documents compares two document states and reports a snapshot diff. Diff changes describe what is different between snapshots; they do not describe edit intent or command history:

use mmdflux::mmds::Subject;
use mmdflux::mmds::diff::{ChangeKind, diff_documents};
use mmdflux::{RenderConfig, materialize_diagram};

let before = materialize_diagram(
    "graph TD\n    A[Gateway] --> B[Billing]",
    &RenderConfig::default(),
)?;
let after = materialize_diagram(
    "graph TD\n    A[Gateway] --> B[Billing]\n    A --> C[Auth]",
    &RenderConfig::default(),
)?;

let diff = diff_documents(&before, &after);
assert!(diff.changes.iter().any(|change| {
    change.kind == ChangeKind::NodeAdded
        && matches!(&change.subject, Subject::Node(id) if id == "C")
}));

§Views

Use views when an adapter needs a focused read model over a canonical MMDS payload. V1 views preserve shared coordinates, keep surviving edge IDs sparse and stable, and return views::ViewEvent values for omitted elements:

use mmdflux::mmds::Document;
use mmdflux::views::{
    AnchorRef, Selector, TraversalDirection, ViewSpec, ViewStatement, project,
};
use mmdflux::{OutputFormat, RenderConfig, materialize_diagram, render_document};

let source = "\
graph TD
A[Gateway] --> B[Auth]
B --> C[Database]
A --> D[Audit]
";
let canonical: Document = materialize_diagram(source, &RenderConfig::default()).unwrap();
let spec = ViewSpec::new(vec![ViewStatement::Include(Selector::Traversal {
        anchor: AnchorRef::Node("A".to_string()),
        direction: TraversalDirection::Downstream,
        hops: 1,
    })]);

let (view, events) = project(&canonical, &spec).unwrap();
let text = render_document(&view, OutputFormat::Text, &RenderConfig::default()).unwrap();
assert!(text.contains("Gateway"));
assert_eq!(view.nodes.len(), 3);
assert!(events.iter().any(|event| matches!(
    event,
    mmdflux::views::ViewEvent::NodeLeftView { id, .. } if id == "C"
)));

§Stability

The commands, mmds::events, mmds::diff, and views modules are early surfaces. The following kinds of changes will land in minor versions and are not considered breaking under this crate’s SemVer policy:

  • new variants on the early-surface enums marked #[non_exhaustive] (including commands::Command, commands::EdgeSelector, commands::CommandApplyError, mmds::events::ModelEventKind, mmds::diff::ChangeKind, mmds::Subject, views::ViewStatement, views::Selector, views::ViewEvent, views::ViewError, and the supporting view vocabulary)
  • new fields on early-surface structs marked #[non_exhaustive] (including mmds::events::ModelEvent, mmds::diff::Change, mmds::diff::Diff, mmds::MmdsTokenError, and views::ViewSpec)

What is not covered:

  • Renaming, removing, or changing the meaning of an existing variant or field remains a breaking change.
  • Adding fields to existing struct-like enum variants (for example, Command::AddNode { ... }) is still breaking; individual variants are not currently marked #[non_exhaustive].
  • The runtime facade (render_diagram, materialize_diagram, render_document, detect_diagram, validate_diagram, OutputFormat, RenderConfig, RenderError) follows standard SemVer.
  • views::TraversalDirection is intentionally exhaustive because its vocabulary is closed.

Re-exports§

pub use errors::RenderError;
pub use format::ColorWhen;
pub use format::OutputFormat;
pub use format::TextColorMode;

Modules§

builtins
Built-in diagram registry assembly.
commands
Command vocabulary and synchronous MMDS command application.
errors
Error and diagnostic types for rendering and validation.
format
Output format, curve, edge preset, and routing style definitions.
graph
Shared graph-family core.
mmds
MMDS interchange contract and document-generation namespace.
payload
Runtime payload contract returned by crate::registry::ParsedDiagram::into_payload.
registry
Diagram registry for type detection and dispatch.
simplification
Post-routing path simplification levels for MMDS and SVG output.
timeline
Timeline-family runtime namespaces.
views
Materialized diagram views over canonical MMDS payloads.

Structs§

EngineAlgorithmId
Combined engine + algorithm identifier for explicit layout engine selection. Combined engine+algorithm identifier for explicit layout engine selection.
GraphTextStyleConfig
Graph-family text style requested through public render config.
LayoutConfig
Layout configuration for the Sugiyama hierarchical engine. Canonical caller-facing graph layout configuration.
RenderConfig
Configuration for rendering.
RuntimeConfigInput
Serde-friendly config input for JSON consumers (Wasm, API). Serde-friendly render config accepted from JSON callers.
SubgraphTitleMargin
Layout configuration for the Sugiyama hierarchical engine. Rank-axis margin reserved around a subgraph’s title text, mirroring Mermaid’s flowchart.subGraphTitleMargin: { top, bottom } knob.
SvgThemeConfig
SVG theme configuration owned by the runtime facade.

Enums§

AlgorithmId
Algorithm identifier (e.g., Layered, Mrtree) used in engine selection. Algorithm identifier used in the combined engine+algorithm taxonomy.
EngineId
Engine identifier (e.g., Flux, Mermaid, Elk). Engine family identifier used in the combined engine+algorithm taxonomy.
LabelDummyPlacement
Layout configuration for the Sugiyama hierarchical engine. Placement strategy for edge-label dummies within long edge chains. Orthogonal to LabelDummyRouting: placement decides where the label dummy sits in the chain, while routing decides how the edge traverses it.
LabelDummyRouting
Layout configuration for the Sugiyama hierarchical engine. Routing strategy for how an edge path traverses its label dummy’s rect. Orthogonal to LabelDummyPlacement.
LayoutDirection
Layout configuration for the Sugiyama hierarchical engine. Direction for the public graph-layout config.
Ranker
Layout configuration for the Sugiyama hierarchical engine. Ranking algorithm selection for the public graph-layout config.
SvgThemeMode
SVG theme rendering mode.

Functions§

apply_svg_surface_defaults
Apply default SVG surface settings (curve, engine) when format is SVG. Apply SVG surface defaults for flux-layered engine.
detect_diagram
Detect the diagram type from input text. Detect the diagram type from input text.
materialize_diagram
Detect, parse, solve, and materialize Mermaid source or MMDS JSON as MMDS. Detect, parse, solve, and materialize graph-family text input as MMDS.
render_diagram
Detect, parse, and render Mermaid source or MMDS JSON in one call. Detect, parse, and render a diagram from text input in one call.
render_document
Render a parsed graph-family MMDS document. Render a parsed graph-family MMDS document.
validate_diagram
Validate input and return structured JSON diagnostics. Validate Mermaid input and return structured diagnostics as JSON.