Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Boshen committed Nov 11, 2024
1 parent 1282221 commit a9a0d7f
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 2 deletions.
4 changes: 4 additions & 0 deletions crates/oxc_transformer/src/common/helper_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ pub enum Helper {
AsyncToGenerator,
ObjectSpread2,
WrapAsyncGenerator,
Extends,
ObjectDestructuringEmpty,
}

impl Helper {
Expand All @@ -154,6 +156,8 @@ impl Helper {
Self::AsyncToGenerator => "asyncToGenerator",
Self::ObjectSpread2 => "objectSpread2",
Self::WrapAsyncGenerator => "wrapAsyncGenerator",
Self::Extends => "extends",
Self::ObjectDestructuringEmpty => "objectDestructuringEmpty",
}
}
}
Expand Down
12 changes: 11 additions & 1 deletion crates/oxc_transformer/src/es2018/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pub(crate) mod async_generator_functions;
mod object_rest_spread;
mod options;

use oxc_ast::ast::{Expression, ForOfStatement, Function, Statement};
use oxc_ast::ast::{Expression, ForOfStatement, Function, Statement, VariableDeclaration};
use oxc_traverse::{Traverse, TraverseCtx};

use crate::context::TransformCtx;
Expand Down Expand Up @@ -67,4 +67,14 @@ 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);
}
}
}
82 changes: 82 additions & 0 deletions crates/oxc_transformer/src/es2018/object_rest_spread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

use serde::Deserialize;

use oxc_allocator::CloneIn;
use oxc_ast::{ast::*, NONE};
use oxc_semantic::{ReferenceFlags, SymbolId};
use oxc_span::SPAN;
Expand All @@ -46,6 +47,7 @@ pub struct ObjectRestSpreadOptions {

pub struct ObjectRestSpread<'a, 'ctx> {
ctx: &'ctx TransformCtx<'a>,

options: ObjectRestSpreadOptions,
}

Expand All @@ -59,6 +61,14 @@ impl<'a, 'ctx> Traverse<'a> for ObjectRestSpread<'a, 'ctx> {
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);
}
}

impl<'a, 'ctx> ObjectRestSpread<'a, 'ctx> {
Expand Down Expand Up @@ -148,3 +158,75 @@ 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>,
) {
for variable_declarator in decl.declarations.iter_mut() {
self.transform_variable_declarator(variable_declarator, ctx);
}
}

fn transform_variable_declarator(
&mut self,
decl: &mut VariableDeclarator<'a>,
ctx: &mut TraverseCtx<'a>,
) {
// Get the object pattern.
let BindingPatternKind::ObjectPattern(pat) = &mut decl.id.kind else { return };
// It is syntax error if rest element is a destructuring pattern, so abort early.
// It is syntax error if missing initializer in destructuring declaration, so abort early.
if decl.init.is_none()
|| pat.rest.is_none()
|| pat.rest.as_ref().is_some_and(|rest| rest.argument.kind.is_destructuring_pattern())
{
return;
}

// let { ...a } = b;
if pat.properties.is_empty()
&& decl.init.as_ref().is_some_and(Expression::is_identifier_reference)
{
// Get the rest spread.
let Some(rest) = std::mem::take(&mut pat.rest) else {
return;
};
// Change to `let a`
decl.id = rest.unbox().argument;

// Change `b` to `_extends({}, (_objectDestructuringEmpty(b), b));`
let init = ctx.ast.move_expression(decl.init.as_mut().unwrap());

let mut arguments = ctx.ast.vec();

// Add `{}`.
arguments.push(Argument::ObjectExpression(ctx.ast.alloc_object_expression(
SPAN,
ctx.ast.vec(),
None,
)));

// Add `_extends({}, (_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,
// FIXME: create a new reference instead of clone.
ctx.ast.vec1(Argument::from(init.clone_in(ctx.ast.allocator))),
ctx,
));
sequence.push(init);
sequence
},
)));

// `let a = _extends({}, (_objectDestructuringEmpty(b), b));`
decl.init = Some(self.ctx.helper_call_expr(Helper::Extends, arguments, ctx));
}
}
}
8 changes: 8 additions & 0 deletions crates/oxc_transformer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,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>,
Expand Down
5 changes: 4 additions & 1 deletion tasks/transform_conformance/snapshots/babel.snap.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,10 @@ x Output mismatch
x Output mismatch

* object-rest/duplicate-decl-bug/input.js
x Output mismatch
Missing ReferenceId: "original"
Symbol reference IDs mismatch for "original":
after transform: SymbolId(0): [ReferenceId(1)]
rebuilt : SymbolId(0): [ReferenceId(3), ReferenceId(4)]

* object-rest/export/input.mjs
x Output mismatch
Expand Down

0 comments on commit a9a0d7f

Please sign in to comment.