use std::path::Path;
use crate::containment::matches_forbidden;
use crate::crate_scope::{extern_resolution, resolve_principal};
use crate::finding::{ExposureKind, SemanticFact, shape_finding, sort_facts};
use crate::module_resolve::resolve_module_items;
use crate::resolve::{ShapeExposure, UseMap, canonical_path_str, collect_uses};
pub(crate) fn shape_module_findings<E>(
src_dir: &Path,
root_file: &Path,
module: &str,
crate_package: &str,
collect: impl Fn(&syn::Item, &str, &UseMap, usize, &mut Vec<E>),
render: impl Fn(E) -> SemanticFact,
) -> Result<Vec<SemanticFact>, String> {
let items = resolve_module_items(src_dir, root_file, module, crate_package)?;
let uses = collect_uses(&items);
let mut collected = Vec::new();
for (ordinal, item) in items.iter().enumerate() {
collect(item, module, &uses, ordinal, &mut collected);
}
let mut findings: Vec<SemanticFact> = collected.into_iter().map(render).collect();
sort_facts(&mut findings);
Ok(findings)
}
pub(crate) fn operand_module_findings(
src_dir: &Path,
root_file: &Path,
module: &str,
forbidden: &[String],
crate_package: &str,
dep_names: &[String],
(fact_kind, collect): (
ExposureKind,
impl Fn(&syn::Item, &str, &UseMap, usize, &mut Vec<ShapeExposure>),
),
) -> Result<Vec<SemanticFact>, String> {
let items = resolve_module_items(src_dir, root_file, module, crate_package)?;
let uses = collect_uses(&items);
let resolution = extern_resolution(src_dir, root_file, crate_package, dep_names, &items)?;
let forbidden: Vec<String> = forbidden.iter().map(|f| canonical_path_str(f)).collect();
let mut exposures = Vec::new();
for (ordinal, item) in items.iter().enumerate() {
collect(item, module, &uses, ordinal, &mut exposures);
}
let mut findings: Vec<SemanticFact> = exposures
.into_iter()
.filter(|exposure| {
forbidden.is_empty()
|| exposure.principals.iter().any(|path| {
resolve_principal(path, &uses, module, &resolution)
.is_some_and(|canonical| matches_forbidden(&canonical, &forbidden))
})
})
.map(|exposure| shape_finding(exposure, fact_kind))
.collect();
sort_facts(&mut findings);
Ok(findings)
}