Skip to main content

secrets_core/
spec_registry.rs

1use crate::SecretSpec;
2use serde_json::json;
3use std::collections::BTreeMap;
4
5/// Registry that merges secrets declared by multiple components.
6#[derive(Default)]
7pub struct SecretSpecRegistry {
8    by_name: BTreeMap<&'static str, SecretSpec>,
9}
10
11impl SecretSpecRegistry {
12    /// Construct an empty registry.
13    pub fn new() -> Self {
14        Self::default()
15    }
16
17    /// Extend the registry with additional specs, deduplicating by name.
18    pub fn extend_with(&mut self, specs: &'static [SecretSpec]) {
19        for spec in specs {
20            match self.by_name.get(spec.name) {
21                None => {
22                    self.by_name.insert(spec.name, spec.clone());
23                }
24                Some(existing) => {
25                    let better = match (existing.description, spec.description) {
26                        (None, Some(_)) => true,
27                        (Some(a), Some(b)) if b.len() > a.len() => true,
28                        _ => false,
29                    };
30                    if better {
31                        self.by_name.insert(spec.name, spec.clone());
32                    }
33                }
34            }
35        }
36    }
37
38    /// Iterate over all stored specs in deterministic order.
39    pub fn all(&self) -> impl Iterator<Item = &SecretSpec> {
40        self.by_name.values()
41    }
42
43    /// Render the registry to a Markdown table suitable for CLI output.
44    pub fn to_markdown_table(&self) -> String {
45        let mut out = String::from("| Name | Description |\n|---|---|\n");
46        for spec in self.by_name.values() {
47            let desc = spec.description.unwrap_or("");
48            out.push_str(&format!(
49                "| `{name}` | {desc} |\n",
50                name = spec.name,
51                desc = desc
52            ));
53        }
54        out
55    }
56
57    /// Render the registry as JSON.
58    pub fn to_json(&self) -> serde_json::Value {
59        let entries = self
60            .by_name
61            .values()
62            .map(|spec| {
63                json!({
64                    "name": spec.name,
65                    "description": spec.description,
66                })
67            })
68            .collect();
69        serde_json::Value::Array(entries)
70    }
71}