fix(transformer): ensure last expression statement in arrow function expression is wrapped in return (#8192)

The class properties plugin will insert new statements after the expression statement, which causes the expression statement to no longer be at the end. This PR fixed it by reverse looping the statements to find the expression statement and transforming it to wrapped in `return`.

This is not a good way to do it, a potential problem is if there is a plugin that inserts a new expression statement after the original expression statement, which will cause a wrong expression wrapped in a `return`
This commit is contained in:
Dunqing 2024-12-31 01:29:53 +00:00
parent 06e1780b8c
commit 3eaff2a51c

View file

@ -482,18 +482,30 @@ impl<'a, 'ctx> Traverse<'a> for TransformerImpl<'a, 'ctx> {
// which can cause issues with the `() => x;` case, as it only allows a single statement.
// To address this, we wrap the last statement in a return statement and set the expression to false.
// This transforms the arrow function into the form `() => { return x; };`.
if arrow.expression && arrow.body.statements.len() > 1 {
let Statement::ExpressionStatement(statement) = arrow.body.statements.pop().unwrap()
else {
unreachable!(
"The last statement in an ArrowFunctionExpression should always be an ExpressionStatement."
)
};
arrow
.body
.statements
.push(ctx.ast.statement_return(SPAN, Some(statement.unbox().expression)));
let statements = &mut arrow.body.statements;
if arrow.expression && statements.len() > 1 {
arrow.expression = false;
// Reverse looping to find the expression statement, because other plugins could
// insert new statements after the expression statement.
// `() => x;`
// ->
// ```
// () => {
// var new_insert_variable;
// return x;
// function new_insert_function() {}
// };
// ```
for stmt in statements.iter_mut().rev() {
let Statement::ExpressionStatement(expr_stmt) = stmt else {
continue;
};
let expression = Some(ctx.ast.move_expression(&mut expr_stmt.expression));
*stmt = ctx.ast.statement_return(SPAN, expression);
return;
}
unreachable!("At least one statement should be expression statement")
}
}