feat(transformer): ES2020 Nullish Coalescing Operator (#1004)

The test runner needs an update for reading options.jon, which I'll work
on in the up coming PR.
This commit is contained in:
Boshen 2023-10-16 21:45:58 +08:00 committed by GitHub
parent 0e9104477f
commit 678db1d955
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 282 additions and 77 deletions

View file

@ -101,6 +101,15 @@ impl<'a> AstBuilder<'a> {
Program { span, source_type, directives, hashbang, body }
}
/* ---------- Constructors ---------- */
/// `void 0`
pub fn void_0(&self) -> Expression<'a> {
let left = self.number_literal(Span::default(), 0.0, "0", NumberBase::Decimal);
let num = self.literal_number_expression(left);
self.unary_expression(Span::default(), UnaryOperator::Void, num)
}
/* ---------- Literals ---------- */
pub fn number_literal(

View file

@ -2,7 +2,7 @@ use oxc_allocator::{Box, Vec};
#[allow(clippy::wildcard_imports)]
use oxc_ast::ast::*;
use oxc_syntax::{
operator::{BinaryOperator, LogicalOperator, UnaryOperator},
operator::{BinaryOperator, UnaryOperator},
precedence::{GetPrecedence, Precedence},
NumberBase,
};
@ -1368,6 +1368,7 @@ impl<'a, const MINIFY: bool> GenExpr<MINIFY> for BinaryExpression<'a> {
p.print_space_before_identifier();
}
self.operator.gen(p, ctx);
p.print_soft_space();
self.right.gen_expr(p, self.precedence(), ctx.union_in_if(wrap));
});
}
@ -1406,11 +1407,9 @@ impl<'a, const MINIFY: bool> GenExpr<MINIFY> for LogicalExpression<'a> {
);
p.wrap(mixed || (precedence > self.precedence()), |p| {
self.left.gen_expr(p, self.precedence(), ctx);
p.print_soft_space();
p.print_str(self.operator.as_str().as_bytes());
let _precedence = match self.operator {
LogicalOperator::And | LogicalOperator::Coalesce => Precedence::BitwiseOr,
LogicalOperator::Or => Precedence::LogicalAnd,
};
p.print_soft_space();
self.right.gen_expr(p, self.precedence(), ctx);
});
}
@ -1421,9 +1420,13 @@ impl<'a, const MINIFY: bool> GenExpr<MINIFY> for ConditionalExpression<'a> {
let wrap = precedence > self.precedence();
p.wrap(wrap, |p| {
self.test.gen_expr(p, self.precedence(), ctx);
p.print_soft_space();
p.print(b'?');
p.print_soft_space();
self.consequent.gen_expr(p, Precedence::Assign, ctx.and_in(true));
p.print_soft_space();
p.print(b':');
p.print_soft_space();
self.alternate.gen_expr(p, Precedence::Assign, ctx.union_in_if(wrap));
});
}

View file

@ -40,13 +40,6 @@ impl<'a> Compressor<'a> {
/* Utilities */
/// `void 0`
fn create_void_0(&mut self) -> Expression<'a> {
let left = self.ast.number_literal(SPAN, 0.0, "0", NumberBase::Decimal);
let num = self.ast.literal_number_expression(left);
self.ast.unary_expression(SPAN, UnaryOperator::Void, num)
}
/// `1/0`
#[allow(unused)]
fn create_one_div_zero(&mut self) -> Expression<'a> {
@ -88,7 +81,7 @@ impl<'a> Compressor<'a> {
fn compress_console(&mut self, expr: &mut Expression<'a>) -> bool {
if self.options.drop_console && util::is_console(expr) {
*expr = self.create_void_0();
*expr = self.ast.void_0();
true
} else {
false
@ -163,12 +156,12 @@ impl<'a> Compressor<'a> {
/* Expressions */
/// Transforms `undefined` => `void 0`
fn compress_undefined(&mut self, expr: &mut Expression<'a>) -> bool {
fn compress_undefined(&self, expr: &mut Expression<'a>) -> bool {
let Expression::Identifier(ident) = expr else { return false };
if ident.name == "undefined" {
// if let Some(reference_id) = ident.reference_id.get() {
// && self.semantic.symbols().is_global_reference(reference_id)
*expr = self.create_void_0();
*expr = self.ast.void_0();
return true;
// }
}
@ -209,14 +202,14 @@ impl<'a> Compressor<'a> {
/// Transforms `typeof foo == "undefined"` into `foo === void 0`
/// Enabled by `compress.typeofs`
fn compress_typeof_undefined(&mut self, expr: &mut BinaryExpression<'a>) {
fn compress_typeof_undefined(&self, expr: &mut BinaryExpression<'a>) {
if expr.operator.is_equality() && self.options.typeofs {
if let Expression::UnaryExpression(unary_expr) = &expr.left {
if unary_expr.operator == UnaryOperator::Typeof {
if let Expression::Identifier(ident) = &unary_expr.argument {
if expr.right.is_specific_string_literal("undefined") {
let left = self.ast.identifier_reference_expression((*ident).clone());
let right = self.create_void_0();
let right = self.ast.void_0();
let operator = BinaryOperator::StrictEquality;
*expr = BinaryExpression { span: SPAN, left, operator, right };
}

View file

@ -1,3 +1,4 @@
use oxc_ast::ast::Expression;
use oxc_index::IndexVec;
use oxc_span::{Atom, Span};
pub use oxc_syntax::{
@ -112,4 +113,26 @@ impl SymbolTable {
.iter()
.map(|reference_id| &self.references[*reference_id])
}
/// Determine whether evaluating the specific input `node` is a consequenceless reference. ie.
/// evaluating it won't result in potentially arbitrary code from being ran. The following are
/// allowed and determined not to cause side effects:
///
/// - `this` expressions
/// - `super` expressions
/// - Bound identifiers
///
/// Reference:
/// <https://github.com/babel/babel/blob/419644f27c5c59deb19e71aaabd417a3bc5483ca/packages/babel-traverse/src/scope/index.ts#L557>
pub fn is_static(&self, expr: &Expression) -> bool {
match expr {
Expression::ThisExpression(_) | Expression::Super(_) => true,
Expression::Identifier(ident)
if ident.reference_id.get().is_some_and(|id| self.has_binding(id)) =>
{
true
}
_ => false,
}
}
}

View file

@ -5,7 +5,9 @@ use oxc_codegen::{Codegen, CodegenOptions};
use oxc_parser::Parser;
use oxc_semantic::SemanticBuilder;
use oxc_span::SourceType;
use oxc_transformer::{TransformOptions, TransformReactOptions, TransformTarget, Transformer};
use oxc_transformer::{
Assumptions, TransformOptions, TransformReactOptions, TransformTarget, Transformer,
};
// Instruction:
// create a `test.js`,
@ -41,6 +43,7 @@ fn main() {
let transform_options = TransformOptions {
target: TransformTarget::ES2015,
react: Some(TransformReactOptions::default()),
assumptions: Assumptions::default(),
};
Transformer::new(&allocator, source_type, &symbols, transform_options).build(program);
let printed = Codegen::<false>::new(source_text.len(), codegen_options).build(program);

View file

@ -1,10 +1,12 @@
use std::{cell::RefCell, rc::Rc};
use oxc_allocator::Vec;
use oxc_ast::{ast::*, AstBuilder};
use oxc_semantic::SymbolTable;
use oxc_span::{Atom, Span};
use oxc_syntax::operator::{AssignmentOperator, BinaryOperator};
use std::{cell::RefCell, mem, rc::Rc};
use crate::utils::CreateVars;
/// ES2016: Exponentiation Operator
///
@ -23,23 +25,22 @@ struct Exploded<'a> {
uid: Expression<'a>,
}
impl<'a> CreateVars<'a> for ExponentiationOperator<'a> {
fn ast(&self) -> &AstBuilder<'a> {
&self.ast
}
fn vars_mut(&mut self) -> &mut Vec<'a, VariableDeclarator<'a>> {
&mut self.vars
}
}
impl<'a> ExponentiationOperator<'a> {
pub fn new(ast: Rc<AstBuilder<'a>>, symbols: Rc<RefCell<SymbolTable>>) -> Self {
let vars = ast.new_vec();
Self { ast, symbols, vars }
}
pub fn leave_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
if self.vars.is_empty() {
return;
}
let decls = mem::replace(&mut self.vars, self.ast.new_vec());
let kind = VariableDeclarationKind::Var;
let decl = self.ast.variable_declaration(Span::default(), kind, decls, Modifiers::empty());
let stmt = Statement::Declaration(Declaration::VariableDeclaration(decl));
stmts.insert(0, stmt);
}
pub fn transform_expression(&mut self, expr: &mut Expression<'a>) {
// left ** right
if let Expression::BinaryExpression(binary_expr) = expr {
@ -218,17 +219,7 @@ impl<'a> ExponentiationOperator<'a> {
expr: Expression<'a>,
nodes: &mut Vec<'a, Expression<'a>>,
) -> Expression<'a> {
let name = generate_uid_identifier_based_on_node(&expr);
// TODO: scope.push({ id: temp });
// Add `var name` to scope
let binding_identifier = BindingIdentifier::new(Span::default(), name.clone());
let binding_pattern_kind = self.ast.binding_pattern_identifier(binding_identifier);
let binding = self.ast.binding_pattern(binding_pattern_kind, None, false);
let kind = VariableDeclarationKind::Var;
let decl = self.ast.variable_declarator(Span::default(), kind, binding, None, false);
self.vars.push(decl);
let name = self.create_new_var(&expr);
// Add new reference `_name = name` to nodes
let ident = IdentifierReference::new(Span::default(), name);
let target = self.ast.simple_assignment_target_identifier(ident.clone());
@ -239,23 +230,6 @@ impl<'a> ExponentiationOperator<'a> {
}
}
// TODO:
// <https://github.com/babel/babel/blob/419644f27c5c59deb19e71aaabd417a3bc5483ca/packages/babel-traverse/src/scope/index.ts#L543>
fn generate_uid_identifier_based_on_node(expr: &Expression) -> Atom {
let mut parts = std::vec::Vec::with_capacity(1);
gather_node_parts(expr, &mut parts);
let name = parts.join("$");
Atom::from(format!("_{name}"))
}
// TODO: use a trait and add this to oxc_ast (syntax directed operations)
fn gather_node_parts(expr: &Expression, parts: &mut std::vec::Vec<Atom>) {
match expr {
Expression::Identifier(ident) => parts.push(ident.name.clone()),
_ => parts.push(Atom::from("ref")),
}
}
#[test]
fn test() {
use crate::{

View file

@ -0,0 +1,3 @@
mod nullish_coalescing_operator;
pub use nullish_coalescing_operator::NullishCoalescingOperator;

View file

@ -0,0 +1,88 @@
use std::{cell::RefCell, rc::Rc};
use oxc_allocator::Vec;
use oxc_ast::{ast::*, AstBuilder};
use oxc_semantic::SymbolTable;
use oxc_span::Span;
use oxc_syntax::operator::{AssignmentOperator, BinaryOperator, LogicalOperator};
use crate::{options::Assumptions, utils::CreateVars};
/// ES2020: Nullish Coalescing Operator
///
/// References:
/// * <https://babeljs.io/docs/babel-plugin-transform-nullish-coalescing-operator>
/// * <https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-nullish-coalescing-operator>
pub struct NullishCoalescingOperator<'a> {
ast: Rc<AstBuilder<'a>>,
symbols: Rc<RefCell<SymbolTable>>,
assumptions: Assumptions,
vars: Vec<'a, VariableDeclarator<'a>>,
}
impl<'a> CreateVars<'a> for NullishCoalescingOperator<'a> {
fn ast(&self) -> &AstBuilder<'a> {
&self.ast
}
fn vars_mut(&mut self) -> &mut Vec<'a, VariableDeclarator<'a>> {
&mut self.vars
}
}
impl<'a> NullishCoalescingOperator<'a> {
pub fn new(
ast: Rc<AstBuilder<'a>>,
symbols: Rc<RefCell<SymbolTable>>,
assumptions: Assumptions,
) -> Self {
let vars = ast.new_vec();
Self { ast, symbols, assumptions, vars }
}
pub fn transform_expression(&mut self, expr: &mut Expression<'a>) {
// left ?? right
let Expression::LogicalExpression(logical_expr) = expr else { return };
if logical_expr.operator != LogicalOperator::Coalesce {
return;
}
let span = Span::default();
let reference;
let assignment;
// skip creating extra reference when `left` is static
if self.symbols.borrow().is_static(&logical_expr.left) {
reference = self.ast.copy(&logical_expr.left);
assignment = self.ast.copy(&logical_expr.left);
} else {
let name = self.create_new_var(&logical_expr.left);
let ident = IdentifierReference::new(span, name);
reference = self.ast.identifier_reference_expression(ident.clone());
let left = AssignmentTarget::SimpleAssignmentTarget(
self.ast.simple_assignment_target_identifier(ident),
);
let right = self.ast.copy(&logical_expr.left);
assignment =
self.ast.assignment_expression(span, AssignmentOperator::Assign, left, right);
};
let test = if self.assumptions.no_document_all {
let null = self.ast.literal_null_expression(NullLiteral::new(span));
self.ast.binary_expression(span, assignment, BinaryOperator::Inequality, null)
} else {
let op = BinaryOperator::StrictInequality;
let null = self.ast.literal_null_expression(NullLiteral::new(span));
let left = self.ast.binary_expression(span, self.ast.copy(&assignment), op, null);
let right =
self.ast.binary_expression(span, self.ast.copy(&reference), op, self.ast.void_0());
self.ast.logical_expression(span, left, LogicalOperator::And, right)
};
let right = self.ast.move_expression(&mut logical_expr.right);
*expr = self.ast.conditional_expression(span, test, reference, right);
}
}

View file

@ -10,6 +10,7 @@
mod es2015;
mod es2016;
mod es2019;
mod es2020;
mod es2021;
mod es2022;
mod options;
@ -18,6 +19,7 @@ mod regexp;
#[cfg(test)]
mod tester;
mod typescript;
mod utils;
use std::{cell::RefCell, rc::Rc};
@ -28,12 +30,12 @@ use oxc_span::SourceType;
use crate::{
es2015::ShorthandProperties, es2016::ExponentiationOperator, es2019::OptionalCatchBinding,
es2021::LogicalAssignmentOperators, react_jsx::ReactJsx, regexp::RegexpFlags,
typescript::TypeScript,
es2020::NullishCoalescingOperator, es2021::LogicalAssignmentOperators, react_jsx::ReactJsx,
regexp::RegexpFlags, typescript::TypeScript, utils::CreateVars,
};
pub use crate::options::{
TransformOptions, TransformReactOptions, TransformReactRuntime, TransformTarget,
Assumptions, TransformOptions, TransformReactOptions, TransformReactRuntime, TransformTarget,
};
#[derive(Default)]
@ -47,6 +49,8 @@ pub struct Transformer<'a> {
es2022_class_static_block: Option<es2022::ClassStaticBlock<'a>>,
// es2021
es2021_logical_assignment_operators: Option<LogicalAssignmentOperators<'a>>,
// es2020
es2020_nullish_coalescing_operators: Option<NullishCoalescingOperator<'a>>,
// es2019
es2019_optional_catch_binding: Option<OptionalCatchBinding<'a>>,
// es2016
@ -70,6 +74,7 @@ impl<'a> Transformer<'a> {
regexp_flags: RegexpFlags::new(Rc::clone(&ast), options.target),
es2022_class_static_block: (options.target < TransformTarget::ES2022).then(|| es2022::ClassStaticBlock::new(Rc::clone(&ast))),
es2021_logical_assignment_operators: (options.target < TransformTarget::ES2021).then(|| LogicalAssignmentOperators::new(Rc::clone(&ast))),
es2020_nullish_coalescing_operators: (options.target < TransformTarget::ES2020).then(|| NullishCoalescingOperator::new(Rc::clone(&ast), Rc::clone(symbols), options.assumptions)),
es2019_optional_catch_binding: (options.target < TransformTarget::ES2019).then(|| OptionalCatchBinding::new(Rc::clone(&ast))),
es2016_exponentiation_operator: (options.target < TransformTarget::ES2016).then(|| ExponentiationOperator::new(Rc::clone(&ast), Rc::clone(symbols))),
es2015_shorthand_properties: (options.target < TransformTarget::ES2015).then(|| ShorthandProperties::new(Rc::clone(&ast))),
@ -86,7 +91,8 @@ impl<'a> VisitMut<'a> for Transformer<'a> {
for stmt in stmts.iter_mut() {
self.visit_statement(stmt);
}
self.es2016_exponentiation_operator.as_mut().map(|t| t.leave_statements(stmts));
self.es2016_exponentiation_operator.as_mut().map(|t| t.add_vars_to_statements(stmts));
self.es2020_nullish_coalescing_operators.as_mut().map(|t| t.add_vars_to_statements(stmts));
}
fn visit_expression(&mut self, expr: &mut Expression<'a>) {
@ -95,6 +101,7 @@ impl<'a> VisitMut<'a> for Transformer<'a> {
self.regexp_flags.as_mut().map(|t| t.transform_expression(expr));
self.es2021_logical_assignment_operators.as_mut().map(|t| t.transform_expression(expr));
self.es2020_nullish_coalescing_operators.as_mut().map(|t| t.transform_expression(expr));
self.es2016_exponentiation_operator.as_mut().map(|t| t.transform_expression(expr));
self.visit_expression_match(expr);

View file

@ -1,7 +1,8 @@
#[derive(Debug, Default, Clone)]
#[derive(Debug, Default, Clone, Copy)]
pub struct TransformOptions {
pub target: TransformTarget,
pub react: Option<TransformReactOptions>,
pub assumptions: Assumptions,
}
/// See <https://www.typescriptlang.org/tsconfig#target>
@ -12,6 +13,7 @@ pub enum TransformTarget {
ES2016,
ES2018,
ES2019,
ES2020,
ES2021,
ES2022,
ES2024,
@ -19,14 +21,24 @@ pub enum TransformTarget {
ESNext,
}
#[derive(Debug, Default, Clone)]
#[derive(Debug, Default, Clone, Copy)]
pub struct TransformReactOptions {
_runtime: TransformReactRuntime,
}
#[derive(Debug, Default, Clone)]
#[derive(Debug, Default, Clone, Copy)]
pub enum TransformReactRuntime {
#[default]
Classic,
Automatic,
}
/// Compiler assumptions
///
/// See <https://babeljs.io/docs/assumptions>
#[derive(Debug, Default, Clone, Copy)]
pub struct Assumptions {
/// When using operators that check for null or undefined, assume that they are never used with the special value document.all.
/// See <https://babeljs.io/docs/assumptions#nodocumentall>.
pub no_document_all: bool,
}

View file

@ -38,8 +38,7 @@ impl Tester {
let symbols = Rc::new(RefCell::new(symbols));
let program = self.allocator.alloc(program);
Transformer::new(&self.allocator, self.source_type, &symbols, self.options.clone())
.build(program);
Transformer::new(&self.allocator, self.source_type, &symbols, self.options).build(program);
Codegen::<false>::new(source_text.len(), CodegenOptions).build(program)
}

View file

@ -0,0 +1,85 @@
use std::mem;
use oxc_allocator::Vec;
use oxc_ast::{ast::*, AstBuilder};
use oxc_span::{Atom, Span};
// TODO:
// <https://github.com/babel/babel/blob/419644f27c5c59deb19e71aaabd417a3bc5483ca/packages/babel-traverse/src/scope/index.ts#L543>
pub fn generate_uid_based_on_node(expr: &Expression) -> Atom {
let mut parts = std::vec::Vec::with_capacity(1);
expr.gather(&mut |part| parts.push(part));
let name = parts.join("$");
Atom::from(format!("_{name}"))
}
// TODO: <https://github.com/babel/babel/blob/419644f27c5c59deb19e71aaabd417a3bc5483ca/packages/babel-traverse/src/scope/index.ts#L61>
pub trait GatherNodeParts {
fn gather<F: FnMut(Atom)>(&self, f: &mut F);
}
impl<'a> GatherNodeParts for Expression<'a> {
fn gather<F: FnMut(Atom)>(&self, f: &mut F) {
match self {
Self::Identifier(ident) => f(ident.name.clone()),
Self::MemberExpression(expr) => expr.gather(f),
_ => f(Atom::from("ref")),
}
}
}
impl<'a> GatherNodeParts for MemberExpression<'a> {
fn gather<F: FnMut(Atom)>(&self, f: &mut F) {
self.object().gather(f);
match self {
MemberExpression::ComputedMemberExpression(expr) => expr.expression.gather(f),
MemberExpression::StaticMemberExpression(expr) => expr.property.gather(f),
MemberExpression::PrivateFieldExpression(expr) => expr.field.gather(f),
}
}
}
impl GatherNodeParts for IdentifierName {
fn gather<F: FnMut(Atom)>(&self, f: &mut F) {
f(self.name.clone());
}
}
impl GatherNodeParts for PrivateIdentifier {
fn gather<F: FnMut(Atom)>(&self, f: &mut F) {
f(self.name.clone());
}
}
pub trait CreateVars<'a> {
fn ast(&self) -> &AstBuilder<'a>;
fn vars_mut(&mut self) -> &mut Vec<'a, VariableDeclarator<'a>>;
fn add_vars_to_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>) {
if self.vars_mut().is_empty() {
return;
}
let new_vec = self.ast().new_vec();
let decls = mem::replace(self.vars_mut(), new_vec);
let kind = VariableDeclarationKind::Var;
let decl =
self.ast().variable_declaration(Span::default(), kind, decls, Modifiers::empty());
let stmt = Statement::Declaration(Declaration::VariableDeclaration(decl));
stmts.insert(0, stmt);
}
fn create_new_var(&mut self, expr: &Expression<'a>) -> Atom {
let name = generate_uid_based_on_node(expr);
// TODO: scope.push({ id: temp });
// Add `var name` to scope
let binding_identifier = BindingIdentifier::new(Span::default(), name.clone());
let binding_pattern_kind = self.ast().binding_pattern_identifier(binding_identifier);
let binding = self.ast().binding_pattern(binding_pattern_kind, None, false);
let kind = VariableDeclarationKind::Var;
let decl = self.ast().variable_declarator(Span::default(), kind, binding, None, false);
self.vars_mut().push(decl);
name
}
}

View file

@ -11,7 +11,7 @@ use oxc::{
parser::{Parser, ParserReturn},
semantic::{SemanticBuilder, SemanticBuilderReturn},
span::SourceType,
transformer::{TransformOptions, TransformTarget, Transformer},
transformer::{Assumptions, TransformOptions, TransformTarget, Transformer},
};
use oxc_linter::{LintContext, Linter};
use oxc_query::{schema, Adapter, SCHEMA_TEXT};
@ -215,7 +215,11 @@ impl Oxc {
let semantic = SemanticBuilder::new(source_text, source_type).build(program).semantic;
let (symbols, _scope_tree) = semantic.into_symbol_table_and_scope_tree();
let symbols = Rc::new(RefCell::new(symbols));
let options = TransformOptions { target: TransformTarget::ES2015, react: None };
let options = TransformOptions {
target: TransformTarget::ES2015,
react: None,
assumptions: Assumptions::default(),
};
Transformer::new(&allocator, source_type, &symbols, options).build(program);
}

View file

@ -1,4 +1,4 @@
Passed: 94/1091
Passed: 95/1091
# babel-plugin-transform-unicode-sets-regex (0/4)
* Failed: basic/basic/input.js
@ -491,8 +491,11 @@ Passed: 94/1091
* Failed: to-native-fields/static-shadow/input.js
* Failed: to-native-fields/static-shadowed-binding/input.js
# babel-plugin-transform-logical-assignment-operators (3/6)
# babel-plugin-transform-logical-assignment-operators (0/6)
* Failed: logical-assignment/anonymous-functions-transform/input.js
* Failed: logical-assignment/arrow-functions-transform/input.js
* Failed: logical-assignment/general-semantics/input.js
* Failed: logical-assignment/named-functions-transform/input.js
* Failed: logical-assignment/null-coalescing/input.js
* Failed: logical-assignment/null-coalescing-without-other/input.js
@ -532,19 +535,15 @@ Passed: 94/1091
* Failed: export-namespace/namespace-string/input.mjs
* Failed: export-namespace/namespace-typescript/input.mjs
# babel-plugin-transform-nullish-coalescing-operator (0/12)
# babel-plugin-transform-nullish-coalescing-operator (4/12)
* Failed: assumption-noDocumentAll/transform/input.js
* Failed: assumption-noDocumentAll/transform-in-default-destructuring/input.js
* Failed: assumption-noDocumentAll/transform-in-default-param/input.js
* Failed: assumption-noDocumentAll/transform-in-function/input.js
* Failed: assumption-noDocumentAll/transform-static-refs-in-default/input.js
* Failed: assumption-noDocumentAll/transform-static-refs-in-function/input.js
* Failed: nullish-coalescing/transform-in-default-destructuring/input.js
* Failed: nullish-coalescing/transform-in-default-param/input.js
* Failed: nullish-coalescing/transform-in-function/input.js
* Failed: nullish-coalescing/transform-loose/input.js
* Failed: nullish-coalescing/transform-static-refs-in-default/input.js
* Failed: nullish-coalescing/transform-static-refs-in-function/input.js
# babel-plugin-transform-optional-chaining (1/46)
* Failed: assumption-noDocumentAll/assignment/input.js

View file

@ -13,7 +13,9 @@ use oxc_parser::Parser;
use oxc_semantic::SemanticBuilder;
use oxc_span::{SourceType, VALID_EXTENSIONS};
use oxc_tasks_common::{normalize_path, project_root};
use oxc_transformer::{TransformOptions, TransformReactOptions, TransformTarget, Transformer};
use oxc_transformer::{
Assumptions, TransformOptions, TransformReactOptions, TransformTarget, Transformer,
};
#[test]
#[cfg(any(coverage, coverage_nightly))]
@ -155,6 +157,7 @@ fn babel_test(input_path: &Path, options: &BabelOptions) -> bool {
let transform_options = TransformOptions {
target: TransformTarget::ES5,
react: Some(TransformReactOptions::default()),
assumptions: Assumptions::default(),
};
let semantic =