forked from vercel/next.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR is a bit big because AST definitions are modified recently because previous AST defs were too error-prone. It will prevent plugin authors from making some common mistakes. - Closes vercel#33088 - Closes vercel#31084 - Closes vercel#33283
- Loading branch information
Showing
25 changed files
with
334 additions
and
373 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,119 +1,119 @@ | ||
use swc_atoms::JsWord; | ||
use swc_common::DUMMY_SP; | ||
use swc_ecmascript::ast::{ | ||
ArrayPat, Decl, Expr, ExprOrSuper, Ident, ImportDecl, ImportSpecifier, KeyValuePatProp, Number, | ||
ObjectPat, ObjectPatProp, Pat, PropName, VarDecl, VarDeclarator, | ||
ArrayPat, Callee, Decl, Expr, Ident, ImportDecl, ImportSpecifier, KeyValuePatProp, Number, | ||
ObjectPat, ObjectPatProp, Pat, PropName, VarDecl, VarDeclarator, | ||
}; | ||
use swc_ecmascript::visit::{Fold, FoldWith}; | ||
|
||
pub fn hook_optimizer() -> impl Fold { | ||
HookOptimizer::default() | ||
HookOptimizer::default() | ||
} | ||
|
||
#[derive(Debug, Default)] | ||
struct HookOptimizer { | ||
hooks: Vec<JsWord>, | ||
hooks: Vec<JsWord>, | ||
} | ||
|
||
impl Fold for HookOptimizer { | ||
// Find hooks imported from react/preact | ||
fn fold_import_decl(&mut self, decl: ImportDecl) -> ImportDecl { | ||
let ImportDecl { | ||
ref src, | ||
ref specifiers, | ||
.. | ||
} = decl; | ||
if &src.value == "react" || &src.value == "preact/hooks" { | ||
for specifier in specifiers { | ||
if let ImportSpecifier::Named(named_specifier) = specifier { | ||
if named_specifier.local.sym.starts_with("use") { | ||
self.hooks.push(named_specifier.local.sym.clone()) | ||
} | ||
// Find hooks imported from react/preact | ||
fn fold_import_decl(&mut self, decl: ImportDecl) -> ImportDecl { | ||
let ImportDecl { | ||
ref src, | ||
ref specifiers, | ||
.. | ||
} = decl; | ||
if &src.value == "react" || &src.value == "preact/hooks" { | ||
for specifier in specifiers { | ||
if let ImportSpecifier::Named(named_specifier) = specifier { | ||
if named_specifier.local.sym.starts_with("use") { | ||
self.hooks.push(named_specifier.local.sym.clone()) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
decl | ||
} | ||
// Transform array desctructing to object destructuring for relevant hooks | ||
fn fold_decl(&mut self, node: Decl) -> Decl { | ||
let node = node.fold_children_with(self); | ||
match node { | ||
Decl::Var(VarDecl { | ||
decls, | ||
span, | ||
kind, | ||
declare, | ||
}) => { | ||
let mut new_decls = Vec::with_capacity(decls.len()); | ||
for decl in decls { | ||
new_decls.push(self.get_decl(decl)); | ||
} | ||
|
||
decl | ||
} | ||
// Transform array desctructing to object destructuring for relevant hooks | ||
fn fold_decl(&mut self, node: Decl) -> Decl { | ||
let node = node.fold_children_with(self); | ||
match node { | ||
Decl::Var(VarDecl { | ||
decls, | ||
span, | ||
kind, | ||
declare, | ||
}) => { | ||
let mut new_decls = Vec::with_capacity(decls.len()); | ||
for decl in decls { | ||
new_decls.push(self.get_decl(decl)); | ||
Decl::Var(VarDecl { | ||
decls: new_decls, | ||
span, | ||
kind, | ||
declare, | ||
}) | ||
} | ||
_ => node, | ||
} | ||
|
||
Decl::Var(VarDecl { | ||
decls: new_decls, | ||
span, | ||
kind, | ||
declare, | ||
}) | ||
} | ||
_ => node, | ||
} | ||
} | ||
} | ||
|
||
impl HookOptimizer { | ||
fn get_decl(&mut self, decl: VarDeclarator) -> VarDeclarator { | ||
let VarDeclarator { | ||
name, | ||
init, | ||
span, | ||
definite, | ||
} = &decl; | ||
let init_clone = init.clone(); | ||
if let Pat::Array(a) = name { | ||
if let Expr::Call(c) = &*init.as_deref().unwrap() { | ||
if let ExprOrSuper::Expr(i) = &c.callee { | ||
if let Expr::Ident(Ident { sym, .. }) = &**i { | ||
if self.hooks.contains(&sym) { | ||
let name = get_object_pattern(&a); | ||
return VarDeclarator { | ||
name, | ||
init: init_clone, | ||
span: *span, | ||
definite: *definite, | ||
}; | ||
fn get_decl(&mut self, decl: VarDeclarator) -> VarDeclarator { | ||
let VarDeclarator { | ||
name, | ||
init, | ||
span, | ||
definite, | ||
} = &decl; | ||
let init_clone = init.clone(); | ||
if let Pat::Array(a) = name { | ||
if let Expr::Call(c) = &*init.as_deref().unwrap() { | ||
if let Callee::Expr(i) = &c.callee { | ||
if let Expr::Ident(Ident { sym, .. }) = &**i { | ||
if self.hooks.contains(&sym) { | ||
let name = get_object_pattern(&a); | ||
return VarDeclarator { | ||
name, | ||
init: init_clone, | ||
span: *span, | ||
definite: *definite, | ||
}; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
return decl; | ||
} | ||
return decl; | ||
} | ||
} | ||
|
||
fn get_object_pattern(array_pattern: &ArrayPat) -> Pat { | ||
let props: Vec<ObjectPatProp> = array_pattern | ||
.elems | ||
.iter() | ||
.enumerate() | ||
.filter_map(|(i, elem)| match elem { | ||
Some(elem) => Some(ObjectPatProp::KeyValue(KeyValuePatProp { | ||
key: PropName::Num(Number { | ||
value: i as f64, | ||
span: DUMMY_SP, | ||
}), | ||
value: Box::new(elem.clone()), | ||
})), | ||
None => None, | ||
}) | ||
.collect(); | ||
let props: Vec<ObjectPatProp> = array_pattern | ||
.elems | ||
.iter() | ||
.enumerate() | ||
.filter_map(|(i, elem)| match elem { | ||
Some(elem) => Some(ObjectPatProp::KeyValue(KeyValuePatProp { | ||
key: PropName::Num(Number { | ||
value: i as f64, | ||
span: DUMMY_SP, | ||
}), | ||
value: Box::new(elem.clone()), | ||
})), | ||
None => None, | ||
}) | ||
.collect(); | ||
|
||
Pat::Object(ObjectPat { | ||
props, | ||
span: DUMMY_SP, | ||
optional: false, | ||
type_ann: None, | ||
}) | ||
Pat::Object(ObjectPat { | ||
props, | ||
span: DUMMY_SP, | ||
optional: false, | ||
type_ann: None, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.