use copyless::BoxHelper;
use serde::{Deserialize, Serialize};
use swc_ecma_ast::{
DefaultDecl, ExportAll, ExportDecl, ExportDefaultDecl, ExportDefaultExpr,
ExportDefaultSpecifier, ExportNamedSpecifier, ExportNamespaceSpecifier, ExportSpecifier, Expr,
ImportDecl, ImportDefaultSpecifier, ImportNamedSpecifier, ImportSpecifier,
ImportStarAsSpecifier, Lit, ModuleDecl, ModuleExportName, NamedExport, ObjectLit, Prop,
PropName, PropOrSpread,
};
use swc_estree_ast::{
ExportAllDeclaration, ExportDefaultDeclType, ExportDefaultDeclaration,
ExportDefaultSpecifier as BabelExportDefaultSpecifier, ExportKind, ExportNamedDeclaration,
ExportNamespaceSpecifier as BabelExportNamespaceSpecifier,
ExportSpecifier as BabelExportSpecifier, ExportSpecifierType, IdOrString, ImportAttribute,
ImportDeclaration, ImportDefaultSpecifier as BabelImportDefaultSpecifier, ImportKind,
ImportNamespaceSpecifier, ImportSpecifier as BabelImportSpecifier, ImportSpecifierType,
ModuleDeclaration, ModuleExportNameType, TSExportAssignment, TSImportEqualsDeclaration,
TSNamespaceExportDeclaration,
};
use crate::babelify::{Babelify, Context};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ModuleDeclOutput {
Import(ImportDeclaration),
ExportDefault(ExportDefaultDeclaration),
ExportNamed(ExportNamedDeclaration),
ExportAll(ExportAllDeclaration),
TsImportEquals(TSImportEqualsDeclaration),
TsExportAssignment(TSExportAssignment),
TsNamespaceExport(TSNamespaceExportDeclaration),
}
impl Babelify for ModuleDecl {
type Output = ModuleDeclOutput;
fn babelify(self, ctx: &Context) -> Self::Output {
match self {
ModuleDecl::Import(i) => ModuleDeclOutput::Import(i.babelify(ctx)),
ModuleDecl::ExportDecl(e) => ModuleDeclOutput::ExportNamed(e.babelify(ctx)),
ModuleDecl::ExportNamed(n) => ModuleDeclOutput::ExportNamed(n.babelify(ctx)),
ModuleDecl::ExportDefaultDecl(e) => ModuleDeclOutput::ExportDefault(e.babelify(ctx)),
ModuleDecl::ExportDefaultExpr(e) => ModuleDeclOutput::ExportDefault(e.babelify(ctx)),
ModuleDecl::ExportAll(a) => ModuleDeclOutput::ExportAll(a.babelify(ctx)),
ModuleDecl::TsImportEquals(i) => ModuleDeclOutput::TsImportEquals(i.babelify(ctx)),
ModuleDecl::TsExportAssignment(a) => {
ModuleDeclOutput::TsExportAssignment(a.babelify(ctx))
}
ModuleDecl::TsNamespaceExport(e) => {
ModuleDeclOutput::TsNamespaceExport(e.babelify(ctx))
}
}
}
}
impl From<ModuleDeclOutput> for ModuleDeclaration {
fn from(module: ModuleDeclOutput) -> Self {
match module {
ModuleDeclOutput::Import(i) => ModuleDeclaration::Import(i),
ModuleDeclOutput::ExportDefault(e) => ModuleDeclaration::ExportDefault(e),
ModuleDeclOutput::ExportNamed(n) => ModuleDeclaration::ExportNamed(n),
ModuleDeclOutput::ExportAll(a) => ModuleDeclaration::ExportAll(a),
_ => panic!(
"illegal conversion: Cannot convert {:?} to ModuleDeclaration",
&module
),
}
}
}
impl Babelify for ExportDefaultExpr {
type Output = ExportDefaultDeclaration;
fn babelify(self, ctx: &Context) -> Self::Output {
ExportDefaultDeclaration {
base: ctx.base(self.span),
declaration: ExportDefaultDeclType::Expr(
Box::alloc().init(self.expr.babelify(ctx).into()),
),
}
}
}
impl Babelify for ExportDecl {
type Output = ExportNamedDeclaration;
fn babelify(self, ctx: &Context) -> Self::Output {
ExportNamedDeclaration {
base: ctx.base(self.span),
declaration: Some(Box::alloc().init(self.decl.babelify(ctx))),
specifiers: Default::default(),
source: Default::default(),
with: Default::default(),
export_kind: Default::default(),
}
}
}
fn convert_import_attrs(
asserts: Option<Box<ObjectLit>>,
ctx: &Context,
) -> Option<Vec<ImportAttribute>> {
asserts.map(|obj| {
let obj_span = obj.span;
obj.props
.into_iter()
.map(|prop_or_spread| {
let prop = match prop_or_spread {
PropOrSpread::Prop(p) => p,
_ => panic!(
"illegal conversion: Cannot convert {:?} to Prop",
&prop_or_spread
),
};
let (key, val) = match *prop {
Prop::KeyValue(keyval) => {
let key = match keyval.key {
PropName::Ident(i) => IdOrString::Id(i.babelify(ctx)),
PropName::Str(s) => IdOrString::String(s.babelify(ctx)),
_ => panic!(
"illegal conversion: Cannot convert {:?} to Prop::KeyValue",
&keyval.key
),
};
let val = match *keyval.value {
Expr::Lit(lit) => match lit {
Lit::Str(s) => s.babelify(ctx),
_ => panic!(
"illegal conversion: Cannot convert {:?} to Expr::Lit",
&lit
),
},
_ => panic!(
"illegal conversion: Cannot convert {:?} to Expr::Lit",
&keyval.value
),
};
(key, val)
}
_ => panic!(
"illegal conversion: Cannot convert {:?} to key, value",
&prop
),
};
ImportAttribute {
base: ctx.base(obj_span),
key,
value: val,
}
})
.collect()
})
}
impl Babelify for ImportDecl {
type Output = ImportDeclaration;
fn babelify(self, ctx: &Context) -> Self::Output {
ImportDeclaration {
base: ctx.base(self.span),
specifiers: self.specifiers.babelify(ctx),
source: self.src.babelify(ctx),
with: convert_import_attrs(self.with, ctx),
import_kind: if self.type_only {
Some(ImportKind::Type)
} else {
None
},
phase: self.phase.babelify(ctx),
}
}
}
impl Babelify for swc_ecma_ast::ImportPhase {
type Output = Option<swc_estree_ast::ImportPhase>;
fn babelify(self, _: &Context) -> Self::Output {
match self {
Self::Evaluation => None,
Self::Source => Some(swc_estree_ast::ImportPhase::Source),
Self::Defer => Some(swc_estree_ast::ImportPhase::Defer),
}
}
}
impl Babelify for ExportAll {
type Output = ExportAllDeclaration;
fn babelify(self, ctx: &Context) -> Self::Output {
ExportAllDeclaration {
base: ctx.base(self.span),
source: self.src.babelify(ctx),
with: convert_import_attrs(self.with, ctx),
export_kind: if self.type_only {
Some(ExportKind::Type)
} else {
None
},
}
}
}
impl Babelify for NamedExport {
type Output = ExportNamedDeclaration;
fn babelify(self, ctx: &Context) -> Self::Output {
ExportNamedDeclaration {
base: ctx.base(self.span),
declaration: Default::default(),
specifiers: self.specifiers.babelify(ctx),
source: self.src.map(|s| s.babelify(ctx)),
with: convert_import_attrs(self.with, ctx),
export_kind: if self.type_only {
Some(ExportKind::Type)
} else {
None
},
}
}
}
impl Babelify for ExportDefaultDecl {
type Output = ExportDefaultDeclaration;
fn babelify(self, ctx: &Context) -> Self::Output {
ExportDefaultDeclaration {
base: ctx.base(self.span),
declaration: self.decl.babelify(ctx),
}
}
}
impl Babelify for DefaultDecl {
type Output = ExportDefaultDeclType;
fn babelify(self, ctx: &Context) -> Self::Output {
match self {
DefaultDecl::Class(c) => ExportDefaultDeclType::Class(c.babelify(ctx).into()),
DefaultDecl::Fn(f) => ExportDefaultDeclType::Func(f.babelify(ctx).into()),
DefaultDecl::TsInterfaceDecl(_) => panic!("unimplemented"), }
}
}
impl Babelify for ImportSpecifier {
type Output = ImportSpecifierType;
fn babelify(self, ctx: &Context) -> Self::Output {
match self {
ImportSpecifier::Named(s) => ImportSpecifierType::Import(s.babelify(ctx)),
ImportSpecifier::Default(s) => ImportSpecifierType::Default(s.babelify(ctx)),
ImportSpecifier::Namespace(s) => ImportSpecifierType::Namespace(s.babelify(ctx)),
}
}
}
impl Babelify for ImportDefaultSpecifier {
type Output = BabelImportDefaultSpecifier;
fn babelify(self, ctx: &Context) -> Self::Output {
BabelImportDefaultSpecifier {
base: ctx.base(self.span),
local: self.local.babelify(ctx),
}
}
}
impl Babelify for ImportStarAsSpecifier {
type Output = ImportNamespaceSpecifier;
fn babelify(self, ctx: &Context) -> Self::Output {
ImportNamespaceSpecifier {
base: ctx.base(self.span),
local: self.local.babelify(ctx),
}
}
}
impl Babelify for ImportNamedSpecifier {
type Output = BabelImportSpecifier;
fn babelify(self, ctx: &Context) -> Self::Output {
BabelImportSpecifier {
base: ctx.base(self.span),
local: self.local.clone().babelify(ctx),
imported: self
.imported
.unwrap_or(ModuleExportName::Ident(self.local))
.babelify(ctx),
import_kind: if self.is_type_only {
Some(ImportKind::Type)
} else {
None
},
}
}
}
impl Babelify for ExportSpecifier {
type Output = ExportSpecifierType;
fn babelify(self, ctx: &Context) -> Self::Output {
match self {
ExportSpecifier::Named(s) => ExportSpecifierType::Export(s.babelify(ctx)),
ExportSpecifier::Default(s) => ExportSpecifierType::Default(s.babelify(ctx)),
ExportSpecifier::Namespace(s) => ExportSpecifierType::Namespace(s.babelify(ctx)),
}
}
}
impl Babelify for ExportNamespaceSpecifier {
type Output = BabelExportNamespaceSpecifier;
fn babelify(self, ctx: &Context) -> Self::Output {
BabelExportNamespaceSpecifier {
base: ctx.base(self.span),
exported: self.name.babelify(ctx),
}
}
}
impl Babelify for ExportDefaultSpecifier {
type Output = BabelExportDefaultSpecifier;
fn babelify(self, ctx: &Context) -> Self::Output {
let exported = self.exported.babelify(ctx);
BabelExportDefaultSpecifier {
base: exported.base.clone(),
exported,
}
}
}
impl Babelify for ExportNamedSpecifier {
type Output = BabelExportSpecifier;
fn babelify(self, ctx: &Context) -> Self::Output {
BabelExportSpecifier {
base: ctx.base(self.span),
local: self.orig.clone().babelify(ctx),
exported: self.exported.unwrap_or(self.orig).babelify(ctx),
export_kind: if self.is_type_only {
ExportKind::Type
} else {
ExportKind::Value
},
}
}
}
impl Babelify for ModuleExportName {
type Output = ModuleExportNameType;
fn babelify(self, ctx: &Context) -> Self::Output {
match self {
ModuleExportName::Ident(ident) => ModuleExportNameType::Ident(ident.babelify(ctx)),
ModuleExportName::Str(..) => unimplemented!("module string names unimplemented"),
}
}
}