mirror of
https://github.com/swc-project/swc.git
synced 2024-11-24 02:06:08 +03:00
refactor(es/module): Reimplement some functions of module/typescript (#8063)
This commit is contained in:
parent
70ec648a63
commit
3e5b062cd2
@ -5,20 +5,22 @@ use swc_atoms::{js_word, JsWord};
|
||||
use swc_common::{
|
||||
comments::{CommentKind, Comments},
|
||||
util::take::Take,
|
||||
FileName, Mark, Span, Spanned, DUMMY_SP,
|
||||
FileName, Mark, Span, DUMMY_SP,
|
||||
};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_transforms_base::{feature::FeatureFlag, helper_expr};
|
||||
use swc_ecma_utils::{
|
||||
member_expr, private_ident, quote_ident, quote_str, ExprFactory, FunctionFactory, IsDirective,
|
||||
member_expr, private_ident, quote_ident, quote_str, undefined, ExprFactory, FunctionFactory,
|
||||
IsDirective,
|
||||
};
|
||||
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
|
||||
|
||||
pub use super::util::Config as InnerConfig;
|
||||
use crate::{
|
||||
module_decl_strip::{Export, Link, LinkFlag, LinkItem, LinkSpecifierReducer, ModuleDeclStrip},
|
||||
module_ref_rewriter::{ImportMap, ModuleRefRewriter},
|
||||
module_ref_rewriter::{rewrite_import_bindings, ImportMap},
|
||||
path::{ImportResolver, Resolver},
|
||||
top_level_this::top_level_this,
|
||||
util::{
|
||||
define_es_module, emit_export_stmts, local_name_for_src, use_strict, ImportInterop,
|
||||
VecStmtLike,
|
||||
@ -130,17 +132,10 @@ where
|
||||
noop_visit_mut_type!();
|
||||
|
||||
fn visit_mut_module(&mut self, n: &mut Module) {
|
||||
if let Some(first) = n.body.first() {
|
||||
if self.module_id.is_none() {
|
||||
self.module_id = self.get_amd_module_id_from_comments(first.span());
|
||||
}
|
||||
if self.module_id.is_none() {
|
||||
self.module_id = self.get_amd_module_id_from_comments(n.span);
|
||||
}
|
||||
|
||||
let import_interop = self.config.import_interop();
|
||||
|
||||
let mut strip = ModuleDeclStrip::new(self.const_var_kind);
|
||||
n.body.visit_mut_with(&mut strip);
|
||||
|
||||
let mut stmts: Vec<Stmt> = Vec::with_capacity(n.body.len() + 4);
|
||||
|
||||
// Collect directives
|
||||
@ -158,6 +153,15 @@ where
|
||||
stmts.push(use_strict());
|
||||
}
|
||||
|
||||
if !self.config.allow_top_level_this {
|
||||
top_level_this(&mut n.body, *undefined(DUMMY_SP));
|
||||
}
|
||||
|
||||
let import_interop = self.config.import_interop();
|
||||
|
||||
let mut strip = ModuleDeclStrip::new(self.const_var_kind);
|
||||
n.body.visit_mut_with(&mut strip);
|
||||
|
||||
let ModuleDeclStrip {
|
||||
link,
|
||||
export,
|
||||
@ -197,11 +201,7 @@ where
|
||||
stmts.visit_mut_children_with(self);
|
||||
}
|
||||
|
||||
stmts.visit_mut_children_with(&mut ModuleRefRewriter::new(
|
||||
import_map,
|
||||
Default::default(),
|
||||
self.config.allow_top_level_this,
|
||||
));
|
||||
rewrite_import_bindings(&mut stmts, import_map, Default::default());
|
||||
|
||||
// ====================
|
||||
// Emit
|
||||
@ -348,7 +348,7 @@ where
|
||||
|
||||
let mut stmts = Vec::with_capacity(link.len());
|
||||
|
||||
let mut export_obj_prop_list = export.into_iter().map(From::from).collect();
|
||||
let mut export_obj_prop_list = export.into_iter().collect();
|
||||
|
||||
link.into_iter().for_each(
|
||||
|(src, LinkItem(src_span, link_specifier_set, mut link_flag))| {
|
||||
@ -429,7 +429,7 @@ where
|
||||
let mut export_stmts = Default::default();
|
||||
|
||||
if !export_obj_prop_list.is_empty() && !is_export_assign {
|
||||
export_obj_prop_list.sort_by_cached_key(|v| v.key().clone());
|
||||
export_obj_prop_list.sort_by_cached_key(|(key, ..)| key.clone());
|
||||
|
||||
let exports = self.exports();
|
||||
|
||||
|
@ -1,23 +1,26 @@
|
||||
use swc_atoms::js_word;
|
||||
use swc_common::{
|
||||
collections::AHashSet, comments::Comments, util::take::Take, FileName, Mark, Span, Spanned,
|
||||
DUMMY_SP,
|
||||
collections::AHashSet, comments::Comments, util::take::Take, FileName, Mark, Span, DUMMY_SP,
|
||||
};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_transforms_base::{feature::FeatureFlag, helper_expr};
|
||||
use swc_ecma_utils::{
|
||||
member_expr, private_ident, quote_expr, quote_ident, ExprFactory, FunctionFactory, IsDirective,
|
||||
member_expr, private_ident, quote_expr, quote_ident, undefined, ExprFactory, FunctionFactory,
|
||||
IsDirective,
|
||||
};
|
||||
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
|
||||
|
||||
pub use super::util::Config;
|
||||
use crate::{
|
||||
module_decl_strip::{Export, Link, LinkFlag, LinkItem, LinkSpecifierReducer, ModuleDeclStrip},
|
||||
module_ref_rewriter::{ImportMap, ModuleRefRewriter},
|
||||
module_decl_strip::{
|
||||
Export, ExportKV, Link, LinkFlag, LinkItem, LinkSpecifierReducer, ModuleDeclStrip,
|
||||
},
|
||||
module_ref_rewriter::{rewrite_import_bindings, ImportMap},
|
||||
path::{ImportResolver, Resolver},
|
||||
top_level_this::top_level_this,
|
||||
util::{
|
||||
define_es_module, emit_export_stmts, local_name_for_src, prop_name, use_strict,
|
||||
ImportInterop, ObjPropKeyIdent, VecStmtLike,
|
||||
ImportInterop, VecStmtLike,
|
||||
},
|
||||
};
|
||||
|
||||
@ -91,6 +94,26 @@ where
|
||||
noop_visit_mut_type!();
|
||||
|
||||
fn visit_mut_module(&mut self, n: &mut Module) {
|
||||
let mut stmts: Vec<ModuleItem> = Vec::with_capacity(n.body.len() + 6);
|
||||
|
||||
// Collect directives
|
||||
stmts.extend(
|
||||
&mut n
|
||||
.body
|
||||
.iter_mut()
|
||||
.take_while(|i| i.directive_continue())
|
||||
.map(|i| i.take()),
|
||||
);
|
||||
|
||||
// "use strict";
|
||||
if self.config.strict_mode && !stmts.has_use_strict() {
|
||||
stmts.push(use_strict().into());
|
||||
}
|
||||
|
||||
if !self.config.allow_top_level_this {
|
||||
top_level_this(&mut n.body, *undefined(DUMMY_SP));
|
||||
}
|
||||
|
||||
let import_interop = self.config.import_interop();
|
||||
|
||||
let mut module_map = Default::default();
|
||||
@ -111,22 +134,6 @@ where
|
||||
let mut strip = ModuleDeclStrip::new(self.const_var_kind);
|
||||
n.body.visit_mut_with(&mut strip);
|
||||
|
||||
let mut stmts: Vec<ModuleItem> = Vec::with_capacity(n.body.len() + 6);
|
||||
|
||||
// Collect directives
|
||||
stmts.extend(
|
||||
&mut n
|
||||
.body
|
||||
.iter_mut()
|
||||
.take_while(|i| i.directive_continue())
|
||||
.map(|i| i.take()),
|
||||
);
|
||||
|
||||
// "use strict";
|
||||
if self.config.strict_mode && !stmts.has_use_strict() {
|
||||
stmts.push(use_strict().into());
|
||||
}
|
||||
|
||||
let ModuleDeclStrip {
|
||||
link,
|
||||
export,
|
||||
@ -181,11 +188,7 @@ where
|
||||
stmts.visit_mut_children_with(self);
|
||||
}
|
||||
|
||||
stmts.visit_mut_children_with(&mut ModuleRefRewriter::new(
|
||||
module_map,
|
||||
lazy_record,
|
||||
self.config.allow_top_level_this,
|
||||
));
|
||||
rewrite_import_bindings(&mut stmts, module_map, lazy_record);
|
||||
|
||||
n.body = stmts;
|
||||
}
|
||||
@ -271,7 +274,7 @@ where
|
||||
|
||||
let mut stmts = Vec::with_capacity(link.len());
|
||||
|
||||
let mut export_obj_prop_list = export.into_iter().map(From::from).collect();
|
||||
let mut export_obj_prop_list = export.into_iter().collect();
|
||||
|
||||
let lexer_reexport = if export_interop_annotation {
|
||||
self.emit_lexer_reexport(&link)
|
||||
@ -364,7 +367,7 @@ where
|
||||
let mut export_stmts: Vec<Stmt> = Default::default();
|
||||
|
||||
if !export_obj_prop_list.is_empty() && !is_export_assign {
|
||||
export_obj_prop_list.sort_by_cached_key(|v| v.key().clone());
|
||||
export_obj_prop_list.sort_by_cached_key(|(key, ..)| key.clone());
|
||||
|
||||
let mut features = self.available_features;
|
||||
let exports = self.exports();
|
||||
@ -457,17 +460,17 @@ where
|
||||
/// 0 && (exports.foo = 0);
|
||||
/// 0 && (module.exports = { foo: _, bar: _ });
|
||||
/// ```
|
||||
fn emit_lexer_exports_init(&mut self, export_id_list: &[ObjPropKeyIdent]) -> Option<Stmt> {
|
||||
fn emit_lexer_exports_init(&mut self, export_id_list: &[ExportKV]) -> Option<Stmt> {
|
||||
match export_id_list.len() {
|
||||
0 => None,
|
||||
1 => {
|
||||
let expr: Expr = 0.into();
|
||||
|
||||
let key_value = &export_id_list[0];
|
||||
let prop = prop_name(key_value.key(), DUMMY_SP).into();
|
||||
let (key, export_item) = &export_id_list[0];
|
||||
let prop = prop_name(key, DUMMY_SP).into();
|
||||
let export_binding = MemberExpr {
|
||||
obj: Box::new(self.exports().into()),
|
||||
span: key_value.span(),
|
||||
span: export_item.export_name_span(),
|
||||
prop,
|
||||
};
|
||||
let expr = expr.make_assign_to(op!("="), export_binding.as_pat_or_expr());
|
||||
@ -483,7 +486,7 @@ where
|
||||
_ => {
|
||||
let props = export_id_list
|
||||
.iter()
|
||||
.map(|key_value| prop_name(key_value.key(), DUMMY_SP))
|
||||
.map(|(key, ..)| prop_name(key, DUMMY_SP))
|
||||
.map(|key| KeyValueProp {
|
||||
key: key.into(),
|
||||
// `cjs-module-lexer` only support identifier as value
|
||||
|
@ -17,6 +17,7 @@ pub(crate) mod module_ref_rewriter;
|
||||
pub mod path;
|
||||
pub mod rewriter;
|
||||
pub mod system_js;
|
||||
mod top_level_this;
|
||||
pub mod umd;
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
|
@ -9,10 +9,12 @@ use swc_ecma_ast::*;
|
||||
use swc_ecma_utils::{find_pat_ids, ident::IdentLike, private_ident, quote_ident, ExprFactory};
|
||||
use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
|
||||
|
||||
use crate::{module_ref_rewriter::ImportMap, util::ObjPropKeyIdent};
|
||||
use crate::module_ref_rewriter::ImportMap;
|
||||
|
||||
/// key: module path
|
||||
pub type Link = IndexMap<JsWord, LinkItem>;
|
||||
pub type Export = AHashMap<(JsWord, Span), Ident>;
|
||||
/// key: export binding name
|
||||
pub type Export = AHashMap<JsWord, ExportItem>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ModuleDeclStrip {
|
||||
@ -135,17 +137,18 @@ impl VisitMut for ModuleDeclStrip {
|
||||
fn visit_mut_export_decl(&mut self, n: &mut ExportDecl) {
|
||||
match &n.decl {
|
||||
Decl::Class(ClassDecl { ident, .. }) | Decl::Fn(FnDecl { ident, .. }) => {
|
||||
let ident = ident.clone();
|
||||
|
||||
self.export.insert((ident.sym.clone(), ident.span), ident);
|
||||
self.export.insert(
|
||||
ident.sym.clone(),
|
||||
ExportItem::new(ident.span, ident.clone()),
|
||||
);
|
||||
}
|
||||
|
||||
Decl::Var(v) => {
|
||||
self.export
|
||||
.extend(find_pat_ids::<_, Ident>(&v.decls).into_iter().map(|id| {
|
||||
let ident = id.clone();
|
||||
((id.sym, id.span), ident)
|
||||
}));
|
||||
self.export.extend(
|
||||
find_pat_ids::<_, Ident>(&v.decls)
|
||||
.into_iter()
|
||||
.map(|id| (id.sym.clone(), ExportItem::new(id.span, id))),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
@ -189,15 +192,14 @@ impl VisitMut for ModuleDeclStrip {
|
||||
};
|
||||
|
||||
if let Some(exported) = exported {
|
||||
let exported = match exported {
|
||||
let (export_name, export_name_span) = match exported {
|
||||
ModuleExportName::Ident(Ident { span, sym, .. }) => (sym, span),
|
||||
ModuleExportName::Str(Str { span, value, .. }) => (value, span),
|
||||
};
|
||||
|
||||
(exported, orig)
|
||||
(export_name, ExportItem::new(export_name_span, orig))
|
||||
} else {
|
||||
let exported = orig.sym.clone();
|
||||
((exported, orig.span), orig)
|
||||
(orig.sym.clone(), ExportItem::new(orig.span, orig))
|
||||
}
|
||||
}
|
||||
}))
|
||||
@ -225,7 +227,8 @@ impl VisitMut for ModuleDeclStrip {
|
||||
.get_or_insert_with(|| private_ident!(n.span, "_default"))
|
||||
.clone();
|
||||
|
||||
self.export.insert((js_word!("default"), n.span), ident);
|
||||
self.export
|
||||
.insert(js_word!("default"), ExportItem::new(n.span, ident));
|
||||
}
|
||||
DefaultDecl::Fn(fn_expr) => {
|
||||
let ident = fn_expr
|
||||
@ -233,7 +236,8 @@ impl VisitMut for ModuleDeclStrip {
|
||||
.get_or_insert_with(|| private_ident!(n.span, "_default"))
|
||||
.clone();
|
||||
|
||||
self.export.insert((js_word!("default"), n.span), ident);
|
||||
self.export
|
||||
.insert(js_word!("default"), ExportItem::new(n.span, ident));
|
||||
}
|
||||
DefaultDecl::TsInterfaceDecl(_) => {}
|
||||
}
|
||||
@ -252,7 +256,7 @@ impl VisitMut for ModuleDeclStrip {
|
||||
let ident = private_ident!(n.span, "_default");
|
||||
|
||||
self.export
|
||||
.insert((js_word!("default"), n.span), ident.clone());
|
||||
.insert(js_word!("default"), ExportItem::new(n.span, ident.clone()));
|
||||
|
||||
self.export_default = Some(Stmt::Decl(
|
||||
n.expr
|
||||
@ -306,7 +310,8 @@ impl VisitMut for ModuleDeclStrip {
|
||||
}) = module_ref
|
||||
{
|
||||
if *is_export {
|
||||
self.export.insert((id.sym.clone(), id.span), id.clone());
|
||||
self.export
|
||||
.insert(id.sym.clone(), ExportItem::new(id.span, id.clone()));
|
||||
}
|
||||
|
||||
self.link
|
||||
@ -623,7 +628,7 @@ impl LinkItem {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type ExportObjPropList = Vec<ObjPropKeyIdent>;
|
||||
pub(crate) type ExportObjPropList = Vec<ExportKV>;
|
||||
|
||||
/// Reduce self to generate ImportMap and ExportObjPropList
|
||||
pub(crate) trait LinkSpecifierReducer {
|
||||
@ -687,10 +692,13 @@ impl LinkSpecifierReducer for AHashSet<LinkSpecifier> {
|
||||
// foo -> mod.foo
|
||||
import_map.insert(orig.to_id(), (mod_ident.clone(), Some(orig.0.clone())));
|
||||
|
||||
let exported = exported.unwrap_or_else(|| orig.clone());
|
||||
let (export_name, export_name_span) = exported.unwrap_or_else(|| orig.clone());
|
||||
|
||||
// bar -> foo
|
||||
export_obj_prop_list.push((exported, quote_ident!(orig.1, orig.0)).into())
|
||||
export_obj_prop_list.push((
|
||||
export_name,
|
||||
ExportItem::new(export_name_span, quote_ident!(orig.1, orig.0)),
|
||||
))
|
||||
}
|
||||
LinkSpecifier::ExportDefaultAs(_, key, span) => {
|
||||
*ref_to_mod_ident = true;
|
||||
@ -702,20 +710,19 @@ impl LinkSpecifierReducer for AHashSet<LinkSpecifier> {
|
||||
// export { foo };
|
||||
// ```
|
||||
|
||||
let exported = (key.clone(), span);
|
||||
|
||||
// foo -> mod.default
|
||||
import_map.insert(
|
||||
exported.to_id(),
|
||||
(key.clone(), span).to_id(),
|
||||
(mod_ident.clone(), Some("default".into())),
|
||||
);
|
||||
|
||||
export_obj_prop_list.push((exported, quote_ident!(span, key)).into())
|
||||
export_obj_prop_list
|
||||
.push((key.clone(), ExportItem::new(span, quote_ident!(span, key))));
|
||||
}
|
||||
LinkSpecifier::ExportStarAs(key, span) => {
|
||||
*ref_to_mod_ident = true;
|
||||
|
||||
export_obj_prop_list.push((key, span, mod_ident.clone()).into())
|
||||
export_obj_prop_list.push((key, ExportItem::new(span, mod_ident.clone())));
|
||||
}
|
||||
LinkSpecifier::ExportStar => {}
|
||||
LinkSpecifier::ImportEqual(id) => {
|
||||
@ -733,3 +740,22 @@ impl LinkSpecifierReducer for AHashSet<LinkSpecifier> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ExportItem(Span, Ident);
|
||||
|
||||
impl ExportItem {
|
||||
pub fn new(export_name_span: Span, local_ident: Ident) -> Self {
|
||||
Self(export_name_span, local_ident)
|
||||
}
|
||||
|
||||
pub fn export_name_span(&self) -> Span {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn into_local_ident(self) -> Ident {
|
||||
self.1
|
||||
}
|
||||
}
|
||||
|
||||
pub type ExportKV = (JsWord, ExportItem);
|
||||
|
@ -1,19 +1,18 @@
|
||||
use swc_atoms::JsWord;
|
||||
use swc_common::{
|
||||
collections::{AHashMap, AHashSet},
|
||||
util::take::Take,
|
||||
SyntaxContext, DUMMY_SP,
|
||||
};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_transforms_base::helpers::HELPERS;
|
||||
use swc_ecma_utils::{undefined, ExprFactory, IntoIndirectCall};
|
||||
use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
|
||||
use swc_ecma_utils::{ExprFactory, QueryRef, RefRewriter};
|
||||
use swc_ecma_visit::VisitMutWith;
|
||||
|
||||
use crate::util::prop_name;
|
||||
|
||||
pub type ImportMap = AHashMap<Id, (Ident, Option<JsWord>)>;
|
||||
|
||||
pub(crate) struct ModuleRefRewriter {
|
||||
pub(crate) struct ImportQuery {
|
||||
/// ```javascript
|
||||
/// import foo, { a as b, c } from "mod";
|
||||
/// import * as x from "x";
|
||||
@ -32,167 +31,18 @@ pub(crate) struct ModuleRefRewriter {
|
||||
/// x => (_x, None),
|
||||
/// )
|
||||
/// ```
|
||||
pub import_map: ImportMap,
|
||||
|
||||
pub lazy_record: AHashSet<Id>,
|
||||
|
||||
pub allow_top_level_this: bool,
|
||||
|
||||
is_global_this: bool,
|
||||
import_map: ImportMap,
|
||||
lazy_record: AHashSet<Id>,
|
||||
helper_ctxt: Option<SyntaxContext>,
|
||||
}
|
||||
|
||||
impl ModuleRefRewriter {
|
||||
pub fn new(
|
||||
import_map: ImportMap,
|
||||
lazy_record: AHashSet<Id>,
|
||||
allow_top_level_this: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
import_map,
|
||||
lazy_record,
|
||||
allow_top_level_this,
|
||||
is_global_this: true,
|
||||
helper_ctxt: {
|
||||
HELPERS
|
||||
.is_set()
|
||||
.then(|| HELPERS.with(|helper| helper.mark()))
|
||||
.map(|mark| SyntaxContext::empty().apply_mark(mark))
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VisitMut for ModuleRefRewriter {
|
||||
noop_visit_mut_type!();
|
||||
|
||||
/// replace bar in binding pattern
|
||||
/// const foo = { bar }
|
||||
fn visit_mut_prop(&mut self, n: &mut Prop) {
|
||||
match n {
|
||||
Prop::Shorthand(shorthand) => {
|
||||
if let Some(expr) = self.map_module_ref_ident(shorthand) {
|
||||
*n = KeyValueProp {
|
||||
key: shorthand.take().into(),
|
||||
value: Box::new(expr),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
_ => n.visit_mut_children_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_expr(&mut self, n: &mut Expr) {
|
||||
match n {
|
||||
Expr::Ident(ref_ident) => {
|
||||
if let Some(expr) = self.map_module_ref_ident(ref_ident) {
|
||||
*n = expr;
|
||||
}
|
||||
}
|
||||
|
||||
Expr::This(ThisExpr { span }) => {
|
||||
if !self.allow_top_level_this && self.is_global_this {
|
||||
*n = *undefined(*span);
|
||||
}
|
||||
}
|
||||
|
||||
_ => n.visit_mut_children_with(self),
|
||||
};
|
||||
}
|
||||
|
||||
fn visit_mut_callee(&mut self, n: &mut Callee) {
|
||||
match n {
|
||||
Callee::Expr(e) if e.is_ident() => {
|
||||
let is_indirect_callee = e
|
||||
.as_ident()
|
||||
.filter(|ident| self.helper_ctxt.iter().all(|ctxt| ctxt != &ident.span.ctxt))
|
||||
.and_then(|ident| self.import_map.get(&ident.to_id()))
|
||||
.map(|(_, prop)| prop.is_some())
|
||||
.unwrap_or_default();
|
||||
|
||||
e.visit_mut_with(self);
|
||||
|
||||
if is_indirect_callee {
|
||||
*n = n.take().into_indirect()
|
||||
}
|
||||
}
|
||||
|
||||
_ => n.visit_mut_children_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_tagged_tpl(&mut self, n: &mut TaggedTpl) {
|
||||
let is_indirect = n
|
||||
.tag
|
||||
.as_ident()
|
||||
.filter(|ident| self.helper_ctxt.iter().all(|ctxt| ctxt != &ident.span.ctxt))
|
||||
.and_then(|ident| self.import_map.get(&ident.to_id()))
|
||||
.map(|(_, prop)| prop.is_some())
|
||||
.unwrap_or_default();
|
||||
|
||||
n.visit_mut_children_with(self);
|
||||
|
||||
if is_indirect {
|
||||
*n = n.take().into_indirect()
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_function(&mut self, n: &mut Function) {
|
||||
self.visit_mut_with_non_global_this(n);
|
||||
}
|
||||
|
||||
fn visit_mut_constructor(&mut self, n: &mut Constructor) {
|
||||
self.visit_mut_with_non_global_this(n);
|
||||
}
|
||||
|
||||
fn visit_mut_class_prop(&mut self, n: &mut ClassProp) {
|
||||
n.key.visit_mut_with(self);
|
||||
|
||||
self.visit_mut_with_non_global_this(&mut n.value);
|
||||
}
|
||||
|
||||
fn visit_mut_private_prop(&mut self, n: &mut PrivateProp) {
|
||||
n.key.visit_mut_with(self);
|
||||
|
||||
self.visit_mut_with_non_global_this(&mut n.value);
|
||||
}
|
||||
|
||||
fn visit_mut_getter_prop(&mut self, n: &mut GetterProp) {
|
||||
n.key.visit_mut_with(self);
|
||||
|
||||
self.visit_mut_with_non_global_this(&mut n.body);
|
||||
}
|
||||
|
||||
fn visit_mut_setter_prop(&mut self, n: &mut SetterProp) {
|
||||
n.key.visit_mut_with(self);
|
||||
|
||||
self.visit_mut_with_non_global_this(&mut n.body);
|
||||
}
|
||||
|
||||
fn visit_mut_static_block(&mut self, n: &mut StaticBlock) {
|
||||
self.visit_mut_with_non_global_this(n);
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleRefRewriter {
|
||||
fn visit_mut_with_non_global_this<T>(&mut self, n: &mut T)
|
||||
where
|
||||
T: VisitMutWith<Self>,
|
||||
{
|
||||
let top_level = self.is_global_this;
|
||||
|
||||
self.is_global_this = false;
|
||||
n.visit_mut_children_with(self);
|
||||
self.is_global_this = top_level;
|
||||
}
|
||||
|
||||
fn map_module_ref_ident(&mut self, ref_ident: &Ident) -> Option<Expr> {
|
||||
impl QueryRef for ImportQuery {
|
||||
fn query_ref(&self, ident: &Ident) -> Option<Expr> {
|
||||
self.import_map
|
||||
.get(&ref_ident.to_id())
|
||||
.get(&ident.to_id())
|
||||
.map(|(mod_ident, mod_prop)| -> Expr {
|
||||
let mut mod_ident = mod_ident.clone();
|
||||
let span = ref_ident.span.with_ctxt(mod_ident.span.ctxt);
|
||||
let span = ident.span.with_ctxt(mod_ident.span.ctxt);
|
||||
mod_ident.span = span;
|
||||
|
||||
let mod_expr = if self.lazy_record.contains(&mod_ident.to_id()) {
|
||||
@ -215,4 +65,43 @@ impl ModuleRefRewriter {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn query_lhs(&self, _: &Ident) -> Option<Expr> {
|
||||
// import binding cannot be used as lhs
|
||||
None
|
||||
}
|
||||
|
||||
fn should_fix_this(&self, ident: &Ident) -> bool {
|
||||
if self.helper_ctxt.iter().any(|ctxt| ctxt == &ident.span.ctxt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.import_map
|
||||
.get(&ident.to_id())
|
||||
.map(|(_, prop)| prop.is_some())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn rewrite_import_bindings<V>(
|
||||
node: &mut V,
|
||||
import_map: ImportMap,
|
||||
lazy_record: AHashSet<Id>,
|
||||
) where
|
||||
V: VisitMutWith<RefRewriter<ImportQuery>>,
|
||||
{
|
||||
let mut v = RefRewriter {
|
||||
query: ImportQuery {
|
||||
import_map,
|
||||
lazy_record,
|
||||
helper_ctxt: {
|
||||
HELPERS
|
||||
.is_set()
|
||||
.then(|| HELPERS.with(|helper| helper.mark()))
|
||||
.map(|mark| SyntaxContext::empty().apply_mark(mark))
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
node.visit_mut_with(&mut v);
|
||||
}
|
||||
|
84
crates/swc_ecma_transforms_module/src/top_level_this.rs
Normal file
84
crates/swc_ecma_transforms_module/src/top_level_this.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
|
||||
|
||||
pub struct TopLevelThis {
|
||||
found: bool,
|
||||
this: Expr,
|
||||
}
|
||||
|
||||
pub(crate) fn top_level_this<V>(node: &mut V, replace_with: Expr) -> bool
|
||||
where
|
||||
V: VisitMutWith<TopLevelThis>,
|
||||
{
|
||||
let mut v = TopLevelThis {
|
||||
this: replace_with,
|
||||
found: false,
|
||||
};
|
||||
node.visit_mut_with(&mut v);
|
||||
v.found
|
||||
}
|
||||
|
||||
impl VisitMut for TopLevelThis {
|
||||
noop_visit_mut_type!();
|
||||
|
||||
noop_visit_mut_type!(visit_mut_function, Function);
|
||||
|
||||
fn visit_mut_class_member(&mut self, n: &mut ClassMember) {
|
||||
match n {
|
||||
ClassMember::Method(ClassMethod {
|
||||
key: PropName::Computed(computed),
|
||||
..
|
||||
})
|
||||
| ClassMember::ClassProp(ClassProp {
|
||||
key: PropName::Computed(computed),
|
||||
..
|
||||
}) => {
|
||||
computed.visit_mut_with(self);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_prop(&mut self, n: &mut Prop) {
|
||||
match n {
|
||||
Prop::KeyValue(..) => {
|
||||
n.visit_mut_children_with(self);
|
||||
}
|
||||
Prop::Getter(GetterProp {
|
||||
key: PropName::Computed(computed),
|
||||
..
|
||||
})
|
||||
| Prop::Setter(SetterProp {
|
||||
key: PropName::Computed(computed),
|
||||
..
|
||||
})
|
||||
| Prop::Method(MethodProp {
|
||||
key: PropName::Computed(computed),
|
||||
..
|
||||
}) => computed.visit_mut_children_with(self),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_expr(&mut self, n: &mut Expr) {
|
||||
if let Expr::This(ThisExpr { span }) = n {
|
||||
self.found = true;
|
||||
|
||||
let mut this = self.this.clone();
|
||||
match &mut this {
|
||||
// for void 0
|
||||
Expr::Unary(unary_expr) => unary_expr.span = *span,
|
||||
Expr::Ident(ident) => ident.span = *span,
|
||||
Expr::Member(member) => member.span = *span,
|
||||
|
||||
_ => {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
*n = this;
|
||||
} else {
|
||||
n.visit_mut_children_with(self);
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ use swc_common::{
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_transforms_base::{feature::FeatureFlag, helper_expr};
|
||||
use swc_ecma_utils::{
|
||||
is_valid_prop_ident, private_ident, quote_ident, quote_str, ExprFactory, IsDirective,
|
||||
is_valid_prop_ident, private_ident, quote_ident, quote_str, undefined, ExprFactory, IsDirective,
|
||||
};
|
||||
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
|
||||
|
||||
@ -14,8 +14,9 @@ use self::config::BuiltConfig;
|
||||
pub use self::config::Config;
|
||||
use crate::{
|
||||
module_decl_strip::{Export, Link, LinkFlag, LinkItem, LinkSpecifierReducer, ModuleDeclStrip},
|
||||
module_ref_rewriter::{ImportMap, ModuleRefRewriter},
|
||||
module_ref_rewriter::{rewrite_import_bindings, ImportMap},
|
||||
path::{ImportResolver, Resolver},
|
||||
top_level_this::top_level_this,
|
||||
util::{
|
||||
define_es_module, emit_export_stmts, local_name_for_src, use_strict, ImportInterop,
|
||||
VecStmtLike,
|
||||
@ -107,13 +108,8 @@ where
|
||||
noop_visit_mut_type!();
|
||||
|
||||
fn visit_mut_module(&mut self, module: &mut Module) {
|
||||
let import_interop = self.config.config.import_interop();
|
||||
|
||||
let module_items = &mut module.body;
|
||||
|
||||
let mut strip = ModuleDeclStrip::new(self.const_var_kind);
|
||||
module_items.visit_mut_with(&mut strip);
|
||||
|
||||
let mut stmts: Vec<Stmt> = Vec::with_capacity(module_items.len() + 4);
|
||||
|
||||
// Collect directives
|
||||
@ -130,6 +126,15 @@ where
|
||||
stmts.push(use_strict());
|
||||
}
|
||||
|
||||
if !self.config.config.allow_top_level_this {
|
||||
top_level_this(module_items, *undefined(DUMMY_SP));
|
||||
}
|
||||
|
||||
let import_interop = self.config.config.import_interop();
|
||||
|
||||
let mut strip = ModuleDeclStrip::new(self.const_var_kind);
|
||||
module_items.visit_mut_with(&mut strip);
|
||||
|
||||
let ModuleDeclStrip {
|
||||
link,
|
||||
export,
|
||||
@ -165,11 +170,7 @@ where
|
||||
stmts.push(return_stmt.into())
|
||||
}
|
||||
|
||||
stmts.visit_mut_children_with(&mut ModuleRefRewriter::new(
|
||||
import_map,
|
||||
Default::default(),
|
||||
self.config.config.allow_top_level_this,
|
||||
));
|
||||
rewrite_import_bindings(&mut stmts, import_map, Default::default());
|
||||
|
||||
// ====================
|
||||
// Emit
|
||||
@ -220,7 +221,7 @@ where
|
||||
|
||||
let mut stmts = Vec::with_capacity(link.len());
|
||||
|
||||
let mut export_obj_prop_list = export.into_iter().map(From::from).collect();
|
||||
let mut export_obj_prop_list = export.into_iter().collect();
|
||||
|
||||
link.into_iter().for_each(
|
||||
|(src, LinkItem(src_span, link_specifier_set, mut link_flag))| {
|
||||
@ -301,7 +302,7 @@ where
|
||||
let mut export_stmts = Default::default();
|
||||
|
||||
if !export_obj_prop_list.is_empty() && !is_export_assign {
|
||||
export_obj_prop_list.sort_by_cached_key(|v| v.key().clone());
|
||||
export_obj_prop_list.sort_by_cached_key(|(key, ..)| key.clone());
|
||||
|
||||
let exports = self.exports();
|
||||
|
||||
|
@ -2,13 +2,15 @@ use is_macro::Is;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use swc_atoms::{js_word, JsWord};
|
||||
use swc_cached::regex::CachedRegex;
|
||||
use swc_common::{Span, Spanned, DUMMY_SP};
|
||||
use swc_common::{Span, DUMMY_SP};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_utils::{
|
||||
is_valid_prop_ident, member_expr, private_ident, quote_ident, quote_str, ExprFactory,
|
||||
FunctionFactory, IsDirective,
|
||||
};
|
||||
|
||||
use crate::module_decl_strip::{ExportItem, ExportKV};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||
pub struct Config {
|
||||
@ -324,15 +326,19 @@ pub(crate) fn esm_export() -> Function {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn emit_export_stmts(exports: Ident, mut prop_list: Vec<ObjPropKeyIdent>) -> Vec<Stmt> {
|
||||
pub(crate) fn emit_export_stmts(exports: Ident, mut prop_list: Vec<ExportKV>) -> Vec<Stmt> {
|
||||
match prop_list.len() {
|
||||
0 | 1 => prop_list
|
||||
.pop()
|
||||
.map(|obj_prop| {
|
||||
.map(|(export_name, export_item)| {
|
||||
object_define_enumerable(
|
||||
exports.as_arg(),
|
||||
quote_str!(obj_prop.span(), obj_prop.key()).as_arg(),
|
||||
prop_function((js_word!("get"), DUMMY_SP, obj_prop.2.clone()).into()).into(),
|
||||
quote_str!(export_item.export_name_span(), export_name).as_arg(),
|
||||
prop_function((
|
||||
js_word!("get"),
|
||||
ExportItem::new(DUMMY_SP, export_item.into_local_ident()),
|
||||
))
|
||||
.into(),
|
||||
)
|
||||
.into_stmt()
|
||||
})
|
||||
@ -397,39 +403,6 @@ impl From<IdentOrStr> for MemberProp {
|
||||
}
|
||||
}
|
||||
|
||||
/// {
|
||||
/// "key": ident,
|
||||
/// }
|
||||
pub(crate) struct ObjPropKeyIdent(JsWord, Span, Ident);
|
||||
|
||||
impl From<((JsWord, Span), Ident)> for ObjPropKeyIdent {
|
||||
fn from(((key, span), ident): ((JsWord, Span), Ident)) -> Self {
|
||||
Self(key, span, ident)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(JsWord, Span, Ident)> for ObjPropKeyIdent {
|
||||
fn from((key, span, ident): (JsWord, Span, Ident)) -> Self {
|
||||
Self(key, span, ident)
|
||||
}
|
||||
}
|
||||
|
||||
impl Spanned for ObjPropKeyIdent {
|
||||
fn span(&self) -> Span {
|
||||
self.1
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjPropKeyIdent {
|
||||
pub fn key(&self) -> &JsWord {
|
||||
&self.0
|
||||
}
|
||||
|
||||
pub fn into_expr(self) -> Expr {
|
||||
self.2.into()
|
||||
}
|
||||
}
|
||||
|
||||
/// ```javascript
|
||||
/// {
|
||||
/// key: function() {
|
||||
@ -437,13 +410,14 @@ impl ObjPropKeyIdent {
|
||||
/// },
|
||||
/// }
|
||||
/// ```
|
||||
pub(crate) fn prop_function(prop: ObjPropKeyIdent) -> Prop {
|
||||
let key = prop_name(prop.key(), prop.span()).into();
|
||||
pub(crate) fn prop_function((key, export_item): ExportKV) -> Prop {
|
||||
let key = prop_name(&key, export_item.export_name_span()).into();
|
||||
|
||||
KeyValueProp {
|
||||
key,
|
||||
value: Box::new(
|
||||
prop.into_expr()
|
||||
export_item
|
||||
.into_local_ident()
|
||||
.into_lazy_fn(Default::default())
|
||||
.into_fn_expr(None)
|
||||
.into(),
|
||||
|
@ -7,12 +7,10 @@ use swc_common::{
|
||||
};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_utils::{
|
||||
alias_ident_for, constructor::inject_after_super, is_literal, member_expr, private_ident,
|
||||
quote_ident, quote_str, ExprFactory,
|
||||
};
|
||||
use swc_ecma_visit::{
|
||||
as_folder, noop_visit_mut_type, noop_visit_type, Fold, Visit, VisitMut, VisitMutWith, VisitWith,
|
||||
alias_ident_for, constructor::inject_after_super, find_pat_ids, is_literal, member_expr,
|
||||
private_ident, quote_ident, quote_str, ExprFactory, QueryRef, RefRewriter,
|
||||
};
|
||||
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};
|
||||
|
||||
use crate::{
|
||||
config::TsImportExportAssignConfig,
|
||||
@ -468,10 +466,7 @@ impl Transform {
|
||||
}
|
||||
|
||||
if !mutable_export_ids.is_empty() {
|
||||
stmts.visit_mut_with(&mut ExportRefRewrriter {
|
||||
namesapce_id: id,
|
||||
export_id_list: mutable_export_ids,
|
||||
});
|
||||
rewrite_export_bindings(&mut stmts, id, mutable_export_ids);
|
||||
}
|
||||
|
||||
BlockStmt { span, stmts }
|
||||
@ -638,9 +633,7 @@ impl Transform {
|
||||
) -> Option<Stmt> {
|
||||
debug_assert!(!var_decl.declare);
|
||||
|
||||
let mut collector = ExportedIdentCollector::default();
|
||||
var_decl.visit_with(&mut collector);
|
||||
mutable_export_ids.extend(collector.export_list);
|
||||
mutable_export_ids.extend(find_pat_ids(&var_decl));
|
||||
|
||||
var_decl.decls.visit_mut_with(&mut ExportedPatRewriter {
|
||||
id: id.clone().into(),
|
||||
@ -1154,79 +1147,42 @@ impl VisitMut for ExportedPatRewriter {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ExportedIdentCollector {
|
||||
export_list: Vec<Id>,
|
||||
}
|
||||
|
||||
impl Visit for ExportedIdentCollector {
|
||||
noop_visit_type!();
|
||||
|
||||
fn visit_binding_ident(&mut self, n: &BindingIdent) {
|
||||
self.export_list.push(n.to_id());
|
||||
}
|
||||
|
||||
fn visit_assign_pat_prop(&mut self, n: &AssignPatProp) {
|
||||
self.export_list.push(n.key.to_id());
|
||||
|
||||
n.visit_children_with(self);
|
||||
}
|
||||
|
||||
fn visit_var_declarator(&mut self, n: &VarDeclarator) {
|
||||
n.name.visit_with(self);
|
||||
}
|
||||
}
|
||||
|
||||
struct ExportRefRewrriter {
|
||||
struct ExportQuery {
|
||||
namesapce_id: Id,
|
||||
export_id_list: AHashSet<Id>,
|
||||
}
|
||||
|
||||
impl VisitMut for ExportRefRewrriter {
|
||||
noop_visit_mut_type!();
|
||||
|
||||
fn visit_mut_pat(&mut self, n: &mut Pat) {
|
||||
match n {
|
||||
Pat::Ident(BindingIdent { id, .. }) => {
|
||||
if self.export_id_list.contains(&id.to_id()) {
|
||||
*n = Pat::Expr(Box::new(self.namesapce_id.clone().make_member(id.take())));
|
||||
}
|
||||
}
|
||||
_ => n.visit_mut_children_with(self),
|
||||
}
|
||||
impl QueryRef for ExportQuery {
|
||||
fn query_ref(&self, ident: &Ident) -> Option<Expr> {
|
||||
self.export_id_list
|
||||
.contains(&ident.to_id())
|
||||
.then(|| self.namesapce_id.clone().make_member(ident.clone()))
|
||||
}
|
||||
|
||||
fn visit_mut_expr(&mut self, n: &mut Expr) {
|
||||
if let Expr::Ident(ref_ident) = n {
|
||||
if self.export_id_list.contains(&ref_ident.to_id()) {
|
||||
*n = self.namesapce_id.clone().make_member(ref_ident.clone());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
n.visit_mut_children_with(self);
|
||||
fn query_lhs(&self, ident: &Ident) -> Option<Expr> {
|
||||
self.query_ref(ident)
|
||||
}
|
||||
|
||||
fn visit_mut_prop(&mut self, n: &mut Prop) {
|
||||
match n {
|
||||
Prop::Shorthand(shorthand) => {
|
||||
if self.export_id_list.contains(&shorthand.to_id()) {
|
||||
*n = KeyValueProp {
|
||||
key: shorthand.clone().into(),
|
||||
value: self
|
||||
.namesapce_id
|
||||
.clone()
|
||||
.make_member(shorthand.take())
|
||||
.into(),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
_ => n.visit_mut_children_with(self),
|
||||
}
|
||||
fn should_fix_this(&self, _: &Ident) -> bool {
|
||||
// tsc does not care about `this` in namespace.
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn rewrite_export_bindings<V>(node: &mut V, namesapce_id: Id, export_id_list: AHashSet<Id>)
|
||||
where
|
||||
V: VisitMutWith<RefRewriter<ExportQuery>>,
|
||||
{
|
||||
let mut v = RefRewriter {
|
||||
query: ExportQuery {
|
||||
namesapce_id,
|
||||
export_id_list,
|
||||
},
|
||||
};
|
||||
|
||||
node.visit_mut_with(&mut v);
|
||||
}
|
||||
|
||||
struct EnumMemberItem {
|
||||
span: Span,
|
||||
name: JsWord,
|
||||
|
@ -20,7 +20,9 @@ use std::{
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
use swc_atoms::{js_word, JsWord};
|
||||
use swc_common::{collections::AHashSet, Mark, Span, Spanned, SyntaxContext, DUMMY_SP};
|
||||
use swc_common::{
|
||||
collections::AHashSet, util::take::Take, Mark, Span, Spanned, SyntaxContext, DUMMY_SP,
|
||||
};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_visit::{
|
||||
noop_visit_mut_type, noop_visit_type, visit_mut_obj_and_computed, visit_obj_and_computed,
|
||||
@ -3052,6 +3054,108 @@ impl VisitMut for IdentRenamer<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait QueryRef {
|
||||
fn query_ref(&self, ident: &Ident) -> Option<Expr>;
|
||||
fn query_lhs(&self, ident: &Ident) -> Option<Expr>;
|
||||
/// when `foo()` is replaced with `bar.baz()`,
|
||||
/// should `bar.baz` be indirect call?
|
||||
fn should_fix_this(&self, ident: &Ident) -> bool;
|
||||
}
|
||||
|
||||
/// Replace `foo` with `bar` or `bar.baz`
|
||||
pub struct RefRewriter<T>
|
||||
where
|
||||
T: QueryRef,
|
||||
{
|
||||
pub query: T,
|
||||
}
|
||||
|
||||
impl<T> VisitMut for RefRewriter<T>
|
||||
where
|
||||
T: QueryRef,
|
||||
{
|
||||
noop_visit_mut_type!();
|
||||
|
||||
/// replace bar in binding pattern
|
||||
/// input:
|
||||
/// ```JavaScript
|
||||
/// const foo = { bar }
|
||||
/// ```
|
||||
/// output:
|
||||
/// ```JavaScript
|
||||
/// cobst foo = { bar: baz }
|
||||
/// ```
|
||||
fn visit_mut_prop(&mut self, n: &mut Prop) {
|
||||
match n {
|
||||
Prop::Shorthand(shorthand) => {
|
||||
if let Some(expr) = self.query.query_ref(shorthand) {
|
||||
*n = KeyValueProp {
|
||||
key: shorthand.take().into(),
|
||||
value: Box::new(expr),
|
||||
}
|
||||
.into()
|
||||
}
|
||||
}
|
||||
_ => n.visit_mut_children_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_pat(&mut self, n: &mut Pat) {
|
||||
match n {
|
||||
Pat::Ident(BindingIdent { id, .. }) => {
|
||||
if let Some(expr) = self.query.query_lhs(id) {
|
||||
*n = Pat::Expr(Box::new(expr));
|
||||
}
|
||||
}
|
||||
_ => n.visit_mut_children_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_expr(&mut self, n: &mut Expr) {
|
||||
match n {
|
||||
Expr::Ident(ref_ident) => {
|
||||
if let Some(expr) = self.query.query_ref(ref_ident) {
|
||||
*n = expr;
|
||||
}
|
||||
}
|
||||
|
||||
_ => n.visit_mut_children_with(self),
|
||||
};
|
||||
}
|
||||
|
||||
fn visit_mut_callee(&mut self, n: &mut Callee) {
|
||||
match n {
|
||||
Callee::Expr(e)
|
||||
if e.as_ident()
|
||||
.map(|ident| self.query.should_fix_this(ident))
|
||||
.unwrap_or_default() =>
|
||||
{
|
||||
e.visit_mut_with(self);
|
||||
|
||||
if e.is_member() {
|
||||
*n = n.take().into_indirect()
|
||||
}
|
||||
}
|
||||
|
||||
_ => n.visit_mut_children_with(self),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_mut_tagged_tpl(&mut self, n: &mut TaggedTpl) {
|
||||
let should_fix_this = n
|
||||
.tag
|
||||
.as_ident()
|
||||
.map(|ident| self.query.should_fix_this(ident))
|
||||
.unwrap_or_default();
|
||||
|
||||
n.visit_mut_children_with(self);
|
||||
|
||||
if should_fix_this && n.tag.is_member() {
|
||||
*n = n.take().into_indirect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use swc_common::{input::StringInput, BytePos};
|
||||
|
Loading…
Reference in New Issue
Block a user