1pub fn escape_python(s: &str) -> String {
5 s.replace('\\', "\\\\")
6 .replace('"', "\\\"")
7 .replace('\n', "\\n")
8 .replace('\r', "\\r")
9 .replace('\t', "\\t")
10}
11
12pub fn escape_rust(s: &str) -> String {
14 s.replace('\\', "\\\\")
15 .replace('"', "\\\"")
16 .replace('\n', "\\n")
17 .replace('\r', "\\r")
18 .replace('\t', "\\t")
19}
20
21pub fn raw_string_hashes(s: &str) -> usize {
23 let mut max_hashes = 0;
24 let mut current = 0;
25 let mut after_quote = false;
26 for ch in s.chars() {
27 if ch == '"' {
28 after_quote = true;
29 current = 0;
30 } else if ch == '#' && after_quote {
31 current += 1;
32 max_hashes = max_hashes.max(current);
33 } else {
34 after_quote = false;
35 current = 0;
36 }
37 }
38 max_hashes + 1
39}
40
41pub fn rust_raw_string(s: &str) -> String {
43 let hashes = raw_string_hashes(s);
44 let h: String = "#".repeat(hashes);
45 format!("r{h}\"{s}\"{h}")
46}
47
48pub fn escape_js(s: &str) -> String {
53 s.replace('\\', "\\\\")
54 .replace('"', "\\\"")
55 .replace('\n', "\\n")
56 .replace('\r', "\\r")
57 .replace('\t', "\\t")
58}
59
60pub fn escape_js_template(s: &str) -> String {
65 s.replace('\\', "\\\\").replace('`', "\\`").replace('$', "\\$")
66}
67
68pub fn go_string_literal(s: &str) -> String {
70 if !s.contains('`') {
71 format!("`{s}`")
72 } else {
73 format!("\"{}\"", escape_go(s))
74 }
75}
76
77pub fn escape_go(s: &str) -> String {
79 s.replace('\\', "\\\\")
80 .replace('"', "\\\"")
81 .replace('\n', "\\n")
82 .replace('\r', "\\r")
83 .replace('\t', "\\t")
84}
85
86pub fn escape_java(s: &str) -> String {
88 s.replace('\\', "\\\\")
89 .replace('"', "\\\"")
90 .replace('\n', "\\n")
91 .replace('\r', "\\r")
92 .replace('\t', "\\t")
93}
94
95pub fn escape_csharp(s: &str) -> String {
97 s.replace('\\', "\\\\")
98 .replace('"', "\\\"")
99 .replace('\n', "\\n")
100 .replace('\r', "\\r")
101 .replace('\t', "\\t")
102}
103
104pub fn escape_php(s: &str) -> String {
106 s.replace('\\', "\\\\")
107 .replace('"', "\\\"")
108 .replace('$', "\\$")
109 .replace('\n', "\\n")
110 .replace('\r', "\\r")
111 .replace('\t', "\\t")
112}
113
114pub fn escape_ruby(s: &str) -> String {
116 s.replace('\\', "\\\\")
117 .replace('"', "\\\"")
118 .replace('#', "\\#")
119 .replace('\n', "\\n")
120 .replace('\r', "\\r")
121 .replace('\t', "\\t")
122}
123
124pub fn escape_ruby_single(s: &str) -> String {
127 s.replace('\\', "\\\\").replace('\'', "\\'")
128}
129
130pub fn ruby_needs_double_quotes(s: &str) -> bool {
133 s.contains('\n') || s.contains('\r') || s.contains('\t') || s.contains('\0')
134}
135
136pub fn ruby_string_literal(s: &str) -> String {
138 if ruby_needs_double_quotes(s) {
139 format!("\"{}\"", escape_ruby(s))
140 } else {
141 format!("'{}'", escape_ruby_single(s))
142 }
143}
144
145pub fn escape_elixir(s: &str) -> String {
147 s.replace('\\', "\\\\")
148 .replace('"', "\\\"")
149 .replace('#', "\\#")
150 .replace('\n', "\\n")
151 .replace('\r', "\\r")
152 .replace('\t', "\\t")
153}
154
155pub fn escape_r(s: &str) -> String {
157 s.replace('\\', "\\\\")
158 .replace('"', "\\\"")
159 .replace('\n', "\\n")
160 .replace('\r', "\\r")
161 .replace('\t', "\\t")
162}
163
164pub fn escape_c(s: &str) -> String {
166 s.replace('\\', "\\\\")
167 .replace('"', "\\\"")
168 .replace('\n', "\\n")
169 .replace('\r', "\\r")
170 .replace('\t', "\\t")
171}
172
173pub fn sanitize_ident(s: &str) -> String {
176 let mut result = String::with_capacity(s.len());
177 for ch in s.chars() {
178 if ch.is_ascii_alphanumeric() || ch == '_' {
179 result.push(ch);
180 } else {
181 result.push('_');
182 }
183 }
184 let trimmed = result.trim_start_matches(|c: char| c.is_ascii_digit());
186 if trimmed.is_empty() {
187 "_".to_string()
188 } else {
189 trimmed.to_string()
190 }
191}
192
193pub fn sanitize_filename(s: &str) -> String {
195 s.chars()
196 .map(|c| if c.is_ascii_alphanumeric() || c == '_' { c } else { '_' })
197 .collect::<String>()
198 .to_lowercase()
199}
200
201pub fn expand_fixture_templates(s: &str) -> String {
208 const PREFIX: &str = "{{ repeat '";
209 const SUFFIX: &str = " times }}";
210
211 let mut result = String::with_capacity(s.len());
212 let mut remaining = s;
213
214 while let Some(start) = remaining.find(PREFIX) {
215 result.push_str(&remaining[..start]);
216 let after_prefix = &remaining[start + PREFIX.len()..];
217
218 if let Some(quote_pos) = after_prefix.find("' ") {
220 let ch = &after_prefix[..quote_pos];
221 let after_quote = &after_prefix[quote_pos + 2..];
222
223 if let Some(end) = after_quote.find(SUFFIX) {
224 let count_str = after_quote[..end].trim();
225 if let Ok(count) = count_str.parse::<usize>() {
226 result.push_str(&ch.repeat(count));
227 remaining = &after_quote[end + SUFFIX.len()..];
228 continue;
229 }
230 }
231 }
232
233 result.push_str(PREFIX);
235 remaining = after_prefix;
236 }
237 result.push_str(remaining);
238 result
239}
240
241pub fn escape_shell(s: &str) -> String {
247 s.replace('\'', r"'\''")
248}