rolldown_ast_template 0.0.1

rolldown_ast_template
Documentation
use swc_core::{
  common::util::take::Take,
  ecma::{ast, atoms::JsWord, utils::quote_ident},
};

pub fn build_exports_stmt(mut exports: Vec<(JsWord, ast::Id)>) -> ast::ModuleItem {
  use ast::{ExportNamedSpecifier, ExportSpecifier, ModuleDecl, ModuleExportName, NamedExport};
  exports.sort_by(|a, b| a.0.cmp(&b.0));

  ast::ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {
    span: Default::default(),
    specifiers: exports
      .into_iter()
      .filter(|(name, _)| name != "*")
      .map(|(name, id)| {
        ExportSpecifier::Named(ExportNamedSpecifier {
          span: Default::default(),
          orig: ModuleExportName::Ident(id.into()),
          exported: Some(quote_ident!(name).into()),
          is_type_only: false,
        })
      })
      .collect::<Vec<_>>(),
    src: None,
    type_only: false,
    asserts: None,
  }))
}

pub fn build_namespace_export_stmt(
  var_name: ast::Id,
  exports: Vec<(JsWord, ast::Id)>,
  external_module_ids: Vec<ast::Id>,
) -> ast::ModuleItem {
  use ast::*;
  let mut exported_name_and_local_id_list = exports.into_iter().collect::<Vec<_>>();
  exported_name_and_local_id_list.sort_by(|a, b| a.0.cmp(&b.0));
  let exports_props = [PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
    key: quote_ident!("__proto__").into(),
    value: Box::new(Expr::Lit(Lit::Null(Null::dummy()))),
  })))]
  .into_iter()
  .chain(
    &mut exported_name_and_local_id_list
      .into_iter()
      .map(|(exported_name, local_id)| {
        PropOrSpread::Prop(Box::new(Prop::Getter(GetterProp {
          span: Default::default(),
          key: Ident::verify_symbol(&exported_name)
            .map(|_| PropName::Ident(quote_ident!(exported_name.clone())))
            .unwrap_or_else(|_| PropName::Str(exported_name.into())),
          type_ann: None,
          body: Some(BlockStmt {
            span: Default::default(),
            stmts: vec![ast::Stmt::Return(ReturnStmt {
              span: Default::default(),
              arg: Some(local_id.into()),
            })],
          }),
        })))
      }),
  )
  .collect::<Vec<_>>();

  if external_module_ids.is_empty() {
    ModuleItem::ModuleDecl(ast::ModuleDecl::ExportDecl(ast::ExportDecl {
      span: Default::default(),
      decl: ast::Decl::Var(Box::new(VarDecl {
        span: Default::default(),
        kind: VarDeclKind::Var,
        declare: false,
        decls: vec![VarDeclarator {
          span: Default::default(),
          definite: false,
          name: var_name.into(),
          init: Some(Box::new(Expr::Call(CallExpr {
            callee: Callee::Expr(Box::new(Expr::Member(MemberExpr {
              obj: quote_ident!("Object").into(),
              prop: quote_ident!("freeze").into(),
              ..MemberExpr::dummy()
            }))),
            args: vec![ExprOrSpread {
              expr: Box::new(Expr::Object(ObjectLit {
                span: Default::default(),
                props: exports_props,
              })),
              spread: None,
            }],
            ..CallExpr::dummy()
          }))),
        }],
      })),
    }))
  } else {
    let merge_namespace_call = Expr::Call(CallExpr {
      callee: Callee::Expr(quote_ident!("_mergeNamespaces").into()),
      args: vec![
        ExprOrSpread {
          expr: Box::new(Expr::Object(ObjectLit {
            span: Default::default(),
            props: exports_props,
          })),
          spread: None,
        },
        ExprOrSpread {
          expr: Box::new(ast::Expr::Array(ast::ArrayLit {
            span: Default::default(),
            elems: external_module_ids
              .into_iter()
              .map(|id| {
                Some(ExprOrSpread {
                  expr: id.into(),
                  spread: None,
                })
              })
              .collect(),
          })),
          spread: None,
        },
      ],
      ..CallExpr::dummy()
    });
    ModuleItem::ModuleDecl(ast::ModuleDecl::ExportDecl(ast::ExportDecl {
      span: Default::default(),
      decl: Decl::Var(Box::new(VarDecl {
        span: Default::default(),
        kind: VarDeclKind::Var,
        declare: false,
        decls: vec![VarDeclarator {
          span: Default::default(),
          definite: false,
          name: var_name.into(),
          init: Some(Box::new(merge_namespace_call)),
        }],
      })),
    }))
  }
}