lean_ctx/core/config/schema/
mod.rs1use serde::Serialize;
7use std::collections::BTreeMap;
8mod sections_advanced;
9mod sections_core;
10mod sections_features;
11
12#[derive(Debug, Clone, Serialize)]
13pub struct ConfigSchema {
14 pub version: u32,
15 pub sections: BTreeMap<String, SectionSchema>,
16}
17
18#[derive(Debug, Clone, Serialize)]
19pub struct SectionSchema {
20 pub description: String,
21 pub keys: BTreeMap<String, KeySchema>,
22}
23
24#[derive(Debug, Clone, Serialize)]
25pub struct KeySchema {
26 #[serde(rename = "type")]
27 pub ty: String,
28 pub default: serde_json::Value,
29 pub description: String,
30 #[serde(skip_serializing_if = "Option::is_none")]
31 pub values: Option<Vec<String>>,
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub env_override: Option<String>,
34}
35
36fn clean_f32(v: f32) -> serde_json::Value {
37 let clean: f64 = format!("{v}").parse().unwrap_or(v as f64);
38 serde_json::json!(clean)
39}
40
41fn key(ty: &str, default: serde_json::Value, desc: &str) -> KeySchema {
42 KeySchema {
43 ty: ty.to_string(),
44 default,
45 description: desc.to_string(),
46 values: None,
47 env_override: None,
48 }
49}
50
51fn key_enum(values: &[&str], default: &str, desc: &str) -> KeySchema {
52 KeySchema {
53 ty: "enum".to_string(),
54 default: serde_json::Value::String(default.to_string()),
55 description: desc.to_string(),
56 values: Some(values.iter().map(ToString::to_string).collect()),
57 env_override: None,
58 }
59}
60
61fn key_with_env(ty: &str, default: serde_json::Value, desc: &str, env: &str) -> KeySchema {
62 KeySchema {
63 ty: ty.to_string(),
64 default,
65 description: desc.to_string(),
66 values: None,
67 env_override: Some(env.to_string()),
68 }
69}
70
71fn key_enum_with_env(values: &[&str], default: &str, desc: &str, env: &str) -> KeySchema {
72 KeySchema {
73 ty: "enum".to_string(),
74 default: serde_json::Value::String(default.to_string()),
75 description: desc.to_string(),
76 values: Some(values.iter().map(ToString::to_string).collect()),
77 env_override: Some(env.to_string()),
78 }
79}
80
81impl ConfigSchema {
82 pub fn generate() -> Self {
83 let mut sections = BTreeMap::new();
84 sections_core::build(&mut sections);
85 sections_features::build(&mut sections);
86 sections_advanced::build(&mut sections);
87
88 ConfigSchema {
89 version: 1,
90 sections,
91 }
92 }
93
94 pub fn lookup(&self, key: &str) -> Option<&KeySchema> {
97 if let Some(dot_pos) = key.find('.') {
98 let section = &key[..dot_pos];
99 let field = &key[dot_pos + 1..];
100 self.sections.get(section)?.keys.get(field)
101 } else {
102 self.sections.get("root")?.keys.get(key)
103 }
104 }
105
106 pub fn known_keys(&self) -> Vec<String> {
108 let mut keys = Vec::new();
109 for (section, schema) in &self.sections {
110 if section == "root" {
111 for key_name in schema.keys.keys() {
112 keys.push(key_name.clone());
113 }
114 } else {
115 if schema.keys.is_empty() {
116 keys.push(section.clone());
117 }
118 for key_name in schema.keys.keys() {
119 keys.push(format!("{section}.{key_name}"));
120 }
121 }
122 }
123 keys
124 }
125}