expr/functions/
string.rs

1use crate::{bail, Parser, Value};
2
3pub fn add_string_functions(p: &mut Parser) {
4    p.add_function("trim", |c| {
5        if c.args.len() != 1 && c.args.len() != 2 {
6            bail!("trim() takes one or two arguments");
7        }
8        if let (Value::String(s), None) = (&c.args[0], c.args.get(1)) {
9            Ok(s.trim().into())
10        } else if let (Value::String(s), Some(Value::String(chars))) = (&c.args[0], c.args.get(1)) {
11            Ok(s.trim_matches(|c| chars.contains(c)).into())
12        } else {
13            bail!("trim() takes a string as the first argument and an optional string of characters to trim");
14        }
15    });
16
17    p.add_function("trimPrefix", |c| {
18        if let (Value::String(s), Value::String(prefix)) = (&c.args[0], &c.args[1]) {
19            Ok(s.strip_prefix(prefix).unwrap_or(s).into())
20        } else {
21            bail!("trimPrefix() takes a string as the first argument and a string to trim as the second argument");
22        }
23    });
24
25    p.add_function("trimSuffix", |c| {
26        if let (Value::String(s), Value::String(suffix)) = (&c.args[0], &c.args[1]) {
27            Ok(s.strip_suffix(suffix).unwrap_or(s).into())
28        } else {
29            bail!("trimSuffix() takes a string as the first argument and a string to trim as the second argument");
30        }
31    });
32
33    p.add_function("upper", |c| {
34        if c.args.len() != 1 {
35            bail!("upper() takes one argument");
36        }
37        if let Value::String(s) = &c.args[0] {
38            Ok(s.to_uppercase().into())
39        } else {
40            bail!("upper() takes a string as the first argument");
41        }
42    });
43
44    p.add_function("lower", |c| {
45        if c.args.len() != 1 {
46            bail!("lower() takes one argument");
47        }
48        if let Value::String(s) = &c.args[0] {
49            Ok(s.to_lowercase().into())
50        } else {
51            bail!("lower() takes a string as the first argument");
52        }
53    });
54
55    p.add_function("split", |c| {
56        if let (Value::String(s), Value::String(sep), None) = (&c.args[0], &c.args[1], c.args.get(2)) {
57            Ok(s.split(sep).map(Value::from).collect::<Vec<_>>().into())
58        } else if let (Value::String(s), Value::String(sep), Some(Value::Number(n))) = (&c.args[0], &c.args[1], c.args.get(2)) {
59            Ok(s.splitn(*n as usize, sep).map(Value::from).collect::<Vec<_>>().into())
60        } else {
61            bail!("split() takes a string as the first argument and a string as the second argument");
62        }
63    });
64
65    p.add_function("splitAfter", |c| {
66        if let (Value::String(s), Value::String(sep), None) = (&c.args[0], &c.args[1], c.args.get(2)) {
67            Ok(s.split_inclusive(sep).map(Value::from).collect::<Vec<_>>().into())
68        } else if let (Value::String(s), Value::String(sep), Some(Value::Number(n))) = (&c.args[0], &c.args[1], c.args.get(2)) {
69            let mut arr = s.split_inclusive(sep).take(*n as usize - 1).map(|s| s.to_string()).collect::<Vec<_>>();
70            arr.push(s.split_inclusive(sep).skip(*n as usize - 1).collect::<Vec<_>>().join(""));
71            Ok(arr.into())
72        } else {
73            bail!("splitAfter() takes a string as the first argument and a string as the second argument");
74        }
75    });
76
77    p.add_function("replace", |c| {
78        if let (Value::String(s), Value::String(from), Value::String(to)) =
79            (&c.args[0], &c.args[1], &c.args[2])
80        {
81            Ok(s.replace(from, to).into())
82        } else {
83            bail!("replace() takes a string as the first argument and two strings to replace");
84        }
85    });
86
87    p.add_function("repeat", |c| {
88        if let (Value::String(s), Value::Number(n)) = (&c.args[0], &c.args[1]) {
89            Ok(s.repeat(*n as usize + 1).into())
90        } else {
91            bail!("repeat() takes a string as the first argument and a number as the second argument");
92        }
93    });
94
95    p.add_function("indexOf", |c| {
96        if let (Value::String(s), Value::String(sub)) = (&c.args[0], &c.args[1]) {
97            Ok(s.find(sub).map(|i| i as i64).unwrap_or(-1).into())
98        } else {
99            bail!("indexOf() takes a string as the first argument and a string to search for as the second argument");
100        }
101    });
102
103    p.add_function("lastIndexOf", |c| {
104        if let (Value::String(s), Value::String(sub)) = (&c.args[0], &c.args[1]) {
105            Ok(s.rfind(sub).map(|i| i as i64).unwrap_or(-1).into())
106        } else {
107            bail!("lastIndexOf() takes a string as the first argument and a string to search for as the second argument");
108        }
109    });
110
111    p.add_function("hasPrefix", |c| {
112        if let (Value::String(s), Value::String(prefix)) = (&c.args[0], &c.args[1]) {
113            Ok(s.starts_with(prefix).into())
114        } else {
115            bail!("hasPrefix() takes a string as the first argument and a string to search for as the second argument");
116        }
117    });
118
119    p.add_function("hasSuffix", |c| {
120        if let (Value::String(s), Value::String(suffix)) = (&c.args[0], &c.args[1]) {
121            Ok(s.ends_with(suffix).into())
122        } else {
123            bail!("hasSuffix() takes a string as the first argument and a string to search for as the second argument");
124        }
125    });
126}