Skip to content

Commit

Permalink
fix(es/decorators): Do not insert duplicate constructors (#8631)
Browse files Browse the repository at this point in the history
**Description:**

Doesn't insert a duplicate ctor when the ctor uses overloads in TS.


**Related issue:** 

 - Closes #8630.
  • Loading branch information
dsherret authored Feb 13, 2024
1 parent 3b76b9b commit 21a447f
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 26 deletions.
58 changes: 33 additions & 25 deletions crates/swc_ecma_transforms_proposal/src/decorator_2022_03.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,39 +276,49 @@ impl Decorator202203 {
}

fn ensure_constructor<'a>(&mut self, c: &'a mut Class) -> &'a mut Constructor {
for member in c.body.iter_mut() {
let mut insert_index = 0;
for (i, member) in c.body.iter_mut().enumerate() {
if let ClassMember::Constructor(constructor) = member {
return unsafe {
// Safety: We need polonius
transmute::<&mut Constructor, &'a mut Constructor>(constructor)
};
insert_index = i + 1;
// decorators occur before typescript's type strip, so skip ctor overloads
if constructor.body.is_some() {
return unsafe {
// Safety: We need polonius
transmute::<&mut Constructor, &'a mut Constructor>(constructor)
};
}
}
}

c.body
.insert(0, default_constructor(c.super_class.is_some()).into());
c.body.insert(
insert_index,
default_constructor(c.super_class.is_some()).into(),
);

for member in c.body.iter_mut() {
if let ClassMember::Constructor(constructor) = member {
return constructor;
}
if let Some(ClassMember::Constructor(c)) = c.body.get_mut(insert_index) {
c
} else {
unreachable!()
}

unreachable!()
}

fn ensure_identity_constructor<'a>(&mut self, c: &'a mut Class) -> &'a mut Constructor {
for member in c.body.iter_mut() {
let mut insert_index = 0;
for (i, member) in c.body.iter_mut().enumerate() {
if let ClassMember::Constructor(constructor) = member {
return unsafe {
// Safety: We need polonius
transmute::<&mut Constructor, &'a mut Constructor>(constructor)
};
insert_index = i + 1;
// decorators occur before typescript's type strip, so skip ctor overloads
if constructor.body.is_some() {
return unsafe {
// Safety: We need polonius
transmute::<&mut Constructor, &'a mut Constructor>(constructor)
};
}
}
}

c.body.insert(
0,
insert_index,
ClassMember::Constructor(Constructor {
span: DUMMY_SP,
key: PropName::Ident(quote_ident!("constructor")),
Expand All @@ -322,13 +332,11 @@ impl Decorator202203 {
}),
);

for member in c.body.iter_mut() {
if let ClassMember::Constructor(constructor) = member {
return constructor;
}
if let Some(ClassMember::Constructor(c)) = c.body.get_mut(insert_index) {
c
} else {
unreachable!()
}

unreachable!()
}

fn handle_super_class(&mut self, class: &mut Class) {
Expand Down
14 changes: 13 additions & 1 deletion crates/swc_ecma_transforms_proposal/tests/decorators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ fn syntax_default() -> Syntax {
})
}

fn syntax_default_ts() -> Syntax {
Syntax::Typescript(TsConfig {
decorators: true,
..Default::default()
})
}

#[testing::fixture("tests/decorators/**/exec.js")]
fn exec(input: PathBuf) {
exec_inner(input)
Expand All @@ -44,6 +51,7 @@ fn exec_inner(input: PathBuf) {

#[testing::fixture("tests/decorators/**/input.js")]
#[testing::fixture("tests/decorators/**/input.mjs")]
#[testing::fixture("tests/decorators/**/input.ts")]
fn fixture(input: PathBuf) {
fixture_inner(input)
}
Expand All @@ -57,7 +65,11 @@ fn fixture_inner(input: PathBuf) {
));

test_fixture(
syntax_default(),
if input.to_string_lossy().ends_with(".ts") {
syntax_default_ts()
} else {
syntax_default()
},
&|t| create_pass(t.comments.clone(), &input),
&input,
&output,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const decorate = (target: unknown, context: DecoratorContext) => {
console.log("decorated");
};

export class Color {
constructor(hex: string);
constructor(r: number, g: number, b: number, a?: number);
constructor(r: string | number, g?: number, b?: number, a = 1) {}

@decorate get rgba() {
return [0, 0, 0, 1];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export default class T {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
var _initProto;
const decorate = (target: unknown, context: DecoratorContext)=>{
console.log("decorated");
};
export class Color {
static{
({ e: [_initProto] } = _apply_decs_2203_r(this, [
[
decorate,
3,
"rgba"
]
], []));
}
constructor(hex: string);
constructor(r: number, g: number, b: number, a?: number);
constructor(r: string | number, g?: number, b?: number, a = 1){
_initProto(this);
}
get rgba() {
return [
0,
0,
0,
1
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"plugins": [["proposal-decorators", { "version": "2022-03" }]]
}

0 comments on commit 21a447f

Please sign in to comment.