use super::{edge::DiagramEdge, node::DiagramNode};
pub struct MermaidParser;
impl MermaidParser {
pub fn parse_node_def(s: &str) -> (String, Option<String>) {
let s = s.trim();
if let Some(bracket_start) = s.find('[') {
if let Some(bracket_end) = s.find(']') {
let id = s[..bracket_start].trim().to_string();
let label = s[bracket_start + 1..bracket_end].to_string();
return (id, Some(label));
}
}
if let Some(brace_start) = s.find('{') {
if let Some(brace_end) = s.find('}') {
let id = s[..brace_start].trim().to_string();
let label = s[brace_start + 1..brace_end].to_string();
return (id, Some(label));
}
}
if let Some(paren_start) = s.find('(') {
if let Some(paren_end) = s.rfind(')') {
let id = s[..paren_start].trim().to_string();
let label = s[paren_start + 1..paren_end].to_string();
return (id, Some(label));
}
}
(s.to_string(), None)
}
}
pub trait ParseMermaid {
fn parse(self, source: &str) -> Self;
}
impl ParseMermaid for super::Diagram {
fn parse(mut self, source: &str) -> Self {
use std::collections::HashMap;
for line in source.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with("%%") {
continue;
}
if let Some((left, right)) = line.split_once("-->") {
let from = left.trim();
let (label, to) = if right.contains('|') {
let parts: Vec<&str> = right.split('|').collect();
if parts.len() >= 3 {
(Some(parts[1].to_string()), parts[2].trim())
} else {
(None, right.trim())
}
} else {
(None, right.trim())
};
let (from_id, from_label) = MermaidParser::parse_node_def(from);
let (to_id, to_label) = MermaidParser::parse_node_def(to);
if !self.nodes.iter().any(|n| n.id == from_id) {
self.nodes.push(DiagramNode::new(
&from_id,
from_label.unwrap_or_else(|| from_id.clone()),
));
}
if !self.nodes.iter().any(|n| n.id == to_id) {
self.nodes.push(DiagramNode::new(
&to_id,
to_label.unwrap_or_else(|| to_id.clone()),
));
}
let mut edge = DiagramEdge::new(from_id, to_id);
if let Some(l) = label {
edge = edge.label(l);
}
self.edges.push(edge);
}
}
self
}
}