feat(transformer/decorators): support method decorator and is not static (#2238)

This commit is contained in:
Dunqing 2024-02-01 11:36:22 +08:00 committed by GitHub
parent d0d708295b
commit ba85b097e0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 89 additions and 9 deletions

View file

@ -9,7 +9,7 @@ use num_bigint::BigInt;
use std::mem;
use oxc_allocator::{Allocator, Box, String, Vec};
use oxc_span::{Atom, GetSpan, SourceType, Span};
use oxc_span::{Atom, GetSpan, SourceType, Span, SPAN};
use oxc_syntax::{
operator::{
AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator,
@ -879,6 +879,23 @@ impl<'a> AstBuilder<'a> {
}))
}
pub fn class_constructor(&self, span: Span, value: Box<'a, Function<'a>>) -> ClassElement<'a> {
ClassElement::MethodDefinition(self.alloc(MethodDefinition {
span,
key: self.property_key_expression(self.identifier_reference_expression(
IdentifierReference::new(SPAN, "constructor".into()),
)),
kind: MethodDefinitionKind::Constructor,
value,
computed: false,
r#static: false,
r#override: false,
optional: false,
accessibility: None,
decorators: self.new_vec(),
}))
}
pub fn accessor_property(
&self,
span: Span,

View file

@ -117,6 +117,19 @@ impl<'a> Decorators<'a> {
Atom::from(format!("_{name}{}", if *uid == 1 { String::new() } else { uid.to_string() }))
}
pub fn get_call_with_this(&self, name: Atom) -> Statement<'a> {
self.ast.expression_statement(
SPAN,
self.ast.call_expression(
SPAN,
self.ast.identifier_reference_expression(IdentifierReference::new(SPAN, name)),
self.ast.new_vec_single(Argument::Expression(self.ast.this_expression(SPAN))),
false,
None,
),
)
}
pub fn transform_program(&mut self, program: &mut Program<'a>) {
program.body.splice(0..0, self.top_statements.drain(..));
program.body.append(&mut self.bottom_statements);
@ -378,7 +391,9 @@ impl<'a> Decorators<'a> {
ast.array_expression(SPAN, decorator_elements, None)
};
let mut is_proto = false;
let mut is_static = false;
class.body.body.iter_mut().for_each(|element| {
if !element.has_decorator() {
return;
@ -387,6 +402,8 @@ impl<'a> Decorators<'a> {
ClassElement::MethodDefinition(def) => {
if def.r#static {
is_static = def.r#static;
} else {
is_proto = true;
}
let name = def.key.name();
let mut flag = DecoratorFlags::get_flag_by_kind(def.kind).bits();
@ -454,6 +471,57 @@ impl<'a> Decorators<'a> {
}
});
if is_proto {
// The class has method decorator and is not static
let name = self.get_unique_name(&"initProto".into());
e_elements.push(self.get_assignment_target_maybe_default(name.clone()));
declarations.push(self.get_variable_declarator(name.clone()));
// constructor() { _initProto(this) }
if let Some(constructor_element) = class.body.body.iter_mut().find(
|element| matches!(element, ClassElement::MethodDefinition(def) if def.kind.is_constructor()),
) {
if let ClassElement::MethodDefinition(def) = constructor_element {
if let Some(body) = &mut def.value.body {
body.statements.insert(0, self.get_call_with_this(name));
}
} else {
unreachable!();
};
} else {
// if the class has no constructor, insert a empty constructor and call initProto
class.body.body.insert(
0,
self.ast.class_constructor(
SPAN,
self.ast.function(
FunctionType::FunctionExpression,
SPAN,
None,
false,
false,
false,
None,
self.ast.formal_parameters(
SPAN,
FormalParameterKind::FormalParameter,
self.ast.new_vec(),
None,
),
Some(self.ast.function_body(
SPAN,
self.ast.new_vec(),
self.ast.new_vec_single(self.get_call_with_this(name)),
)),
None,
None,
Modifiers::empty(),
),
),
);
}
}
if is_static {
let name = self.get_unique_name(&"initStatic".into());
e_elements.push(self.get_assignment_target_maybe_default(name.clone()));
@ -478,7 +546,7 @@ impl<'a> Decorators<'a> {
}
{
// call babelHelpers.applyDecs2305
// call babelHelpers.applyDecs2305
let callee = self.ast.static_member_expression(
SPAN,
self.ast.identifier_reference_expression(IdentifierReference::new(

View file

@ -1,4 +1,4 @@
Passed: 335/1369
Passed: 340/1369
# All Passed:
* babel-plugin-transform-numeric-separator
@ -911,7 +911,7 @@ Passed: 335/1369
* spread-transform/transform-to-babel-extend/input.js
* spread-transform/transform-to-object-assign/input.js
# babel-plugin-proposal-decorators (11/190)
# babel-plugin-proposal-decorators (16/190)
* 2018-09-transformation/async-generator-method/input.js
* 2018-09-transformation/class-decorators-yield-await/input.js
* 2021-12-accessors/context-name/input.js
@ -1013,7 +1013,6 @@ Passed: 335/1369
* 2023-05-duplicated-keys/computed-keys-same-ast/input.js
* 2023-05-duplicated-keys/computed-keys-same-value/input.js
* 2023-05-duplicated-keys/method-and-field/input.js
* 2023-05-duplicated-keys/methods-with-same-key/input.js
* 2023-05-duplicated-keys--to-es2015/computed-keys-same-ast/input.js
* 2023-05-duplicated-keys--to-es2015/computed-keys-same-value/input.js
* 2023-05-duplicated-keys--to-es2015/method-and-field/input.js
@ -1030,7 +1029,6 @@ Passed: 335/1369
* 2023-05-fields--to-es2015/static-public/input.js
* 2023-05-getters/context-name/input.js
* 2023-05-getters/private/input.js
* 2023-05-getters/public/input.js
* 2023-05-getters/static-private/input.js
* 2023-05-getters--to-es2015/context-name/input.js
* 2023-05-getters--to-es2015/private/input.js
@ -1038,7 +1036,6 @@ Passed: 335/1369
* 2023-05-getters--to-es2015/static-private/input.js
* 2023-05-getters--to-es2015/static-public/input.js
* 2023-05-getters-and-setters/private/input.js
* 2023-05-getters-and-setters/public/input.js
* 2023-05-getters-and-setters/static-private/input.js
* 2023-05-getters-and-setters--to-es2015/private/input.js
* 2023-05-getters-and-setters--to-es2015/public/input.js
@ -1046,7 +1043,6 @@ Passed: 335/1369
* 2023-05-getters-and-setters--to-es2015/static-public/input.js
* 2023-05-methods/context-name/input.js
* 2023-05-methods/private/input.js
* 2023-05-methods/public/input.js
* 2023-05-methods/static-private/input.js
* 2023-05-methods--to-es2015/context-name/input.js
* 2023-05-methods--to-es2015/private/input.js
@ -1079,7 +1075,6 @@ Passed: 335/1369
* 2023-05-ordering--to-es2015/initializers-and-static-blocks/input.js
* 2023-05-setters/context-name/input.js
* 2023-05-setters/private/input.js
* 2023-05-setters/public/input.js
* 2023-05-setters/static-private/input.js
* 2023-05-setters--to-es2015/context-name/input.js
* 2023-05-setters--to-es2015/private/input.js