portal_jsc_swc_batch/
lib.rs

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                    // if let Some(module) = &import_named_specifier.imported{
52                    //     self.mapping.insert(import_named_specifier.local.to_id(), (Mark::new(),src.clone(),Some(module.atom().clone())));
53                    //     }else{
54                    self.mapping.insert(
55                        import_default_specifier.local.to_id(),
56                        (src.clone(), ImportMap::Default),
57                    );
58                    // }
59                }
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                    // match d{ModuleItem::ModuleDecl(d) => {
101                    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}