raz_common/
parse.rs

1//! Parsing utilities for command-line arguments and options
2
3use crate::error::{CommonError, Result};
4
5/// Parse a command option string into parts, handling quoted arguments properly
6///
7/// # Examples
8/// ```
9/// use raz_common::parse::parse_option;
10///
11/// let parts = parse_option("--features foo bar").unwrap();
12/// assert_eq!(parts, vec!["--features", "foo", "bar"]);
13///
14/// let parts = parse_option("--message \"hello world\"").unwrap();
15/// assert_eq!(parts, vec!["--message", "hello world"]);
16/// ```
17pub fn parse_option(option: &str) -> Result<Vec<String>> {
18    shell_words::split(option)
19        .map_err(|e| CommonError::ShellParse(format!("Failed to parse option '{option}': {e}")))
20}
21
22/// Parse multiple space-separated options, each potentially containing quoted values
23pub fn parse_options(options: &[String]) -> Result<Vec<String>> {
24    let mut result = Vec::new();
25    for option in options {
26        result.extend(parse_option(option)?);
27    }
28    Ok(result)
29}
30
31/// Check if a command argument list contains a specific flag
32pub fn has_flag(args: &[String], flag: &str) -> bool {
33    args.iter().any(|arg| arg == flag)
34}
35
36/// Extract the value for a flag from command arguments
37/// Returns None if flag not found or if it has no value
38pub fn get_flag_value(args: &[String], flag: &str) -> Option<String> {
39    let mut iter = args.iter();
40    while let Some(arg) = iter.next() {
41        if arg == flag {
42            return iter.next().cloned();
43        }
44    }
45    None
46}
47
48/// Remove a flag and its value from command arguments
49pub fn remove_flag(args: &mut Vec<String>, flag: &str) -> Option<String> {
50    if let Some(pos) = args.iter().position(|arg| arg == flag) {
51        args.remove(pos);
52        if pos < args.len() {
53            Some(args.remove(pos))
54        } else {
55            None
56        }
57    } else {
58        None
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn test_parse_option() {
68        assert_eq!(
69            parse_option("--features foo").unwrap(),
70            vec!["--features", "foo"]
71        );
72
73        assert_eq!(
74            parse_option("--message \"hello world\"").unwrap(),
75            vec!["--message", "hello world"]
76        );
77    }
78
79    #[test]
80    fn test_has_flag() {
81        let args = vec!["--release".to_string(), "--verbose".to_string()];
82        assert!(has_flag(&args, "--release"));
83        assert!(!has_flag(&args, "--debug"));
84    }
85
86    #[test]
87    fn test_get_flag_value() {
88        let args = vec![
89            "--features".to_string(),
90            "foo".to_string(),
91            "--target".to_string(),
92            "wasm32".to_string(),
93        ];
94        assert_eq!(get_flag_value(&args, "--features"), Some("foo".to_string()));
95        assert_eq!(
96            get_flag_value(&args, "--target"),
97            Some("wasm32".to_string())
98        );
99        assert_eq!(get_flag_value(&args, "--missing"), None);
100    }
101}