fix(transformer): arrow function transform handle this in arrow function in class static block (#5848)

Class static blocks also hold a `this` binding.
This commit is contained in:
overlookmotel 2024-09-18 09:46:57 +00:00
parent bcdbba3981
commit 49ee1dcff2
6 changed files with 57 additions and 4 deletions

View file

@ -99,6 +99,9 @@ impl<'a> ArrowFunctions<'a> {
}
impl<'a> Traverse<'a> for ArrowFunctions<'a> {
// Note: No visitors for `TSModuleBlock` because `this` is not legal in TS module blocks.
// <https://www.typescriptlang.org/play/?#code/HYQwtgpgzgDiDGEAEAxA9mpBvAsAKCSXjWCgBckANJAXiQAoBKWgPiTIAsBLKAbnwC++fGDQATAK4AbZACEQAJ2z5CxUhWp0mrdtz6D8QA>
/// Insert `var _this = this;` for the global scope.
fn exit_program(&mut self, program: &mut Program<'a>, _ctx: &mut TraverseCtx<'a>) {
debug_assert!(self.inside_arrow_function_stack.len() == 1);
@ -168,6 +171,18 @@ impl<'a> Traverse<'a> for ArrowFunctions<'a> {
self.inside_arrow_function_stack.pop().unwrap();
}
fn enter_static_block(&mut self, _block: &mut StaticBlock<'a>, _ctx: &mut TraverseCtx<'a>) {
self.this_var_stack.push(None);
// No need to push to `inside_arrow_function_stack` because `enter_class` already pushed `false`
}
fn exit_static_block(&mut self, block: &mut StaticBlock<'a>, _ctx: &mut TraverseCtx<'a>) {
let this_var = self.this_var_stack.pop().unwrap();
if let Some(this_var) = this_var {
self.insert_this_var_statement_at_the_top_of_statements(&mut block.body, &this_var);
}
}
fn enter_jsx_element_name(
&mut self,
element_name: &mut JSXElementName<'a>,
@ -255,13 +270,16 @@ impl<'a> ArrowFunctions<'a> {
let target_scope_id = ctx
.scopes()
.ancestors(ctx.current_scope_id())
// We're inside arrow function, so parent scope can't be what we're looking for.
// It's either the arrow function, or a block nested within arrow function.
.skip(1)
.find(|&scope_id| {
let scope_flags = ctx.scopes().get_flags(scope_id);
// Function but not arrow function
scope_flags & (ScopeFlags::Function | ScopeFlags::Arrow) == ScopeFlags::Function
scope_flags.intersects(
ScopeFlags::Function | ScopeFlags::Top | ScopeFlags::ClassStaticBlock,
) && !scope_flags.contains(ScopeFlags::Arrow)
})
.unwrap_or(ctx.scopes().root_scope_id());
.unwrap();
this_var.replace(BoundIdentifier::new_uid(
"this",

View file

@ -95,6 +95,18 @@ impl<'a> Traverse<'a> for ES2015<'a> {
}
}
fn enter_static_block(&mut self, block: &mut StaticBlock<'a>, ctx: &mut TraverseCtx<'a>) {
if self.options.arrow_function.is_some() {
self.arrow_functions.enter_static_block(block, ctx);
}
}
fn exit_static_block(&mut self, block: &mut StaticBlock<'a>, ctx: &mut TraverseCtx<'a>) {
if self.options.arrow_function.is_some() {
self.arrow_functions.exit_static_block(block, ctx);
}
}
fn enter_variable_declarator(
&mut self,
node: &mut VariableDeclarator<'a>,

View file

@ -167,6 +167,14 @@ impl<'a> Traverse<'a> for Transformer<'a> {
self.x0_typescript.enter_class_body(body, ctx);
}
fn enter_static_block(&mut self, block: &mut StaticBlock<'a>, ctx: &mut TraverseCtx<'a>) {
self.x3_es2015.enter_static_block(block, ctx);
}
fn exit_static_block(&mut self, block: &mut StaticBlock<'a>, ctx: &mut TraverseCtx<'a>) {
self.x3_es2015.exit_static_block(block, ctx);
}
fn enter_ts_module_declaration(
&mut self,
decl: &mut TSModuleDeclaration<'a>,

View file

@ -1,6 +1,6 @@
commit: 3bcfee23
Passed: 43/53
Passed: 44/54
# All Passed:
* babel-plugin-transform-nullish-coalescing-operator

View file

@ -0,0 +1,6 @@
let f;
class C {
static {
f = () => this;
}
}

View file

@ -0,0 +1,9 @@
let f;
class C {
static {
var _this = this;
f = function() {
return _this;
};
}
}