use oxc::ast::ast::{self, Expression, IdentifierReference};
use rolldown_common::SymbolRef;
use rolldown_ecmascript_utils::ExpressionExt;
use super::ScopeHoistingFinalizer;
impl<'ast> ScopeHoistingFinalizer<'_, 'ast> {
pub fn generate_finalized_expr_for_reference(
&self,
id_ref: &IdentifierReference<'ast>,
is_callee: bool,
) -> Option<ast::Expression<'ast>> {
let reference_id = id_ref.reference_id.get()?;
let symbol_id = self.scope.symbol_id_for(reference_id)?;
let symbol_ref: SymbolRef = (self.ctx.idx, symbol_id).into();
let (mut expr, _) = self.finalized_expr_for_symbol_ref(symbol_ref, is_callee, false);
match &mut expr {
ast::Expression::Identifier(it) => {
it.span = id_ref.span;
}
ast::Expression::StaticMemberExpression(it) => {
it.span = id_ref.span;
it.property.span = id_ref.span;
if let Some(object) = it.object.as_identifier_mut() {
object.span = id_ref.span;
}
}
_ => {}
}
Some(expr)
}
pub fn generate_finalized_simple_assignment_target_for_reference(
&self,
id_ref: &IdentifierReference,
) -> Option<ast::SimpleAssignmentTarget<'ast>> {
let reference_id = id_ref.reference_id.get()?;
let symbol_id = self.scope.symbol_id_for(reference_id)?;
let symbol_ref: SymbolRef = (self.ctx.idx, symbol_id).into();
let canonical_ref = self.ctx.symbol_db.canonical_ref_for(symbol_ref);
let symbol = self.ctx.symbol_db.get(canonical_ref);
if let Some(ns_alias) = &symbol.namespace_alias {
let canonical_ns_name = self.canonical_name_for(ns_alias.namespace_ref);
let prop_name = &ns_alias.property_name;
let access_expr = self.snippet.literal_prop_access_member_expr(canonical_ns_name, prop_name);
return Some(ast::SimpleAssignmentTarget::from(access_expr));
}
let canonical_name = self.canonical_name_for(canonical_ref);
if id_ref.name != canonical_name {
return Some(ast::SimpleAssignmentTarget::AssignmentTargetIdentifier(
self.snippet.alloc_id_ref(canonical_name, id_ref.span),
));
}
None
}
pub fn try_rewrite_identifier_reference_expr(
&self,
ident_ref: &ast::IdentifierReference<'ast>,
is_callee: bool,
) -> Option<Expression<'ast>> {
if self.ctx.module.dummy_record_set.contains(&ident_ref.span) {
return Some(self.finalized_expr_for_runtime_symbol("__require"));
}
if let Some(new_expr) = self.generate_finalized_expr_for_reference(ident_ref, is_callee) {
Some(new_expr)
} else {
ident_ref.reference_id.take();
None
}
}
pub fn rewrite_simple_assignment_target(
&self,
target: &mut ast::SimpleAssignmentTarget<'ast>,
) -> Option<()> {
match target {
ast::SimpleAssignmentTarget::AssignmentTargetIdentifier(target_id_ref) => {
let reference_id = target_id_ref.reference_id.get()?;
let symbol_id = self.scope.symbol_id_for(reference_id)?;
let symbol_ref = (self.ctx.idx, symbol_id).into();
let canonical_ref = self.ctx.symbol_db.canonical_ref_for(symbol_ref);
let symbol = self.ctx.symbol_db.get(canonical_ref);
if let Some(ns_alias) = &symbol.namespace_alias {
*target =
ast::SimpleAssignmentTarget::from(self.snippet.literal_prop_access_member_expr(
self.canonical_name_for(ns_alias.namespace_ref),
&ns_alias.property_name,
));
} else {
let canonical_name = self.canonical_name_for(canonical_ref);
if target_id_ref.name != canonical_name {
target_id_ref.name = self.snippet.atom(canonical_name).into();
}
target_id_ref.reference_id.take();
}
}
ast::SimpleAssignmentTarget::StaticMemberExpression(_)
| ast::SimpleAssignmentTarget::ComputedMemberExpression(_) => {
if let Some(new_target) = self.try_rewrite_cjs_member_expr_assignment_target(target) {
*target = new_target;
}
}
_ => {}
}
None
}
pub fn rewrite_object_pat_shorthand(&self, pat: &mut ast::ObjectPattern<'ast>) {
for prop in &mut pat.properties {
match &mut prop.value {
ast::BindingPattern::BindingIdentifier(ident) if prop.shorthand => {
if let Some(symbol_id) = ident.symbol_id.get() {
let canonical_name = self.canonical_name_for((self.ctx.idx, symbol_id).into());
if ident.name != canonical_name {
ident.name = self.snippet.atom(canonical_name).into();
prop.shorthand = false;
}
ident.symbol_id.get_mut().take();
}
}
ast::BindingPattern::AssignmentPattern(assign_pat) if prop.shorthand => {
let ast::BindingPattern::BindingIdentifier(ident) = &mut assign_pat.left else {
continue;
};
if let Some(symbol_id) = ident.symbol_id.get() {
let canonical_name = self.canonical_name_for((self.ctx.idx, symbol_id).into());
if ident.name != canonical_name {
ident.name = self.snippet.atom(canonical_name).into();
prop.shorthand = false;
}
ident.symbol_id.get_mut().take();
}
}
_ => {
}
}
}
}
}