From e2558ed64acbdad2ee0b791ef6fac7c34907d1ec Mon Sep 17 00:00:00 2001 From: Boshen Date: Tue, 29 Oct 2024 22:24:04 +0800 Subject: [PATCH] wip --- crates/oxc_ast/src/ast_impl/js.rs | 10 + .../oxc_transformer/examples/transformer.rs | 6 +- .../src/common/helper_loader.rs | 8 + .../src/compiler_assumptions.rs | 2 - crates/oxc_transformer/src/context.rs | 5 +- crates/oxc_transformer/src/es2018/mod.rs | 27 +- .../src/es2018/object_rest_spread.rs | 525 +++++++++++++++++- crates/oxc_transformer/src/lib.rs | 10 + .../snapshots/babel.snap.md | 229 ++++++-- .../snapshots/babel_exec.snap.md | 98 +--- 10 files changed, 775 insertions(+), 145 deletions(-) diff --git a/crates/oxc_ast/src/ast_impl/js.rs b/crates/oxc_ast/src/ast_impl/js.rs index 60d4f5ee9a5227..3350bb052a84d9 100644 --- a/crates/oxc_ast/src/ast_impl/js.rs +++ b/crates/oxc_ast/src/ast_impl/js.rs @@ -931,6 +931,16 @@ impl<'a> BindingPatternKind<'a> { matches!(self, Self::BindingIdentifier(_)) } + #[allow(missing_docs)] + pub fn is_object_pattern(&self) -> bool { + matches!(self, Self::ObjectPattern(_)) + } + + #[allow(missing_docs)] + pub fn is_array_pattern(&self) -> bool { + matches!(self, Self::ArrayPattern(_)) + } + #[allow(missing_docs)] pub fn is_assignment_pattern(&self) -> bool { matches!(self, Self::AssignmentPattern(_)) diff --git a/crates/oxc_transformer/examples/transformer.rs b/crates/oxc_transformer/examples/transformer.rs index d6153ac8b645ea..ee37ca3b75dc6e 100644 --- a/crates/oxc_transformer/examples/transformer.rs +++ b/crates/oxc_transformer/examples/transformer.rs @@ -6,7 +6,7 @@ use oxc_codegen::CodeGenerator; use oxc_parser::Parser; use oxc_semantic::SemanticBuilder; use oxc_span::SourceType; -use oxc_transformer::{EnvOptions, TransformOptions, Transformer}; +use oxc_transformer::{EnvOptions, HelperLoaderMode, TransformOptions, Transformer}; use pico_args::Arguments; // Instruction: @@ -55,7 +55,7 @@ fn main() { let (symbols, scopes) = ret.semantic.into_symbol_table_and_scope_tree(); - let transform_options = if let Some(query) = &targets { + let mut transform_options = if let Some(query) = &targets { TransformOptions { env: EnvOptions::from_browserslist_query(query).unwrap(), ..TransformOptions::default() @@ -66,6 +66,8 @@ fn main() { TransformOptions::enable_all() }; + transform_options.helper_loader.mode = HelperLoaderMode::External; + let ret = Transformer::new(&allocator, path, &transform_options).build_with_symbols_and_scopes( symbols, scopes, diff --git a/crates/oxc_transformer/src/common/helper_loader.rs b/crates/oxc_transformer/src/common/helper_loader.rs index 555491703b1749..43cacb650d6c32 100644 --- a/crates/oxc_transformer/src/common/helper_loader.rs +++ b/crates/oxc_transformer/src/common/helper_loader.rs @@ -143,6 +143,10 @@ pub enum Helper { AsyncToGenerator, ObjectSpread2, WrapAsyncGenerator, + Extends, + ObjectDestructuringEmpty, + ObjectWithoutProperties, + ToPropertyKey, } impl Helper { @@ -154,6 +158,10 @@ impl Helper { Self::AsyncToGenerator => "asyncToGenerator", Self::ObjectSpread2 => "objectSpread2", Self::WrapAsyncGenerator => "wrapAsyncGenerator", + Self::Extends => "extends", + Self::ObjectDestructuringEmpty => "objectDestructuringEmpty", + Self::ObjectWithoutProperties => "objectWithoutProperties", + Self::ToPropertyKey => "toPropertyKey", } } } diff --git a/crates/oxc_transformer/src/compiler_assumptions.rs b/crates/oxc_transformer/src/compiler_assumptions.rs index f37995fa930cd4..d878c399eb95f8 100644 --- a/crates/oxc_transformer/src/compiler_assumptions.rs +++ b/crates/oxc_transformer/src/compiler_assumptions.rs @@ -25,7 +25,6 @@ pub struct CompilerAssumptions { pub enumerable_module_meta: bool, #[serde(default)] - #[deprecated = "Not Implemented"] pub ignore_function_length: bool, #[serde(default)] @@ -61,7 +60,6 @@ pub struct CompilerAssumptions { pub no_uninitialized_private_field_access: bool, #[serde(default)] - #[deprecated = "Not Implemented"] pub object_rest_no_symbols: bool, #[serde(default)] diff --git a/crates/oxc_transformer/src/context.rs b/crates/oxc_transformer/src/context.rs index 12963d856dc1fb..03de53e06327ab 100644 --- a/crates/oxc_transformer/src/context.rs +++ b/crates/oxc_transformer/src/context.rs @@ -13,7 +13,7 @@ use crate::{ statement_injector::StatementInjectorStore, top_level_statements::TopLevelStatementsStore, var_declarations::VarDeclarationsStore, }, - Module, TransformOptions, + CompilerAssumptions, Module, TransformOptions, }; pub struct TransformCtx<'a> { @@ -31,6 +31,8 @@ pub struct TransformCtx<'a> { pub module: Module, + pub assumptions: CompilerAssumptions, + // Helpers /// Manage helper loading pub helper_loader: HelperLoaderStore<'a>, @@ -61,6 +63,7 @@ impl<'a> TransformCtx<'a> { source_type: SourceType::default(), source_text: "", module: options.env.module, + assumptions: options.assumptions, helper_loader: HelperLoaderStore::new(&options.helper_loader), module_imports: ModuleImportsStore::new(), var_declarations: VarDeclarationsStore::new(), diff --git a/crates/oxc_transformer/src/es2018/mod.rs b/crates/oxc_transformer/src/es2018/mod.rs index caeaf33a29e205..874c38cdb1ba41 100644 --- a/crates/oxc_transformer/src/es2018/mod.rs +++ b/crates/oxc_transformer/src/es2018/mod.rs @@ -2,10 +2,13 @@ pub(crate) mod async_generator_functions; mod object_rest_spread; mod options; -use oxc_ast::ast::{Expression, ForOfStatement, Function, Statement}; +use oxc_ast::ast::{ + CatchClause, Expression, ForOfStatement, Function, Statement, VariableDeclaration, +}; use oxc_traverse::{Traverse, TraverseCtx}; use crate::context::TransformCtx; + use async_generator_functions::AsyncGeneratorFunctions; pub use object_rest_spread::{ObjectRestSpread, ObjectRestSpreadOptions}; pub use options::ES2018Options; @@ -32,6 +35,12 @@ impl<'a, 'ctx> ES2018<'a, 'ctx> { } impl<'a, 'ctx> Traverse<'a> for ES2018<'a, 'ctx> { + fn exit_program(&mut self, program: &mut oxc_ast::ast::Program<'a>, ctx: &mut TraverseCtx<'a>) { + if self.options.object_rest_spread.is_some() { + self.object_rest_spread.exit_program(program, ctx); + } + } + fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { if self.options.object_rest_spread.is_some() { self.object_rest_spread.enter_expression(expr, ctx); @@ -67,4 +76,20 @@ impl<'a, 'ctx> Traverse<'a> for ES2018<'a, 'ctx> { self.async_generator_functions.exit_function(node, ctx); } } + + fn enter_variable_declaration( + &mut self, + decl: &mut VariableDeclaration<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + if self.options.object_rest_spread.is_some() { + self.object_rest_spread.enter_variable_declaration(decl, ctx); + } + } + + fn enter_catch_clause(&mut self, clause: &mut CatchClause<'a>, ctx: &mut TraverseCtx<'a>) { + if self.options.object_rest_spread.is_some() { + self.object_rest_spread.enter_catch_clause(clause, ctx); + } + } } diff --git a/crates/oxc_transformer/src/es2018/object_rest_spread.rs b/crates/oxc_transformer/src/es2018/object_rest_spread.rs index cb20c5e093abbd..40a94e1a05f3d3 100644 --- a/crates/oxc_transformer/src/es2018/object_rest_spread.rs +++ b/crates/oxc_transformer/src/es2018/object_rest_spread.rs @@ -26,39 +26,88 @@ //! * Babel plugin implementation: //! * Object rest/spread TC39 proposal: +use std::mem; + use serde::Deserialize; +use oxc_allocator::{CloneIn, Vec as ArenaVec}; use oxc_ast::{ast::*, NONE}; -use oxc_semantic::{ReferenceFlags, SymbolId}; -use oxc_span::SPAN; -use oxc_traverse::{Traverse, TraverseCtx}; +use oxc_diagnostics::OxcDiagnostic; +use oxc_ecmascript::ToJsString; +use oxc_semantic::{IsGlobalReference, ReferenceFlags, SymbolFlags, SymbolId}; +use oxc_span::{GetSpan, SPAN}; +use oxc_traverse::{MaybeBoundIdentifier, Traverse, TraverseCtx}; use crate::{common::helper_loader::Helper, TransformCtx}; #[derive(Debug, Default, Clone, Copy, Deserialize)] #[serde(default, rename_all = "camelCase")] pub struct ObjectRestSpreadOptions { - #[serde(alias = "loose")] - pub(crate) set_spread_properties: bool, + pub loose: bool, - pub(crate) use_built_ins: bool, + pub use_built_ins: bool, } pub struct ObjectRestSpread<'a, 'ctx> { ctx: &'ctx TransformCtx<'a>, + options: ObjectRestSpreadOptions, + + excluded_variabled_declarators: Vec>, } impl<'a, 'ctx> ObjectRestSpread<'a, 'ctx> { pub fn new(options: ObjectRestSpreadOptions, ctx: &'ctx TransformCtx<'a>) -> Self { - Self { ctx, options } + if options.loose { + ctx.error(OxcDiagnostic::error( + "Option `loose` is not implemented for object-rest-spread.", + )); + } + if options.use_built_ins { + ctx.error(OxcDiagnostic::error( + "Option `useBuiltIns` is not implemented for object-rest-spread.", + )); + } + if ctx.assumptions.object_rest_no_symbols { + ctx.error(OxcDiagnostic::error( + "Compiler assumption `objectRestNoSymbols` is not implemented for object-rest-spread.", + )); + } + if ctx.assumptions.ignore_function_length { + ctx.error(OxcDiagnostic::error( + "Compiler assumption `ignoreFunctionLength` is not implemented for object-rest-spread.", + )); + } + Self { ctx, options, excluded_variabled_declarators: vec![] } } } impl<'a, 'ctx> Traverse<'a> for ObjectRestSpread<'a, 'ctx> { + fn exit_program(&mut self, _node: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) { + if !self.excluded_variabled_declarators.is_empty() { + let declarators = ctx.ast.vec_from_iter(self.excluded_variabled_declarators.drain(..)); + let kind = VariableDeclarationKind::Const; + let declaration = ctx.ast.alloc_variable_declaration(SPAN, kind, declarators, false); + let statement = Statement::VariableDeclaration(declaration); + self.ctx.top_level_statements.insert_statement(statement); + } + } + fn enter_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) { self.transform_object_expression(expr, ctx); } + + fn enter_variable_declaration( + &mut self, + decl: &mut VariableDeclaration<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + self.transform_variable_declaration(decl, ctx); + } + + fn enter_catch_clause(&mut self, clause: &mut CatchClause<'a>, ctx: &mut TraverseCtx<'a>) { + self.transform_catch_clause(clause, ctx); + } } impl<'a, 'ctx> ObjectRestSpread<'a, 'ctx> { @@ -79,19 +128,19 @@ impl<'a, 'ctx> ObjectRestSpread<'a, 'ctx> { return; } + let properties = &mut obj_expr.properties; + // collect `y` and `z` from `{ ...x, y, z }` let mut obj_prop_list = ctx.ast.vec(); - while obj_expr - .properties + while properties .last() .map_or(false, |prop| matches!(prop, ObjectPropertyKind::ObjectProperty(..))) { - let prop = obj_expr.properties.pop().unwrap(); + let prop = properties.pop().unwrap(); obj_prop_list.push(prop); } - let Some(ObjectPropertyKind::SpreadProperty(mut spread_prop)) = obj_expr.properties.pop() - else { + let Some(ObjectPropertyKind::SpreadProperty(mut spread_prop)) = properties.pop() else { unreachable!(); }; @@ -120,7 +169,7 @@ impl<'a, 'ctx> ObjectRestSpread<'a, 'ctx> { #[expect(clippy::option_option)] fn get_object_symbol_id(&self, ctx: &mut TraverseCtx<'a>) -> Option> { - if self.options.set_spread_properties { + if self.options.loose { Some(ctx.scopes().find_binding(ctx.current_scope_id(), "Object")) } else { None @@ -148,3 +197,453 @@ impl<'a, 'ctx> ObjectRestSpread<'a, 'ctx> { Expression::from(ctx.ast.member_expression_static(SPAN, object, property, false)) } } + +impl<'a, 'ctx> ObjectRestSpread<'a, 'ctx> { + fn transform_variable_declaration( + &mut self, + decl: &mut VariableDeclaration<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + let mut new_decls = vec![]; + for (i, variable_declarator) in decl.declarations.iter_mut().enumerate() { + if Self::has_nested_object_rest(&variable_declarator.id) { + if let Some(decls) = self.transform_variable_declarator(variable_declarator, ctx) { + new_decls.push((i, decls)); + } + } + } + // TODO: performance can be improved by not shuffling the vec multiple times. + for (i, decls) in new_decls { + decl.declarations.splice(i..=i, decls); + } + } + + /// Recursively check for object rest. + fn has_nested_object_rest(pat: &BindingPattern<'a>) -> bool { + match &pat.kind { + BindingPatternKind::ObjectPattern(pat) => { + pat.rest.is_some() + || pat.properties.iter().any(|p| Self::has_nested_object_rest(&p.value)) + } + BindingPatternKind::ArrayPattern(pat) => { + pat.elements.iter().any(|e| e.as_ref().is_some_and(Self::has_nested_object_rest)) + } + _ => false, + } + } + + // The algorithm depth first searches for object rest, + // and then mutates the object pattern in-place. + fn transform_variable_declarator( + &mut self, + decl: &mut VariableDeclarator<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> Option>> { + let BindingPatternKind::ObjectPattern(_) = &decl.id.kind else { + return None; + }; + // It is syntax error if missing initializer in destructuring pattern. + let init = decl.init.as_mut()?; + + let mut builder = DeclsBuilder { + decls: ctx.ast.vec(), + kind: decl.kind, + symbol_flags: match decl.kind { + VariableDeclarationKind::Var => SymbolFlags::FunctionScopedVariable, + VariableDeclarationKind::Let + | VariableDeclarationKind::Using + | VariableDeclarationKind::AwaitUsing => SymbolFlags::BlockScopedVariable, + VariableDeclarationKind::Const => { + SymbolFlags::BlockScopedVariable | SymbolFlags::ConstVariable + } + }, + }; + + let maybe_bound_identifier = if let Expression::Identifier(ident) = init { + MaybeBoundIdentifier::from_identifier_reference(ident, ctx) + } else { + let bound_identifier = + ctx.generate_uid_in_current_scope_based_on_node(init, builder.symbol_flags); + let id = bound_identifier.create_binding_pattern(ctx); + let init = ctx.ast.move_expression(init); + builder.decls.push(ctx.ast.variable_declarator(SPAN, decl.kind, id, Some(init), false)); + bound_identifier.to_maybe_bound_identifier() + }; + + // DFS walk the declarator and collect data. + let data = Self::walk_binding_pattern(&mut decl.id.kind, &mut builder, ctx); + + // Insert the original declarator by copying its data out. + if let BindingPatternKind::ObjectPattern(object_pattern) = &mut decl.id.kind { + if !object_pattern.properties.is_empty() { + let binding_pattern_kind = ctx.ast.binding_pattern_kind_object_pattern( + object_pattern.span, + ctx.ast.move_vec(&mut object_pattern.properties), + NONE, + ); + builder.decls.push(ctx.ast.variable_declarator( + decl.span, + decl.kind, + ctx.ast.binding_pattern(binding_pattern_kind, NONE, false), + Some(maybe_bound_identifier.create_read_expression(ctx)), + false, + )); + }; + } + // Insert rest access. + // There can be multiple object rest spread. + // ```js + // var { + // [++key]: { y, ...rest_y }, + // [++key]: { z, ...rest_z } + // } = {}; + // ``` + for datum in data { + // `let { ...a } = z` -> `_extends({}, (_objectDestructuringEmpty(z), z));` + let rhs = if datum.has_no_properties { + // The `ObjectDestructuringEmpty` function throws a type error when destructuring null. + // `function _objectDestructuringEmpty(t) { if (null == t) throw new TypeError("Cannot destructure " + t); }` + let mut arguments = ctx.ast.vec(); + // Add `{}`. + arguments.push(Argument::ObjectExpression(ctx.ast.alloc_object_expression( + SPAN, + ctx.ast.vec(), + None, + ))); + // Add `(_objectDestructuringEmpty(b), b);` + arguments.push(Argument::SequenceExpression(ctx.ast.alloc_sequence_expression( + SPAN, + { + let mut sequence = ctx.ast.vec(); + sequence.push(self.ctx.helper_call_expr( + Helper::ObjectDestructuringEmpty, + ctx.ast.vec1(Argument::from( + datum.create_arg(&maybe_bound_identifier, ctx), + )), + ctx, + )); + sequence.push(datum.create_arg(&maybe_bound_identifier, ctx)); + sequence + }, + ))); + self.ctx.helper_call_expr(Helper::Extends, arguments, ctx) + } else { + // / `let { a, b, ...c } = z` -> _objectWithoutProperties(_z, ["a", "b"]); + // / `_objectWithoutProperties(_z, ["a", "b"])` + let mut arguments = + ctx.ast.vec1(Argument::from(datum.create_arg(&maybe_bound_identifier, ctx))); + let key_expression = ctx.ast.expression_array(SPAN, datum.keys, None); + + let key_expression = if datum.all_primitives + && ctx.scoping.current_scope_id() != ctx.scopes().root_scope_id() + { + // Move the key_expression to the root scope. + let bound_identifier = ctx.generate_uid_in_root_scope( + "excluded", + SymbolFlags::BlockScopedVariable | SymbolFlags::ConstVariable, + ); + let kind = VariableDeclarationKind::Const; + let declarator = ctx.ast.variable_declarator( + SPAN, + kind, + bound_identifier.create_binding_pattern(ctx), + Some(key_expression), + false, + ); + self.excluded_variabled_declarators.push(declarator); + bound_identifier.create_read_expression(ctx) + } else if !datum.all_primitives { + // map to `toPropertyKey` to handle the possible non-string values + // `[_ref].map(babelHelpers.toPropertyKey))` + let property = ctx.ast.identifier_name(SPAN, "map"); + let callee = + Expression::StaticMemberExpression(ctx.ast.alloc_static_member_expression( + SPAN, + key_expression, + property, + false, + )); + let arguments = ctx + .ast + .vec1(Argument::from(self.ctx.helper_load(Helper::ToPropertyKey, ctx))); + ctx.ast.expression_call(SPAN, callee, NONE, arguments, false) + } else { + key_expression + }; + arguments.push(Argument::from(key_expression)); + self.ctx.helper_call_expr(Helper::ObjectWithoutProperties, arguments, ctx) + }; + // Finally, insert the declarator. + builder.decls.push(ctx.ast.variable_declarator( + SPAN, + decl.kind, + datum.rest, + Some(rhs), + false, + )); + } + Some(builder.decls) + } + + fn walk_binding_pattern( + binding_pattern: &mut BindingPatternKind<'a>, + builder: &mut DeclsBuilder<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> Vec> { + match binding_pattern { + BindingPatternKind::ObjectPattern(object_pattern) => { + let mut index_to_remove = vec![]; + // For computed keys, key path need to be evaluated with a new reference. + // ```js + // var { + // [++a]: { y, ...rest_y }, + // [++b]: { z, ...rest_z } + // } = {}; + // ``` + let bound_identifiers = object_pattern + .properties + .iter_mut() + .rev() // References are inserted in reverse order `_b = ++b, _a = ++a` + .map(|binding_property| { + if Self::has_nested_object_rest(&binding_property.value) { + if let Some(expr) = binding_property.key.as_expression_mut() { + if !expr.is_literal() { + let bound_identifier = ctx + .generate_uid_in_current_scope_based_on_node( + expr, + builder.symbol_flags, + ); + let mut lhs = bound_identifier.create_read_expression(ctx); + mem::swap(&mut lhs, expr); + builder.decls.push(ctx.ast.variable_declarator( + SPAN, + builder.kind, + bound_identifier.create_binding_pattern(ctx), + Some(lhs), + false, + )); + return Some(bound_identifier); + } + } + } + None + }) + .collect::>(); + + let mut data = object_pattern + .properties + .iter_mut() + .enumerate() + .flat_map(|(i, binding_property)| { + let data = Self::walk_binding_pattern( + &mut binding_property.value.kind, + builder, + ctx, + ) + .into_iter() + .map(|mut datum| { + let key = if let Some(bound_identifier) = + &bound_identifiers[bound_identifiers.len() - 1 - i] + { + PropertyKey::from(bound_identifier.create_read_expression(ctx)) + } else { + binding_property.key.clone_in(ctx.ast.allocator) + }; + datum.path.push(key); + datum + }) + .collect::>(); + // The object pattern becomes empty after rest element is removed. + if binding_property.value.kind.is_object_pattern() + && data.len() == 1 + && data[0].has_no_properties + { + index_to_remove.push(i); + } + data + }) + .collect::>(); + + if let Some(datum) = Self::transform_object_pattern(object_pattern, builder, ctx) { + data.push(datum); + } + // Remove the binding property if the object pattern becomes empty. + // `let { x: { ...y} } = foo` -> `let { x: {} } = foo` -> `let {} = foo` + let mut i = 0; + object_pattern.properties.retain(|_| { + let retain = !index_to_remove.contains(&i); + i += 1; + retain + }); + data + } + _ => vec![], + } + } + + fn transform_object_pattern( + object_pattern: &mut ObjectPattern<'a>, + builder: &mut DeclsBuilder<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> Option> { + let rest = mem::take(&mut object_pattern.rest).map(|rest| rest.unbox().argument)?; + let mut all_primitives = true; + // Create the access keys. + // `let { a, b, ...c } = foo` -> `["a", "b"]` + let mut keys = ctx.ast.vec(); + for binding_property in object_pattern.properties.iter_mut() { + match &mut binding_property.key { + // `let { a, ... rest }` + PropertyKey::StaticIdentifier(ident) => { + let name = ident.name.clone(); + let expr = ctx.ast.expression_string_literal(SPAN, name); + keys.push(ArrayExpressionElement::from(expr)); + } + // `let { 'a', ... rest }` + // `let { ['a'], ... rest }` + PropertyKey::StringLiteral(lit) => { + let name = lit.value.clone(); + let expr = ctx.ast.expression_string_literal(SPAN, name.clone()); + keys.push(ArrayExpressionElement::from(expr)); + } + // `let { [`a`], ... rest }` + PropertyKey::TemplateLiteral(lit) if lit.is_no_substitution_template() => { + let expr = Expression::TemplateLiteral(lit.clone_in(ctx.ast.allocator)); + keys.push(ArrayExpressionElement::from(expr)); + } + PropertyKey::PrivateIdentifier(_) => { /* syntax error */ } + key => { + let Some(expr) = key.as_expression_mut() else { + continue; + }; + // `let { [1], ... rest }` + if expr.is_literal() { + let span = expr.span(); + let s = expr.to_js_string().unwrap(); + let expr = ctx.ast.expression_string_literal(span, s); + keys.push(ArrayExpressionElement::from(expr)); + continue; + } + all_primitives = false; + if let Expression::Identifier(ident) = expr { + if !ident.is_global_reference(ctx.symbols()) { + let expr = MaybeBoundIdentifier::from_identifier_reference(ident, ctx) + .create_read_expression(ctx); + keys.push(ArrayExpressionElement::from(expr)); + continue; + } + } + let bound_identifier = + ctx.generate_uid_in_current_scope_based_on_node(expr, builder.symbol_flags); + let p = bound_identifier.create_binding_pattern(ctx); + let mut lhs = bound_identifier.create_read_expression(ctx); + mem::swap(&mut lhs, expr); + builder.decls.push(ctx.ast.variable_declarator( + SPAN, + builder.kind, + p, + Some(lhs), + false, + )); + keys.push(ArrayExpressionElement::from( + bound_identifier.create_read_expression(ctx), + )); + } + } + } + // Remove the object pattern that became empty. + object_pattern.properties.retain(|binding_property| match &binding_property.value.kind { + BindingPatternKind::ObjectPattern(object_pattern) => { + !object_pattern.properties.is_empty() + } + _ => true, + }); + Some(Datum { + rest, + path: vec![], + keys, + has_no_properties: object_pattern.properties.is_empty(), + all_primitives, + }) + } + + /// Move the catch parameter binding to the catch body if it contains an object rest. + /// It will be transform by `transform_object_pattern` afterwards. + fn transform_catch_clause(&mut self, clause: &mut CatchClause<'a>, ctx: &mut TraverseCtx<'a>) { + let Some(catch_parameter) = &mut clause.param else { return }; + if !Self::has_nested_object_rest(&catch_parameter.pattern) { + return; + } + let scope_id = clause.body.scope_id(); + let bound_identifier = ctx.generate_uid( + "ref", + scope_id, + SymbolFlags::FunctionScopedVariable | SymbolFlags::CatchVariable, + ); + let kind = VariableDeclarationKind::Let; + let id = mem::replace( + &mut catch_parameter.pattern, + bound_identifier.create_binding_pattern(ctx), + ); + let init = bound_identifier.create_read_expression(ctx); + let declarations = + ctx.ast.vec1(ctx.ast.variable_declarator(SPAN, kind, id, Some(init), false)); + let declaration = ctx.ast.alloc_variable_declaration(SPAN, kind, declarations, false); + let statement = Statement::VariableDeclaration(declaration); + clause.body.body.insert(0, statement); + } +} + +struct DeclsBuilder<'a> { + decls: ArenaVec<'a, VariableDeclarator<'a>>, + kind: VariableDeclarationKind, + symbol_flags: SymbolFlags, +} + +/// Datum containing path to a object rest. +#[derive(Debug)] +struct Datum<'a> { + rest: BindingPattern<'a>, + path: Vec>, + keys: ArenaVec<'a, ArrayExpressionElement<'a>>, + has_no_properties: bool, + all_primitives: bool, +} + +impl<'a> Datum<'a> { + fn create_arg( + &self, + maybe_bound_identifier: &MaybeBoundIdentifier<'a>, + ctx: &mut TraverseCtx<'a>, + ) -> Expression<'a> { + let mut arg = maybe_bound_identifier.create_read_expression(ctx); + // For nested case, `let { x: { [y]: { ...z } } } = foo` + // Create rhs access `foo.x[y]`. + for property_key in self.path.iter().rev() { + let span = property_key.span(); + match property_key { + PropertyKey::StaticIdentifier(ident) => { + let property = ctx.ast.identifier_name(ident.span, ident.name.clone()); + arg = Expression::StaticMemberExpression( + ctx.ast.alloc_static_member_expression(span, arg, property, false), + ); + } + PropertyKey::Identifier(ident) => { + let expr = MaybeBoundIdentifier::from_identifier_reference(ident, ctx) + .create_read_expression(ctx); + arg = Expression::ComputedMemberExpression( + ctx.ast.alloc_computed_member_expression(span, arg, expr, false), + ); + } + PropertyKey::PrivateIdentifier(_) => continue, // syntax error + _ => { + let expr = property_key.clone_in(&ctx.ast.allocator).into_expression(); + arg = Expression::ComputedMemberExpression( + ctx.ast.alloc_computed_member_expression(span, arg, expr, false), + ); + } + } + } + arg + } +} diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index dd321309b39e68..7bb050800838d4 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -161,6 +161,7 @@ impl<'a, 'ctx> Traverse<'a> for TransformerImpl<'a, 'ctx> { if let Some(typescript) = self.x0_typescript.as_mut() { typescript.exit_program(program, ctx); } + self.x2_es2018.exit_program(program, ctx); self.common.exit_program(program, ctx); } @@ -176,6 +177,14 @@ impl<'a, 'ctx> Traverse<'a> for TransformerImpl<'a, 'ctx> { } } + fn enter_variable_declaration( + &mut self, + decl: &mut VariableDeclaration<'a>, + ctx: &mut TraverseCtx<'a>, + ) { + self.x2_es2018.enter_variable_declaration(decl, ctx); + } + fn enter_variable_declarator( &mut self, decl: &mut VariableDeclarator<'a>, @@ -499,6 +508,7 @@ impl<'a, 'ctx> Traverse<'a> for TransformerImpl<'a, 'ctx> { fn enter_catch_clause(&mut self, clause: &mut CatchClause<'a>, ctx: &mut TraverseCtx<'a>) { self.x2_es2019.enter_catch_clause(clause, ctx); + self.x2_es2018.enter_catch_clause(clause, ctx); } fn enter_import_declaration( diff --git a/tasks/transform_conformance/snapshots/babel.snap.md b/tasks/transform_conformance/snapshots/babel.snap.md index 19eea87d11d7ff..e0e2acd573b72c 100644 --- a/tasks/transform_conformance/snapshots/babel.snap.md +++ b/tasks/transform_conformance/snapshots/babel.snap.md @@ -1,6 +1,6 @@ commit: d20b314c -Passed: 319/633 +Passed: 317/633 # All Passed: * babel-plugin-transform-class-static-block @@ -296,21 +296,36 @@ x Output mismatch x Output mismatch -# babel-plugin-transform-object-rest-spread (5/59) +# babel-plugin-transform-object-rest-spread (4/59) * assumption-ignoreFunctionLength/parameters-object-rest-used-in-default/input.js -x Output mismatch + + x Compiler assumption `ignoreFunctionLength` is not implemented for object- + | rest-spread. + * assumption-objectRestNoSymbols/rest-assignment-expression/input.js -x Output mismatch + + x Compiler assumption `objectRestNoSymbols` is not implemented for object- + | rest-spread. + * assumption-objectRestNoSymbols/rest-computed/input.js -x Output mismatch + + x Compiler assumption `objectRestNoSymbols` is not implemented for object- + | rest-spread. + * assumption-objectRestNoSymbols/rest-nested/input.js -x Output mismatch + + x Compiler assumption `objectRestNoSymbols` is not implemented for object- + | rest-spread. + * assumption-objectRestNoSymbols/rest-var-declaration/input.js -x Output mismatch + + x Compiler assumption `objectRestNoSymbols` is not implemented for object- + | rest-spread. + * assumption-pureGetters/rest-remove-unused-excluded-keys/input.js x Output mismatch @@ -328,19 +343,66 @@ x Output mismatch x Output mismatch * assumption-setSpreadProperties-with-useBuiltIns/assignment/input.js -x Output mismatch + + x Option `useBuiltIns` is not implemented for object-rest-spread. + * assumption-setSpreadProperties-with-useBuiltIns/expression/input.js -x Output mismatch + + x Option `useBuiltIns` is not implemented for object-rest-spread. + * object-rest/assignment-expression/input.js x Output mismatch * object-rest/catch-clause/input.js -x Output mismatch +Symbol reference IDs mismatch for "_ref": +after transform: SymbolId(12): [ReferenceId(0), ReferenceId(1), ReferenceId(3)] +rebuilt : SymbolId(3): [ReferenceId(2), ReferenceId(3)] +Symbol flags mismatch for "a34": +after transform: SymbolId(0): SymbolFlags(BlockScopedVariable | CatchVariable) +rebuilt : SymbolId(4): SymbolFlags(BlockScopedVariable) +Symbol reference IDs mismatch for "_ref2": +after transform: SymbolId(13): [ReferenceId(5), ReferenceId(6), ReferenceId(7)] +rebuilt : SymbolId(5): [ReferenceId(4), ReferenceId(6)] +Symbol flags mismatch for "a1": +after transform: SymbolId(1): SymbolFlags(BlockScopedVariable | CatchVariable) +rebuilt : SymbolId(6): SymbolFlags(BlockScopedVariable) +Symbol flags mismatch for "b1": +after transform: SymbolId(2): SymbolFlags(BlockScopedVariable | CatchVariable) +rebuilt : SymbolId(7): SymbolFlags(BlockScopedVariable) +Symbol reference IDs mismatch for "_ref3": +after transform: SymbolId(15): [ReferenceId(10), ReferenceId(11), ReferenceId(12)] +rebuilt : SymbolId(8): [ReferenceId(8), ReferenceId(10)] +Symbol flags mismatch for "a2": +after transform: SymbolId(3): SymbolFlags(BlockScopedVariable | CatchVariable) +rebuilt : SymbolId(9): SymbolFlags(BlockScopedVariable) +Symbol flags mismatch for "b2": +after transform: SymbolId(4): SymbolFlags(BlockScopedVariable | CatchVariable) +rebuilt : SymbolId(10): SymbolFlags(BlockScopedVariable) +Symbol flags mismatch for "c2": +after transform: SymbolId(5): SymbolFlags(BlockScopedVariable | CatchVariable) +rebuilt : SymbolId(11): SymbolFlags(BlockScopedVariable) +Symbol reference IDs mismatch for "_ref4": +after transform: SymbolId(17): [ReferenceId(15), ReferenceId(16), ReferenceId(17)] +rebuilt : SymbolId(12): [ReferenceId(12), ReferenceId(14)] +Symbol flags mismatch for "a2": +after transform: SymbolId(6): SymbolFlags(BlockScopedVariable | CatchVariable) +rebuilt : SymbolId(13): SymbolFlags(BlockScopedVariable) +Symbol flags mismatch for "b2": +after transform: SymbolId(7): SymbolFlags(BlockScopedVariable | CatchVariable) +rebuilt : SymbolId(14): SymbolFlags(BlockScopedVariable) +Symbol flags mismatch for "c3": +after transform: SymbolId(8): SymbolFlags(BlockScopedVariable | CatchVariable) +rebuilt : SymbolId(15): SymbolFlags(BlockScopedVariable) +Symbol flags mismatch for "c4": +after transform: SymbolId(9): SymbolFlags(BlockScopedVariable | CatchVariable) +rebuilt : SymbolId(16): SymbolFlags(BlockScopedVariable) * object-rest/duplicate-decl-bug/input.js -x Output mismatch +Symbol reference IDs mismatch for "original": +after transform: SymbolId(0): [ReferenceId(1), ReferenceId(2), ReferenceId(4)] +rebuilt : SymbolId(0): [ReferenceId(3), ReferenceId(4)] * object-rest/export/input.mjs x Output mismatch @@ -358,10 +420,14 @@ x Output mismatch x Output mismatch * object-rest/nested/input.js -x Output mismatch +Symbol reference IDs mismatch for "defunct": +after transform: SymbolId(0): [ReferenceId(0), ReferenceId(1), ReferenceId(2)] +rebuilt : SymbolId(0): [ReferenceId(0), ReferenceId(2)] * object-rest/nested-2/input.js -x Output mismatch +Symbol reference IDs mismatch for "test": +after transform: SymbolId(0): [ReferenceId(0), ReferenceId(1), ReferenceId(2)] +rebuilt : SymbolId(0): [ReferenceId(0), ReferenceId(2)] * object-rest/nested-array/input.js x Output mismatch @@ -376,19 +442,33 @@ x Output mismatch x Output mismatch * object-rest/nested-literal-property/input.js -x Output mismatch +Symbol reference IDs mismatch for "useState": +after transform: SymbolId(0): [ReferenceId(0), ReferenceId(1), ReferenceId(2), ReferenceId(4)] +rebuilt : SymbolId(0): [ReferenceId(0), ReferenceId(2), ReferenceId(4)] * object-rest/nested-order/input.js -x Output mismatch +Unresolved reference IDs mismatch for "obj": +after transform: [ReferenceId(0), ReferenceId(1), ReferenceId(3), ReferenceId(5), ReferenceId(7), ReferenceId(9), ReferenceId(11)] +rebuilt : [ReferenceId(2), ReferenceId(3), ReferenceId(6), ReferenceId(7), ReferenceId(10), ReferenceId(11)] * object-rest/non-string-computed/input.js -x Output mismatch - -* object-rest/null-destructuring/input.js -x Output mismatch +Symbol reference IDs mismatch for "a": +after transform: SymbolId(0): [ReferenceId(0), ReferenceId(40), ReferenceId(41)] +rebuilt : SymbolId(0): [ReferenceId(0), ReferenceId(2)] +Symbol reference IDs mismatch for "c": +after transform: SymbolId(8): [ReferenceId(16), ReferenceId(48), ReferenceId(49)] +rebuilt : SymbolId(8): [ReferenceId(18), ReferenceId(20)] * object-rest/object-ref-computed/input.js -x Output mismatch +Symbol reference IDs mismatch for "_key": +after transform: SymbolId(7): [ReferenceId(21), ReferenceId(22), ReferenceId(25)] +rebuilt : SymbolId(5): [ReferenceId(2), ReferenceId(6)] +Symbol reference IDs mismatch for "_key2": +after transform: SymbolId(9): [ReferenceId(27), ReferenceId(30), ReferenceId(36)] +rebuilt : SymbolId(7): [ReferenceId(17), ReferenceId(24)] +Symbol reference IDs mismatch for "_key3": +after transform: SymbolId(10): [ReferenceId(28), ReferenceId(29), ReferenceId(33)] +rebuilt : SymbolId(8): [ReferenceId(16), ReferenceId(21)] * object-rest/parameters/input.js x Output mismatch @@ -397,7 +477,9 @@ x Output mismatch x Output mismatch * object-rest/remove-unused-excluded-keys-loose/input.js -x Output mismatch + + x Option `loose` is not implemented for object-rest-spread. + * object-rest/symbol/input.js x Output mismatch @@ -406,17 +488,18 @@ x Output mismatch x Output mismatch * object-rest/template-literal-property-allLiterals-false/input.js -x Output mismatch +Symbol reference IDs mismatch for "input": +after transform: SymbolId(0): [ReferenceId(2), ReferenceId(7), ReferenceId(8)] +rebuilt : SymbolId(0): [ReferenceId(4), ReferenceId(6)] * object-rest/template-literal-property-allLiterals-true/input.js -x Output mismatch +Symbol reference IDs mismatch for "input": +after transform: SymbolId(0): [ReferenceId(0), ReferenceId(1), ReferenceId(2)] +rebuilt : SymbolId(0): [ReferenceId(0), ReferenceId(2)] * object-rest/variable-destructuring/input.js x Output mismatch -* object-rest/with-array-rest/input.js -x Output mismatch - * object-spread/expression/input.js x Output mismatch @@ -424,45 +507,104 @@ x Output mismatch x Output mismatch * object-spread-loose/assignment/input.js -x Output mismatch + + x Option `loose` is not implemented for object-rest-spread. + * object-spread-loose/expression/input.js -x Output mismatch + + x Option `loose` is not implemented for object-rest-spread. + * object-spread-loose/parameters-object-rest-used-in-default/input.js -x Output mismatch + + x Option `loose` is not implemented for object-rest-spread. + * object-spread-loose/side-effect/input.js -x Output mismatch + + x Option `loose` is not implemented for object-rest-spread. + + +* object-spread-loose/targets-support-object-assign/input.js + + x Option `loose` is not implemented for object-rest-spread. + * object-spread-loose/variable-declaration/input.js -x Output mismatch + + x Option `loose` is not implemented for object-rest-spread. + + +* object-spread-loose-builtins/assignment/input.js + + x Option `loose` is not implemented for object-rest-spread. + + + x Option `useBuiltIns` is not implemented for object-rest-spread. + * object-spread-loose-builtins/expression/input.js -x Output mismatch + + x Option `loose` is not implemented for object-rest-spread. + + + x Option `useBuiltIns` is not implemented for object-rest-spread. + * object-spread-loose-builtins/side-effect/input.js -x Output mismatch + + x Option `loose` is not implemented for object-rest-spread. + + + x Option `useBuiltIns` is not implemented for object-rest-spread. + + +* object-spread-loose-builtins/variable-declaration/input.js + + x Option `loose` is not implemented for object-rest-spread. + + + x Option `useBuiltIns` is not implemented for object-rest-spread. + * regression/gh-4904/input.js x Output mismatch * regression/gh-5151/input.js -x Output mismatch +Unresolved reference IDs mismatch for "a": +after transform: [ReferenceId(0), ReferenceId(9), ReferenceId(10)] +rebuilt : [ReferenceId(0), ReferenceId(2)] +Unresolved reference IDs mismatch for "r": +after transform: [ReferenceId(3), ReferenceId(12), ReferenceId(14)] +rebuilt : [ReferenceId(7), ReferenceId(8)] * regression/gh-7304/input.mjs x Output mismatch * regression/gh-7388/input.js -x Output mismatch +Symbol reference IDs mismatch for "obj2": +after transform: SymbolId(5): [ReferenceId(0), ReferenceId(5), ReferenceId(6)] +rebuilt : SymbolId(6): [ReferenceId(0), ReferenceId(2)] * regression/gh-8323/input.js -x Output mismatch + + x Option `loose` is not implemented for object-rest-spread. -# babel-plugin-transform-async-to-generator (11/28) + +# babel-plugin-transform-async-to-generator (10/28) * assumption-ignoreFunctionLength-true/basic/input.mjs -x Output mismatch + + x Compiler assumption `ignoreFunctionLength` is not implemented for object- + | rest-spread. + + +* assumption-ignoreFunctionLength-true/export-default-function/input.mjs + + x Compiler assumption `ignoreFunctionLength` is not implemented for object- + | rest-spread. + * assumption-noNewArrows-false/basic/input.js x Output mismatch @@ -2274,10 +2416,17 @@ Spread children are not supported in React. pragma and pragmaFrag cannot be set when runtime is automatic. * spread-transform/transform-to-babel-extend/input.js -x Output mismatch + + x Option `loose` is not implemented for object-rest-spread. + * spread-transform/transform-to-object-assign/input.js -x Output mismatch + + x Option `loose` is not implemented for object-rest-spread. + + + x Option `useBuiltIns` is not implemented for object-rest-spread. + # babel-plugin-transform-react-jsx-development (8/11) diff --git a/tasks/transform_conformance/snapshots/babel_exec.snap.md b/tasks/transform_conformance/snapshots/babel_exec.snap.md index 293b58bda7efca..30b3dd696d6ba9 100644 --- a/tasks/transform_conformance/snapshots/babel_exec.snap.md +++ b/tasks/transform_conformance/snapshots/babel_exec.snap.md @@ -11,27 +11,9 @@ Error: 'eval' and 'arguments' cannot be used as a binding identifier in strict m ❯ ssrTransformScript ../../node_modules/.pnpm/vite@5.4.8_@types+node@22.9.0/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:52319:11 ❯ loadAndTransform ../../node_modules/.pnpm/vite@5.4.8_@types+node@22.9.0/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:51917:72 -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/14]⎯ +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[1/10]⎯ -⎯⎯⎯⎯⎯⎯ Failed Tests 13 ⎯⎯⎯⎯⎯⎯⎯ - - FAIL fixtures/babel-plugin-transform-object-rest-spread-test-fixtures-assumption-objectRestNoSymbols-rest-ignore-symbols-exec.test.js > exec -AssertionError: expected true to be false // Object.is equality - -- Expected -+ Received - -- false -+ true - - ❯ fixtures/babel-plugin-transform-object-rest-spread-test-fixtures-assumption-objectRestNoSymbols-rest-ignore-symbols-exec.test.js:12:19 - 10| expect(a).toBe(1); - 11| expect(r.b).toBe(2); - 12| expect(sym in r).toBe(false); - | ^ - 13| }) - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/14]⎯ +⎯⎯⎯⎯⎯⎯⎯ Failed Tests 9 ⎯⎯⎯⎯⎯⎯⎯ FAIL fixtures/babel-plugin-transform-object-rest-spread-test-fixtures-assumption-pureGetters-rest-remove-unused-excluded-keys-exec.test.js > exec AssertionError: expected true to be false // Object.is equality @@ -43,13 +25,13 @@ AssertionError: expected true to be false // Object.is equality + true ❯ fixtures/babel-plugin-transform-object-rest-spread-test-fixtures-assumption-pureGetters-rest-remove-unused-excluded-keys-exec.test.js:10:17 - 8| let { foo,...rest } = obj; + 8| let { foo } = obj, rest = _objectWithoutProperties(obj, ["foo"]); 9| expect("foo" in rest).toBe(false); 10| expect(called).toBe(false); | ^ 11| }) -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/14]⎯ +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[2/10]⎯ FAIL fixtures/babel-plugin-transform-object-rest-spread-test-fixtures-assumption-pureGetters-spread-single-call-exec.test.js > exec AssertionError: expected { foo: +0, middle: 1, bar: 1 } to deeply equal { foo: +0, middle: +0, bar: 1 } @@ -72,7 +54,7 @@ AssertionError: expected { foo: +0, middle: 1, bar: 1 } to deeply equal { foo: + 13| foo: 0, 14| middle: 0, -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/14]⎯ +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[3/10]⎯ FAIL fixtures/babel-plugin-transform-object-rest-spread-test-fixtures-assumption-setSpreadProperties-no-object-assign-exec-exec.test.js > exec AssertionError: expected [Function] to throw an error @@ -84,19 +66,7 @@ AssertionError: expected [Function] to throw an error 14| const obj2 = { "NOWRITE": 456 }; 15| expect(() => { -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/14]⎯ - - FAIL fixtures/babel-plugin-transform-object-rest-spread-test-fixtures-assumption-setSpreadProperties-with-useBuiltIns-no-object-assign-exec-exec.test.js > exec -AssertionError: expected [Function] to throw an error - ❯ fixtures/babel-plugin-transform-object-rest-spread-test-fixtures-assumption-setSpreadProperties-with-useBuiltIns-no-object-assign-exec-exec.test.js:13:5 - 11| expect(() => { - 12| const objSpread = _objectSpread({}, obj); - 13| }).toThrow(); - | ^ - 14| const obj2 = { "NOWRITE": 456 }; - 15| expect(() => { - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/14]⎯ +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/10]⎯ FAIL fixtures/babel-plugin-transform-object-rest-spread-test-fixtures-object-spread-expression-exec.test.js > exec AssertionError: expected [ 1, 2 ] to deeply equal [ 1 ] @@ -116,51 +86,7 @@ AssertionError: expected [ 1, 2 ] to deeply equal [ 1 ] | ^ 11| }) -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/14]⎯ - - FAIL fixtures/babel-plugin-transform-object-rest-spread-test-fixtures-object-spread-loose-builtins-side-effect-exec.test.js > exec -AssertionError: expected { a: 1, b: 1 } to deeply equal { a: 2, b: 1 } - -- Expected -+ Received - - Object { -- "a": 2, -+ "a": 1, - "b": 1, - } - - ❯ fixtures/babel-plugin-transform-object-rest-spread-test-fixtures-object-spread-loose-builtins-side-effect-exec.test.js:9:12 - 7| }; - 8| var o = Object.assign(Object.assign({ a: 3 }, k), { b: k.a++ }); - 9| expect(o).toEqual({ - | ^ - 10| a: 2, - 11| b: 1 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/14]⎯ - - FAIL fixtures/babel-plugin-transform-object-rest-spread-test-fixtures-object-spread-loose-side-effect-exec.test.js > exec -AssertionError: expected { a: 1, b: 1 } to deeply equal { a: 2, b: 1 } - -- Expected -+ Received - - Object { -- "a": 2, -+ "a": 1, - "b": 1, - } - - ❯ fixtures/babel-plugin-transform-object-rest-spread-test-fixtures-object-spread-loose-side-effect-exec.test.js:9:12 - 7| }; - 8| var o = Object.assign(Object.assign({ a: 3 }, k), { b: k.a++ }); - 9| expect(o).toEqual({ - | ^ - 10| a: 2, - 11| b: 1 - -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[9/14]⎯ +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[5/10]⎯ FAIL fixtures/babel-plugin-transform-react-jsx-source-test-fixtures-react-source-basic-sample-exec.test.js > exec ReferenceError: transformAsync is not defined @@ -172,7 +98,7 @@ ReferenceError: transformAsync is not defined 5| var expected = ` 6| var _jsxFileName = "/fake/path/mock.js"; -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[10/14]⎯ +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[6/10]⎯ FAIL fixtures/babel-plugin-transform-react-jsx-source-test-fixtures-react-source-with-source-exec.test.js > exec ReferenceError: transformAsync is not defined @@ -184,7 +110,7 @@ ReferenceError: transformAsync is not defined 5| var expected = "var x = ;"; 6| return actualP.then((actual) => { -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[11/14]⎯ +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[7/10]⎯ FAIL fixtures/babel-preset-env-test-fixtures-plugins-integration-issue-15170-exec.test.js > exec AssertionError: expected [Function] to not throw an error but 'ReferenceError: x is not defined' was thrown @@ -202,7 +128,7 @@ undefined | ^ 7| }) -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[12/14]⎯ +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[8/10]⎯ FAIL fixtures/babel-preset-env-test-fixtures-sanity-check-es2015-constants-exec.test.js > exec TypeError: Assignment to constant variable. @@ -213,7 +139,7 @@ TypeError: Assignment to constant variable. | ^ 6| }) -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[13/14]⎯ +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[9/10]⎯ FAIL fixtures/babel-preset-env-test-fixtures-sanity-regex-dot-all-exec.test.js > exec AssertionError: expected false to be true // Object.is equality @@ -232,5 +158,5 @@ AssertionError: expected false to be true // Object.is equality 11| expect(/hello.world/su.test(input)).toBe(true); 12| }) -⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[14/14]⎯ +⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[10/10]⎯