Skip to main content

lean_ctx/core/patterns/
bun.rs

1pub fn compress(cmd: &str, output: &str) -> Option<String> {
2    let trimmed = output.trim();
3    if trimmed.is_empty() {
4        return Some("ok".to_string());
5    }
6
7    if cmd.contains("test") {
8        return Some(compress_test(trimmed));
9    }
10    if cmd.contains("install") || cmd.contains("add") || cmd.contains("remove") {
11        return Some(compress_install(trimmed));
12    }
13    if cmd.contains("build") || cmd.contains("run") {
14        return Some(compress_build(trimmed));
15    }
16
17    Some(compact_lines(trimmed, 15))
18}
19
20fn compress_test(output: &str) -> String {
21    let mut passed = 0u32;
22    let mut failed = 0u32;
23    let mut skipped = 0u32;
24    let mut failures = Vec::new();
25    let mut time = String::new();
26
27    for line in output.lines() {
28        let trimmed = line.trim();
29        let plain = strip_ansi(trimmed);
30        if plain.contains("pass") && (plain.contains("tests") || plain.contains("test")) {
31            for word in plain.split_whitespace() {
32                if let Ok(n) = word.parse::<u32>() {
33                    passed = n;
34                    break;
35                }
36            }
37        }
38        if plain.contains("fail") && !plain.starts_with("FAIL") {
39            for word in plain.split_whitespace() {
40                if let Ok(n) = word.parse::<u32>() {
41                    failed = n;
42                    break;
43                }
44            }
45        }
46        if plain.contains("skip") {
47            for word in plain.split_whitespace() {
48                if let Ok(n) = word.parse::<u32>() {
49                    skipped = n;
50                    break;
51                }
52            }
53        }
54        if plain.starts_with("FAIL") || plain.starts_with("✗") || plain.starts_with("×") {
55            failures.push(plain.clone());
56        }
57        if (plain.contains("Ran") || plain.contains("Done"))
58            && (plain.contains("ms") || plain.contains("s"))
59        {
60            time = plain.clone();
61        }
62    }
63
64    if passed == 0 && failed == 0 {
65        return compact_lines(output, 10);
66    }
67
68    let mut result = format!("bun test: {passed} passed");
69    if failed > 0 {
70        result.push_str(&format!(", {failed} failed"));
71    }
72    if skipped > 0 {
73        result.push_str(&format!(", {skipped} skipped"));
74    }
75    if !time.is_empty() {
76        result.push_str(&format!(" ({time})"));
77    }
78    for f in failures.iter().take(5) {
79        result.push_str(&format!("\n  {f}"));
80    }
81    result
82}
83
84fn compress_install(output: &str) -> String {
85    let mut installed = 0u32;
86    let mut removed = 0u32;
87    let mut time = String::new();
88
89    for line in output.lines() {
90        let plain = strip_ansi(line.trim());
91        if plain.contains("installed") || plain.starts_with('+') {
92            installed += 1;
93        }
94        if plain.contains("removed") || plain.starts_with('-') {
95            removed += 1;
96        }
97        if plain.contains("done") && (plain.contains("ms") || plain.contains("s")) {
98            time = plain.clone();
99        }
100    }
101
102    let mut parts = Vec::new();
103    if installed > 0 {
104        parts.push(format!("{installed} installed"));
105    }
106    if removed > 0 {
107        parts.push(format!("{removed} removed"));
108    }
109    if !time.is_empty() {
110        parts.push(time);
111    }
112
113    if parts.is_empty() {
114        return compact_lines(output, 5);
115    }
116    format!("bun: {}", parts.join(", "))
117}
118
119fn compress_build(output: &str) -> String {
120    let lines: Vec<&str> = output.lines().collect();
121    let errors: Vec<&&str> = lines
122        .iter()
123        .filter(|l| l.contains("error") || l.contains("Error"))
124        .collect();
125    if !errors.is_empty() {
126        let mut result = format!("{} errors:", errors.len());
127        for e in errors.iter().take(10) {
128            result.push_str(&format!("\n  {}", e.trim()));
129        }
130        return result;
131    }
132    compact_lines(output, 10)
133}
134
135fn strip_ansi(s: &str) -> String {
136    let mut result = String::with_capacity(s.len());
137    let mut in_escape = false;
138    for c in s.chars() {
139        if c == '\x1b' {
140            in_escape = true;
141        } else if in_escape {
142            if c.is_ascii_alphabetic() {
143                in_escape = false;
144            }
145        } else {
146            result.push(c);
147        }
148    }
149    result
150}
151
152fn compact_lines(text: &str, max: usize) -> String {
153    let lines: Vec<&str> = text.lines().filter(|l| !l.trim().is_empty()).collect();
154    if lines.len() <= max {
155        return lines.join("\n");
156    }
157    format!(
158        "{}\n... ({} more lines)",
159        lines[..max].join("\n"),
160        lines.len() - max
161    )
162}