code-buster 0.10.0

Repository-aware static analysis for AI-assisted development
Documentation
use std::collections::{BTreeMap, BTreeSet};

use crate::dependency_graph::DependencyGraph;

pub fn layer_for<'a>(source: &str, layers: &'a [String]) -> Option<&'a str> {
    let normalized = source.replace('\\', "/");
    let segments = normalized.split('/').collect::<Vec<_>>();
    for layer in layers {
        let pattern = layer.split('/').collect::<Vec<_>>();
        if pattern.len() == 1 && segments.contains(&pattern[0]) {
            return Some(layer);
        }
        if pattern.len() <= segments.len()
            && segments.windows(pattern.len()).any(|window| {
                window
                    .iter()
                    .zip(&pattern)
                    .all(|(segment, expected)| *expected == "*" || segment == expected)
            })
        {
            return Some(layer);
        }
    }
    None
}

pub fn layer_edges(
    graph: &DependencyGraph,
    layers: &[String],
) -> BTreeMap<String, BTreeSet<String>> {
    let mut edges: BTreeMap<String, BTreeSet<String>> = BTreeMap::new();
    for source in graph.nodes() {
        let Some(source_layer) = layer_for(source, layers) else {
            continue;
        };
        for target in graph.dependencies(source) {
            if let Some(target_layer) = layer_for(target, layers)
                && target_layer != source_layer
            {
                edges
                    .entry(source_layer.to_owned())
                    .or_default()
                    .insert(target_layer.to_owned());
            }
        }
    }
    edges
}