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