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}