Skip to main content

bctx_forge/awareness/
lint.rs

1use super::{AwarenessMap, EcosystemAwareness};
2use once_cell::sync::Lazy;
3use regex::Regex;
4
5static CLIPPY_ERR_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"error\[(\w+)\]").unwrap());
6static CLIPPY_WARN_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"warning: ").unwrap());
7static RUFF_RE: Lazy<Regex> = Lazy::new(|| Regex::new(r"Found (\d+) error").unwrap());
8
9pub struct LintAwareness;
10
11impl EcosystemAwareness for LintAwareness {
12    fn matches(&self, program: &str, args: &[String]) -> bool {
13        let prog = program.split('/').next_back().unwrap_or(program);
14        let sub = args.first().map(|s| s.as_str()).unwrap_or("");
15        matches!(prog, "ruff" | "mypy" | "eslint" | "golangci-lint")
16            || (prog == "cargo" && sub == "clippy")
17    }
18
19    fn extract(&self, stdout: &str, stderr: &str, exit_code: i32) -> AwarenessMap {
20        let mut map = AwarenessMap::new("lint", "check");
21        map.insert("exit_code", exit_code.to_string());
22
23        let combined = format!("{stdout}\n{stderr}");
24        let error_count = CLIPPY_ERR_RE.captures_iter(&combined).count();
25        let warning_count = CLIPPY_WARN_RE.find_iter(&combined).count();
26        map.insert("error_count", error_count.to_string());
27        map.insert("warning_count", warning_count.to_string());
28
29        if let Some(cap) = RUFF_RE.captures(&combined) {
30            map.insert("ruff_errors", cap[1].to_string());
31        }
32
33        map
34    }
35}