use oxc::span::CompactStr;
use crate::{stages::link_stage::LinkStageOutput, utils::renamer::Renamer};
use arcstr::ArcStr;
use rolldown_common::{
Chunk, ChunkIdx, ChunkKind, GetLocalDb, ModuleScopeSymbolIdMap, OutputFormat, TaggedSymbolRef,
};
use rolldown_utils::ecmascript::legitimize_identifier_name;
use rustc_hash::FxHashMap;
#[tracing::instrument(level = "trace", skip_all)]
pub fn deconflict_chunk_symbols(
chunk: &mut Chunk,
link_output: &LinkStageOutput,
format: OutputFormat,
index_chunk_id_to_name: &FxHashMap<ChunkIdx, ArcStr>,
map: &ModuleScopeSymbolIdMap<'_>,
) {
let mut renamer = Renamer::new(&link_output.symbol_db, format);
if matches!(format, OutputFormat::Iife | OutputFormat::Umd | OutputFormat::Cjs) {
chunk
.direct_imports_from_external_modules
.iter()
.filter_map(|(idx, _)| link_output.module_table[*idx].as_external())
.for_each(|external_module| {
renamer.add_symbol_in_root_scope(external_module.namespace_ref);
});
chunk
.import_symbol_from_external_modules
.iter()
.filter_map(|idx| link_output.module_table[*idx].as_external())
.for_each(|external_module| {
renamer.add_symbol_in_root_scope(external_module.namespace_ref);
});
match chunk.entry_module_idx() {
Some(module) => {
let entry_module =
link_output.module_table[module].as_normal().expect("should be normal module");
link_output.metas[entry_module.idx].star_exports_from_external_modules.iter().for_each(
|rec_idx| {
let rec = &entry_module.ecma_view.import_records[*rec_idx];
let external_module = &link_output.module_table[rec.resolved_module]
.as_external()
.expect("Should be external module here");
renamer.add_symbol_in_root_scope(external_module.namespace_ref);
},
);
}
None => {}
}
}
chunk
.modules
.iter()
.copied()
.filter_map(|id| link_output.module_table[id].as_normal())
.flat_map(|m| {
link_output.symbol_db[m.idx]
.as_ref()
.unwrap()
.ast_scopes
.scoping()
.root_unresolved_references()
.keys()
})
.for_each(|name| {
renamer.reserve(CompactStr::new(name));
});
match chunk.kind {
ChunkKind::EntryPoint { module, .. } => {
let meta = &link_output.metas[module];
meta.referenced_symbols_by_entry_point_chunk.iter().for_each(
|(symbol_ref, came_from_cjs)| {
if !came_from_cjs {
renamer.add_symbol_in_root_scope(*symbol_ref);
}
},
);
}
ChunkKind::Common => {}
}
if matches!(format, OutputFormat::Esm) {
chunk.direct_imports_from_external_modules.iter().for_each(|(module, _)| {
let db = link_output.symbol_db.local_db(*module);
db.classic_data.iter_enumerated().for_each(|(symbol, _)| {
let symbol_ref = (*module, symbol).into();
if link_output.used_symbol_refs.contains(&symbol_ref) {
renamer.add_symbol_in_root_scope(symbol_ref);
}
});
for symbol_id in db.ast_scopes.facade_symbol_classic_data().keys() {
let symbol_ref = (*module, *symbol_id).into();
if link_output.used_symbol_refs.contains(&symbol_ref) {
renamer.add_symbol_in_root_scope(symbol_ref);
}
}
});
}
chunk
.modules
.iter()
.copied()
.rev()
.filter_map(|id| link_output.module_table[id].as_normal())
.for_each(|module| {
if let Some(hmr_hot_ref) = module.hmr_hot_ref {
renamer.add_symbol_in_root_scope(hmr_hot_ref);
}
module
.stmt_infos
.iter()
.filter(|stmt_info| stmt_info.is_included)
.flat_map(|stmt_info| {
stmt_info
.declared_symbols
.iter()
.filter(|item| matches!(item, TaggedSymbolRef::Normal(_)))
.copied()
})
.for_each(|symbol_ref| {
renamer.add_symbol_in_root_scope(symbol_ref.inner());
});
});
chunk.imports_from_other_chunks.iter().flat_map(|(_, items)| items.iter()).for_each(|item| {
renamer.add_symbol_in_root_scope(item.import_ref);
});
chunk.require_binding_names_for_other_chunks = chunk
.imports_from_other_chunks
.iter()
.map(|(id, _)| {
(
*id,
renamer.create_conflictless_name(&legitimize_identifier_name(&format!(
"require_{}",
index_chunk_id_to_name[id]
))),
)
})
.collect();
renamer.rename_non_root_symbol(&chunk.modules, link_output, map);
chunk.canonical_names = renamer.into_canonical_names();
}