Skip to content

Commit 81cc96a

Browse files
committed
fix(transformer): skip design:returntype metadata for getter/setter methods
Getter and setter methods should not have design:returntype metadata according to TypeScript's emitDecoratorMetadata behavior. They should only have design:type and design:paramtypes. This change: - Updates enter_method_definition to conditionally emit design:returntype only for regular methods - Adds comprehensive test case for getter/setter metadata emission - Ensures compatibility with TypeScript's decorator metadata implementation Fixes #14493
1 parent a631dd7 commit 81cc96a

File tree

6 files changed

+96
-19
lines changed

6 files changed

+96
-19
lines changed

crates/oxc_transformer/src/decorator/legacy/metadata.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,18 @@ enum EnumType {
115115

116116
pub struct LegacyDecoratorMetadata<'a, 'ctx> {
117117
ctx: &'ctx TransformCtx<'a>,
118-
/// Stack of method metadata arrays, each array contains 3 expressions:
119-
/// `[design:type, design:paramtypes, design:returntype]`
118+
/// Stack of method metadata arrays.
119+
/// Each array contains metadata expressions in order:
120+
/// `[design:type, design:paramtypes, design:returntype (optional)]`
121+
///
122+
/// Note: `design:returntype` is omitted for getter and setter methods.
120123
///
121124
/// Only the method that needs to be pushed onto a stack is the method metadata,
122125
/// which should be inserted after all real decorators. However, method parameters
123126
/// will be processed before the metadata generation, so we need to temporarily store
124127
/// them in a stack and pop them when in exit_method_definition.
125-
method_metadata_stack: SparseStack<[Expression<'a>; 3]>,
128+
// method_metadata_stack: SparseStack<[Option<Expression<'a>>; 3]>,
129+
method_metadata_stack: SparseStack<[Option<Expression<'a>>; 3]>,
126130
/// Stack of constructor metadata expressions, each expression
127131
/// is the `design:paramtypes`.
128132
///
@@ -208,16 +212,25 @@ impl<'a> Traverse<'a, TransformState<'a>> for LegacyDecoratorMetadata<'a, '_> {
208212
|| method.value.params.items.iter().any(|param| !param.decorators.is_empty()));
209213

210214
let metadata = is_decorated.then(|| {
215+
// TypeScript only emits `design:returntype` for regular methods,
216+
// not for getters or setters.
217+
let should_add_return_type = !method.kind.is_get() && !method.kind.is_set();
218+
211219
[
212-
self.create_metadata("design:type", Self::global_function(ctx), ctx),
220+
Some(self.create_metadata("design:type", Self::global_function(ctx), ctx)),
213221
{
214222
let serialized_type =
215223
self.serialize_parameter_types_of_node(&method.value.params, ctx);
216-
self.create_metadata("design:paramtypes", serialized_type, ctx)
224+
Some(self.create_metadata("design:paramtypes", serialized_type, ctx))
217225
},
218226
{
219-
let serialized_type = self.serialize_return_type_of_node(&method.value, ctx);
220-
self.create_metadata("design:returntype", serialized_type, ctx)
227+
if should_add_return_type {
228+
let serialized_type =
229+
self.serialize_return_type_of_node(&method.value, ctx);
230+
Some(self.create_metadata("design:returntype", serialized_type, ctx))
231+
} else {
232+
None
233+
}
221234
},
222235
]
223236
});
@@ -302,7 +315,7 @@ impl<'a> LegacyDecoratorMetadata<'a, '_> {
302315
enum_type
303316
}
304317

305-
pub fn pop_method_metadata(&mut self) -> Option<[Expression<'a>; 3]> {
318+
pub fn pop_method_metadata(&mut self) -> Option<[Option<Expression<'a>>; 3]> {
306319
self.method_metadata_stack.pop()
307320
}
308321

crates/oxc_transformer/src/decorator/legacy/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,8 @@ impl<'a> LegacyDecorator<'a, '_> {
999999
decorations.push(ArrayExpressionElement::from(metadata));
10001000
}
10011001
} else if let Some(metadata) = self.metadata.pop_method_metadata() {
1002-
decorations.extend(metadata.map(ArrayExpressionElement::from));
1002+
decorations
1003+
.extend(metadata.into_iter().flatten().map(ArrayExpressionElement::from));
10031004
}
10041005
}
10051006

tasks/coverage/snapshots/semantic_typescript.snap

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39221,10 +39221,10 @@ Bindings mismatch:
3922139221
after transform: ScopeId(0): ["C", "_decorate", "_decorateMetadata", "_method", "_method2", "dec", "method3"]
3922239222
rebuilt : ScopeId(0): ["C", "_decorate", "_decorateMetadata", "_method", "_method2", "method3"]
3922339223
Reference flags mismatch for "_method":
39224-
after transform: ReferenceId(39): ReferenceFlags(Read | Write)
39224+
after transform: ReferenceId(34): ReferenceFlags(Read | Write)
3922539225
rebuilt : ReferenceId(2): ReferenceFlags(Write)
3922639226
Reference flags mismatch for "_method2":
39227-
after transform: ReferenceId(48): ReferenceFlags(Read | Write)
39227+
after transform: ReferenceId(42): ReferenceFlags(Read | Write)
3922839228
rebuilt : ReferenceId(4): ReferenceFlags(Write)
3922939229
Reference symbol mismatch for "dec":
3923039230
after transform: SymbolId(0) "dec"
@@ -39267,10 +39267,10 @@ Bindings mismatch:
3926739267
after transform: ScopeId(0): ["C", "_decorate", "_decorateMetadata", "_method", "_method2", "dec", "method3"]
3926839268
rebuilt : ScopeId(0): ["C", "_decorate", "_decorateMetadata", "_method", "_method2", "method3"]
3926939269
Reference flags mismatch for "_method":
39270-
after transform: ReferenceId(39): ReferenceFlags(Read | Write)
39270+
after transform: ReferenceId(34): ReferenceFlags(Read | Write)
3927139271
rebuilt : ReferenceId(2): ReferenceFlags(Write)
3927239272
Reference flags mismatch for "_method2":
39273-
after transform: ReferenceId(48): ReferenceFlags(Read | Write)
39273+
after transform: ReferenceId(42): ReferenceFlags(Read | Write)
3927439274
rebuilt : ReferenceId(4): ReferenceFlags(Write)
3927539275
Reference symbol mismatch for "dec":
3927639276
after transform: SymbolId(0) "dec"
@@ -39302,13 +39302,13 @@ Symbol span mismatch for "D":
3930239302
after transform: SymbolId(3): Span { start: 137, end: 138 }
3930339303
rebuilt : SymbolId(9): Span { start: 0, end: 0 }
3930439304
Symbol reference IDs mismatch for "D":
39305-
after transform: SymbolId(3): [ReferenceId(23), ReferenceId(25)]
39306-
rebuilt : SymbolId(9): [ReferenceId(20), ReferenceId(30), ReferenceId(33)]
39305+
after transform: SymbolId(3): [ReferenceId(21), ReferenceId(23)]
39306+
rebuilt : SymbolId(9): [ReferenceId(18), ReferenceId(28), ReferenceId(31)]
3930739307
Symbol span mismatch for "D":
3930839308
after transform: SymbolId(14): Span { start: 0, end: 0 }
3930939309
rebuilt : SymbolId(10): Span { start: 137, end: 138 }
3931039310
Symbol reference IDs mismatch for "D":
39311-
after transform: SymbolId(14): [ReferenceId(28)]
39311+
after transform: SymbolId(14): [ReferenceId(26)]
3931239312
rebuilt : SymbolId(10): []
3931339313
Reference symbol mismatch for "dec":
3931439314
after transform: SymbolId(0) "dec"
@@ -40331,7 +40331,7 @@ Bindings mismatch:
4033140331
after transform: ScopeId(0): ["_C", "_decorateMetadata", "_defineProperty", "_get_x", "_method", "_set_x", "_y", "dec"]
4033240332
rebuilt : ScopeId(0): ["_C", "_decorateMetadata", "_defineProperty", "_get_x", "_method", "_set_x", "_y"]
4033340333
Symbol reference IDs mismatch for "_decorateMetadata":
40334-
after transform: SymbolId(10): [ReferenceId(24), ReferenceId(25), ReferenceId(26), ReferenceId(28), ReferenceId(29), ReferenceId(30), ReferenceId(32), ReferenceId(34), ReferenceId(35), ReferenceId(37), ReferenceId(39), ReferenceId(41), ReferenceId(42), ReferenceId(43), ReferenceId(45), ReferenceId(46), ReferenceId(47), ReferenceId(49), ReferenceId(51), ReferenceId(52), ReferenceId(54), ReferenceId(56)]
40334+
after transform: SymbolId(10): [ReferenceId(24), ReferenceId(25), ReferenceId(26), ReferenceId(28), ReferenceId(29), ReferenceId(31), ReferenceId(33), ReferenceId(35), ReferenceId(37), ReferenceId(39), ReferenceId(40), ReferenceId(41), ReferenceId(43), ReferenceId(44), ReferenceId(46), ReferenceId(48), ReferenceId(50), ReferenceId(52)]
4033540335
rebuilt : SymbolId(1): []
4033640336
Reference symbol mismatch for "dec":
4033740337
after transform: SymbolId(0) "dec"

tasks/transform_conformance/snapshots/oxc.snap.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
commit: 41d96516
22

3-
Passed: 188/316
3+
Passed: 188/317
44

55
# All Passed:
66
* babel-plugin-transform-class-static-block
@@ -544,7 +544,7 @@ x Output mismatch
544544
x Output mismatch
545545

546546

547-
# legacy-decorators (6/85)
547+
# legacy-decorators (6/86)
548548
* oxc/class-without-name-with-decorated_class/input.ts
549549
Bindings mismatch:
550550
after transform: ScopeId(0): ["dec"]
@@ -698,6 +698,26 @@ Symbol reference IDs mismatch for "ComputedEnum":
698698
after transform: SymbolId(25): [ReferenceId(19), ReferenceId(72)]
699699
rebuilt : SymbolId(15): [ReferenceId(52)]
700700

701+
* oxc/metadata/getter-setter-method/input.ts
702+
Bindings mismatch:
703+
after transform: ScopeId(0): ["C", "dec"]
704+
rebuilt : ScopeId(0): ["C"]
705+
Scope children mismatch:
706+
after transform: ScopeId(0): [ScopeId(1), ScopeId(2)]
707+
rebuilt : ScopeId(0): [ScopeId(1)]
708+
Reference symbol mismatch for "dec":
709+
after transform: SymbolId(0) "dec"
710+
rebuilt : <None>
711+
Reference symbol mismatch for "dec":
712+
after transform: SymbolId(0) "dec"
713+
rebuilt : <None>
714+
Reference symbol mismatch for "dec":
715+
after transform: SymbolId(0) "dec"
716+
rebuilt : <None>
717+
Unresolved references mismatch:
718+
after transform: ["Function", "PropertyDescriptor", "String", "babelHelpers"]
719+
rebuilt : ["Function", "String", "babelHelpers", "dec"]
720+
701721
* oxc/metadata/imports/input.ts
702722
Bindings mismatch:
703723
after transform: ScopeId(0): ["Bar", "Cls", "Foo", "Zoo", "_ref", "dec"]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
declare function dec(target: any, propertyKey: string, descriptor: PropertyDescriptor): void;
2+
3+
class C {
4+
@dec
5+
get address(): string {
6+
return "test";
7+
}
8+
9+
@dec
10+
set address(value: string) {
11+
}
12+
13+
@dec
14+
regularMethod(): string {
15+
return "test";
16+
}
17+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
class C {
2+
get address() {
3+
return "test";
4+
}
5+
set address(value) {
6+
}
7+
regularMethod() {
8+
return "test";
9+
}
10+
}
11+
babelHelpers.decorate([
12+
dec,
13+
babelHelpers.decorateMetadata("design:type", Function),
14+
babelHelpers.decorateMetadata("design:paramtypes", [])
15+
], C.prototype, "address", null);
16+
babelHelpers.decorate([
17+
dec,
18+
babelHelpers.decorateMetadata("design:type", Function),
19+
babelHelpers.decorateMetadata("design:paramtypes", [String])
20+
], C.prototype, "address", null);
21+
babelHelpers.decorate([
22+
dec,
23+
babelHelpers.decorateMetadata("design:type", Function),
24+
babelHelpers.decorateMetadata("design:paramtypes", []),
25+
babelHelpers.decorateMetadata("design:returntype", String)
26+
], C.prototype, "regularMethod", null);

0 commit comments

Comments
 (0)