1use std::{collections::BTreeMap, sync::Arc};
2
3use portal_jsc_swc_util::{ImportMap, ImportMapper, ModuleMapper};
4use swc_atoms::Atom;
5use swc_common::{sync::Lrc, Mark, Spanned, SyntaxContext};
6use swc_ecma_ast::{
7 BlockStmt, CallExpr, Decl, Expr, ExprOrSpread, FnDecl, FnExpr, Function, Id, Ident, IdentName,
8 Import, ImportDecl, Lit, MemberExpr, MethodProp, Module, ModuleDecl, ModuleItem, ObjectLit,
9 PropOrSpread, ReturnStmt, Stmt, Str, VarDecl, VarDeclarator,
10};
11use swc_ecma_visit::{Visit, VisitMut, VisitMutWith};
12pub fn setup(mut module: Module) -> (ImportMapping, ModuleMapping) {
13 let mut i = ImportMapping::default();
14 module.visit_mut_with(&mut i);
15 (i, ModuleMapping::new(module))
16}
17
18#[derive(Default)]
19pub struct ImportMapping {
20 pub mapping: BTreeMap<(Atom, SyntaxContext), (Atom, ImportMap<Atom>)>,
21}
22impl VisitMut for ImportMapping {
23 fn visit_mut_import_decl(&mut self, a: &mut ImportDecl) {
24 let src = a.src.as_ref().value.clone();
25 for s in a.specifiers.iter() {
26 match s {
27 swc_ecma_ast::ImportSpecifier::Named(import_named_specifier) => {
28 if let Some(module) = &import_named_specifier.imported {
29 self.mapping.insert(
30 import_named_specifier.local.to_id(),
31 (
32 src.clone(),
33 ImportMap::Named {
34 name: module.atom().clone(),
35 },
36 ),
37 );
38 } else {
39 self.mapping.insert(
40 import_named_specifier.local.to_id(),
41 (
42 src.clone(),
43 ImportMap::Named {
44 name: import_named_specifier.local.to_id().0,
45 },
46 ),
47 );
48 }
49 }
50 swc_ecma_ast::ImportSpecifier::Default(import_default_specifier) => {
51 self.mapping.insert(
55 import_default_specifier.local.to_id(),
56 (src.clone(), ImportMap::Default),
57 );
58 }
60 swc_ecma_ast::ImportSpecifier::Namespace(import_star_as_specifier) => {
61 self.mapping.insert(
62 import_star_as_specifier.local.to_id(),
63 (src.clone(), ImportMap::Star),
64 );
65 }
66 }
67 }
68 a.visit_mut_children_with(self);
69 }
70 fn visit_mut_ident(&mut self, ident: &mut Ident) {
71 ident.visit_mut_children_with(self);
72 }
73}
74impl ImportMapper for ImportMapping {
75 fn import_of(&self, cx: &Id) -> Option<(Atom, ImportMap<Atom>)> {
76 if let Some(a) = self.mapping.get(cx) {
77 return Some(a.clone());
78 }
79 return None;
80 }
81}
82#[derive(Default)]
83pub struct ModuleMapping {
84 pub mapping: BTreeMap<Id, Arc<ModuleItem>>,
85 pub remainder: Vec<ModuleItem>,
86}
87impl ModuleMapper for ModuleMapping {
88 fn item_of(&self, id: &Id) -> Option<&ModuleItem> {
89 self.mapping.get(id).map(|a| &**a)
90 }
91}
92impl ModuleMapping {
93 pub fn new(m: Module) -> Self {
94 let mut r = vec![];
95 Self {
96 mapping: m
97 .body
98 .into_iter()
99 .flat_map(|d| {
100 let d = Arc::new(d);
102 match &*d {
103 ModuleItem::ModuleDecl(module_decl) => match &module_decl {
104 ModuleDecl::Import(import_decl) => import_decl
105 .specifiers
106 .iter()
107 .flat_map(|s| match s {
108 swc_ecma_ast::ImportSpecifier::Named(
109 import_named_specifier,
110 ) => vec![(import_named_specifier.local.to_id(), d.clone())],
111 swc_ecma_ast::ImportSpecifier::Default(
112 import_default_specifier,
113 ) => vec![(import_default_specifier.local.to_id(), d.clone())],
114 swc_ecma_ast::ImportSpecifier::Namespace(
115 import_star_as_specifier,
116 ) => vec![(import_star_as_specifier.local.to_id(), d.clone())],
117 })
118 .collect::<Vec<_>>(),
119 _ => {
120 r.push(d);
121 vec![]
122 }
123 },
124 ModuleItem::Stmt(stmt) => match stmt {
125 Stmt::Decl(d2) => match d2 {
126 Decl::Var(v) => v
127 .decls
128 .iter()
129 .filter_map(|d2| d2.name.as_ident())
130 .map(|i| (i.id.to_id(), d.clone()))
131 .collect(),
132 Decl::Fn(f) => vec![(f.ident.to_id(), d.clone())],
133 _ => {
134 r.push(d);
135 vec![]
136 }
137 },
138 _ => {
139 r.push(d);
140 vec![]
141 }
142 },
143 }
144 })
145 .collect(),
146 remainder: r.into_iter().map(|a| Arc::unwrap_or_clone(a)).collect(),
147 }
148 }
149}
150pub struct SourceMapper {
151 pub sm: Lrc<swc_common::SourceMap>,
152}
153impl VisitMut for SourceMapper {
154 fn visit_mut_decl(&mut self, node: &mut Decl) {
155 if let Decl::Fn(f) = node.clone() {
156 *node = Decl::Var(Box::new(VarDecl {
157 span: f.span(),
158 ctxt: f.ident.ctxt.clone(),
159 kind: swc_ecma_ast::VarDeclKind::Const,
160 declare: true,
161 decls: vec![VarDeclarator {
162 span: f.span(),
163 name: f.ident.clone().into(),
164 init: Some(Box::new(Expr::Fn(FnExpr {
165 ident: Some(f.ident),
166 function: f.function,
167 }))),
168 definite: false,
169 }],
170 }))
171 }
172 node.visit_mut_children_with(self);
173 }
174 fn visit_mut_expr(&mut self, node: &mut Expr) {
175 node.visit_mut_children_with(self);
176 if let Expr::Fn(f) = node.clone() {
177 let a = Expr::Object(ObjectLit {
178 span: f.span(),
179 props: vec![PropOrSpread::Prop(Box::new(swc_ecma_ast::Prop::Method(
180 MethodProp {
181 key: swc_ecma_ast::PropName::Ident(IdentName {
182 span: f.span(),
183 sym: Atom::new("toString"),
184 }),
185 function: Box::new(Function {
186 params: vec![],
187 decorators: vec![],
188 span: f.span(),
189 ctxt: f.function.ctxt.clone(),
190 body: Some(BlockStmt {
191 span: f.span(),
192 ctxt: f.function.ctxt.clone(),
193 stmts: vec![Stmt::Return(ReturnStmt {
194 span: f.span(),
195 arg: Some(Box::new(Expr::Lit(Lit::Str(Str {
196 span: f.span(),
197 raw: None,
198 value: Atom::new(self.sm.span_to_string(f.span())),
199 })))),
200 })],
201 }),
202 is_async: false,
203 is_generator: false,
204 type_params: None,
205 return_type: None,
206 }),
207 },
208 )))],
209 });
210 *node = Expr::Call(CallExpr {
211 span: f.span(),
212 ctxt: SyntaxContext::empty(),
213 callee: swc_ecma_ast::Callee::Expr(Box::new(Expr::Member(MemberExpr {
214 span: f.span(),
215 obj: Box::new(
216 Ident::new(Atom::new("Object"), f.span(), f.function.ctxt.clone()).into(),
217 ),
218 prop: swc_ecma_ast::MemberProp::Ident(IdentName {
219 span: f.span(),
220 sym: Atom::new("assign"),
221 }),
222 }))),
223 args: vec![
224 ExprOrSpread {
225 spread: None,
226 expr: Box::new(Expr::Fn(f)),
227 },
228 ExprOrSpread {
229 spread: None,
230 expr: Box::new(a),
231 },
232 ],
233 type_args: None,
234 })
235 }
236 }
237}