use farmfe_core::{
module::{meta_data::script::EXPORT_NAMESPACE, module_graph::ModuleGraph, ModuleId},
plugin::ResolveKind,
swc_common::{Mark, SyntaxContext, DUMMY_SP},
swc_ecma_ast::{CallExpr, Callee, Expr, Ident, IdentName, MemberExpr, MemberProp},
HashMap, HashSet,
};
use swc_ecma_visit::{VisitMut, VisitMutWith};
use crate::script::create_export_namespace_ident;
use super::unique_idents::TopLevelIdentsRenameHandler;
pub struct DynamicImportVisitor<'a> {
module_id: &'a ModuleId,
module_graph: &'a ModuleGraph,
module_ids: &'a HashSet<ModuleId>,
rename_handler: &'a TopLevelIdentsRenameHandler,
unresolved_mark: Mark,
pub external_modules: HashMap<(String, ResolveKind), ModuleId>,
}
impl<'a> DynamicImportVisitor<'a> {
pub fn new(
module_id: &'a ModuleId,
module_graph: &'a ModuleGraph,
module_ids: &'a HashSet<ModuleId>,
rename_handler: &'a TopLevelIdentsRenameHandler,
) -> Self {
let module = module_graph.module(module_id).unwrap();
let unresolved_mark = module.meta.as_script().unresolved_mark;
Self {
module_id,
module_graph,
module_ids,
rename_handler,
unresolved_mark: Mark::from_u32(unresolved_mark),
external_modules: HashMap::default(),
}
}
}
impl<'a> VisitMut for DynamicImportVisitor<'a> {
fn visit_mut_call_expr(&mut self, call_expr: &mut CallExpr) {
call_expr.visit_mut_children_with(self);
if !call_expr.callee.is_import() {
return;
}
let source = match &call_expr.args[0].expr.as_lit() {
Some(lit) => match lit {
farmfe_core::swc_ecma_ast::Lit::Str(s) => s.value.to_string(),
_ => return,
},
None => return,
};
let dep_module_id = self.module_graph.get_dep_by_source(
self.module_id,
&source,
Some(ResolveKind::DynamicImport),
);
if self.module_ids.contains(&dep_module_id) {
let dep_module = self.module_graph.module(&dep_module_id).unwrap();
if dep_module.external || !dep_module.module_type.is_script() {
return;
}
let namespace_ident = if let Some(export_ident) = dep_module
.meta
.as_script()
.export_ident_map
.get(EXPORT_NAMESPACE)
{
export_ident.as_internal().ident.clone()
} else {
create_export_namespace_ident(&dep_module_id).to_id().into()
};
let namespace_ident = self
.rename_handler
.get_renamed_ident(&dep_module_id, &namespace_ident)
.unwrap_or(namespace_ident);
let ctxt = namespace_ident.ctxt();
*call_expr = CallExpr {
span: DUMMY_SP,
callee: Callee::Expr(Box::new(Expr::Member(MemberExpr {
span: DUMMY_SP,
obj: Box::new(Expr::Ident(Ident::new(
"Promise".into(),
DUMMY_SP,
SyntaxContext::empty().apply_mark(self.unresolved_mark),
))),
prop: MemberProp::Ident(IdentName {
sym: "resolve".into(),
span: DUMMY_SP,
}),
}))),
args: vec![farmfe_core::swc_ecma_ast::ExprOrSpread {
spread: None,
expr: Box::new(Expr::Ident(Ident::new(namespace_ident.sym, DUMMY_SP, ctxt))),
}],
type_args: None,
ctxt: SyntaxContext::empty(),
};
}
else {
self
.external_modules
.insert((source, ResolveKind::DynamicImport), dep_module_id);
}
}
}