mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 20:32:10 +00:00
feat(transformer/decorators): support method decorator and is not static (#2238)
This commit is contained in:
parent
d0d708295b
commit
ba85b097e0
3 changed files with 89 additions and 9 deletions
|
|
@ -9,7 +9,7 @@ use num_bigint::BigInt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use oxc_allocator::{Allocator, Box, String, Vec};
|
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::{
|
use oxc_syntax::{
|
||||||
operator::{
|
operator::{
|
||||||
AssignmentOperator, BinaryOperator, LogicalOperator, UnaryOperator, UpdateOperator,
|
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(
|
pub fn accessor_property(
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,19 @@ impl<'a> Decorators<'a> {
|
||||||
Atom::from(format!("_{name}{}", if *uid == 1 { String::new() } else { uid.to_string() }))
|
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>) {
|
pub fn transform_program(&mut self, program: &mut Program<'a>) {
|
||||||
program.body.splice(0..0, self.top_statements.drain(..));
|
program.body.splice(0..0, self.top_statements.drain(..));
|
||||||
program.body.append(&mut self.bottom_statements);
|
program.body.append(&mut self.bottom_statements);
|
||||||
|
|
@ -378,7 +391,9 @@ impl<'a> Decorators<'a> {
|
||||||
ast.array_expression(SPAN, decorator_elements, None)
|
ast.array_expression(SPAN, decorator_elements, None)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut is_proto = false;
|
||||||
let mut is_static = false;
|
let mut is_static = false;
|
||||||
|
|
||||||
class.body.body.iter_mut().for_each(|element| {
|
class.body.body.iter_mut().for_each(|element| {
|
||||||
if !element.has_decorator() {
|
if !element.has_decorator() {
|
||||||
return;
|
return;
|
||||||
|
|
@ -387,6 +402,8 @@ impl<'a> Decorators<'a> {
|
||||||
ClassElement::MethodDefinition(def) => {
|
ClassElement::MethodDefinition(def) => {
|
||||||
if def.r#static {
|
if def.r#static {
|
||||||
is_static = def.r#static;
|
is_static = def.r#static;
|
||||||
|
} else {
|
||||||
|
is_proto = true;
|
||||||
}
|
}
|
||||||
let name = def.key.name();
|
let name = def.key.name();
|
||||||
let mut flag = DecoratorFlags::get_flag_by_kind(def.kind).bits();
|
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 {
|
if is_static {
|
||||||
let name = self.get_unique_name(&"initStatic".into());
|
let name = self.get_unique_name(&"initStatic".into());
|
||||||
e_elements.push(self.get_assignment_target_maybe_default(name.clone()));
|
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(
|
let callee = self.ast.static_member_expression(
|
||||||
SPAN,
|
SPAN,
|
||||||
self.ast.identifier_reference_expression(IdentifierReference::new(
|
self.ast.identifier_reference_expression(IdentifierReference::new(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
Passed: 335/1369
|
Passed: 340/1369
|
||||||
|
|
||||||
# All Passed:
|
# All Passed:
|
||||||
* babel-plugin-transform-numeric-separator
|
* babel-plugin-transform-numeric-separator
|
||||||
|
|
@ -911,7 +911,7 @@ Passed: 335/1369
|
||||||
* spread-transform/transform-to-babel-extend/input.js
|
* spread-transform/transform-to-babel-extend/input.js
|
||||||
* spread-transform/transform-to-object-assign/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/async-generator-method/input.js
|
||||||
* 2018-09-transformation/class-decorators-yield-await/input.js
|
* 2018-09-transformation/class-decorators-yield-await/input.js
|
||||||
* 2021-12-accessors/context-name/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-ast/input.js
|
||||||
* 2023-05-duplicated-keys/computed-keys-same-value/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/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-ast/input.js
|
||||||
* 2023-05-duplicated-keys--to-es2015/computed-keys-same-value/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
|
* 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-fields--to-es2015/static-public/input.js
|
||||||
* 2023-05-getters/context-name/input.js
|
* 2023-05-getters/context-name/input.js
|
||||||
* 2023-05-getters/private/input.js
|
* 2023-05-getters/private/input.js
|
||||||
* 2023-05-getters/public/input.js
|
|
||||||
* 2023-05-getters/static-private/input.js
|
* 2023-05-getters/static-private/input.js
|
||||||
* 2023-05-getters--to-es2015/context-name/input.js
|
* 2023-05-getters--to-es2015/context-name/input.js
|
||||||
* 2023-05-getters--to-es2015/private/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-private/input.js
|
||||||
* 2023-05-getters--to-es2015/static-public/input.js
|
* 2023-05-getters--to-es2015/static-public/input.js
|
||||||
* 2023-05-getters-and-setters/private/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/static-private/input.js
|
||||||
* 2023-05-getters-and-setters--to-es2015/private/input.js
|
* 2023-05-getters-and-setters--to-es2015/private/input.js
|
||||||
* 2023-05-getters-and-setters--to-es2015/public/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-getters-and-setters--to-es2015/static-public/input.js
|
||||||
* 2023-05-methods/context-name/input.js
|
* 2023-05-methods/context-name/input.js
|
||||||
* 2023-05-methods/private/input.js
|
* 2023-05-methods/private/input.js
|
||||||
* 2023-05-methods/public/input.js
|
|
||||||
* 2023-05-methods/static-private/input.js
|
* 2023-05-methods/static-private/input.js
|
||||||
* 2023-05-methods--to-es2015/context-name/input.js
|
* 2023-05-methods--to-es2015/context-name/input.js
|
||||||
* 2023-05-methods--to-es2015/private/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-ordering--to-es2015/initializers-and-static-blocks/input.js
|
||||||
* 2023-05-setters/context-name/input.js
|
* 2023-05-setters/context-name/input.js
|
||||||
* 2023-05-setters/private/input.js
|
* 2023-05-setters/private/input.js
|
||||||
* 2023-05-setters/public/input.js
|
|
||||||
* 2023-05-setters/static-private/input.js
|
* 2023-05-setters/static-private/input.js
|
||||||
* 2023-05-setters--to-es2015/context-name/input.js
|
* 2023-05-setters--to-es2015/context-name/input.js
|
||||||
* 2023-05-setters--to-es2015/private/input.js
|
* 2023-05-setters--to-es2015/private/input.js
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue