Skip to content

Commit 751a310

Browse files
authoredJan 15, 2025··
fix(es/decorators): Fix init order of 2022-03 impl (#9760)
**Description:** Fix the order of initialization for 2022-03 decorators. TBH the [proposal](https://github.com/tc39/proposal-decorators) isn't very clear on how `init` is executed for [auto-accessor](https://github.com/tc39/proposal-decorators) decorator **Related issue:** - Closes #9669
1 parent 2d6f9a5 commit 751a310

File tree

21 files changed

+74
-102
lines changed

21 files changed

+74
-102
lines changed
 

‎.changeset/tame-hairs-applaud.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
swc_ecma_transforms_proposal: patch
3+
swc_core: patch
4+
---
5+
6+
Fix 2022-03 decorators initialization order

‎crates/swc/tests/fixture/issues-7xxx/7220/1/output/index.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ var TestClass = /*#__PURE__*/ function() {
1414
"use strict";
1515
function TestClass() {
1616
_class_call_check(this, TestClass);
17-
_define_property(this, "calls", []);
18-
_initProto(this);
17+
_define_property(this, "calls", (_initProto(this), []));
1918
}
2019
_create_class(TestClass, [
2120
{

‎crates/swc_ecma_transforms_proposal/src/decorator_impl.rs

+42-40
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ struct ClassState {
5151
/// If not empty, `initProto` should be injected to the constructor.
5252
init_proto: Option<Ident>,
5353
init_proto_args: Vec<Option<ExprOrSpread>>,
54-
is_init_proto_called: bool,
5554

5655
init_static: Option<Ident>,
5756
init_static_args: Vec<Option<ExprOrSpread>>,
@@ -718,10 +717,10 @@ impl DecoratorPass {
718717
}
719718
}
720719
body.visit_mut_with(self);
721-
c.visit_mut_with(self);
722720
c.ident = preserved_class_name.clone();
723721
replace_ident(&mut c.class, c.ident.to_id(), &preserved_class_name);
724722
c.class.body.extend(body);
723+
c.visit_mut_with(self);
725724
c.class.body.push(ClassMember::StaticBlock(StaticBlock {
726725
span: DUMMY_SP,
727726
body: BlockStmt {
@@ -814,19 +813,48 @@ impl VisitMut for DecoratorPass {
814813

815814
n.visit_mut_children_with(self);
816815

817-
if !self.state.is_init_proto_called {
818-
if let Some(init_proto) = self.state.init_proto.clone() {
816+
if let Some(init_proto) = self.state.init_proto.clone() {
817+
let init_proto_expr = CallExpr {
818+
span: DUMMY_SP,
819+
callee: init_proto.clone().as_callee(),
820+
args: vec![ThisExpr { span: DUMMY_SP }.as_arg()],
821+
..Default::default()
822+
};
823+
let mut proto_inited = false;
824+
for member in n.body.iter_mut() {
825+
if let ClassMember::ClassProp(prop) = member {
826+
if prop.is_static {
827+
continue;
828+
}
829+
if let Some(value) = prop.value.clone() {
830+
prop.value = Some(Expr::from_exprs(vec![
831+
init_proto_expr.clone().into(),
832+
value,
833+
]));
834+
835+
proto_inited = true;
836+
break;
837+
}
838+
} else if let ClassMember::PrivateProp(prop) = member {
839+
if prop.is_static {
840+
continue;
841+
}
842+
if let Some(value) = prop.value.clone() {
843+
prop.value = Some(Expr::from_exprs(vec![
844+
init_proto_expr.clone().into(),
845+
value,
846+
]));
847+
848+
proto_inited = true;
849+
break;
850+
}
851+
}
852+
}
853+
854+
if !proto_inited {
819855
let c = self.ensure_constructor(n);
820856

821-
inject_after_super(
822-
c,
823-
vec![Box::new(Expr::Call(CallExpr {
824-
span: DUMMY_SP,
825-
callee: init_proto.as_callee(),
826-
args: vec![ThisExpr { span: DUMMY_SP }.as_arg()],
827-
..Default::default()
828-
}))],
829-
)
857+
inject_after_super(c, vec![Box::new(init_proto_expr.into())])
830858
}
831859
}
832860

@@ -847,7 +875,6 @@ impl VisitMut for DecoratorPass {
847875
}
848876

849877
self.state.init_proto = None;
850-
self.state.is_init_proto_called = false;
851878

852879
self.state.extra_stmts = old_stmts;
853880
}
@@ -1045,29 +1072,6 @@ impl VisitMut for DecoratorPass {
10451072
value: if accessor.decorators.is_empty() {
10461073
accessor.value
10471074
} else {
1048-
let init_proto =
1049-
if self.state.is_init_proto_called || accessor.is_static {
1050-
None
1051-
} else {
1052-
self.state.is_init_proto_called = true;
1053-
1054-
let init_proto = self
1055-
.state
1056-
.init_proto
1057-
.get_or_insert_with(|| private_ident!("_initProto"))
1058-
.clone();
1059-
1060-
Some(
1061-
CallExpr {
1062-
span: DUMMY_SP,
1063-
callee: init_proto.clone().as_callee(),
1064-
args: vec![ThisExpr { span: DUMMY_SP }.as_arg()],
1065-
..Default::default()
1066-
}
1067-
.into(),
1068-
)
1069-
};
1070-
10711075
let init_call = CallExpr {
10721076
span: DUMMY_SP,
10731077
callee: init.clone().as_callee(),
@@ -1078,9 +1082,7 @@ impl VisitMut for DecoratorPass {
10781082
}
10791083
.into();
10801084

1081-
Some(Expr::from_exprs(
1082-
init_proto.into_iter().chain(once(init_call)).collect(),
1083-
))
1085+
Some(init_call)
10841086
},
10851087
type_ann: None,
10861088
is_static: accessor.is_static,

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-duplicated-keys/method-and-field/output.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ var _init_a, _initProto;
22
const dec = ()=>{};
33
class Foo {
44
static{
5-
({ e: [_init_a, _initProto] } = _apply_decs_2203_r(this, [
5+
({ e: [_init_a, _initProto] } = _apply_decs_2203_r(this, [
66
[
77
dec,
88
2,
@@ -15,10 +15,7 @@ class Foo {
1515
]
1616
], []));
1717
}
18-
constructor(){
19-
_initProto(this);
20-
}
21-
a = _init_a(this, 123);
18+
a = (_initProto(this), _init_a(this, 123));
2219
a() {
2320
return 1;
2421
}

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/private/output.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ class Foo {
1010
get: get_a,
1111
set: void 0
1212
});
13-
_define_property(this, "value", 1);
14-
_initProto(this);
13+
_define_property(this, "value", (_initProto(this), 1));
1514
}
1615
}
1716
({ e: [_call_a, _initProto] } = _apply_decs_2203_r(Foo, [

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters--to-es2015/public/output.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ class Foo {
1010
return this.value;
1111
}
1212
constructor(){
13-
_define_property(this, "value", 1);
14-
_initProto(this);
13+
_define_property(this, "value", (_initProto(this), 1));
1514
}
1615
}
1716
({ e: [_initProto] } = _apply_decs_2203_r(Foo, [

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/private/output.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ class Foo {
1313
get: get_a,
1414
set: set_a
1515
});
16-
_define_property(this, "value", 1);
17-
_initProto(this);
16+
_define_property(this, "value", (_initProto(this), 1));
1817
}
1918
}
2019
({ e: [_call_a, _call_a1, _initProto] } = _apply_decs_2203_r(Foo, [

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters--to-es2015/public/output.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ class Foo {
1616
this.value = v;
1717
}
1818
constructor(){
19-
_define_property(this, "value", 1);
20-
_initProto(this);
19+
_define_property(this, "value", (_initProto(this), 1));
2120
}
2221
}
2322
({ e: [_initProto] } = _apply_decs_2203_r(Foo, [

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/private/output.js

+1-4
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@ class Foo {
2121
]
2222
], []));
2323
}
24-
constructor(){
25-
_initProto(this);
26-
}
27-
value = 1;
24+
value = (_initProto(this), 1);
2825
get #a() {
2926
return _call_a(this);
3027
}

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters-and-setters/public/output.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const dec = ()=>{};
33
_computedKey = 'b', _computedKey1 = 'b';
44
class Foo {
55
static{
6-
({ e: [_initProto] } = _apply_decs_2203_r(this, [
6+
({ e: [_initProto] } = _apply_decs_2203_r(this, [
77
[
88
dec,
99
3,
@@ -26,10 +26,7 @@ class Foo {
2626
]
2727
], []));
2828
}
29-
constructor(){
30-
_initProto(this);
31-
}
32-
value = 1;
29+
value = (_initProto(this), 1);
3330
get a() {
3431
return this.value;
3532
}

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/private/output.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ var _call_a, _initProto;
22
const dec = ()=>{};
33
class Foo {
44
static{
5-
({ e: [_call_a, _initProto] } = _apply_decs_2203_r(this, [
5+
({ e: [_call_a, _initProto] } = _apply_decs_2203_r(this, [
66
[
77
dec,
88
3,
@@ -13,10 +13,7 @@ class Foo {
1313
]
1414
], []));
1515
}
16-
constructor(){
17-
_initProto(this);
18-
}
19-
value = 1;
16+
value = (_initProto(this), 1);
2017
get #a() {
2118
return _call_a(this);
2219
}

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-getters/public/output.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const dec = ()=>{};
33
_computedKey = 'b';
44
class Foo {
55
static{
6-
({ e: [_initProto] } = _apply_decs_2203_r(this, [
6+
({ e: [_initProto] } = _apply_decs_2203_r(this, [
77
[
88
dec,
99
3,
@@ -16,10 +16,7 @@ class Foo {
1616
]
1717
], []));
1818
}
19-
constructor(){
20-
_initProto(this);
21-
}
22-
value = 1;
19+
value = (_initProto(this), 1);
2320
get a() {
2421
return this.value;
2522
}

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/private/output.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ class Foo {
1010
get: get_a,
1111
set: void 0
1212
});
13-
_define_property(this, "value", 1);
14-
_initProto(this);
13+
_define_property(this, "value", (_initProto(this), 1));
1514
}
1615
}
1716
({ e: [_call_a, _initProto] } = _apply_decs_2203_r(Foo, [

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods--to-es2015/public/output.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ class Foo {
1010
return this.value;
1111
}
1212
constructor(){
13-
_define_property(this, "value", 1);
14-
_initProto(this);
13+
_define_property(this, "value", (_initProto(this), 1));
1514
}
1615
}
1716
({ e: [_initProto] } = _apply_decs_2203_r(Foo, [

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/private/output.js

+1-4
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ class Foo {
1313
]
1414
], []));
1515
}
16-
constructor(){
17-
_initProto(this);
18-
}
19-
value = 1;
16+
value = (_initProto(this), 1);
2017
get #a() {
2118
return _call_a;
2219
}

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-methods/public/output.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const dec = ()=>{};
33
_computedKey = 'b';
44
class Foo {
55
static{
6-
({ e: [_initProto] } = _apply_decs_2203_r(this, [
6+
({ e: [_initProto] } = _apply_decs_2203_r(this, [
77
[
88
dec,
99
2,
@@ -16,10 +16,7 @@ class Foo {
1616
]
1717
], []));
1818
}
19-
constructor(){
20-
_initProto(this);
21-
}
22-
value = 1;
19+
value = (_initProto(this), 1);
2320
a() {
2421
return this.value;
2522
}

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-misc/all-decorators/output.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -144,11 +144,11 @@ new class extends _identity {
144144
]));
145145
_initStatic(this);
146146
}
147-
a = _init_a(this);
147+
a = (_initProto(this), _init_a(this));
148148
b() {}
149149
get c() {}
150150
set c(v) {}
151-
#___private_d_1 = (_initProto(this), _init_d(this));
151+
#___private_d_1 = _init_d(this);
152152
get d() {
153153
return this.#___private_d_1;
154154
}

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/private/output.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ class Foo {
1010
get: void 0,
1111
set: set_a
1212
});
13-
_define_property(this, "value", 1);
14-
_initProto(this);
13+
_define_property(this, "value", (_initProto(this), 1));
1514
}
1615
}
1716
({ e: [_call_a, _initProto] } = _apply_decs_2203_r(Foo, [

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters--to-es2015/public/output.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ class Foo {
1010
return this.value = v;
1111
}
1212
constructor(){
13-
_define_property(this, "value", 1);
14-
_initProto(this);
13+
_define_property(this, "value", (_initProto(this), 1));
1514
}
1615
}
1716
({ e: [_initProto] } = _apply_decs_2203_r(Foo, [

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/private/output.js

+1-4
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ class Foo {
1313
]
1414
], []));
1515
}
16-
constructor(){
17-
_initProto(this);
18-
}
19-
value = 1;
16+
value = (_initProto(this), 1);
2017
set #a(v) {
2118
return _call_a(this, v);
2219
}

‎crates/swc_ecma_transforms_proposal/tests/decorators/2022-03-setters/public/output.js

+2-5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const dec = ()=>{};
33
_computedKey = 'b';
44
class Foo {
55
static{
6-
({ e: [_initProto] } = _apply_decs_2203_r(this, [
6+
({ e: [_initProto] } = _apply_decs_2203_r(this, [
77
[
88
dec,
99
4,
@@ -16,10 +16,7 @@ class Foo {
1616
]
1717
], []));
1818
}
19-
constructor(){
20-
_initProto(this);
21-
}
22-
value = 1;
19+
value = (_initProto(this), 1);
2320
set a(v) {
2421
return this.value = v;
2522
}

0 commit comments

Comments
 (0)
Please sign in to comment.