Skip to main content

cli/lib/utils/
remaining_flags.rs

1//! Upstream source: `../nest-cli/lib/utils/remaining-flags.ts`.
2
3use std::collections::BTreeMap;
4
5#[derive(Clone, Debug, Default, PartialEq, Eq)]
6pub struct CommanderOption {
7    pub short: Option<String>,
8    pub long: String,
9}
10
11pub fn get_remaining_flags(
12    raw_args: &[String],
13    consumed_options: &[CommanderOption],
14    consumed_values: &BTreeMap<String, String>,
15) -> Vec<String> {
16    let start = raw_args
17        .iter()
18        .position(|item| item.starts_with("--"))
19        .unwrap_or(0);
20
21    raw_args[start..]
22        .iter()
23        .enumerate()
24        .filter_map(|(index, item)| {
25            if consumed_options
26                .iter()
27                .any(|option| option.short.as_deref() == Some(item) || option.long == *item)
28            {
29                return None;
30            }
31
32            if let Some(previous) = index
33                .checked_sub(1)
34                .and_then(|previous| raw_args[start..].get(previous))
35            {
36                let previous_key =
37                    camel_case_flag(&previous.replace("--", "").replacen("no", "", 1));
38                if consumed_values
39                    .get(&previous_key)
40                    .is_some_and(|value| value == item)
41                {
42                    return None;
43                }
44            }
45
46            Some(item.clone())
47        })
48        .collect()
49}
50
51pub fn get_remaining_flags_simple(raw_args: &[String], consumed_options: &[&str]) -> Vec<String> {
52    let options = consumed_options
53        .iter()
54        .map(|option| CommanderOption {
55            short: None,
56            long: (*option).to_string(),
57        })
58        .collect::<Vec<_>>();
59    get_remaining_flags(raw_args, &options, &BTreeMap::new())
60}
61
62pub fn camel_case_flag(flag: &str) -> String {
63    let mut words = flag.split('-');
64    let Some(first) = words.next() else {
65        return String::new();
66    };
67
68    words.fold(first.to_string(), |mut output, word| {
69        let mut chars = word.chars();
70        if let Some(first_char) = chars.next() {
71            output.push(first_char.to_ascii_uppercase());
72            output.push_str(chars.as_str());
73        }
74        output
75    })
76}