use super::BoundarySignal;
use crate::audits::context::classify::helpers::is_test_file;
use crate::review::diff::ChangedFile;
use crate::review::paths::normalized_review_path;
use crate::scan::types::CouplingGraph;
use std::collections::{BTreeMap, BTreeSet};
use std::path::{Path, PathBuf};
pub fn build_importers_by_target(
graph: &CouplingGraph,
repo_root: &Path,
) -> BTreeMap<PathBuf, BTreeSet<PathBuf>> {
let mut importers: BTreeMap<PathBuf, BTreeSet<PathBuf>> = BTreeMap::new();
for (source, targets) in &graph.edges {
let source = normalized_review_path(source, repo_root);
for target in targets {
importers
.entry(normalized_review_path(target, repo_root))
.or_default()
.insert(source.clone());
}
}
importers
}
pub fn enrich_blast_radius(
signals: &mut [BoundarySignal],
graph: Option<&CouplingGraph>,
repo_root: &Path,
) {
let Some(graph) = graph else {
return;
};
let importers = build_importers_by_target(graph, repo_root);
for signal in signals.iter_mut() {
let normalized = normalized_review_path(Path::new(&signal.path), repo_root);
signal.blast_radius = importers.get(&normalized).map_or(0, BTreeSet::len);
}
}
pub fn any_test_changed(changed_files: &[ChangedFile]) -> bool {
changed_files
.iter()
.any(|file| is_test_file(&file.path, false))
}
pub fn missing_test_for_code_boundary(
signals: &[BoundarySignal],
changed_files: &[ChangedFile],
) -> bool {
signals
.iter()
.any(|signal| signal.category.is_code_boundary())
&& !any_test_changed(changed_files)
}