pub fn strip_string_literals(line: &str) -> String {
let bytes = line.as_bytes();
let mut out = Vec::with_capacity(bytes.len());
let mut i = 0;
while i < bytes.len() {
let c = bytes[i];
if c == b'\'' || c == b'"' || c == b'`' {
let quote = c;
out.push(c);
i += 1;
while i < bytes.len() {
let b = bytes[i];
if b == b'\\' && i + 1 < bytes.len() {
out.push(b' ');
out.push(b' ');
i += 2;
continue;
}
if b == quote {
out.push(b);
i += 1;
break;
}
if quote == b'`' && b == b'$' && i + 1 < bytes.len() && bytes[i + 1] == b'{' {
out.push(b'$');
out.push(b'{');
i += 2;
let mut depth: i32 = 1;
while i < bytes.len() && depth > 0 {
let bb = bytes[i];
if bb == b'{' {
depth += 1;
} else if bb == b'}' {
depth -= 1;
if depth == 0 {
out.push(b'}');
i += 1;
break;
}
}
out.push(bb);
i += 1;
}
continue;
}
out.push(b' ');
i += 1;
}
} else {
out.push(c);
i += 1;
}
}
String::from_utf8(out).unwrap_or_else(|_| line.to_string())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn blanks_double_quoted_contents() {
assert_eq!(
strip_string_literals(r#"const x = "Promise.then";"#),
r#"const x = " ";"#,
);
}
#[test]
fn blanks_single_quoted_contents() {
assert_eq!(
strip_string_literals(r#"const x = 'Promise.then';"#),
r#"const x = ' ';"#,
);
}
#[test]
fn preserves_real_code_outside_strings() {
let line = r#"new Promise((res) => res(1)).then(handle);"#;
assert_eq!(strip_string_literals(line), line);
}
#[test]
fn keeps_template_interpolations_scannable() {
let stripped = strip_string_literals(r#"`prefix ${new Promise(r)} suffix`"#);
assert!(stripped.contains("new Promise"));
assert!(stripped.contains("${"));
}
#[test]
fn blanks_escape_sequences() {
let stripped = strip_string_literals(r#"const x = "a\"Promise";"#);
assert!(!stripped.contains("Promise"));
assert_eq!(stripped.len(), r#"const x = "a\"Promise";"#.len());
}
#[test]
fn preserves_length_for_column_stability() {
let line = r#"const desc = "fix Promise leak"; new Promise(r);"#;
let stripped = strip_string_literals(line);
assert_eq!(stripped.len(), line.len());
let inside_idx = line.find("\"fix Promise").unwrap();
let outside_idx = line.find("new Promise").unwrap();
assert!(!stripped[inside_idx..outside_idx].contains("Promise"));
assert!(stripped[outside_idx..].contains("Promise"));
}
}