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
//! mmdflux — Mermaid diagrams to text, SVG, and MMDS
//!
//! mmdflux parses [Mermaid](https://mermaid.js.org/) diagram syntax and
//! renders it as Unicode/ASCII text, SVG, or structured JSON ([MMDS](https://mmds.dev/)).
//! Supported diagram types: **flowchart**, **class**, and **sequence**.
//!
//! # High-Level API
//!
//! Most consumers only need three functions and two config types:
//!
//! - [`render_diagram`] — detect, parse, and render in one call
//! - [`detect_diagram`] — detect the diagram type without rendering
//! - [`validate_diagram`] — parse and return structured JSON diagnostics
//! - [`OutputFormat`] — `Text`, `Ascii`, `Svg`, or `Mmds`
//! - [`RenderConfig`] — layout engine, routing, padding, color, and more
//!
//! ```
//! 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\""));
//! ```
//!
//! ## 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:
//!
//! - [`builtins::default_registry`] — the built-in diagram registry
//! - [`registry`] — [`DiagramRegistry`](registry::DiagramRegistry),
//! [`DiagramInstance`](registry::DiagramInstance), and
//! [`ParsedDiagram`](registry::ParsedDiagram) traits
//! - [`payload`] — the [`payload::Diagram`] enum returned by
//! [`ParsedDiagram::into_payload`](registry::ParsedDiagram::into_payload)
//! - [`graph`] — graph-family IR types ([`Graph`](graph::Graph),
//! [`Node`](graph::Node), [`Edge`](graph::Edge),
//! [`Shape`](graph::Shape), [`Direction`](graph::Direction))
//! - [`timeline`] — timeline-family types
//! ([`Sequence`](timeline::Sequence))
//! - [`mmds`] — MMDS parsing, hydration to [`graph::Graph`],
//! profile negotiation, and Mermaid regeneration
//!
//! ```no_run
//! 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](https://mmds.dev/) is a 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"));
//! ```
// Facade functions and config_input are re-exported below as public API.
pub
// Public re-exports from public modules (convenience aliases).
// Re-exports from public modules for convenience at crate root.
/// Algorithm identifier (e.g., `Layered`, `Mrtree`) used in engine selection.
pub use AlgorithmId;
/// Combined engine + algorithm identifier for explicit layout engine selection.
pub use EngineAlgorithmId;
/// Engine identifier (e.g., `Flux`, `Mermaid`, `Elk`).
pub use EngineId;
pub use RenderError;
/// Policy for resolving `--color auto` in CLI/WASM adapters.
pub use ColorWhen;
pub use OutputFormat;
/// Text output color mode (plain, styled, or ANSI).
pub use TextColorMode;
/// Layout configuration for the Sugiyama hierarchical engine.
pub use ;
pub use ;
/// Serde-friendly config input for JSON consumers (WASM, API).
pub use RuntimeConfigInput;
/// Apply default SVG surface settings (curve, engine) when format is SVG.
pub use apply_svg_surface_defaults;
/// Detect the diagram type from input text.
pub use detect_diagram;
/// Detect, parse, and render a diagram in one call.
pub use render_diagram;
/// Validate input and return structured JSON diagnostics.
pub use validate_diagram;
// Residual crate-local tests stay narrowly scoped to cross-pipeline coverage.