use crate::config::model::{Config, SpecEntry};
use crate::error::{ConfigError, GenerationError, Result};
use dialoguer::Select;
pub fn list_specs(config: &Config) -> Vec<SpecEntry> {
config.specs.clone()
}
pub fn get_spec_by_name(config: &Config, name: &str) -> Result<SpecEntry> {
config
.specs
.iter()
.find(|s| s.name == name)
.cloned()
.ok_or_else(|| {
let available: Vec<String> = config.specs.iter().map(|s| s.name.clone()).collect();
GenerationError::SpecNotFound {
name: name.to_string(),
available,
}
.into()
})
}
pub fn resolve_spec_selection(
config: &Config,
cli_spec: Option<String>,
all_specs: bool,
) -> Result<Vec<SpecEntry>> {
let specs = list_specs(config);
if specs.is_empty() {
return Err(ConfigError::NoSpecDefined.into());
}
if all_specs {
Ok(specs)
} else if let Some(spec_name) = cli_spec {
let spec = get_spec_by_name(config, &spec_name)?;
Ok(vec![spec])
} else if specs.len() == 1 {
Ok(specs)
} else {
let spec_names: Vec<String> = specs.iter().map(|s| s.name.clone()).collect();
let selection = Select::new()
.with_prompt("Which spec do you want to generate?")
.items(&spec_names)
.interact()
.map_err(|e| GenerationError::InvalidOperation {
message: format!("Failed to get user selection: {}", e),
})?;
let selected_spec =
specs
.get(selection)
.ok_or_else(|| GenerationError::InvalidOperation {
message: "Invalid selection".to_string(),
})?;
Ok(vec![selected_spec.clone()])
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::model::{ApisConfig, ModulesConfig, SchemasConfig};
#[test]
fn test_list_specs_multi_mode() {
let config = Config {
specs: vec![
SpecEntry {
name: "auth".to_string(),
path: "specs/auth.yaml".to_string(),
schemas: SchemasConfig::default(),
apis: ApisConfig::default(),
hooks: None,
modules: ModulesConfig::default(),
},
SpecEntry {
name: "orders".to_string(),
path: "specs/orders.json".to_string(),
schemas: SchemasConfig::default(),
apis: ApisConfig::default(),
hooks: None,
modules: ModulesConfig::default(),
},
],
..Default::default()
};
let specs = list_specs(&config);
assert_eq!(specs.len(), 2);
assert_eq!(specs[0].name, "auth");
assert_eq!(specs[1].name, "orders");
}
#[test]
fn test_get_spec_by_name_single_mode() {
let config = Config {
specs: vec![SpecEntry {
name: "default".to_string(),
path: "openapi.json".to_string(),
schemas: SchemasConfig::default(),
apis: ApisConfig::default(),
hooks: None,
modules: ModulesConfig::default(),
}],
..Default::default()
};
let spec = get_spec_by_name(&config, "default").unwrap();
assert_eq!(spec.name, "default");
assert_eq!(spec.path, "openapi.json");
let result = get_spec_by_name(&config, "auth");
assert!(result.is_err());
}
#[test]
fn test_get_spec_by_name_multi_mode() {
let config = Config {
specs: vec![
SpecEntry {
name: "auth".to_string(),
path: "specs/auth.yaml".to_string(),
schemas: SchemasConfig::default(),
apis: ApisConfig::default(),
hooks: None,
modules: ModulesConfig::default(),
},
SpecEntry {
name: "orders".to_string(),
path: "specs/orders.json".to_string(),
schemas: SchemasConfig::default(),
apis: ApisConfig::default(),
hooks: None,
modules: ModulesConfig::default(),
},
],
..Default::default()
};
let spec = get_spec_by_name(&config, "auth").unwrap();
assert_eq!(spec.name, "auth");
assert_eq!(spec.path, "specs/auth.yaml");
let result = get_spec_by_name(&config, "nonexistent");
assert!(result.is_err());
}
#[test]
fn test_resolve_spec_selection_all_specs() {
let config = Config {
specs: vec![
SpecEntry {
name: "auth".to_string(),
path: "specs/auth.yaml".to_string(),
schemas: SchemasConfig::default(),
apis: ApisConfig::default(),
hooks: None,
modules: ModulesConfig::default(),
},
SpecEntry {
name: "orders".to_string(),
path: "specs/orders.json".to_string(),
schemas: SchemasConfig::default(),
apis: ApisConfig::default(),
hooks: None,
modules: ModulesConfig::default(),
},
],
..Default::default()
};
let specs = resolve_spec_selection(&config, None, true).unwrap();
assert_eq!(specs.len(), 2);
}
#[test]
fn test_resolve_spec_selection_specific_spec() {
let config = Config {
specs: vec![
SpecEntry {
name: "auth".to_string(),
path: "specs/auth.yaml".to_string(),
schemas: SchemasConfig::default(),
apis: ApisConfig::default(),
hooks: None,
modules: ModulesConfig::default(),
},
SpecEntry {
name: "orders".to_string(),
path: "specs/orders.json".to_string(),
schemas: SchemasConfig::default(),
apis: ApisConfig::default(),
hooks: None,
modules: ModulesConfig::default(),
},
],
..Default::default()
};
let specs = resolve_spec_selection(&config, Some("auth".to_string()), false).unwrap();
assert_eq!(specs.len(), 1);
assert_eq!(specs[0].name, "auth");
}
#[test]
fn test_resolve_spec_selection_single_mode() {
let config = Config {
specs: vec![SpecEntry {
name: "default".to_string(),
path: "openapi.json".to_string(),
schemas: SchemasConfig::default(),
apis: ApisConfig::default(),
hooks: None,
modules: ModulesConfig::default(),
}],
..Default::default()
};
let specs = resolve_spec_selection(&config, None, false).unwrap();
assert_eq!(specs.len(), 1);
assert_eq!(specs[0].name, "default");
}
}