Skip to content

Commit 21a447f

Browse files
authoredFeb 13, 2024··
fix(es/decorators): Do not insert duplicate constructors (#8631)
**Description:** Doesn't insert a duplicate ctor when the ctor uses overloads in TS. **Related issue:** - Closes #8630.
1 parent 3b76b9b commit 21a447f

File tree

6 files changed

+92
-26
lines changed

6 files changed

+92
-26
lines changed
 

‎crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs

+33-25
Original file line numberDiff line numberDiff line change
@@ -276,39 +276,49 @@ impl Decorator202203 {
276276
}
277277

278278
fn ensure_constructor<'a>(&mut self, c: &'a mut Class) -> &'a mut Constructor {
279-
for member in c.body.iter_mut() {
279+
let mut insert_index = 0;
280+
for (i, member) in c.body.iter_mut().enumerate() {
280281
if let ClassMember::Constructor(constructor) = member {
281-
return unsafe {
282-
// Safety: We need polonius
283-
transmute::<&mut Constructor, &'a mut Constructor>(constructor)
284-
};
282+
insert_index = i + 1;
283+
// decorators occur before typescript's type strip, so skip ctor overloads
284+
if constructor.body.is_some() {
285+
return unsafe {
286+
// Safety: We need polonius
287+
transmute::<&mut Constructor, &'a mut Constructor>(constructor)
288+
};
289+
}
285290
}
286291
}
287292

288-
c.body
289-
.insert(0, default_constructor(c.super_class.is_some()).into());
293+
c.body.insert(
294+
insert_index,
295+
default_constructor(c.super_class.is_some()).into(),
296+
);
290297

291-
for member in c.body.iter_mut() {
292-
if let ClassMember::Constructor(constructor) = member {
293-
return constructor;
294-
}
298+
if let Some(ClassMember::Constructor(c)) = c.body.get_mut(insert_index) {
299+
c
300+
} else {
301+
unreachable!()
295302
}
296-
297-
unreachable!()
298303
}
299304

300305
fn ensure_identity_constructor<'a>(&mut self, c: &'a mut Class) -> &'a mut Constructor {
301-
for member in c.body.iter_mut() {
306+
let mut insert_index = 0;
307+
for (i, member) in c.body.iter_mut().enumerate() {
302308
if let ClassMember::Constructor(constructor) = member {
303-
return unsafe {
304-
// Safety: We need polonius
305-
transmute::<&mut Constructor, &'a mut Constructor>(constructor)
306-
};
309+
insert_index = i + 1;
310+
// decorators occur before typescript's type strip, so skip ctor overloads
311+
if constructor.body.is_some() {
312+
return unsafe {
313+
// Safety: We need polonius
314+
transmute::<&mut Constructor, &'a mut Constructor>(constructor)
315+
};
316+
}
307317
}
308318
}
309319

310320
c.body.insert(
311-
0,
321+
insert_index,
312322
ClassMember::Constructor(Constructor {
313323
span: DUMMY_SP,
314324
key: PropName::Ident(quote_ident!("constructor")),
@@ -322,13 +332,11 @@ impl Decorator202203 {
322332
}),
323333
);
324334

325-
for member in c.body.iter_mut() {
326-
if let ClassMember::Constructor(constructor) = member {
327-
return constructor;
328-
}
335+
if let Some(ClassMember::Constructor(c)) = c.body.get_mut(insert_index) {
336+
c
337+
} else {
338+
unreachable!()
329339
}
330-
331-
unreachable!()
332340
}
333341

334342
fn handle_super_class(&mut self, class: &mut Class) {

‎crates/swc_ecma_transforms_proposal/tests/decorators.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ fn syntax_default() -> Syntax {
2323
})
2424
}
2525

26+
fn syntax_default_ts() -> Syntax {
27+
Syntax::Typescript(TsConfig {
28+
decorators: true,
29+
..Default::default()
30+
})
31+
}
32+
2633
#[testing::fixture("tests/decorators/**/exec.js")]
2734
fn exec(input: PathBuf) {
2835
exec_inner(input)
@@ -44,6 +51,7 @@ fn exec_inner(input: PathBuf) {
4451

4552
#[testing::fixture("tests/decorators/**/input.js")]
4653
#[testing::fixture("tests/decorators/**/input.mjs")]
54+
#[testing::fixture("tests/decorators/**/input.ts")]
4755
fn fixture(input: PathBuf) {
4856
fixture_inner(input)
4957
}
@@ -57,7 +65,11 @@ fn fixture_inner(input: PathBuf) {
5765
));
5866

5967
test_fixture(
60-
syntax_default(),
68+
if input.to_string_lossy().ends_with(".ts") {
69+
syntax_default_ts()
70+
} else {
71+
syntax_default()
72+
},
6173
&|t| create_pass(t.comments.clone(), &input),
6274
&input,
6375
&output,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const decorate = (target: unknown, context: DecoratorContext) => {
2+
console.log("decorated");
3+
};
4+
5+
export class Color {
6+
constructor(hex: string);
7+
constructor(r: number, g: number, b: number, a?: number);
8+
constructor(r: string | number, g?: number, b?: number, a = 1) {}
9+
10+
@decorate get rgba() {
11+
return [0, 0, 0, 1];
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export default class T {
2+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
var _initProto;
2+
const decorate = (target: unknown, context: DecoratorContext)=>{
3+
console.log("decorated");
4+
};
5+
export class Color {
6+
static{
7+
({ e: [_initProto] } = _apply_decs_2203_r(this, [
8+
[
9+
decorate,
10+
3,
11+
"rgba"
12+
]
13+
], []));
14+
}
15+
constructor(hex: string);
16+
constructor(r: number, g: number, b: number, a?: number);
17+
constructor(r: string | number, g?: number, b?: number, a = 1){
18+
_initProto(this);
19+
}
20+
get rgba() {
21+
return [
22+
0,
23+
0,
24+
0,
25+
1
26+
];
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"plugins": [["proposal-decorators", { "version": "2022-03" }]]
3+
}

0 commit comments

Comments
 (0)
Please sign in to comment.