diff --git a/crates/oxc_transformer/examples/transformer.rs b/crates/oxc_transformer/examples/transformer.rs index 8342c795236a9a..53f586bd2e3c96 100644 --- a/crates/oxc_transformer/examples/transformer.rs +++ b/crates/oxc_transformer/examples/transformer.rs @@ -45,6 +45,7 @@ fn main() { let ret = SemanticBuilder::new() // Estimate transformer will triple scopes, symbols, references .with_excess_capacity(2.0) + .with_scope_tree_child_ids(true) .build(&program); if !ret.errors.is_empty() { diff --git a/crates/oxc_transformer/src/common/helper_loader.rs b/crates/oxc_transformer/src/common/helper_loader.rs index 86fa1350f9ddf2..4ddd1eb5d333b4 100644 --- a/crates/oxc_transformer/src/common/helper_loader.rs +++ b/crates/oxc_transformer/src/common/helper_loader.rs @@ -167,6 +167,7 @@ pub enum Helper { Decorate, DecorateParam, DecorateMetadata, + UsingCtx, } impl Helper { @@ -199,6 +200,7 @@ impl Helper { Self::Decorate => "decorate", Self::DecorateParam => "decorateParam", Self::DecorateMetadata => "decorateMetadata", + Self::UsingCtx => "usingCtx", } } } diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index 0a0a4f3c565b60..ad8689236e1070 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -31,6 +31,7 @@ mod es2020; mod es2021; mod es2022; mod jsx; +mod proposals; mod regexp; mod typescript; @@ -49,6 +50,7 @@ use es2020::ES2020; use es2021::ES2021; use es2022::ES2022; use jsx::Jsx; +use proposals::explicit_resource_management::ExplicitResourceManagement; use regexp::RegExp; use rustc_hash::FxHashMap; use typescript::TypeScript; @@ -122,6 +124,7 @@ impl<'a> Transformer<'a> { let mut transformer = TransformerImpl { common: Common::new(&self.env, &self.ctx), decorator: Decorator::new(self.decorator, &self.ctx), + explicit_resource_management: ExplicitResourceManagement::new(&self.ctx), x0_typescript: program .source_type .is_typescript() @@ -149,6 +152,7 @@ struct TransformerImpl<'a, 'ctx> { // NOTE: all callbacks must run in order. x0_typescript: Option>, decorator: Decorator<'a, 'ctx>, + explicit_resource_management: ExplicitResourceManagement<'a, 'ctx>, x1_jsx: Jsx<'a, 'ctx>, x2_es2022: ES2022<'a, 'ctx>, x2_es2021: ES2021<'a, 'ctx>, @@ -169,6 +173,7 @@ impl<'a> Traverse<'a> for TransformerImpl<'a, '_> { typescript.enter_program(program, ctx); } self.x1_jsx.enter_program(program, ctx); + self.explicit_resource_management.enter_program(program, ctx); } fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) { @@ -211,6 +216,10 @@ impl<'a> Traverse<'a> for TransformerImpl<'a, '_> { } } + fn enter_block_statement(&mut self, node: &mut BlockStatement<'a>, ctx: &mut TraverseCtx<'a>) { + self.explicit_resource_management.enter_block_statement(node, ctx); + } + fn enter_big_int_literal(&mut self, node: &mut BigIntLiteral<'a>, ctx: &mut TraverseCtx<'a>) { self.x2_es2020.enter_big_int_literal(node, ctx); } @@ -271,6 +280,7 @@ impl<'a> Traverse<'a> for TransformerImpl<'a, '_> { fn enter_static_block(&mut self, block: &mut StaticBlock<'a>, ctx: &mut TraverseCtx<'a>) { self.common.enter_static_block(block, ctx); self.x2_es2022.enter_static_block(block, ctx); + self.explicit_resource_management.enter_static_block(block, ctx); } fn exit_static_block(&mut self, block: &mut StaticBlock<'a>, ctx: &mut TraverseCtx<'a>) { @@ -374,6 +384,7 @@ impl<'a> Traverse<'a> for TransformerImpl<'a, '_> { fn enter_function_body(&mut self, body: &mut FunctionBody<'a>, ctx: &mut TraverseCtx<'a>) { self.common.enter_function_body(body, ctx); + self.explicit_resource_management.enter_function_body(body, ctx); } fn exit_function_body(&mut self, body: &mut FunctionBody<'a>, ctx: &mut TraverseCtx<'a>) { @@ -482,6 +493,7 @@ impl<'a> Traverse<'a> for TransformerImpl<'a, '_> { if let Some(typescript) = self.x0_typescript.as_mut() { typescript.enter_statements(stmts, ctx); } + self.explicit_resource_management.enter_statements(stmts, ctx); } fn exit_arrow_function_expression( @@ -538,6 +550,7 @@ impl<'a> Traverse<'a> for TransformerImpl<'a, '_> { typescript.exit_statement(stmt, ctx); } self.decorator.enter_statement(stmt, ctx); + self.explicit_resource_management.enter_statement(stmt, ctx); self.x2_es2018.exit_statement(stmt, ctx); self.x2_es2017.exit_statement(stmt, ctx); } @@ -557,6 +570,7 @@ impl<'a> Traverse<'a> for TransformerImpl<'a, '_> { typescript.enter_statement(stmt, ctx); } self.x2_es2018.enter_statement(stmt, ctx); + self.explicit_resource_management.enter_statement(stmt, ctx); } fn enter_declaration(&mut self, decl: &mut Declaration<'a>, ctx: &mut TraverseCtx<'a>) { @@ -597,6 +611,7 @@ impl<'a> Traverse<'a> for TransformerImpl<'a, '_> { if let Some(typescript) = self.x0_typescript.as_mut() { typescript.enter_for_of_statement(stmt, ctx); } + self.explicit_resource_management.enter_for_of_statement(stmt, ctx); self.x2_es2018.enter_for_of_statement(stmt, ctx); } diff --git a/crates/oxc_transformer/src/proposals/explicit_resource_management.rs b/crates/oxc_transformer/src/proposals/explicit_resource_management.rs new file mode 100644 index 00000000000000..227c71558d8242 --- /dev/null +++ b/crates/oxc_transformer/src/proposals/explicit_resource_management.rs @@ -0,0 +1,733 @@ +use std::mem; + +use oxc_allocator::Address; +use oxc_allocator::GetAddress; +use oxc_ast::ast::BlockStatement; +use oxc_ast::ast::Class; +use oxc_ast::ast::ClassType; +use oxc_ast::{ + NONE, + ast::{ + BindingPatternKind, CatchClause, Declaration, ExportDefaultDeclarationKind, Expression, + ForStatementLeft, ImportOrExportKind, ModuleExportName, Program, SimpleAssignmentTarget, + Statement, VariableDeclarationKind, + }, +}; +use oxc_ecmascript::BoundNames; +use oxc_semantic::ScopeId; +use oxc_semantic::{ScopeFlags, SymbolFlags}; +use oxc_span::{Atom, SPAN}; +use oxc_traverse::{BoundIdentifier, Traverse}; +use rustc_hash::FxHashMap; + +use crate::{Helper, context::TransformCtx}; + +pub struct ExplicitResourceManagement<'a, 'ctx> { + ctx: &'ctx TransformCtx<'a>, + + top_level_using: FxHashMap, +} + +impl<'a, 'ctx> ExplicitResourceManagement<'a, 'ctx> { + pub fn new(ctx: &'ctx TransformCtx<'a>) -> Self { + Self { ctx, top_level_using: FxHashMap::default() } + } +} + +impl<'a> Traverse<'a> for ExplicitResourceManagement<'a, '_> { + /// Transforms ready for `enter_block_statement` to do the rest. + /// + /// ```ts + /// for await (using x of y) {} + /// ``` + /// into + /// ```ts + /// for (const _x of y) { + /// await using x = _x; + /// } + /// ``` + fn enter_for_of_statement( + &mut self, + node: &mut oxc_ast::ast::ForOfStatement<'a>, + ctx: &mut oxc_traverse::TraverseCtx<'a>, + ) { + let for_of_stmt_scope_id = node.scope_id(); + let ForStatementLeft::VariableDeclaration(decl) = &mut node.left else { return }; + if !matches!( + decl.kind, + VariableDeclarationKind::Using | VariableDeclarationKind::AwaitUsing + ) { + return; + } + let variable_decl_kind = decl.kind; + decl.kind = VariableDeclarationKind::Const; + + let variable_declarator = decl.declarations.first_mut().unwrap(); + variable_declarator.kind = VariableDeclarationKind::Const; + + let temp_id = ctx.generate_uid_based_on_node( + variable_declarator.id.get_binding_identifier().unwrap(), + for_of_stmt_scope_id, + SymbolFlags::ConstVariable | SymbolFlags::BlockScopedVariable, + ); + + let binding_pattern = + mem::replace(&mut variable_declarator.id, temp_id.create_binding_pattern(ctx)); + + let stmt = Statement::from(ctx.ast.declaration_variable( + SPAN, + variable_decl_kind, + ctx.ast.vec1(ctx.ast.variable_declarator( + SPAN, + variable_decl_kind, + binding_pattern, + Some(temp_id.create_read_expression(ctx)), + false, + )), + false, + )); + + if let Statement::BlockStatement(body) = &mut node.body { + body.body.insert(0, stmt); + } else { + let old_body = ctx.ast.move_statement(&mut node.body); + + let new_body = ctx.ast.vec_from_array([stmt, old_body]); + node.body = Statement::BlockStatement(ctx.ast.alloc_block_statement_with_scope_id( + SPAN, + new_body, + ctx.create_child_scope(ctx.current_scope_id(), ScopeFlags::empty()), + )); + }; + } + + fn enter_static_block( + &mut self, + node: &mut oxc_ast::ast::StaticBlock<'a>, + ctx: &mut oxc_traverse::TraverseCtx<'a>, + ) { + let scope_id = node.scope_id(); + if let Some(replacement) = + self.transform_statements(&mut node.body, None, scope_id, scope_id, ctx) + { + node.body = ctx.ast.vec_from_array([replacement]); + } + } + + fn enter_function_body( + &mut self, + node: &mut oxc_ast::ast::FunctionBody<'a>, + ctx: &mut oxc_traverse::TraverseCtx<'a>, + ) { + if let Some(replacement) = self.transform_statements( + &mut node.statements, + None, + ctx.current_hoist_scope_id(), + ctx.current_hoist_scope_id(), + ctx, + ) { + node.statements = ctx.ast.vec_from_array([replacement]); + } + } + + fn enter_statement( + &mut self, + node: &mut Statement<'a>, + ctx: &mut oxc_traverse::TraverseCtx<'a>, + ) { + match node { + Statement::BlockStatement(block_stmt) => { + let scope_id = block_stmt.scope_id(); + if let Some(replacement) = self.transform_statements( + &mut block_stmt.body, + Some(scope_id), + ctx.current_scope_id(), + ctx.current_hoist_scope_id(), + ctx, + ) { + *node = replacement; + } + } + Statement::SwitchStatement(_) => { + if let Some(replacement) = self.transform_switch_statement(node, ctx) { + *node = replacement; + } + } + _ => {} + } + } + + fn enter_program(&mut self, node: &mut Program<'a>, ctx: &mut oxc_traverse::TraverseCtx<'a>) { + self.top_level_using.clear(); + if !node.body.iter().any(|stmt| match stmt { + Statement::VariableDeclaration(var_decl) => matches!( + var_decl.kind, + VariableDeclarationKind::Using | VariableDeclarationKind::AwaitUsing + ), + _ => false, + }) { + return; + } + + let program_body = ctx.ast.move_vec(&mut node.body); + + let mut scopes_to_skip_move: Vec = Vec::new(); + + let (mut program_body, inner_block): ( + oxc_allocator::Vec<'a, Statement<'a>>, + oxc_allocator::Vec<'a, Statement<'a>>, + ) = program_body.into_iter().fold( + (ctx.ast.vec(), ctx.ast.vec()), + |(mut program_body, mut inner_block), mut stmt| { + let address = stmt.address(); + match stmt { + Statement::FunctionDeclaration(ref fun) => { + scopes_to_skip_move.push(fun.scope_id()); + program_body.push(stmt); + } + Statement::ImportDeclaration(_) | Statement::ExportAllDeclaration(_) => { + program_body.push(stmt); + } + Statement::ExportDefaultDeclaration(ref mut export_default_decl) => { + let (var_id, span) = match &mut export_default_decl.declaration { + ExportDefaultDeclarationKind::ClassDeclaration(class_decl) + if class_decl.id.is_some() => + { + let id = class_decl.id.take().unwrap(); + + *ctx.symbols_mut().get_flags_mut(id.symbol_id()) = + SymbolFlags::FunctionScopedVariable; + + (BoundIdentifier::from_binding_ident(&id), id.span) + } + ExportDefaultDeclarationKind::FunctionDeclaration(fun) => { + scopes_to_skip_move.push(fun.scope_id()); + program_body.push(stmt); + return (program_body, inner_block); + } + _ => ( + ctx.generate_binding_in_current_scope( + Atom::from("_default"), + SymbolFlags::FunctionScopedVariable, + ), + SPAN, + ), + }; + + let decl = mem::replace( + &mut export_default_decl.declaration, + ExportDefaultDeclarationKind::NullLiteral( + ctx.ast.alloc_null_literal(SPAN), + ), + ); + + let expr = match decl { + ExportDefaultDeclarationKind::FunctionDeclaration(decl) => { + Expression::FunctionExpression(decl) + } + ExportDefaultDeclarationKind::ClassDeclaration(mut decl) => { + decl.r#type = ClassType::ClassExpression; + Expression::ClassExpression(decl) + } + _ => decl.into_expression(), + }; + + inner_block.push(Statement::VariableDeclaration(ctx.ast.alloc( + ctx.ast.variable_declaration( + span, + VariableDeclarationKind::Var, + ctx.ast.vec_from_array([ctx.ast.variable_declarator( + span, + VariableDeclarationKind::Var, + ctx.ast.binding_pattern( + BindingPatternKind::BindingIdentifier( + ctx.ast.alloc(var_id.create_binding_identifier(ctx)), + ), + NONE, + false, + ), + Some(expr), + false, + )]), + false, + ), + ))); + + program_body.push(Statement::ExportNamedDeclaration(ctx.ast.alloc( + ctx.ast.export_named_declaration( + SPAN, + None, + ctx.ast.vec_from_array([ctx.ast.export_specifier( + SPAN, + ModuleExportName::IdentifierReference( + var_id.create_read_reference(ctx), + ), + ctx.ast.module_export_name_identifier_name(SPAN, "default"), + ImportOrExportKind::Value, + )]), + None, + ImportOrExportKind::Value, + NONE, + ), + ))); + } + Statement::ExportNamedDeclaration(ref mut export_named_declaration) => { + let Some(ref mut decl) = export_named_declaration.declaration else { + program_body.push(stmt); + return (program_body, inner_block); + }; + if matches!( + decl, + Declaration::FunctionDeclaration(_) + | Declaration::TSTypeAliasDeclaration(_) + | Declaration::TSInterfaceDeclaration(_) + | Declaration::TSEnumDeclaration(_) + | Declaration::TSModuleDeclaration(_) + | Declaration::TSImportEqualsDeclaration(_) + ) { + if let Some(stmt_scope) = match decl { + Declaration::FunctionDeclaration(fun) => Some(fun.scope_id()), + Declaration::TSTypeAliasDeclaration(decl) => Some(decl.scope_id()), + Declaration::TSInterfaceDeclaration(decl) => Some(decl.scope_id()), + Declaration::TSEnumDeclaration(decl) => Some(decl.scope_id()), + Declaration::TSModuleDeclaration(decl) => Some(decl.scope_id()), + Declaration::TSImportEqualsDeclaration(_) => None, + _ => unreachable!(), + } { + scopes_to_skip_move.push(stmt_scope); + } + program_body.push(stmt); + + return (program_body, inner_block); + } + let decl = ctx.ast.move_declaration(decl); + + let export_specifiers = match decl { + Declaration::ClassDeclaration(class_decl) => { + let class_binding = class_decl.id.as_ref().unwrap(); + let class_binding_name = class_binding.name; + + let xx = BoundIdentifier::from_binding_ident(class_binding) + .create_read_reference(ctx); + + inner_block + .push(Self::transform_class_decl(class_decl.unbox(), ctx)); + + let local = ModuleExportName::IdentifierReference(xx); + let exported = ctx + .ast + .module_export_name_identifier_name(SPAN, class_binding_name); + ctx.ast.vec1(ctx.ast.export_specifier( + SPAN, + local, + exported, + ImportOrExportKind::Value, + )) + } + Declaration::VariableDeclaration(mut var_decl) => { + var_decl.kind = VariableDeclarationKind::Var; + let mut export_specifiers = ctx.ast.vec(); + + for decl in &mut var_decl.declarations { + decl.kind = VariableDeclarationKind::Var; + } + + var_decl.bound_names(&mut |ident| { + *ctx.symbols_mut().get_flags_mut(ident.symbol_id()) = + SymbolFlags::FunctionScopedVariable; + + export_specifiers.push( + ctx.ast.export_specifier( + SPAN, + ModuleExportName::IdentifierReference( + BoundIdentifier::from_binding_ident(ident) + .create_read_reference(ctx), + ), + ctx.ast.module_export_name_identifier_name( + SPAN, ident.name, + ), + ImportOrExportKind::Value, + ), + ); + }); + inner_block.push(Statement::VariableDeclaration(var_decl)); + export_specifiers + } + _ => unreachable!(), + }; + + program_body.push(Statement::ExportNamedDeclaration(ctx.ast.alloc( + ctx.ast.export_named_declaration( + SPAN, + None, + export_specifiers, + None, + export_named_declaration.export_kind, + NONE, + ), + ))); + } + Statement::ClassDeclaration(class_decl) => { + inner_block.push(transform_class_decl(class_decl.unbox(), ctx)); + } + Statement::VariableDeclaration(ref mut var_declaration) => { + if var_declaration.kind == VariableDeclarationKind::Using { + self.top_level_using.insert(address, false); + } else if var_declaration.kind == VariableDeclarationKind::AwaitUsing { + self.top_level_using.insert(address, true); + } + var_declaration.kind = VariableDeclarationKind::Var; + + for decl in &mut var_declaration.declarations { + decl.kind = VariableDeclarationKind::Var; + decl.id.bound_names(&mut |c| { + *ctx.symbols_mut().get_flags_mut(c.symbol_id()) = + SymbolFlags::FunctionScopedVariable; + }); + } + + inner_block.push(stmt); + } + _ => inner_block.push(stmt), + } + + (program_body, inner_block) + }, + ); + + let current_scope_id = ctx.current_scope_id(); + let block_scope_id = ctx.create_child_scope(current_scope_id, ScopeFlags::empty()); + + let scopes = ctx.scopes_mut(); + + let child_ids = scopes.get_child_ids(current_scope_id); + let child_ids = child_ids.to_vec(); + + for id in child_ids + .iter() + .filter(|id| !scopes_to_skip_move.contains(id) && *id != &block_scope_id) + { + scopes.change_parent_id(*id, Some(block_scope_id)); + } + + program_body.push(Statement::BlockStatement( + ctx.ast.alloc(ctx.ast.block_statement_with_scope_id(SPAN, inner_block, block_scope_id)), + )); + + std::mem::swap(&mut node.body, &mut program_body); + } +} + +impl<'a> ExplicitResourceManagement<'a, '_> { + fn transform_switch_statement( + &self, + node: &mut oxc_ast::ast::Statement<'a>, + ctx: &mut oxc_traverse::TraverseCtx<'a>, + ) -> Option> { + let mut using_ctx = None; + let mut needs_await = false; + let current_scope_id = ctx.current_scope_id(); + + let Statement::SwitchStatement(switch_stmt) = node else { unreachable!() }; + + let switch_stmt_scope_id = switch_stmt.scope_id(); + + for case in &mut switch_stmt.cases { + for stmt in &mut case.consequent { + let Statement::VariableDeclaration(stmt) = stmt else { continue }; + if !matches!( + stmt.kind, + VariableDeclarationKind::Using | VariableDeclarationKind::AwaitUsing + ) { + continue; + }; + needs_await = needs_await || stmt.kind == VariableDeclarationKind::AwaitUsing; + + stmt.kind = VariableDeclarationKind::Const; + + using_ctx = using_ctx.or_else(|| { + Some(ctx.generate_uid( + "usingCtx", + current_scope_id, + SymbolFlags::FunctionScopedVariable, + )) + }); + + for decl in &mut stmt.declarations { + if let Some(old_init) = decl.init.take() { + decl.init = Some( + ctx.ast.expression_call( + SPAN, + ctx.ast + .member_expression_static( + SPAN, + using_ctx + .as_ref() + .expect("`using_ctx` should have been set") + .create_read_expression(ctx), + ctx.ast.identifier_name( + SPAN, + if needs_await { "a" } else { "u" }, + ), + false, + ) + .into(), + NONE, + ctx.ast.vec_from_array([old_init.into()]), + false, + ), + ); + } + } + } + } + + let using_ctx = using_ctx?; + + let block_stmt_sid = ctx.create_child_scope(ctx.current_scope_id(), ScopeFlags::empty()); + + ctx.scopes_mut().change_parent_id(switch_stmt_scope_id, Some(block_stmt_sid)); + + let callee = self.ctx.helper_load(Helper::UsingCtx, ctx); + + let block = { + let vec = ctx.ast.vec_from_array([ + Statement::from(ctx.ast.declaration_variable( + SPAN, + VariableDeclarationKind::Var, + ctx.ast.vec1(ctx.ast.variable_declarator( + SPAN, + VariableDeclarationKind::Var, + using_ctx.create_binding_pattern(ctx), + Some(ctx.ast.expression_call(SPAN, callee, NONE, ctx.ast.vec(), false)), + false, + )), + false, + )), + ctx.ast.move_statement(node), + ]); + + ctx.ast.block_statement_with_scope_id(SPAN, vec, block_stmt_sid) + }; + + let catch = Self::create_catch_clause(&using_ctx, ctx.current_scope_id(), ctx); + + let finally = Self::create_finally_block(&using_ctx, current_scope_id, needs_await, ctx); + + Some(ctx.ast.statement_try(SPAN, block, Some(catch), Some(finally))) + } + + /// Transforms: + /// - `node` - the statements to transform + /// - `scope_id` - if provided, it will be used as the scope_id for the new block. + /// - `parent_scope_id` - the parent scope + /// - `hoist_scope_id` - the hoist scope, used for generating new var bindings + /// - `ctx` - the traverse context + /// + /// Returns `Some` if the statements were transformed, `None` otherwise. + fn transform_statements( + &mut self, + node: &mut oxc_allocator::Vec<'a, Statement<'a>>, + scope_id: Option, + parent_scope_id: ScopeId, + hoist_scope_id: ScopeId, + ctx: &mut oxc_traverse::TraverseCtx<'a>, + ) -> Option> { + let mut needs_await = false; + + let mut using_ctx = None; + + for stmt in node.iter_mut() { + let address = stmt.address(); + let Statement::VariableDeclaration(variable_declaration) = stmt else { continue }; + if !matches!( + variable_declaration.kind, + VariableDeclarationKind::Using | VariableDeclarationKind::AwaitUsing + ) && !self.top_level_using.contains_key(&address) + { + continue; + }; + let is_await_using = variable_declaration.kind == VariableDeclarationKind::AwaitUsing + || self.top_level_using.get(&address).copied().unwrap_or(false); + needs_await = needs_await || is_await_using; + + if self.top_level_using.remove(&address).is_none() { + variable_declaration.kind = VariableDeclarationKind::Const; + } + + using_ctx = using_ctx.or_else(|| { + let binding = ctx.generate_uid( + "usingCtx", + hoist_scope_id, + SymbolFlags::FunctionScopedVariable, + ); + Some(binding) + }); + + for decl in &mut variable_declaration.declarations { + if let Some(old_init) = decl.init.take() { + decl.init = Some( + ctx.ast.expression_call( + SPAN, + ctx.ast + .member_expression_static( + SPAN, + using_ctx.as_ref().unwrap().create_read_expression(ctx), + ctx.ast.identifier_name( + SPAN, + if is_await_using { "a" } else { "u" }, + ), + false, + ) + .into(), + NONE, + ctx.ast.vec_from_array([old_init.into()]), + false, + ), + ); + } + } + } + + let using_ctx = using_ctx?; + + let mut stmts = ctx.ast.move_vec(&mut *node); + + let callee = self.ctx.helper_load(Helper::UsingCtx, ctx); + stmts.insert( + 0, + Statement::from(ctx.ast.declaration_variable( + SPAN, + VariableDeclarationKind::Var, + ctx.ast.vec1(ctx.ast.variable_declarator( + SPAN, + VariableDeclarationKind::Var, + using_ctx.create_binding_pattern(ctx), + Some(ctx.ast.expression_call(SPAN, callee, NONE, ctx.ast.vec(), false)), + false, + )), + false, + )), + ); + + let scope_id_children_to_move = scope_id.unwrap_or(parent_scope_id); + + let scope_id = scope_id + .unwrap_or_else(|| ctx.create_child_scope(parent_scope_id, ScopeFlags::empty())); + let block = ctx.ast.block_statement_with_scope_id(SPAN, stmts, scope_id); + + let scopes = ctx.scopes_mut(); + let child_ids = scopes.get_child_ids(scope_id_children_to_move); + let child_ids = child_ids.to_vec(); + + for id in child_ids.iter().filter(|id| *id != &scope_id) { + scopes.change_parent_id(*id, Some(scope_id)); + } + + let catch = Self::create_catch_clause(&using_ctx, parent_scope_id, ctx); + let finally = Self::create_finally_block(&using_ctx, parent_scope_id, needs_await, ctx); + + Some(ctx.ast.statement_try(SPAN, block, Some(catch), Some(finally))) + } + + fn create_catch_clause( + using_ctx: &BoundIdentifier<'a>, + parent_scope_id: ScopeId, + ctx: &mut oxc_traverse::TraverseCtx<'a>, + ) -> CatchClause<'a> { + let catch_scope_id = ctx.create_child_scope(parent_scope_id, ScopeFlags::CatchClause); + let block_scope_id = ctx.create_child_scope(catch_scope_id, ScopeFlags::empty()); + let ident = ctx.generate_binding( + Atom::from("_"), + block_scope_id, + SymbolFlags::CatchVariable | SymbolFlags::FunctionScopedVariable, + ); + + let catch_parameter = ctx.ast.catch_parameter(SPAN, ident.create_binding_pattern(ctx)); + + let stmt = ctx.ast.statement_expression( + SPAN, + ctx.ast.expression_assignment( + SPAN, + oxc_ast::ast::AssignmentOperator::Assign, + SimpleAssignmentTarget::from(ctx.ast.member_expression_static( + SPAN, + using_ctx.create_read_expression(ctx), + ctx.ast.identifier_name(SPAN, "e"), + false, + )) + .into(), + ident.create_read_expression(ctx), + ), + ); + + ctx.ast.catch_clause_with_scope_id( + SPAN, + Some(catch_parameter), + ctx.ast.block_statement_with_scope_id( + SPAN, + ctx.ast.vec_from_array([stmt]), + block_scope_id, + ), + catch_scope_id, + ) + } + + fn create_finally_block( + using_ctx: &BoundIdentifier<'a>, + parent_scope_id: ScopeId, + needs_await: bool, + ctx: &mut oxc_traverse::TraverseCtx<'a>, + ) -> BlockStatement<'a> { + let finally_scope_id = ctx.create_child_scope(parent_scope_id, ScopeFlags::empty()); + let expr = ctx.ast.expression_call( + SPAN, + ctx.ast + .member_expression_static( + SPAN, + using_ctx.create_read_expression(ctx), + ctx.ast.identifier_name(SPAN, "d"), + false, + ) + .into(), + NONE, + ctx.ast.vec(), + false, + ); + let stmt = if needs_await { ctx.ast.expression_await(SPAN, expr) } else { expr }; + ctx.ast.block_statement_with_scope_id( + SPAN, + ctx.ast.vec_from_array([ctx.ast.statement_expression(SPAN, stmt)]), + finally_scope_id, + ) + } + + fn transform_class_decl( + mut class_decl: Class<'a>, + ctx: &mut oxc_traverse::TraverseCtx<'a>, + ) -> Statement<'a> { + let id = class_decl.id.take().expect("ClassDeclaration should have an id"); + + class_decl.r#type = ClassType::ClassExpression; + let class_expr = Expression::ClassExpression(ctx.ast.alloc(class_decl)); + + *ctx.symbols_mut().get_flags_mut(id.symbol_id()) = SymbolFlags::FunctionScopedVariable; + + Statement::VariableDeclaration(ctx.ast.alloc(ctx.ast.variable_declaration( + SPAN, + VariableDeclarationKind::Var, + ctx.ast.vec_from_array([ctx.ast.variable_declarator( + SPAN, + VariableDeclarationKind::Var, + ctx.ast.binding_pattern( + BindingPatternKind::BindingIdentifier(ctx.ast.alloc(id)), + NONE, + false, + ), + Some(class_expr), + false, + )]), + false, + ))) + } +} diff --git a/crates/oxc_transformer/src/proposals/mod.rs b/crates/oxc_transformer/src/proposals/mod.rs new file mode 100644 index 00000000000000..bb096b0f2da37c --- /dev/null +++ b/crates/oxc_transformer/src/proposals/mod.rs @@ -0,0 +1 @@ +pub mod explicit_resource_management; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ce7ce3e854d74f..9f7363a57d2cb2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -120,6 +120,8 @@ importers: npm/runtime: {} + npm/wasm-web: {} + tasks/benchmark/codspeed: devDependencies: axios: @@ -180,6 +182,9 @@ importers: '@babel/plugin-proposal-decorators': specifier: ^7.25.9 version: 7.25.9(@babel/core@7.26.8) + '@babel/plugin-proposal-explicit-resource-management': + specifier: ^7.25.9 + version: 7.25.9(@babel/core@7.26.8) '@babel/plugin-transform-arrow-functions': specifier: ^7.25.9 version: 7.25.9(@babel/core@7.26.8) @@ -413,6 +418,12 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/plugin-proposal-explicit-resource-management@7.25.9': + resolution: {integrity: sha512-EbtfSvb6s4lZwef1nH52nw4DTUAvHY6bl1mbLgEHUkR6L8j4WY70mM/InB8Ozgdlok/7etbiSW+Wc88ZebZAKQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-decorators@7.25.9': resolution: {integrity: sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==} engines: {node: '>=6.9.0'} @@ -3897,6 +3908,11 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-proposal-explicit-resource-management@7.25.9(@babel/core@7.26.8)': + dependencies: + '@babel/core': 7.26.8 + '@babel/helper-plugin-utils': 7.26.5 + '@babel/plugin-syntax-decorators@7.25.9(@babel/core@7.26.8)': dependencies: '@babel/core': 7.26.8 diff --git a/tasks/coverage/snapshots/semantic_typescript.snap b/tasks/coverage/snapshots/semantic_typescript.snap index 8453f2e8554a2d..3bfd1382cce52d 100644 --- a/tasks/coverage/snapshots/semantic_typescript.snap +++ b/tasks/coverage/snapshots/semantic_typescript.snap @@ -40396,23 +40396,32 @@ after transform: ScopeId(2): [ScopeId(4)] rebuilt : ScopeId(9): [] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarations.1.ts -semantic error: Symbol flags mismatch for "N": -after transform: SymbolId(26): SymbolFlags(NameSpaceModule | ValueModule) -rebuilt : SymbolId(32): SymbolFlags(BlockScopedVariable) +semantic error: Bindings mismatch: +after transform: ScopeId(0): ["C1", "C2", "C3", "N", "_af", "_ag", "_asyncToGenerator", "_awaitAsyncGenerator", "_defineProperty", "_usingCtx2", "_usingCtx20", "_usingCtx23", "_usingCtx24", "_usingCtx25", "_usingCtx26", "_usingCtx27", "_usingCtx28", "_usingCtx29", "_usingCtx6", "_wrapAsyncGenerator", "a", "af", "ag", "d1", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", "d32", "f", "g"] +rebuilt : ScopeId(0): ["C1", "C2", "C3", "N", "_af", "_ag", "_asyncToGenerator", "_awaitAsyncGenerator", "_defineProperty", "_usingCtx2", "_usingCtx20", "_usingCtx21", "_usingCtx22", "_usingCtx23", "_usingCtx24", "_usingCtx25", "_usingCtx26", "_usingCtx27", "_usingCtx28", "_usingCtx29", "_usingCtx6", "_wrapAsyncGenerator", "a", "af", "ag", "d1", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", "d32", "f", "g"] +Bindings mismatch: +after transform: ScopeId(70): ["_usingCtx21", "_usingCtx22"] +rebuilt : ScopeId(29): [] Symbol span mismatch for "N": after transform: SymbolId(26): Span { start: 1385, end: 1386 } -rebuilt : SymbolId(32): Span { start: 0, end: 0 } +rebuilt : SymbolId(66): Span { start: 0, end: 0 } +Symbol scope ID mismatch for "_usingCtx21": +after transform: SymbolId(90): ScopeId(70) +rebuilt : SymbolId(74): ScopeId(0) +Symbol scope ID mismatch for "_usingCtx22": +after transform: SymbolId(92): ScopeId(70) +rebuilt : SymbolId(78): ScopeId(0) tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsDeclarationEmit.2.ts semantic error: Scope children mismatch: -after transform: ScopeId(0): [ScopeId(1), ScopeId(2), ScopeId(4), ScopeId(5)] -rebuilt : ScopeId(0): [ScopeId(1), ScopeId(2)] +after transform: ScopeId(0): [ScopeId(2), ScopeId(4), ScopeId(5), ScopeId(6), ScopeId(8)] +rebuilt : ScopeId(0): [ScopeId(1), ScopeId(5), ScopeId(7)] Symbol reference IDs mismatch for "r1": after transform: SymbolId(0): [ReferenceId(1)] -rebuilt : SymbolId(1): [] +rebuilt : SymbolId(3): [] Symbol reference IDs mismatch for "r2": after transform: SymbolId(2): [ReferenceId(3)] -rebuilt : SymbolId(2): [] +rebuilt : SymbolId(4): [] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsInForAwaitOf.ts semantic error: Scope children mismatch: @@ -40427,8 +40436,8 @@ rebuilt : ScopeId(7): [] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsNamedEvaluationDecoratorsAndClassFields.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C1", "C2", "C3", "C4", "_Class", "_Class2", "_Symbol$dispose", "_Symbol$dispose2", "_defineProperty", "dec"] -rebuilt : ScopeId(0): ["C1", "C2", "C3", "C4", "_Class", "_Class2", "_Symbol$dispose", "_Symbol$dispose2", "_defineProperty"] +after transform: ScopeId(0): ["C1", "C2", "C3", "C4", "_Class", "_Class2", "_defineProperty", "_usingCtx", "_usingCtx2", "dec"] +rebuilt : ScopeId(0): ["C1", "C2", "C3", "C4", "_Class", "_Class2", "_defineProperty", "_usingCtx", "_usingCtx2"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40441,8 +40450,8 @@ rebuilt : ["Symbol", "dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithESClassDecorators.1.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "before", "dec"] -rebuilt : ScopeId(0): ["C", "before"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40452,8 +40461,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithESClassDecorators.10.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["after", "dec"] -rebuilt : ScopeId(0): ["after"] +after transform: ScopeId(0): ["_default", "_usingCtx", "_usingCtx2", "after", "dec"] +rebuilt : ScopeId(0): ["_default", "_usingCtx", "_usingCtx2", "after"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40463,8 +40472,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithESClassDecorators.11.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "after", "dec"] -rebuilt : ScopeId(0): ["C", "after"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40474,8 +40483,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithESClassDecorators.12.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "after", "dec"] -rebuilt : ScopeId(0): ["C", "after"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40485,8 +40494,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithESClassDecorators.2.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "before", "dec"] -rebuilt : ScopeId(0): ["C", "before"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40496,8 +40505,11 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithESClassDecorators.3.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "before", "dec"] -rebuilt : ScopeId(0): ["C", "before"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before"] +Symbol span mismatch for "C": +after transform: SymbolId(2): Span { start: 83, end: 84 } +rebuilt : SymbolId(3): Span { start: 0, end: 0 } Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40507,8 +40519,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithESClassDecorators.4.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["before", "dec"] -rebuilt : ScopeId(0): ["before"] +after transform: ScopeId(0): ["_default", "_usingCtx", "_usingCtx2", "before", "dec"] +rebuilt : ScopeId(0): ["_default", "_usingCtx", "_usingCtx2", "before"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40518,8 +40530,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithESClassDecorators.5.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "before", "dec"] -rebuilt : ScopeId(0): ["C", "before"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40529,8 +40541,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithESClassDecorators.6.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "before", "dec"] -rebuilt : ScopeId(0): ["C", "before"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40540,8 +40552,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithESClassDecorators.7.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "after", "dec"] -rebuilt : ScopeId(0): ["C", "after"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40551,8 +40563,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithESClassDecorators.8.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "after", "dec"] -rebuilt : ScopeId(0): ["C", "after"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40562,8 +40574,11 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithESClassDecorators.9.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "after", "dec"] -rebuilt : ScopeId(0): ["C", "after"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after"] +Symbol span mismatch for "C": +after transform: SymbolId(1): Span { start: 61, end: 62 } +rebuilt : SymbolId(2): Span { start: 0, end: 0 } Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40573,8 +40588,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithLegacyClassDecorators.1.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "before", "dec"] -rebuilt : ScopeId(0): ["C", "before"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40584,8 +40599,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithLegacyClassDecorators.10.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["after", "dec"] -rebuilt : ScopeId(0): ["after"] +after transform: ScopeId(0): ["_default", "_usingCtx", "_usingCtx2", "after", "dec"] +rebuilt : ScopeId(0): ["_default", "_usingCtx", "_usingCtx2", "after"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40595,8 +40610,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithLegacyClassDecorators.11.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "after", "dec"] -rebuilt : ScopeId(0): ["C", "after"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40606,8 +40621,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithLegacyClassDecorators.12.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "after", "dec"] -rebuilt : ScopeId(0): ["C", "after"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40617,8 +40632,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithLegacyClassDecorators.2.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "before", "dec"] -rebuilt : ScopeId(0): ["C", "before"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40628,8 +40643,11 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithLegacyClassDecorators.3.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "before", "dec"] -rebuilt : ScopeId(0): ["C", "before"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before"] +Symbol span mismatch for "C": +after transform: SymbolId(2): Span { start: 83, end: 84 } +rebuilt : SymbolId(3): Span { start: 0, end: 0 } Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40639,8 +40657,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithLegacyClassDecorators.4.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["before", "dec"] -rebuilt : ScopeId(0): ["before"] +after transform: ScopeId(0): ["_default", "_usingCtx", "_usingCtx2", "before", "dec"] +rebuilt : ScopeId(0): ["_default", "_usingCtx", "_usingCtx2", "before"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40650,8 +40668,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithLegacyClassDecorators.5.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "before", "dec"] -rebuilt : ScopeId(0): ["C", "before"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40661,8 +40679,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithLegacyClassDecorators.6.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "before", "dec"] -rebuilt : ScopeId(0): ["C", "before"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "before"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40672,8 +40690,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithLegacyClassDecorators.7.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "after", "dec"] -rebuilt : ScopeId(0): ["C", "after"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40683,8 +40701,8 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithLegacyClassDecorators.8.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "after", "dec"] -rebuilt : ScopeId(0): ["C", "after"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after"] Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : @@ -40694,8 +40712,11 @@ rebuilt : ["dec"] tasks/coverage/typescript/tests/cases/conformance/statements/VariableStatements/usingDeclarations/usingDeclarationsWithLegacyClassDecorators.9.ts semantic error: Bindings mismatch: -after transform: ScopeId(0): ["C", "after", "dec"] -rebuilt : ScopeId(0): ["C", "after"] +after transform: ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after", "dec"] +rebuilt : ScopeId(0): ["C", "_usingCtx", "_usingCtx2", "after"] +Symbol span mismatch for "C": +after transform: SymbolId(1): Span { start: 61, end: 62 } +rebuilt : SymbolId(2): Span { start: 0, end: 0 } Reference symbol mismatch for "dec": after transform: SymbolId(0) "dec" rebuilt : diff --git a/tasks/transform_conformance/package.json b/tasks/transform_conformance/package.json index 76a2405055cbd2..3cac9459b5433d 100644 --- a/tasks/transform_conformance/package.json +++ b/tasks/transform_conformance/package.json @@ -15,6 +15,7 @@ "@babel/plugin-transform-class-static-block": "^7.26.0", "@babel/plugin-transform-exponentiation-operator": "^7.25.9", "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-proposal-explicit-resource-management": "^7.25.9", "@babel/plugin-transform-optional-chaining": "^7.25.9", "@babel/plugin-transform-private-methods": "^7.25.9", "@babel/plugin-transform-private-property-in-object": "^7.25.9", diff --git a/tasks/transform_conformance/snapshots/babel.snap.md b/tasks/transform_conformance/snapshots/babel.snap.md index 5ceb94cf2651f0..a89c256b3ef550 100644 --- a/tasks/transform_conformance/snapshots/babel.snap.md +++ b/tasks/transform_conformance/snapshots/babel.snap.md @@ -1,6 +1,6 @@ commit: acbc09a8 -Passed: 698/1168 +Passed: 721/1192 # All Passed: * babel-plugin-transform-logical-assignment-operators @@ -2744,3 +2744,10 @@ transform-react-jsx: unknown field `autoImport`, expected one of `runtime`, `dev x Output mismatch +# babel-plugin-proposal-explicit-resource-management (23/24) +* transform-top-level/hoisting-default-class/input.mjs +Symbol span mismatch for "C": +after transform: SymbolId(1): Span { start: 37, end: 38 } +rebuilt : SymbolId(2): Span { start: 0, end: 0 } + + diff --git a/tasks/transform_conformance/src/constants.rs b/tasks/transform_conformance/src/constants.rs index 6292771971448d..37d16ab33593dc 100644 --- a/tasks/transform_conformance/src/constants.rs +++ b/tasks/transform_conformance/src/constants.rs @@ -56,7 +56,7 @@ pub const PLUGINS: &[&str] = &[ "babel-plugin-transform-react-jsx-development", // // Proposal // "babel-plugin-proposal-decorators", - + "babel-plugin-proposal-explicit-resource-management", // RegExp tests ported from esbuild + a few additions "regexp", // Legacy decorators, tests almost ported from TypeScript diff --git a/tasks/transform_conformance/update_fixtures.mjs b/tasks/transform_conformance/update_fixtures.mjs index d7f0ff24730528..dda43b04c38d12 100644 --- a/tasks/transform_conformance/update_fixtures.mjs +++ b/tasks/transform_conformance/update_fixtures.mjs @@ -21,6 +21,7 @@ const PACKAGES = [ 'babel-plugin-transform-private-methods', 'babel-plugin-transform-private-property-in-object', 'babel-plugin-transform-logical-assignment-operators', + 'babel-plugin-proposal-explicit-resource-management', ]; const FILTER_OUT_PRESETS = ['env']; const FILTER_OUT_PLUGINS = [