use oxc_allocator::TakeIn;
use oxc_ast::{NONE, ast::*};
use oxc_semantic::SymbolFlags;
use oxc_span::SPAN;
use oxc_traverse::Traverse;
use crate::{context::TraverseCtx, state::TransformState};
pub struct ExportNamespaceFrom;
impl ExportNamespaceFrom {
pub fn new() -> Self {
Self
}
}
impl<'a> Traverse<'a, TransformState<'a>> for ExportNamespaceFrom {
fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
let has_export_namespace = program.body.iter().any(
|stmt| matches!(stmt, Statement::ExportAllDeclaration(decl) if decl.exported.is_some()),
);
if !has_export_namespace {
return;
}
let mut new_statements = ctx.ast.vec_with_capacity(program.body.len());
for stmt in program.body.take_in(ctx.ast) {
match stmt {
Statement::ExportAllDeclaration(export_all) if export_all.exported.is_some() => {
let ExportAllDeclaration { span, exported, source, export_kind, .. } =
export_all.unbox();
let exported_name = exported.unwrap();
let binding = ctx.generate_uid_based_on_node(
&exported_name,
program.scope_id(),
SymbolFlags::Import,
);
let import_specifier = ImportDeclarationSpecifier::ImportNamespaceSpecifier(
ctx.ast.alloc_import_namespace_specifier(
SPAN,
binding.create_binding_identifier(ctx),
),
);
let import_decl = ctx.ast.alloc_import_declaration(
SPAN,
Some(ctx.ast.vec1(import_specifier)),
source,
None,
NONE,
export_kind,
);
new_statements.push(Statement::ImportDeclaration(import_decl));
let local =
ModuleExportName::IdentifierReference(binding.create_read_reference(ctx));
let export_specifier =
ctx.ast.export_specifier(span, local, exported_name, export_kind);
let export_named_decl = ctx.ast.alloc_export_named_declaration(
span,
None,
ctx.ast.vec1(export_specifier),
None,
export_kind,
NONE,
);
new_statements.push(Statement::ExportNamedDeclaration(export_named_decl));
}
_ => {
new_statements.push(stmt);
}
}
}
program.body = new_statements;
}
}