use forge::signal::compactor;
use once_cell::sync::Lazy;
use regex::Regex;
static VITEST_PASS_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?m)^\s+✓[^\n]+\n?").unwrap());
static STDOUT_HDR_RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"(?m)^\s+stdout \|[^\n]+\n?").unwrap());
static STDERR_HDR_RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"(?m)^\s+stderr \|[^\n]+\n?").unwrap());
static RERUN_RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"(?m)^(RERUN|Re-running)[^\n]*\n?").unwrap());
#[allow(dead_code)]
static DURATION_RE: Lazy<Regex> =
Lazy::new(|| Regex::new(r"(?m)^( Duration\s+\d+\.\d+\w+)[^\n]*\n?").unwrap());
pub fn compress_vitest(raw: &str, exit_code: i32) -> String {
let cleaned = compactor::normalise(raw);
let s = RERUN_RE.replace_all(&cleaned, "");
let s = STDOUT_HDR_RE.replace_all(&s, "");
let s = STDERR_HDR_RE.replace_all(&s, "");
if exit_code == 0 {
let out: Vec<&str> = s
.lines()
.filter(|l| {
let t = l.trim();
!t.is_empty()
&& (l.contains("✓") && (l.contains("Test Files") || l.contains("Tests"))
|| t.starts_with("Test Files")
|| t.starts_with("Tests")
|| t.starts_with("Duration")
|| t.starts_with("Start")
|| t.starts_with("PASS")
|| t.starts_with("FAIL")
|| l.contains("passed")
|| l.contains("failed"))
})
.collect();
if !out.is_empty() {
return out.join("\n");
}
let lines: Vec<&str> = s.lines().collect();
let tail_start = lines.len().saturating_sub(8);
return lines[tail_start..].join("\n");
}
let s = VITEST_PASS_RE.replace_all(&s, "");
compactor::collapse_blanks(&s)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn success_strips_passing_lines_keeps_summary() {
let raw = " ✓ src/foo.test.ts (3)\n ✓ adds numbers 1ms\n ✓ subtracts numbers 1ms\n\n Test Files 1 passed (1)\n Tests 3 passed (3)\n Duration 142ms\n";
let out = compress_vitest(raw, 0);
assert!(!out.contains("✓ adds numbers"), "{out}");
assert!(
out.contains("Test Files") || out.contains("Tests") || out.contains("Duration"),
"{out}"
);
}
#[test]
fn failure_keeps_failing_test_details() {
let raw = " ✓ src/foo.test.ts (2)\n ✓ test one 1ms\n ✓ test two 1ms\n ✗ src/bar.test.ts (1)\n × test three\n AssertionError: expected 1 to be 2\n\n Test Files 1 failed | 1 passed (2)\n Tests 1 failed | 2 passed (3)\n";
let out = compress_vitest(raw, 1);
assert!(!out.contains("✓ test one"), "{out}");
assert!(
out.contains("AssertionError") || out.contains("failed"),
"{out}"
);
}
#[test]
fn strips_rerun_and_stdout_headers() {
let raw = "RERUN src/foo.test.ts x3\n stdout | src/foo.test.ts\n some log output\n ✗ failing test\n";
let out = compress_vitest(raw, 1);
assert!(!out.contains("RERUN"), "{out}");
assert!(!out.contains("stdout |"), "{out}");
}
}