mod build;
mod error;
mod help;
mod resolve;
mod spec;
#[cfg(test)]
mod tests;
pub use error::{CliError, CliErrorRule};
pub(crate) use help::argument_key;
pub use help::{CliHelpV2, CliShape, ResolvedDocs, ResolvedHelp, ResolvedVersion};
pub use resolve::{
BoundCliSpec, BuiltCliSpec, CliOutcome, OutputPlan, ResolvedInvocation, SyntheticInvocation,
};
pub use spec::{
ArgSpec, ArgSyntax, ArgValueType, CliSpec, CliSpecError, CliValue, Combination, CommandSpec,
FixedValue, OutputLifecycle, OutputSpec,
};
pub(crate) const RESERVED_ARGUMENTS: &[&str] = &[
"--help",
"--version",
"--docs",
"--output",
"--output-to",
"--stdout-file",
"--stderr-file",
];
fn nonempty(value: String) -> Option<String> {
(!value.is_empty()).then_some(value)
}
fn is_false(value: &bool) -> bool {
!*value
}
fn is_snake_case(value: &str) -> bool {
let mut chars = value.chars();
chars.next().is_some_and(|first| first.is_ascii_lowercase())
&& chars.all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '_')
}
fn is_canonical_long(value: &str) -> bool {
let Some(name) = value.strip_prefix("--") else {
return false;
};
!name.is_empty()
&& !name.starts_with('-')
&& name
.chars()
.all(|ch| ch.is_ascii_lowercase() || ch.is_ascii_digit() || ch == '-')
}