1use nu_utils::escape_quote_string;
2
3fn string_should_be_quoted(input: &str) -> bool {
4 input.is_empty()
5 || input.starts_with('$')
6 || input.chars().any(|c| {
7 c.is_whitespace()
8 || c == '('
9 || c == '['
10 || c == '{'
11 || c == '}'
12 || c == '\''
13 || c == '`'
14 || c == '"'
15 || c == '\\'
16 || c == ';'
17 || c == '|'
18 })
19}
20
21pub fn escape_for_script_arg(input: &str) -> String {
29 if input.starts_with("--") {
31 if let Some((arg_name, arg_val)) = input.split_once('=') {
32 let arg_val = if string_should_be_quoted(arg_val) {
34 escape_quote_string(arg_val)
35 } else {
36 arg_val.into()
37 };
38
39 return format!("{arg_name}={arg_val}");
40 } else {
41 return input.into();
42 }
43 }
44 if string_should_be_quoted(input) {
45 escape_quote_string(input)
46 } else {
47 input.into()
48 }
49}
50
51#[cfg(test)]
52mod test {
53 use super::escape_for_script_arg;
54
55 #[test]
56 fn test_not_extra_quote() {
57 assert_eq!(escape_for_script_arg("word"), "word".to_string());
60 assert_eq!(escape_for_script_arg("8"), "8".to_string());
61 }
62
63 #[test]
64 fn test_quote_special() {
65 let cases = vec![
66 ("two words", r#""two words""#),
67 ("$nake", r#""$nake""#),
68 ("`123", r#""`123""#),
69 ("this|cat", r#""this|cat""#),
70 ("this;cat", r#""this;cat""#),
71 ];
72
73 for (input, expected) in cases {
74 assert_eq!(escape_for_script_arg(input).as_str(), expected);
75 }
76 }
77
78 #[test]
79 fn test_quote_newline() {
80 assert_eq!(escape_for_script_arg("c\nd"), format!("\"c\nd\""));
81 }
82
83 #[test]
84 fn test_arg_with_flag() {
85 assert_eq!(escape_for_script_arg("--linux"), "--linux".to_string());
88 assert_eq!(
89 escape_for_script_arg("--version=v5.2"),
90 "--version=v5.2".to_string()
91 );
92
93 assert_eq!(escape_for_script_arg("--version"), "--version".to_string());
96 assert_eq!(escape_for_script_arg("v5.2"), "v5.2".to_string());
97 }
98
99 #[test]
100 fn test_flag_arg_with_values_contains_special() {
101 assert_eq!(
104 escape_for_script_arg("--version='xx yy'"),
105 r#"--version="'xx yy'""#.to_string()
106 );
107 assert_eq!(
108 escape_for_script_arg("--separator=`"),
109 r#"--separator="`""#.to_string()
110 );
111 }
112
113 #[test]
114 fn test_escape() {
115 assert_eq!(escape_for_script_arg(r"\"), r#""\\""#.to_string());
118 assert_eq!(
119 escape_for_script_arg(r#"--arg=""#),
120 r#"--arg="\"""#.to_string()
121 );
122 }
123}