Skip to content

Commit

Permalink
fix: fail parsing if required args/flags not found
Browse files Browse the repository at this point in the history
Fixes #108
  • Loading branch information
jdx committed Sep 27, 2024
1 parent 6240460 commit 409145a
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 1 deletion.
2 changes: 1 addition & 1 deletion cli/src/cli/complete_word.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl CompleteWord {
ctx.insert("PREV", &(cword - 1));
}

let parsed = usage::parse::parse(spec, &words)?;
let parsed = usage::parse::parse_partial(spec, &words)?;
debug!("parsed cmd: {}", parsed.cmd.full_cmd.join(" "));
let choices = if ctoken == "-" {
let shorts = self.complete_short_flag_names(&parsed.available_flags, "");
Expand Down
26 changes: 26 additions & 0 deletions lib/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub struct ParseOutput {
pub flags: IndexMap<SpecFlag, ParseValue>,
pub available_flags: BTreeMap<String, SpecFlag>,
pub flag_awaiting_value: Option<SpecFlag>,
pub errors: Vec<String>,
}

#[derive(Debug, EnumTryAs)]
Expand All @@ -26,6 +27,14 @@ pub enum ParseValue {
}

pub fn parse(spec: &Spec, input: &[String]) -> Result<ParseOutput, miette::Error> {
let out = parse_partial(spec, input)?;
if !out.errors.is_empty() {
bail!("{}", out.errors.join("\n"));
}
Ok(out)
}

pub fn parse_partial(spec: &Spec, input: &[String]) -> Result<ParseOutput, miette::Error> {
let mut input = input.iter().cloned().collect::<VecDeque<_>>();
input.pop_front();

Expand Down Expand Up @@ -54,6 +63,7 @@ pub fn parse(spec: &Spec, input: &[String]) -> Result<ParseOutput, miette::Error
flags: IndexMap::new(),
available_flags: gather_flags(&spec.cmd),
flag_awaiting_value: None,
errors: vec![],
};

while !input.is_empty() {
Expand Down Expand Up @@ -190,6 +200,22 @@ pub fn parse(spec: &Spec, input: &[String]) -> Result<ParseOutput, miette::Error
bail!("unexpected word: {w}");
}

for arg in out.cmd.args.iter().skip(out.args.len()) {
if arg.required {
out.errors
.push(format!("missing required arg <{}>", arg.name));
}
}

for flag in out.available_flags.values() {
if flag.required && !out.flags.contains_key(flag) {
out.errors.push(format!(
"missing required option --{} <{}>",
flag.name, flag.name
));
}
}

Ok(out)
}

Expand Down
10 changes: 10 additions & 0 deletions lib/tests/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ macro_rules! tests {
}

tests! {
required_arg:
spec=r#"arg "<name>""#,
args="",
expected=r#"missing required arg <name>"#,

required_option:
spec=r#"flag "--name <name>" required=true"#,
args="",
expected=r#"missing required option --name <name>"#,

negate:
spec=r#"flag "--force" negate="--no-force""#,
args="--no-force",
Expand Down

0 comments on commit 409145a

Please sign in to comment.