mod propagate;
#[cfg(test)]
mod tests;
use rustc_hash::{FxHashMap, FxHashSet};
use fallow_types::discover::FileId;
use super::ModuleGraph;
use propagate::{propagate_named_re_export, propagate_star_re_export};
impl ModuleGraph {
pub(super) fn resolve_re_export_chains(&mut self) {
let re_export_info: Vec<(FileId, FileId, String, String)> = self
.modules
.iter()
.flat_map(|m| {
m.re_exports.iter().map(move |re| {
(
m.file_id,
re.source_file,
re.imported_name.clone(),
re.exported_name.clone(),
)
})
})
.collect();
if re_export_info.is_empty() {
return;
}
let entry_star_targets: FxHashSet<FileId> = self
.modules
.iter()
.filter(|m| m.is_entry_point())
.flat_map(|m| {
m.re_exports
.iter()
.filter(|re| re.exported_name == "*")
.map(|re| re.source_file)
})
.collect();
let mut edges_by_target: FxHashMap<FileId, Vec<usize>> = FxHashMap::default();
for (idx, edge) in self.edges.iter().enumerate() {
edges_by_target.entry(edge.target).or_default().push(idx);
}
let mut changed = true;
let max_iterations = 20; let mut iteration = 0;
let mut existing_refs: FxHashSet<FileId> = FxHashSet::default();
while changed && iteration < max_iterations {
changed = false;
iteration += 1;
for &(barrel_id, source_id, ref imported_name, ref exported_name) in &re_export_info {
let barrel_idx = barrel_id.0 as usize;
let source_idx = source_id.0 as usize;
if barrel_idx >= self.modules.len() || source_idx >= self.modules.len() {
continue;
}
if exported_name == "*" {
changed |= propagate_star_re_export(
&mut self.modules,
&self.edges,
&edges_by_target,
barrel_id,
barrel_idx,
source_idx,
&entry_star_targets,
);
} else {
changed |= propagate_named_re_export(
&mut self.modules,
barrel_id,
barrel_idx,
source_idx,
imported_name,
exported_name,
&mut existing_refs,
);
}
}
}
if iteration >= max_iterations {
tracing::warn!(
iterations = max_iterations,
"Re-export chain resolution hit iteration limit, some chains may be incomplete"
);
}
}
}