use std::collections::BTreeMap;
use std::path::PathBuf;
use usage::go::{GoOptions, ValueType};
use usage::miette::Result;
use usage_rs::Args;
use crate::cli::generate;
#[derive(Args)]
#[usage(effect = "read")]
pub struct Go {
#[usage(short, long)]
file: Option<PathBuf>,
#[usage(
short,
long,
value_hint = usage_rs::ValueHint::FilePath,
effect = "write"
)]
out_file: Option<PathBuf>,
#[usage(short, long)]
package: Option<String>,
#[usage(long)]
field_type: Vec<String>,
#[usage(long, required_unless = "--file", overrides = "--file")]
spec: Option<String>,
}
impl usage_rs::Run for Go {
type Output = Result<()>;
fn run(self) -> Self::Output {
if let Some(package) = &self.package
&& !usage::go::is_valid_package(package)
{
usage::miette::bail!(
"`--package {package}` is not a Go package name. It must be \
letters, digits and underscores, not start with a digit, and \
not be one of Go's keywords."
);
}
let spec = generate::file_or_spec(&self.file, &self.spec)?;
let mut field_types = BTreeMap::new();
for binding in &self.field_type {
let (key, value) = binding
.split_once('=')
.ok_or_else(|| usage::miette::miette!("--field-type requires KEY=TYPE"))?;
let ty = value
.parse::<ValueType>()
.map_err(|err| usage::miette::miette!("{err}"))?;
if field_types.insert(key.to_string(), ty).is_some() {
usage::miette::bail!("duplicate --field-type for {key}");
}
}
let out = usage::go::generate_with_types(
&spec,
&GoOptions {
package: self.package.clone(),
},
&field_types,
)
.map_err(|err| usage::miette::miette!("{err}"))?;
generate::write_or_stdout(self.out_file.as_deref(), &out)?;
Ok(())
}
}