use std::collections::HashMap;
use std::str::FromStr;
use clap::Parser;
use super::errors::ConfigError;
use super::global_config::GlobalConfig;
use crate::codegen::GeneratorType;
#[derive(Debug, Parser)]
#[command(name = "openapi-nexus")]
#[command(about = "Generate code from OpenAPI 3.1 specifications")]
#[command(version)]
pub struct CliArgs {
#[command(subcommand)]
pub command: Commands,
}
#[derive(Debug, Parser)]
pub enum Commands {
Generate {
#[arg(short, long, env = "OPENAPI_NEXUS_INPUT")]
input: String,
#[arg(short, long, env = "OPENAPI_NEXUS_VERBOSE")]
verbose: bool,
#[arg(long, env = "OPENAPI_NEXUS_CONFIG")]
config: Option<String>,
#[command(flatten)]
global: GlobalConfig,
#[arg(long = "generator-config", value_name = "GENERATOR.KEY=VALUE")]
generator_config: Vec<String>,
},
}
impl Commands {
pub fn parse_generator_overrides(
&self,
) -> Result<HashMap<GeneratorType, toml::value::Table>, ConfigError> {
let generator_configs = match self {
Commands::Generate {
generator_config, ..
} => generator_config,
};
let mut overrides: HashMap<GeneratorType, toml::value::Table> = HashMap::new();
for config_str in generator_configs {
let parts: Vec<&str> = config_str.splitn(2, '=').collect();
if parts.len() != 2 {
return Err(ConfigError::ParseOverrides(format!(
"Invalid generator config format: '{}'. Expected format: <generator>.<key>=<value>",
config_str
)));
}
let key_part = parts[0];
let value_str = parts[1];
let key_parts: Vec<&str> = key_part.splitn(2, '.').collect();
if key_parts.len() != 2 {
return Err(ConfigError::ParseOverrides(format!(
"Invalid generator config format: '{}'. Expected format: <generator>.<key>=<value>",
config_str
)));
}
let generator_str = key_parts[0];
let key = key_parts[1].to_string();
let generator = GeneratorType::from_str(generator_str).map_err(|e| {
ConfigError::ParseOverrides(format!(
"Invalid generator name '{}': {}",
generator_str, e
))
})?;
let toml_value = Self::parse_toml_value(value_str);
overrides
.entry(generator)
.or_default()
.insert(key, toml_value);
}
Ok(overrides)
}
fn parse_toml_value(value: &str) -> toml::Value {
if let Ok(b) = value.parse::<bool>() {
return toml::Value::Boolean(b);
}
if let Ok(i) = value.parse::<i64>() {
return toml::Value::Integer(i);
}
if let Ok(f) = value.parse::<f64>() {
return toml::Value::Float(f);
}
toml::Value::String(value.to_string())
}
}