1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct Config {
18 #[serde(rename = "$schema", default = "default_schema")]
19 pub schema: String,
20
21 #[serde(default = "default_root_dir")]
22 pub root_dir: String,
23
24 #[serde(default)]
25 pub schemas: SchemasConfig,
26
27 #[serde(default)]
28 pub apis: ApisConfig,
29
30 #[serde(default)]
31 pub modules: ModulesConfig,
32
33 #[serde(default)]
34 pub generation: GenerationConfig,
35
36 #[serde(skip_serializing_if = "Option::is_none")]
37 pub spec_path: Option<String>,
38}
39
40pub fn default_schema() -> String {
41 "https://raw.githubusercontent.com/vikarno/vika-cli/main/schema/vika-config.schema.json"
42 .to_string()
43}
44
45fn default_root_dir() -> String {
46 "src".to_string()
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct SchemasConfig {
54 #[serde(default = "default_schemas_output")]
55 pub output: String,
56
57 #[serde(default = "default_naming")]
58 pub naming: String,
59}
60
61fn default_naming() -> String {
62 "PascalCase".to_string()
63}
64
65fn default_schemas_output() -> String {
66 "src/schemas".to_string()
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct ApisConfig {
74 #[serde(default = "default_apis_output")]
75 pub output: String,
76
77 #[serde(default = "default_style")]
78 pub style: String,
79
80 #[serde(skip_serializing_if = "Option::is_none")]
81 pub base_url: Option<String>,
82
83 #[serde(default = "default_header_strategy")]
84 pub header_strategy: String,
85}
86
87fn default_header_strategy() -> String {
88 "consumerInjected".to_string()
89}
90
91fn default_apis_output() -> String {
92 "src/apis".to_string()
93}
94
95fn default_style() -> String {
96 "fetch".to_string()
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize, Default)]
103pub struct ModulesConfig {
104 #[serde(default)]
105 pub ignore: Vec<String>,
106
107 #[serde(default)]
108 pub selected: Vec<String>,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
115pub struct GenerationConfig {
116 #[serde(default = "default_enable_cache")]
117 pub enable_cache: bool,
118
119 #[serde(default = "default_enable_backup")]
120 pub enable_backup: bool,
121
122 #[serde(default = "default_conflict_strategy")]
123 pub conflict_strategy: String,
124}
125
126fn default_enable_cache() -> bool {
127 true
128}
129
130fn default_enable_backup() -> bool {
131 false
132}
133
134fn default_conflict_strategy() -> String {
135 "ask".to_string()
136}
137
138impl Default for GenerationConfig {
139 fn default() -> Self {
140 Self {
141 enable_cache: default_enable_cache(),
142 enable_backup: default_enable_backup(),
143 conflict_strategy: default_conflict_strategy(),
144 }
145 }
146}
147
148impl Default for Config {
149 fn default() -> Self {
150 Self {
151 schema: default_schema(),
152 root_dir: default_root_dir(),
153 schemas: SchemasConfig {
154 output: default_schemas_output(),
155 naming: default_naming(),
156 },
157 apis: ApisConfig {
158 output: default_apis_output(),
159 style: default_style(),
160 base_url: None,
161 header_strategy: default_header_strategy(),
162 },
163 modules: ModulesConfig {
164 ignore: vec![],
165 selected: vec![],
166 },
167 generation: GenerationConfig::default(),
168 spec_path: None,
169 }
170 }
171}
172
173impl Default for SchemasConfig {
174 fn default() -> Self {
175 Self {
176 output: default_schemas_output(),
177 naming: default_naming(),
178 }
179 }
180}
181
182impl Default for ApisConfig {
183 fn default() -> Self {
184 Self {
185 output: default_apis_output(),
186 style: default_style(),
187 base_url: None,
188 header_strategy: default_header_strategy(),
189 }
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 #[test]
198 fn test_load_default_config() {
199 let config = Config::default();
200 assert_eq!(config.root_dir, "src");
201 assert_eq!(config.schemas.output, "src/schemas");
202 assert_eq!(config.apis.output, "src/apis");
203 assert_eq!(config.apis.style, "fetch");
204 assert!(!config.schema.is_empty());
205 }
206
207 #[test]
208 fn test_config_serialization() {
209 let config = Config::default();
210 let json = serde_json::to_string_pretty(&config).unwrap();
211
212 assert!(json.contains("\"root_dir\""));
213 assert!(json.contains("\"schemas\""));
214 assert!(json.contains("\"apis\""));
215 assert!(json.contains("\"$schema\""));
216 }
217
218 #[test]
219 fn test_config_deserialization() {
220 let json = r#"
221 {
222 "$schema": "https://example.com/schema.json",
223 "root_dir": "test",
224 "schemas": {
225 "output": "test/schemas",
226 "naming": "camelCase"
227 },
228 "apis": {
229 "output": "test/apis",
230 "style": "fetch",
231 "header_strategy": "bearerToken"
232 },
233 "modules": {
234 "ignore": ["test"],
235 "selected": []
236 }
237 }
238 "#;
239
240 let config: Config = serde_json::from_str(json).unwrap();
241 assert_eq!(config.root_dir, "test");
242 assert_eq!(config.schemas.output, "test/schemas");
243 assert_eq!(config.schemas.naming, "camelCase");
244 assert_eq!(config.apis.header_strategy, "bearerToken");
245 assert_eq!(config.modules.ignore, vec!["test"]);
246 }
247
248 #[test]
249 fn test_schemas_config_default() {
250 let config = SchemasConfig::default();
251 assert_eq!(config.output, "src/schemas");
252 assert_eq!(config.naming, "PascalCase");
253 }
254
255 #[test]
256 fn test_apis_config_default() {
257 let config = ApisConfig::default();
258 assert_eq!(config.output, "src/apis");
259 assert_eq!(config.style, "fetch");
260 assert_eq!(config.header_strategy, "consumerInjected");
261 assert!(config.base_url.is_none());
262 }
263
264 #[test]
265 fn test_config_with_base_url() {
266 let mut config = Config::default();
267 config.apis.base_url = Some("/api/v1".to_string());
268
269 let json = serde_json::to_string_pretty(&config).unwrap();
270 assert!(json.contains("\"base_url\""));
271 assert!(json.contains("/api/v1"));
272 }
273
274 #[test]
275 fn test_config_schema_field() {
276 let config = Config::default();
277 let json = serde_json::to_string_pretty(&config).unwrap();
278
279 assert!(json.contains("\"$schema\""));
281 }
282
283 #[test]
284 fn test_generation_config_defaults() {
285 let config = Config::default();
286 assert!(config.generation.enable_cache);
287 assert!(!config.generation.enable_backup);
288 assert_eq!(config.generation.conflict_strategy, "ask");
289 }
290
291 #[test]
292 fn test_config_with_generation_settings() {
293 let json = r#"
294 {
295 "$schema": "https://example.com/schema.json",
296 "root_dir": "test",
297 "schemas": {
298 "output": "test/schemas",
299 "naming": "camelCase"
300 },
301 "apis": {
302 "output": "test/apis",
303 "style": "fetch",
304 "header_strategy": "bearerToken"
305 },
306 "modules": {
307 "ignore": ["test"],
308 "selected": []
309 },
310 "generation": {
311 "enable_cache": false,
312 "enable_backup": true,
313 "conflict_strategy": "force"
314 }
315 }
316 "#;
317
318 let config: Config = serde_json::from_str(json).unwrap();
319 assert!(!config.generation.enable_cache);
320 assert!(config.generation.enable_backup);
321 assert_eq!(config.generation.conflict_strategy, "force");
322 }
323}