1use crate::config::model::{Config, SpecEntry};
2use crate::error::{ConfigError, GenerationError, Result};
3use dialoguer::Select;
4
5pub fn list_specs(config: &Config) -> Vec<SpecEntry> {
7 config.specs.clone()
8}
9
10pub fn get_spec_by_name(config: &Config, name: &str) -> Result<SpecEntry> {
12 config
13 .specs
14 .iter()
15 .find(|s| s.name == name)
16 .cloned()
17 .ok_or_else(|| {
18 let available: Vec<String> = config.specs.iter().map(|s| s.name.clone()).collect();
19 GenerationError::SpecNotFound {
20 name: name.to_string(),
21 available,
22 }
23 .into()
24 })
25}
26
27pub fn resolve_spec_selection(
29 config: &Config,
30 cli_spec: Option<String>,
31 all_specs: bool,
32) -> Result<Vec<SpecEntry>> {
33 let specs = list_specs(config);
34
35 if specs.is_empty() {
36 return Err(ConfigError::NoSpecDefined.into());
37 }
38
39 if all_specs {
40 Ok(specs)
42 } else if let Some(spec_name) = cli_spec {
43 let spec = get_spec_by_name(config, &spec_name)?;
45 Ok(vec![spec])
46 } else if specs.len() == 1 {
47 Ok(specs)
49 } else {
50 let spec_names: Vec<String> = specs.iter().map(|s| s.name.clone()).collect();
52 let selection = Select::new()
53 .with_prompt("Which spec do you want to generate?")
54 .items(&spec_names)
55 .interact()
56 .map_err(|e| GenerationError::InvalidOperation {
57 message: format!("Failed to get user selection: {}", e),
58 })?;
59
60 let selected_spec =
61 specs
62 .get(selection)
63 .ok_or_else(|| GenerationError::InvalidOperation {
64 message: "Invalid selection".to_string(),
65 })?;
66
67 Ok(vec![selected_spec.clone()])
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use crate::config::model::{ApisConfig, ModulesConfig, SchemasConfig};
75
76 #[test]
77 fn test_list_specs_multi_mode() {
78 let mut config = Config::default();
79 config.specs = vec![
80 SpecEntry {
81 name: "auth".to_string(),
82 path: "specs/auth.yaml".to_string(),
83 schemas: SchemasConfig::default(),
84 apis: ApisConfig::default(),
85 modules: ModulesConfig::default(),
86 },
87 SpecEntry {
88 name: "orders".to_string(),
89 path: "specs/orders.json".to_string(),
90 schemas: SchemasConfig::default(),
91 apis: ApisConfig::default(),
92 modules: ModulesConfig::default(),
93 },
94 ];
95
96 let specs = list_specs(&config);
97 assert_eq!(specs.len(), 2);
98 assert_eq!(specs[0].name, "auth");
99 assert_eq!(specs[1].name, "orders");
100 }
101
102 #[test]
103 fn test_get_spec_by_name_single_mode() {
104 let mut config = Config::default();
105 config.specs = vec![SpecEntry {
106 name: "default".to_string(),
107 path: "openapi.json".to_string(),
108 schemas: SchemasConfig::default(),
109 apis: ApisConfig::default(),
110 modules: ModulesConfig::default(),
111 }];
112
113 let spec = get_spec_by_name(&config, "default").unwrap();
114 assert_eq!(spec.name, "default");
115 assert_eq!(spec.path, "openapi.json");
116
117 let result = get_spec_by_name(&config, "auth");
118 assert!(result.is_err());
119 }
120
121 #[test]
122 fn test_get_spec_by_name_multi_mode() {
123 let mut config = Config::default();
124 config.specs = vec![
125 SpecEntry {
126 name: "auth".to_string(),
127 path: "specs/auth.yaml".to_string(),
128 schemas: SchemasConfig::default(),
129 apis: ApisConfig::default(),
130 modules: ModulesConfig::default(),
131 },
132 SpecEntry {
133 name: "orders".to_string(),
134 path: "specs/orders.json".to_string(),
135 schemas: SchemasConfig::default(),
136 apis: ApisConfig::default(),
137 modules: ModulesConfig::default(),
138 },
139 ];
140
141 let spec = get_spec_by_name(&config, "auth").unwrap();
142 assert_eq!(spec.name, "auth");
143 assert_eq!(spec.path, "specs/auth.yaml");
144
145 let result = get_spec_by_name(&config, "nonexistent");
146 assert!(result.is_err());
147 }
148
149 #[test]
150 fn test_resolve_spec_selection_all_specs() {
151 let mut config = Config::default();
152 config.specs = vec![
153 SpecEntry {
154 name: "auth".to_string(),
155 path: "specs/auth.yaml".to_string(),
156 schemas: SchemasConfig::default(),
157 apis: ApisConfig::default(),
158 modules: ModulesConfig::default(),
159 },
160 SpecEntry {
161 name: "orders".to_string(),
162 path: "specs/orders.json".to_string(),
163 schemas: SchemasConfig::default(),
164 apis: ApisConfig::default(),
165 modules: ModulesConfig::default(),
166 },
167 ];
168
169 let specs = resolve_spec_selection(&config, None, true).unwrap();
170 assert_eq!(specs.len(), 2);
171 }
172
173 #[test]
174 fn test_resolve_spec_selection_specific_spec() {
175 let mut config = Config::default();
176 config.specs = vec![
177 SpecEntry {
178 name: "auth".to_string(),
179 path: "specs/auth.yaml".to_string(),
180 schemas: SchemasConfig::default(),
181 apis: ApisConfig::default(),
182 modules: ModulesConfig::default(),
183 },
184 SpecEntry {
185 name: "orders".to_string(),
186 path: "specs/orders.json".to_string(),
187 schemas: SchemasConfig::default(),
188 apis: ApisConfig::default(),
189 modules: ModulesConfig::default(),
190 },
191 ];
192
193 let specs = resolve_spec_selection(&config, Some("auth".to_string()), false).unwrap();
194 assert_eq!(specs.len(), 1);
195 assert_eq!(specs[0].name, "auth");
196 }
197
198 #[test]
199 fn test_resolve_spec_selection_single_mode() {
200 let mut config = Config::default();
201 config.specs = vec![SpecEntry {
202 name: "default".to_string(),
203 path: "openapi.json".to_string(),
204 schemas: SchemasConfig::default(),
205 apis: ApisConfig::default(),
206 modules: ModulesConfig::default(),
207 }];
208
209 let specs = resolve_spec_selection(&config, None, false).unwrap();
210 assert_eq!(specs.len(), 1);
211 assert_eq!(specs[0].name, "default");
212 }
213}