use oxc::{
allocator::{Allocator, GetAllocator},
ast::{
ast::{
Argument, BindingIdentifier, BindingPattern, Expression, FormalParameter,
FormalParameterKind, FormalParameters, FunctionBody, IdentifierName, Statement,
VariableDeclarator,
},
builder::{AstBuilder, GetAstBuilder},
},
ast_visit::{VisitJsMut, walk_js_mut},
span::SPAN,
};
const HELPER_NAME: &str = "__unwrap_lazy_compilation_entry";
pub struct LazyCompilationRuntimeInjector<'ast> {
ast_builder: AstBuilder<'ast>,
pub transformed_count: usize,
}
impl<'ast> LazyCompilationRuntimeInjector<'ast> {
pub fn new(allocator: &'ast Allocator) -> Self {
Self { ast_builder: AstBuilder::new(allocator), transformed_count: 0 }
}
}
impl<'ast> VisitJsMut<'ast> for LazyCompilationRuntimeInjector<'ast> {
fn visit_expression(&mut self, expr: &mut Expression<'ast>) {
walk_js_mut::walk_expression(self, expr);
if matches!(expr, Expression::ImportExpression(_)) {
let import_expr = std::mem::replace(expr, Expression::new_null_literal(SPAN, self));
*expr = Expression::new_call_expression(
SPAN,
Expression::new_static_member_expression(
SPAN,
import_expr,
IdentifierName::new(SPAN, "then", self),
false,
self,
),
None,
[Argument::new_identifier(SPAN, HELPER_NAME, self)],
false,
self,
);
self.transformed_count += 1;
}
}
}
impl<'ast> GetAstBuilder<'ast> for LazyCompilationRuntimeInjector<'ast> {
type Builder = AstBuilder<'ast>;
#[inline]
fn builder(&self) -> &AstBuilder<'ast> {
&self.ast_builder
}
}
impl<'ast> GetAllocator<'ast> for LazyCompilationRuntimeInjector<'ast> {
#[inline]
fn allocator(&self) -> &'ast Allocator {
self.ast_builder.allocator()
}
}
pub fn create_unwrap_lazy_compilation_entry_helper(allocator: &Allocator) -> Statement<'_> {
let ast_builder = AstBuilder::new(allocator);
let params = FormalParameters::boxed(
SPAN,
FormalParameterKind::FormalParameter,
[FormalParameter::new(
SPAN,
[],
BindingPattern::new_binding_identifier(SPAN, "m", &ast_builder),
None,
None,
false,
None,
false,
false,
&ast_builder,
)],
None,
&ast_builder,
);
let var_decl_stmt = Statement::new_variable_declaration(
SPAN,
oxc::ast::ast::VariableDeclarationKind::Var,
[VariableDeclarator::new(
SPAN,
BindingPattern::new_binding_identifier(SPAN, "e", &ast_builder),
None,
Some(Expression::new_computed_member_expression(
SPAN,
Expression::new_identifier(SPAN, "m", &ast_builder),
Expression::new_string_literal(SPAN, "rolldown:exports", None, &ast_builder),
false,
&ast_builder,
)),
false,
&ast_builder,
)],
false,
&ast_builder,
);
let return_stmt = Statement::new_return_statement(
SPAN,
Some(Expression::new_conditional_expression(
SPAN,
Expression::new_identifier(SPAN, "e", &ast_builder),
Expression::new_identifier(SPAN, "e", &ast_builder),
Expression::new_identifier(SPAN, "m", &ast_builder),
&ast_builder,
)),
&ast_builder,
);
let mut body_stmts = oxc::allocator::Vec::with_capacity_in(2, &ast_builder);
body_stmts.push(var_decl_stmt);
body_stmts.push(return_stmt);
let body = FunctionBody::boxed(SPAN, [], body_stmts, &ast_builder);
Statement::new_function_declaration(
SPAN,
oxc::ast::ast::FunctionType::FunctionDeclaration,
Some(BindingIdentifier::new(SPAN, HELPER_NAME, &ast_builder)),
false, false, false, None, None, params,
None, Some(body),
&ast_builder,
)
}