feat(transformer): add partial support for babel-plugin-transform-instanceof (#1802)

This commit is contained in:
秦宇航 2023-12-25 15:06:41 +08:00 committed by GitHub
parent a1accdca7f
commit ae27a8d1e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 90 additions and 2 deletions

View file

@ -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:
/// * <https://babel.dev/docs/babel-plugin-transform-instanceof>
/// * <https://github.com/babel/babel/tree/main/packages/babel-plugin-transform-instanceof>
pub struct Instanceof<'a> {
ast: Rc<AstBuilder<'a>>,
ctx: TransformerCtx<'a>,
}
impl<'a> Instanceof<'a> {
pub fn new(
ast: Rc<AstBuilder<'a>>,
ctx: TransformerCtx<'a>,
options: &TransformOptions,
) -> Option<Self> {
(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);
}
}
}
}

View file

@ -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;

View file

@ -68,6 +68,7 @@ pub struct Transformer<'a> {
es2015_shorthand_properties: Option<ShorthandProperties<'a>>,
es2015_template_literals: Option<TemplateLiterals<'a>>,
es2015_duplicate_keys: Option<DuplicateKeys<'a>>,
es2015_instanceof: Option<Instanceof<'a>>,
es3_property_literal: Option<PropertyLiteral<'a>>,
}
@ -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));

View file

@ -31,6 +31,7 @@ pub struct TransformOptions {
pub template_literals: bool,
pub property_literals: bool,
pub babel_8_breaking: Option<bool>,
pub instanceof: bool,
}
/// See <https://www.typescriptlang.org/tsconfig#target>

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -94,6 +94,7 @@ pub trait TestCase {
.map(get_options::<ReactJsxOptions>),
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")