dampen_cli/commands/check/
custom_widgets.rs

1use serde::{Deserialize, Serialize};
2use std::collections::{HashMap, HashSet};
3use std::fs;
4use std::path::Path;
5
6use super::errors::CheckError;
7
8/// Configuration for a custom widget's allowed attributes.
9#[derive(Debug, Clone, Serialize, Deserialize, Default)]
10pub struct CustomWidgetConfig {
11    #[serde(default)]
12    pub allowed_attributes: HashSet<String>,
13}
14
15/// Registry of custom widget configurations.
16#[derive(Debug, Clone, Default)]
17pub struct CustomWidgetRegistry {
18    widgets: HashMap<String, CustomWidgetConfig>,
19}
20
21impl CustomWidgetRegistry {
22    /// Creates a new empty registry.
23    pub fn new() -> Self {
24        Self {
25            widgets: HashMap::new(),
26        }
27    }
28
29    /// Loads a custom widget registry from a JSON file.
30    ///
31    /// # Arguments
32    ///
33    /// * `path` - Path to the JSON file containing widget configurations
34    ///
35    /// # Returns
36    ///
37    /// A `Result` containing the registry or a `CheckError` if loading fails.
38    ///
39    /// # Example JSON format
40    ///
41    /// ```json
42    /// {
43    ///   "CustomWidget": {
44    ///     "allowed_attributes": ["value", "mode", "format"]
45    ///   },
46    ///   "DataGrid": {
47    ///     "allowed_attributes": ["columns", "rows", "sortable"]
48    ///   }
49    /// }
50    /// ```
51    pub fn load_from_json(path: &Path) -> Result<Self, CheckError> {
52        let content = fs::read_to_string(path).map_err(|e| CheckError::Io(e))?;
53        let widgets: HashMap<String, CustomWidgetConfig> =
54            serde_json::from_str(&content).map_err(|e| {
55                CheckError::CustomWidgetConfigLoadError {
56                    path: path.to_path_buf(),
57                    source: e,
58                }
59            })?;
60
61        Ok(Self { widgets })
62    }
63
64    /// Checks if a widget is registered.
65    pub fn has_widget(&self, widget_name: &str) -> bool {
66        self.widgets.contains_key(widget_name)
67    }
68
69    /// Checks if an attribute is allowed for a custom widget.
70    ///
71    /// # Arguments
72    ///
73    /// * `widget_name` - Name of the custom widget
74    /// * `attribute` - Name of the attribute to check
75    ///
76    /// # Returns
77    ///
78    /// `true` if the attribute is allowed, `false` otherwise.
79    /// If the widget is not registered, returns `false`.
80    pub fn is_attribute_allowed(&self, widget_name: &str, attribute: &str) -> bool {
81        self.widgets
82            .get(widget_name)
83            .map(|config| config.allowed_attributes.contains(attribute))
84            .unwrap_or(false)
85    }
86
87    /// Gets all allowed attributes for a custom widget.
88    ///
89    /// # Arguments
90    ///
91    /// * `widget_name` - Name of the custom widget
92    ///
93    /// # Returns
94    ///
95    /// A vector of attribute names, or an empty vector if the widget is not registered.
96    pub fn get_allowed_attributes(&self, widget_name: &str) -> Vec<&str> {
97        self.widgets
98            .get(widget_name)
99            .map(|config| {
100                config
101                    .allowed_attributes
102                    .iter()
103                    .map(|s| s.as_str())
104                    .collect()
105            })
106            .unwrap_or_default()
107    }
108
109    /// Adds a custom widget configuration.
110    pub fn add_widget(&mut self, name: String, config: CustomWidgetConfig) {
111        self.widgets.insert(name, config);
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use super::*;
118
119    #[test]
120    fn test_empty_registry() {
121        let registry = CustomWidgetRegistry::new();
122        assert!(!registry.has_widget("CustomWidget"));
123        assert!(!registry.is_attribute_allowed("CustomWidget", "value"));
124    }
125
126    #[test]
127    fn test_add_widget() {
128        let mut registry = CustomWidgetRegistry::new();
129        let mut config = CustomWidgetConfig::default();
130        config.allowed_attributes.insert("value".to_string());
131        config.allowed_attributes.insert("mode".to_string());
132
133        registry.add_widget("CustomWidget".to_string(), config);
134
135        assert!(registry.has_widget("CustomWidget"));
136        assert!(registry.is_attribute_allowed("CustomWidget", "value"));
137        assert!(registry.is_attribute_allowed("CustomWidget", "mode"));
138        assert!(!registry.is_attribute_allowed("CustomWidget", "unknown"));
139    }
140
141    #[test]
142    fn test_get_allowed_attributes() {
143        let mut registry = CustomWidgetRegistry::new();
144        let mut config = CustomWidgetConfig::default();
145        config.allowed_attributes.insert("value".to_string());
146        config.allowed_attributes.insert("mode".to_string());
147
148        registry.add_widget("CustomWidget".to_string(), config);
149
150        let attrs = registry.get_allowed_attributes("CustomWidget");
151        assert_eq!(attrs.len(), 2);
152        assert!(attrs.contains(&"value"));
153        assert!(attrs.contains(&"mode"));
154    }
155
156    #[test]
157    fn test_get_allowed_attributes_unknown_widget() {
158        let registry = CustomWidgetRegistry::new();
159        let attrs = registry.get_allowed_attributes("UnknownWidget");
160        assert!(attrs.is_empty());
161    }
162}