diff --git a/crates/oxc_transformer/src/es2015/instanceof.rs b/crates/oxc_transformer/src/es2015/instanceof.rs new file mode 100644 index 000000000..025d4d206 --- /dev/null +++ b/crates/oxc_transformer/src/es2015/instanceof.rs @@ -0,0 +1,76 @@ +use oxc_ast::{ast::*, AstBuilder, AstKind}; +use oxc_semantic::AstNodeId; +use oxc_span::SPAN; +use std::rc::Rc; + +use oxc_syntax::operator::BinaryOperator; + +use crate::context::TransformerCtx; +use crate::options::TransformOptions; +use crate::TransformTarget; + +/// ES2015: instanceof +/// +/// References: +/// * +/// * +pub struct Instanceof<'a> { + ast: Rc>, + ctx: TransformerCtx<'a>, +} + +impl<'a> Instanceof<'a> { + pub fn new( + ast: Rc>, + ctx: TransformerCtx<'a>, + options: &TransformOptions, + ) -> Option { + (options.target < TransformTarget::ES2015 || options.instanceof).then(|| Self { ast, ctx }) + } + + pub fn transform_expression(&mut self, expr: &mut Expression<'a>) { + // if instanceof syntax is under a helper, it should not be transformed + if let Expression::BinaryExpression(be) = expr { + if let BinaryExpression { operator: BinaryOperator::Instanceof, left, right, .. } = + &**be + { + let is_under_helper = self + .ctx + .semantic() + .nodes() + // FIXME: how to get the AstNodeId of the expression? + .iter_parents(AstNodeId::new(1)) // expr.get_id or sth + .any(|parent| { + if let AstKind::CallExpression(CallExpression { callee, .. }) = + parent.kind() + { + return callee.is_specific_member_access("babelHelpers", "instanceof"); + }; + false + }); + + if is_under_helper { + return; + } + + let object = self.ast.identifier_reference_expression(IdentifierReference::new( + SPAN, + "babelHelpers".into(), + )); + + let property = IdentifierName::new(SPAN, "instanceof".into()); + let helper = self.ast.member_expression(MemberExpression::StaticMemberExpression( + StaticMemberExpression { span: SPAN, object, property, optional: false }, + )); + + let left = self.ast.copy(left); + let right = self.ast.copy(right); + let mut args = self.ast.new_vec_with_capacity(2); + args.push(Argument::Expression(left)); + args.push(Argument::Expression(right)); + + *expr = self.ast.call_expression(SPAN, helper, args, false, None); + } + } + } +} diff --git a/crates/oxc_transformer/src/es2015/mod.rs b/crates/oxc_transformer/src/es2015/mod.rs index ea89390f3..b77842f79 100644 --- a/crates/oxc_transformer/src/es2015/mod.rs +++ b/crates/oxc_transformer/src/es2015/mod.rs @@ -1,11 +1,13 @@ mod arrow_functions; mod duplicate_keys; mod function_name; +mod instanceof; mod shorthand_properties; mod template_literals; pub use arrow_functions::{ArrowFunctions, ArrowFunctionsOptions}; pub use duplicate_keys::DuplicateKeys; pub use function_name::FunctionName; +pub use instanceof::Instanceof; pub use shorthand_properties::ShorthandProperties; pub use template_literals::TemplateLiterals; diff --git a/crates/oxc_transformer/src/lib.rs b/crates/oxc_transformer/src/lib.rs index df2f808e2..51836ea0d 100644 --- a/crates/oxc_transformer/src/lib.rs +++ b/crates/oxc_transformer/src/lib.rs @@ -68,6 +68,7 @@ pub struct Transformer<'a> { es2015_shorthand_properties: Option>, es2015_template_literals: Option>, es2015_duplicate_keys: Option>, + es2015_instanceof: Option>, es3_property_literal: Option>, } @@ -106,6 +107,7 @@ impl<'a> Transformer<'a> { es2015_shorthand_properties: ShorthandProperties::new(Rc::clone(&ast), &options), es2015_template_literals: TemplateLiterals::new(Rc::clone(&ast), &options), es2015_duplicate_keys: DuplicateKeys::new(Rc::clone(&ast), &options), + es2015_instanceof: Instanceof::new(Rc::clone(&ast), ctx.clone(), &options), // other es3_property_literal: PropertyLiteral::new(Rc::clone(&ast), &options), react_jsx: ReactJsx::new(Rc::clone(&ast), ctx.clone(), options) @@ -179,6 +181,7 @@ impl<'a> VisitMut<'a> for Transformer<'a> { 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.es2015_arrow_functions.as_mut().map(|t| t.transform_expression(expr)); + self.es2015_instanceof.as_mut().map(|t| t.transform_expression(expr)); self.es2016_exponentiation_operator.as_mut().map(|t| t.transform_expression(expr)); self.es2015_template_literals.as_mut().map(|t| t.transform_expression(expr)); diff --git a/crates/oxc_transformer/src/options.rs b/crates/oxc_transformer/src/options.rs index eaef7e82c..19caf8709 100644 --- a/crates/oxc_transformer/src/options.rs +++ b/crates/oxc_transformer/src/options.rs @@ -31,6 +31,7 @@ pub struct TransformOptions { pub template_literals: bool, pub property_literals: bool, pub babel_8_breaking: Option, + pub instanceof: bool, } /// See diff --git a/tasks/transform_conformance/babel.snap.md b/tasks/transform_conformance/babel.snap.md index d499daf7a..2394472f9 100644 --- a/tasks/transform_conformance/babel.snap.md +++ b/tasks/transform_conformance/babel.snap.md @@ -1,4 +1,4 @@ -Passed: 294/1170 +Passed: 295/1171 # All Passed: * babel-plugin-transform-numeric-separator @@ -6,6 +6,7 @@ Passed: 294/1170 * babel-plugin-transform-json-strings * babel-plugin-transform-shorthand-properties * babel-plugin-transform-sticky-regex +* babel-plugin-transform-instanceof * babel-plugin-transform-property-literals diff --git a/tasks/transform_conformance/babel_exec.snap.md b/tasks/transform_conformance/babel_exec.snap.md index 7be9face3..d406c3cae 100644 --- a/tasks/transform_conformance/babel_exec.snap.md +++ b/tasks/transform_conformance/babel_exec.snap.md @@ -1,4 +1,4 @@ -Passed: 379/444 +Passed: 379/445 # All Passed: * babel-plugin-transform-class-static-block @@ -95,3 +95,6 @@ Passed: 379/444 # babel-plugin-transform-arrow-functions (2/3) * arrow-functions/implicit-var-arguments/exec.js +# babel-plugin-transform-instanceof (0/1) +* instanceof/instanceof/exec.js + diff --git a/tasks/transform_conformance/src/lib.rs b/tasks/transform_conformance/src/lib.rs index da7fb2676..a50df966b 100644 --- a/tasks/transform_conformance/src/lib.rs +++ b/tasks/transform_conformance/src/lib.rs @@ -81,6 +81,7 @@ const CASES: &[&str] = &[ "babel-plugin-transform-unicode-regex", "babel-plugin-transform-template-literals", "babel-plugin-transform-duplicate-keys", + "babel-plugin-transform-instanceof", // ES3 "babel-plugin-transform-property-literals", // TypeScript diff --git a/tasks/transform_conformance/src/test_case.rs b/tasks/transform_conformance/src/test_case.rs index 1fc8ce67a..486d57867 100644 --- a/tasks/transform_conformance/src/test_case.rs +++ b/tasks/transform_conformance/src/test_case.rs @@ -94,6 +94,7 @@ pub trait TestCase { .map(get_options::), assumptions: options.assumptions, class_static_block: options.get_plugin("transform-class-static-block").is_some(), + instanceof: options.get_plugin("transform-instanceof").is_some(), function_name: options.get_plugin("transform-function-name").is_some(), arrow_functions: options .get_plugin("transform-arrow-functions")