#![allow(clippy::too_many_arguments)]
#![allow(clippy::collapsible_else_if)]
mod d2_parser;
mod error;
mod grid;
mod layout;
mod parser;
mod pathfinding;
mod pie_parser;
mod renderer;
mod seq_parser;
mod state_parser;
mod text;
mod types;
pub use error::MermaidError;
pub use layout::{compute_layout, compute_layout_with_options};
pub use types::{
DiagramWarning, Direction, Edge, EdgeStyle, Graph, Node, NodeId, NodeShape, RenderOptions,
RenderResult, Subgraph, TableField,
};
use d2_parser::{parse_d2, D2ParseResult};
use parser::parse_mermaid;
use pie_parser::{parse_pie_chart as parse_pie, render_pie_chart as render_pie};
use renderer::render_graph;
use seq_parser::{parse_sequence_diagram as parse_seq, render_sequence_diagram as render_seq};
use state_parser::parse_state_diagram;
pub const SUPPORTED_LANGUAGES: &[&str] = &["mermaid", "d2"];
pub fn is_supported(lang: &str) -> bool {
let lower = lang.to_lowercase();
SUPPORTED_LANGUAGES.iter().any(|&l| l == lower)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DiagramFormat {
Mermaid,
StateDiagram,
SequenceDiagram,
PieChart,
D2,
}
pub fn detect_format(input: &str) -> DiagramFormat {
let trimmed = input.trim();
let lower = trimmed.to_lowercase();
if lower.starts_with("sequencediagram") {
return DiagramFormat::SequenceDiagram;
}
if lower.starts_with("statediagram") {
return DiagramFormat::StateDiagram;
}
if lower.starts_with("pie") {
return DiagramFormat::PieChart;
}
if trimmed.starts_with("flowchart")
|| trimmed.starts_with("graph ")
|| trimmed.contains("-->")
|| trimmed.contains("-.-")
|| trimmed.contains("==>")
{
return DiagramFormat::Mermaid;
}
DiagramFormat::D2
}
pub fn render(
lang: &str,
code: &str,
options: RenderOptions,
) -> Result<RenderResult, MermaidError> {
match lang.to_lowercase().as_str() {
"d2" => render_d2_to_tui(code, options),
_ => render_diagram(code, options),
}
}
pub fn check(lang: &str, code: &str) -> Result<Vec<DiagramWarning>, MermaidError> {
match lang.to_lowercase().as_str() {
"d2" => {
let D2ParseResult {
mut graph,
mut warnings,
} = parse_d2(code)?;
warnings.extend(compute_layout(&mut graph));
Ok(warnings)
}
_ => check_mermaid(code),
}
}
fn check_mermaid(code: &str) -> Result<Vec<DiagramWarning>, MermaidError> {
let format = detect_format(code);
match format {
DiagramFormat::D2 => {
let D2ParseResult {
mut graph,
mut warnings,
} = parse_d2(code)?;
warnings.extend(compute_layout(&mut graph));
Ok(warnings)
}
DiagramFormat::Mermaid => {
let mut graph = parse_mermaid(code)?;
Ok(compute_layout(&mut graph))
}
DiagramFormat::StateDiagram => {
let mut graph = parse_state_diagram(code)?;
Ok(compute_layout(&mut graph))
}
DiagramFormat::SequenceDiagram => {
parse_seq(code)?;
Ok(Vec::new())
}
DiagramFormat::PieChart => {
parse_pie(code)?;
Ok(Vec::new())
}
}
}
pub fn render_diagram(input: &str, options: RenderOptions) -> Result<RenderResult, MermaidError> {
match detect_format(input) {
DiagramFormat::Mermaid => render_mermaid_to_tui(input, options),
DiagramFormat::StateDiagram => render_state_diagram(input, options),
DiagramFormat::SequenceDiagram => render_sequence_diagram(input, options),
DiagramFormat::PieChart => render_pie_chart(input, options),
DiagramFormat::D2 => render_d2_to_tui(input, options),
}
}
pub fn render_mermaid_to_tui(
input: &str,
options: RenderOptions,
) -> Result<RenderResult, MermaidError> {
let mut graph = parse_mermaid(input)?;
let mut warnings = compute_layout_with_options(&mut graph, &options);
Ok(RenderResult {
output: render_graph(&graph, &options, &mut warnings),
warnings,
})
}
pub fn render_state_diagram(
input: &str,
options: RenderOptions,
) -> Result<RenderResult, MermaidError> {
let mut graph = parse_state_diagram(input)?;
let mut warnings = compute_layout_with_options(&mut graph, &options);
Ok(RenderResult {
output: render_graph(&graph, &options, &mut warnings),
warnings,
})
}
pub fn render_pie_chart(input: &str, options: RenderOptions) -> Result<RenderResult, MermaidError> {
let chart = parse_pie(input)?;
Ok(RenderResult {
output: render_pie(&chart, &options),
warnings: Vec::new(),
})
}
pub fn render_d2_to_tui(input: &str, options: RenderOptions) -> Result<RenderResult, MermaidError> {
let D2ParseResult {
mut graph,
mut warnings,
} = parse_d2(input)?;
warnings.extend(compute_layout_with_options(&mut graph, &options));
Ok(RenderResult {
output: render_graph(&graph, &options, &mut warnings),
warnings,
})
}
pub fn render_sequence_diagram(
input: &str,
options: RenderOptions,
) -> Result<RenderResult, MermaidError> {
let diagram = parse_seq(input)?;
Ok(RenderResult {
output: render_seq(&diagram, &options),
warnings: Vec::new(),
})
}