kroki_rs/diagrams/
registry.rs

1use crate::browser::BrowserManager;
2use crate::capabilities::Capabilities;
3use crate::diagrams::{
4    providers::{
5        bpmn::BpmnProvider,
6        cmd::CommandProvider,
7        d2::D2Provider,
8        ditaa::DitaaProvider,
9        excalidraw::ExcalidrawProvider,
10        mermaid::MermaidProvider,
11        vega::{VegaLiteProvider, VegaProvider},
12        wavedrom::WavedromProvider,
13    },
14    DiagramProvider,
15};
16use std::collections::HashMap;
17use std::sync::Arc;
18
19pub struct DiagramRegistry {
20    providers: HashMap<String, Arc<dyn DiagramProvider + Send + Sync>>,
21}
22
23impl DiagramRegistry {
24    pub fn new(
25        capabilities: &Capabilities,
26        config: &crate::config::Config,
27        browser_manager: Option<Arc<BrowserManager>>,
28    ) -> Self {
29        let mut providers: HashMap<String, Arc<dyn DiagramProvider + Send + Sync>> = HashMap::new();
30
31        if let Some(path) = &capabilities.graphviz {
32            let provider = Arc::new(CommandProvider::new(
33                path.clone(),
34                config.graphviz.timeout_ms,
35            )) as Arc<dyn DiagramProvider + Send + Sync>;
36            providers.insert("graphviz".to_string(), provider.clone());
37            providers.insert("dot".to_string(), provider);
38        }
39
40        if let (Some(_), Some(browser)) = (&capabilities.mermaid, &browser_manager) {
41            let provider = Arc::new(MermaidProvider::new(
42                browser.clone(),
43                config.mermaid.timeout_ms,
44            )) as Arc<dyn DiagramProvider + Send + Sync>;
45            providers.insert("mermaid".to_string(), provider);
46        }
47
48        if let Some(path) = &capabilities.vega {
49            let provider = Arc::new(VegaProvider::new(path.clone(), config.vega.timeout_ms))
50                as Arc<dyn DiagramProvider + Send + Sync>;
51            providers.insert("vega".to_string(), provider);
52        }
53
54        if let Some(vl_path) = &capabilities.vegalite {
55            if let Some(vg_path) = &capabilities.vega {
56                let provider = Arc::new(VegaLiteProvider::new(
57                    vl_path.clone(),
58                    vg_path.clone(),
59                    config.vegalite.timeout_ms,
60                )) as Arc<dyn DiagramProvider + Send + Sync>;
61                providers.insert("vegalite".to_string(), provider);
62            }
63        }
64
65        if let Some(path) = &capabilities.wavedrom {
66            let provider = Arc::new(WavedromProvider::new(
67                path.clone(),
68                config.wavedrom.timeout_ms,
69            )) as Arc<dyn DiagramProvider + Send + Sync>;
70            providers.insert("wavedrom".to_string(), provider);
71        }
72
73        if let (Some(_), Some(browser)) = (&capabilities.bpmn, &browser_manager) {
74            let provider = Arc::new(BpmnProvider::new(browser.clone(), config.bpmn.timeout_ms))
75                as Arc<dyn DiagramProvider + Send + Sync>;
76            providers.insert("bpmn".to_string(), provider);
77        }
78
79        if let Some(path) = &capabilities.d2 {
80            let provider = Arc::new(D2Provider::new(path.clone(), config.d2.timeout_ms))
81                as Arc<dyn DiagramProvider + Send + Sync>;
82            providers.insert("d2".to_string(), provider);
83        }
84
85        if let Some(path) = &capabilities.ditaa {
86            let provider = Arc::new(DitaaProvider::new(path.clone(), config.ditaa.timeout_ms))
87                as Arc<dyn DiagramProvider + Send + Sync>;
88            providers.insert("ditaa".to_string(), provider);
89        }
90
91        if let Some(path) = &capabilities.excalidraw {
92            let provider = Arc::new(ExcalidrawProvider::new(
93                path.clone(),
94                config.excalidraw.timeout_ms,
95            )) as Arc<dyn DiagramProvider + Send + Sync>;
96            providers.insert("excalidraw".to_string(), provider);
97        }
98
99        // 2. Register custom plugins (TD-05 / ADR 0007)
100        for plugin_cfg in &config.plugins {
101            if providers.contains_key(&plugin_cfg.name) {
102                tracing::error!(
103                    "Plugin collision: '{}' already exists as a built-in provider. Skipping.",
104                    plugin_cfg.name
105                );
106                continue;
107            }
108
109            tracing::info!("Registering custom plugin: {}", plugin_cfg.name);
110            let provider = Arc::new(crate::diagrams::providers::plugin::PluginProvider::new(
111                plugin_cfg,
112            )) as Arc<dyn DiagramProvider + Send + Sync>;
113            providers.insert(plugin_cfg.name.clone(), provider);
114        }
115
116        Self { providers }
117    }
118
119    /// Returns the provider for a given diagram type, if available.
120    pub fn get(&self, name: &str) -> Option<Arc<dyn DiagramProvider + Send + Sync>> {
121        self.providers.get(name).cloned()
122    }
123
124    /// Returns the list of all registered diagram type names.
125    pub fn known_types(&self) -> Vec<String> {
126        let mut types: Vec<String> = self.providers.keys().cloned().collect();
127        types.sort();
128        types
129    }
130}