-
-
Notifications
You must be signed in to change notification settings - Fork 496
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(transformer): Class Static Block
- Loading branch information
1 parent
a710e73
commit abf31e9
Showing
6 changed files
with
159 additions
and
5 deletions.
There are no files selected for viewing
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
105 changes: 105 additions & 0 deletions
105
crates/oxc_transformer/src/es2022/class_static_block.rs
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 |
---|---|---|
@@ -0,0 +1,105 @@ | ||
use oxc_ast::{ast::*, AstBuilder}; | ||
use oxc_span::{Atom, Span}; | ||
|
||
use std::{collections::HashSet, mem, ops::DerefMut, rc::Rc}; | ||
|
||
/// ES2022: Class Static Block | ||
/// | ||
/// References: | ||
/// * <https://babel.dev/docs/babel-plugin-transform-class-static-block> | ||
/// * <https://github.com/babel/babel/blob/main/packages/babel-plugin-transform-class-static-block> | ||
pub struct ClassStaticBlock<'a> { | ||
ast: Rc<AstBuilder<'a>>, | ||
} | ||
|
||
impl<'a> ClassStaticBlock<'a> { | ||
pub fn new(ast: Rc<AstBuilder<'a>>) -> Self { | ||
Self { ast } | ||
} | ||
|
||
pub fn transform_class_body<'b>(&mut self, class_body: &'b mut ClassBody<'a>) { | ||
if !class_body.body.iter().any(|e| matches!(e, ClassElement::StaticBlock(..))) { | ||
return; | ||
} | ||
|
||
let private_names: HashSet<Atom> = class_body | ||
.body | ||
.iter() | ||
.filter_map(ClassElement::property_key) | ||
.filter_map(|p| match p { | ||
PropertyKey::PrivateIdentifier(p) => Some(p.name.clone()), | ||
_ => None, | ||
}) | ||
.collect(); | ||
|
||
let mut i = 0; | ||
for element in class_body.body.iter_mut() { | ||
let ClassElement::StaticBlock(block) = element else { | ||
continue; | ||
}; | ||
|
||
let static_block_private_id = generate_uid(&private_names, &mut i); | ||
let key = PropertyKey::PrivateIdentifier(self.ast.alloc(PrivateIdentifier { | ||
span: Span::default(), | ||
name: static_block_private_id.clone(), | ||
})); | ||
|
||
let value = (block.body.len() == 1 | ||
&& matches!(block.body[0], Statement::ExpressionStatement(..))) | ||
.then(|| { | ||
// We special-case the single expression case to avoid the iife, since it's common. | ||
let stmt = self.ast.move_statement(&mut block.body.deref_mut()[0]); | ||
match stmt { | ||
Statement::ExpressionStatement(mut expr_stmt) => { | ||
self.ast.move_expression(&mut expr_stmt.expression) | ||
} | ||
_ => unreachable!(), | ||
} | ||
}) | ||
.unwrap_or_else(|| { | ||
let statements = mem::replace(&mut block.body, self.ast.new_vec()); | ||
let callee = self.ast.parenthesized_expression( | ||
Span::default(), | ||
self.ast.arrow_expression( | ||
Span::default(), | ||
false, | ||
false, | ||
false, | ||
self.ast.formal_parameters( | ||
Span::default(), | ||
FormalParameterKind::ArrowFormalParameters, | ||
self.ast.new_vec(), | ||
None, | ||
), | ||
self.ast.function_body(Span::default(), self.ast.new_vec(), statements), | ||
None, | ||
None, | ||
), | ||
); | ||
|
||
self.ast.call_expression(Span::default(), callee, self.ast.new_vec(), false, None) | ||
}); | ||
|
||
*element = self.ast.class_property( | ||
block.span, | ||
key, | ||
Some(value), | ||
false, | ||
true, | ||
self.ast.new_vec(), | ||
); | ||
} | ||
} | ||
} | ||
|
||
fn generate_uid(deny_list: &HashSet<Atom>, i: &mut u32) -> Atom { | ||
*i += 1; | ||
|
||
let mut uid: Atom = if *i == 1 { "_".to_string() } else { format!("_{i}") }.into(); | ||
while deny_list.contains(&uid) { | ||
*i += 1; | ||
uid = format!("_{i}").into(); | ||
} | ||
|
||
uid | ||
} |
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 |
---|---|---|
@@ -0,0 +1,3 @@ | ||
mod class_static_block; | ||
|
||
pub use class_static_block::ClassStaticBlock; |
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 |
---|---|---|
|
@@ -12,6 +12,7 @@ pub enum TransformTarget { | |
ES2016, | ||
ES2019, | ||
ES2021, | ||
ES2022, | ||
#[default] | ||
ESNext, | ||
} | ||
|
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