Skip to content

Commit 76a9865

Browse files
committed
fix(transformer/legacy-decorator): metadata should be inserted after all params decorators (#13215)
* Fixes #13210
1 parent 8264664 commit 76a9865

File tree

11 files changed

+193
-39
lines changed

11 files changed

+193
-39
lines changed

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

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -835,10 +835,26 @@ impl<'a> LegacyDecorator<'a, '_> {
835835
}
836836

837837
let mut decorations = ctx.ast.vec_with_capacity(method_decoration_count);
838+
839+
// Split metadata decorators from method decorators.
840+
// Metadata decorators (typically used for emitting design-time type information)
841+
// are identified by having an "unspanned" span. According to TypeScript's legacy
842+
// decorator semantics, metadata decorators must be applied *after* all parameter
843+
// decorators, so we separate them here and will insert them last.
844+
let mut method_decorators = method.decorators.take_in(ctx.ast.allocator);
845+
let metadata_position = method_decorators
846+
.iter()
847+
.position(|decorator| {
848+
// All metadata decorators are unspanned
849+
decorator.span.is_unspanned()
850+
})
851+
.unwrap_or(method_decorators.len());
852+
let metadata_decorators = method_decorators.split_off(metadata_position);
853+
854+
// Method decorators should always be injected before all other decorators
838855
decorations.extend(
839-
method
840-
.decorators
841-
.drain(..)
856+
method_decorators
857+
.into_iter()
842858
.map(|decorator| ArrayExpressionElement::from(decorator.expression)),
843859
);
844860

@@ -847,6 +863,13 @@ impl<'a> LegacyDecorator<'a, '_> {
847863
self.transform_decorators_of_parameters(&mut decorations, params, ctx);
848864
}
849865

866+
// `decorateMetadata` should always be injected after param decorators
867+
decorations.extend(
868+
metadata_decorators
869+
.into_iter()
870+
.map(|decorator| ArrayExpressionElement::from(decorator.expression)),
871+
);
872+
850873
Some(ctx.ast.expression_array(SPAN, decorations))
851874
}
852875

napi/transform/test/transform.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,10 @@ describe('legacy decorator', () => {
322322
};
323323
_decorate([dce, _decorateMetadata("design:type", Object)], C.prototype, "prop", void 0);
324324
_decorate([
325+
_decorateParam(0, dce),
325326
_decorateMetadata("design:type", Function),
326327
_decorateMetadata("design:paramtypes", [Object]),
327-
_decorateMetadata("design:returntype", void 0),
328-
_decorateParam(0, dce)
328+
_decorateMetadata("design:returntype", void 0)
329329
], C.prototype, "method", null);
330330
C = _decorate([dce], C);
331331
export default C;

tasks/coverage/snapshots/semantic_misc.snap

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,28 +73,28 @@ after transform: SymbolId(1): [ReferenceId(109), ReferenceId(117), ReferenceId(1
7373
rebuilt : SymbolId(1): [ReferenceId(212), ReferenceId(214), ReferenceId(216), ReferenceId(218)]
7474
Symbol reference IDs mismatch for "IEditorService":
7575
after transform: SymbolId(2): [ReferenceId(23), ReferenceId(24), ReferenceId(67), ReferenceId(184), ReferenceId(370), ReferenceId(371)]
76-
rebuilt : SymbolId(2): [ReferenceId(57), ReferenceId(58), ReferenceId(79), ReferenceId(111), ReferenceId(239)]
76+
rebuilt : SymbolId(2): [ReferenceId(38), ReferenceId(73), ReferenceId(74), ReferenceId(111), ReferenceId(239)]
7777
Symbol reference IDs mismatch for "IEditorGroupsService":
7878
after transform: SymbolId(4): [ReferenceId(25), ReferenceId(26), ReferenceId(57), ReferenceId(176), ReferenceId(375), ReferenceId(376)]
79-
rebuilt : SymbolId(3): [ReferenceId(62), ReferenceId(63), ReferenceId(81), ReferenceId(102), ReferenceId(232)]
79+
rebuilt : SymbolId(3): [ReferenceId(40), ReferenceId(78), ReferenceId(79), ReferenceId(102), ReferenceId(232)]
8080
Symbol reference IDs mismatch for "EditorService":
8181
after transform: SymbolId(5): [ReferenceId(61), ReferenceId(64), ReferenceId(178), ReferenceId(181)]
8282
rebuilt : SymbolId(4): [ReferenceId(108), ReferenceId(236)]
8383
Symbol reference IDs mismatch for "IWorkingCopyBackupService":
8484
after transform: SymbolId(7): [ReferenceId(11), ReferenceId(12), ReferenceId(51), ReferenceId(170), ReferenceId(340), ReferenceId(341)]
85-
rebuilt : SymbolId(5): [ReferenceId(27), ReferenceId(28), ReferenceId(67), ReferenceId(96), ReferenceId(226)]
85+
rebuilt : SymbolId(5): [ReferenceId(26), ReferenceId(43), ReferenceId(44), ReferenceId(96), ReferenceId(226)]
8686
Symbol reference IDs mismatch for "IFilesConfigurationService":
8787
after transform: SymbolId(10): [ReferenceId(13), ReferenceId(14), ReferenceId(345), ReferenceId(346)]
88-
rebuilt : SymbolId(8): [ReferenceId(32), ReferenceId(33), ReferenceId(69)]
88+
rebuilt : SymbolId(8): [ReferenceId(28), ReferenceId(48), ReferenceId(49)]
8989
Symbol reference IDs mismatch for "IWorkingCopyService":
9090
after transform: SymbolId(11): [ReferenceId(15), ReferenceId(16), ReferenceId(350), ReferenceId(351)]
91-
rebuilt : SymbolId(9): [ReferenceId(37), ReferenceId(38), ReferenceId(71)]
91+
rebuilt : SymbolId(9): [ReferenceId(30), ReferenceId(53), ReferenceId(54)]
9292
Symbol reference IDs mismatch for "ILogService":
9393
after transform: SymbolId(13): [ReferenceId(19), ReferenceId(20), ReferenceId(360), ReferenceId(361)]
94-
rebuilt : SymbolId(10): [ReferenceId(47), ReferenceId(48), ReferenceId(75)]
94+
rebuilt : SymbolId(10): [ReferenceId(34), ReferenceId(63), ReferenceId(64)]
9595
Symbol reference IDs mismatch for "ILifecycleService":
9696
after transform: SymbolId(14): [ReferenceId(17), ReferenceId(18), ReferenceId(355), ReferenceId(356)]
97-
rebuilt : SymbolId(11): [ReferenceId(42), ReferenceId(43), ReferenceId(73)]
97+
rebuilt : SymbolId(11): [ReferenceId(32), ReferenceId(58), ReferenceId(59)]
9898
Symbol reference IDs mismatch for "UntitledTextEditorInput":
9999
after transform: SymbolId(17): [ReferenceId(38), ReferenceId(87)]
100100
rebuilt : SymbolId(13): [ReferenceId(83)]
@@ -106,7 +106,7 @@ after transform: SymbolId(21): [ReferenceId(1), ReferenceId(40), ReferenceId(71)
106106
rebuilt : SymbolId(17): [ReferenceId(115), ReferenceId(243)]
107107
Symbol reference IDs mismatch for "IWorkingCopyEditorService":
108108
after transform: SymbolId(32): [ReferenceId(21), ReferenceId(22), ReferenceId(365), ReferenceId(366)]
109-
rebuilt : SymbolId(26): [ReferenceId(52), ReferenceId(53), ReferenceId(77)]
109+
rebuilt : SymbolId(26): [ReferenceId(36), ReferenceId(68), ReferenceId(69)]
110110
Symbol span mismatch for "TestWorkingCopyBackupTracker":
111111
after transform: SymbolId(39): Span { start: 3208, end: 3236 }
112112
rebuilt : SymbolId(46): Span { start: 0, end: 0 }

tasks/coverage/snapshots/semantic_typescript.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8599,7 +8599,7 @@ rebuilt : [ReferenceId(13)]
85998599
semantic Error: tasks/coverage/typescript/tests/cases/compiler/decoratorMetadataElidedImport.ts
86008600
Symbol reference IDs mismatch for "Observable":
86018601
after transform: SymbolId(0): [ReferenceId(2), ReferenceId(8), ReferenceId(9)]
8602-
rebuilt : SymbolId(0): [ReferenceId(8), ReferenceId(9)]
8602+
rebuilt : SymbolId(0): [ReferenceId(12), ReferenceId(13)]
86038603

86048604
semantic Error: tasks/coverage/typescript/tests/cases/compiler/decoratorMetadataElidedImportOnDeclare.ts
86058605
Symbol reference IDs mismatch for "Observable":
@@ -8791,7 +8791,7 @@ rebuilt : ["Object", "database"]
87918791
semantic Error: tasks/coverage/typescript/tests/cases/compiler/decoratorReferenceOnOtherProperty.ts
87928792
Symbol reference IDs mismatch for "Yoha":
87938793
after transform: SymbolId(0): [ReferenceId(1), ReferenceId(5), ReferenceId(6)]
8794-
rebuilt : SymbolId(0): [ReferenceId(6), ReferenceId(7)]
8794+
rebuilt : SymbolId(0): [ReferenceId(8), ReferenceId(9)]
87958795

87968796
semantic Error: tasks/coverage/typescript/tests/cases/compiler/decoratorReferences.ts
87978797
Bindings mismatch:

tasks/transform_conformance/snapshots/oxc.snap.md

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
commit: 98d18aa4
22

3-
Passed: 183/303
3+
Passed: 183/304
44

55
# All Passed:
66
* babel-plugin-transform-class-static-block
@@ -539,7 +539,7 @@ x Output mismatch
539539
x Output mismatch
540540

541541

542-
# legacy-decorators (6/79)
542+
# legacy-decorators (6/80)
543543
* oxc/metadata/abstract-class/input.ts
544544
Symbol reference IDs mismatch for "Dependency":
545545
after transform: SymbolId(1): [ReferenceId(1), ReferenceId(2), ReferenceId(3)]
@@ -554,7 +554,7 @@ rebuilt : SymbolId(4): Span { start: 69, end: 82 }
554554
* oxc/metadata/bound-type-reference/input.ts
555555
Symbol reference IDs mismatch for "BoundTypeReference":
556556
after transform: SymbolId(0): [ReferenceId(1), ReferenceId(3), ReferenceId(4), ReferenceId(5), ReferenceId(6)]
557-
rebuilt : SymbolId(0): [ReferenceId(1), ReferenceId(6), ReferenceId(7)]
557+
rebuilt : SymbolId(0): [ReferenceId(1), ReferenceId(8), ReferenceId(9)]
558558
Symbol span mismatch for "Example":
559559
after transform: SymbolId(1): Span { start: 87, end: 94 }
560560
rebuilt : SymbolId(2): Span { start: 0, end: 0 }
@@ -571,7 +571,7 @@ after transform: ScopeId(0): [ScopeId(1), ScopeId(2)]
571571
rebuilt : ScopeId(0): [ScopeId(1)]
572572
Symbol reference IDs mismatch for "Foo":
573573
after transform: SymbolId(0): [ReferenceId(2), ReferenceId(3), ReferenceId(12), ReferenceId(13)]
574-
rebuilt : SymbolId(0): [ReferenceId(9), ReferenceId(10)]
574+
rebuilt : SymbolId(0): [ReferenceId(11), ReferenceId(12)]
575575
Symbol span mismatch for "Cls":
576576
after transform: SymbolId(7): Span { start: 145, end: 148 }
577577
rebuilt : SymbolId(2): Span { start: 0, end: 0 }
@@ -585,6 +585,41 @@ Unresolved references mismatch:
585585
after transform: ["Object", "PropertyDescriptor", "babelHelpers", "console"]
586586
rebuilt : ["Object", "babelHelpers", "console", "dec"]
587587

588+
* oxc/metadata/params/input.ts
589+
Bindings mismatch:
590+
after transform: ScopeId(0): ["Foo", "methodDecorator", "paramDecorator"]
591+
rebuilt : ScopeId(0): ["Foo"]
592+
Scope children mismatch:
593+
after transform: ScopeId(0): [ScopeId(1), ScopeId(2), ScopeId(3)]
594+
rebuilt : ScopeId(0): [ScopeId(1)]
595+
Reference symbol mismatch for "methodDecorator":
596+
after transform: SymbolId(0) "methodDecorator"
597+
rebuilt : <None>
598+
Reference symbol mismatch for "methodDecorator":
599+
after transform: SymbolId(0) "methodDecorator"
600+
rebuilt : <None>
601+
Reference symbol mismatch for "paramDecorator":
602+
after transform: SymbolId(2) "paramDecorator"
603+
rebuilt : <None>
604+
Reference symbol mismatch for "methodDecorator":
605+
after transform: SymbolId(0) "methodDecorator"
606+
rebuilt : <None>
607+
Reference symbol mismatch for "methodDecorator":
608+
after transform: SymbolId(0) "methodDecorator"
609+
rebuilt : <None>
610+
Reference symbol mismatch for "paramDecorator":
611+
after transform: SymbolId(2) "paramDecorator"
612+
rebuilt : <None>
613+
Reference symbol mismatch for "paramDecorator":
614+
after transform: SymbolId(2) "paramDecorator"
615+
rebuilt : <None>
616+
Reference symbol mismatch for "paramDecorator":
617+
after transform: SymbolId(2) "paramDecorator"
618+
rebuilt : <None>
619+
Unresolved references mismatch:
620+
after transform: ["Boolean", "Function", "String", "babelHelpers"]
621+
rebuilt : ["Boolean", "Function", "String", "babelHelpers", "methodDecorator", "paramDecorator"]
622+
588623
* oxc/metadata/this/input.ts
589624
Symbol span mismatch for "Example":
590625
after transform: SymbolId(0): Span { start: 6, end: 13 }
@@ -614,13 +649,13 @@ after transform: SymbolId(3): Span { start: 0, end: 0 }
614649
rebuilt : SymbolId(2): Span { start: 6, end: 13 }
615650
Reference flags mismatch for "UnboundTypeReference":
616651
after transform: ReferenceId(2): ReferenceFlags(Read | Type)
617-
rebuilt : ReferenceId(4): ReferenceFlags(Read)
652+
rebuilt : ReferenceId(6): ReferenceFlags(Read)
618653
Reference flags mismatch for "UnboundTypeReference":
619654
after transform: ReferenceId(3): ReferenceFlags(Read | Type)
620-
rebuilt : ReferenceId(5): ReferenceFlags(Read)
655+
rebuilt : ReferenceId(7): ReferenceFlags(Read)
621656
Unresolved reference IDs mismatch for "UnboundTypeReference":
622657
after transform: [ReferenceId(1), ReferenceId(2), ReferenceId(3)]
623-
rebuilt : [ReferenceId(4), ReferenceId(5)]
658+
rebuilt : [ReferenceId(6), ReferenceId(7)]
624659

625660
* oxc/metadata/without-decorator/input.ts
626661
Symbol span mismatch for "C":

tasks/transform_conformance/tests/legacy-decorators/test/fixtures/oxc/metadata/bound-type-reference/output.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@ var _ref;
55
console.log(BoundTypeReference);
66

77
let Example = class Example {
8-
constructor(count) { }
9-
prop = 1;
8+
constructor(count) {}
9+
prop = 1;
1010
};
1111

1212
Example = babelHelpers.decorate(
13-
[
14-
babelHelpers.decorateMetadata("design:paramtypes", [
15-
typeof (_ref =
16-
typeof BoundTypeReference !== "undefined" && BoundTypeReference) ===
17-
"function"
18-
? _ref
19-
: Object,
20-
]),
21-
babelHelpers.decorateParam(0, dce),
22-
],
23-
Example,
13+
[
14+
babelHelpers.decorateParam(0, dce),
15+
babelHelpers.decorateMetadata("design:paramtypes", [
16+
typeof (_ref =
17+
typeof BoundTypeReference !== "undefined" && BoundTypeReference) ===
18+
"function"
19+
? _ref
20+
: Object,
21+
]),
22+
],
23+
Example,
2424
);

tasks/transform_conformance/tests/legacy-decorators/test/fixtures/oxc/metadata/imports/output.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ let Cls = class Cls {
99

1010
Cls = babelHelpers.decorate(
1111
[
12+
babelHelpers.decorateParam(0, dec),
1213
babelHelpers.decorateMetadata("design:paramtypes", [
1314
typeof (_ref = typeof Foo !== "undefined" && Foo) === "function"
1415
? _ref
@@ -17,7 +18,6 @@ Cls = babelHelpers.decorate(
1718
Object,
1819
Object,
1920
]),
20-
babelHelpers.decorateParam(0, dec),
2121
],
2222
Cls,
2323
);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
declare function methodDecorator(target: any);
2+
declare function paramDecorator(target: any);
3+
4+
export class Foo {
5+
@methodDecorator(1)
6+
@methodDecorator(2)
7+
method1(@paramDecorator param: string): boolean {
8+
return !!param
9+
}
10+
11+
@methodDecorator(1)
12+
@methodDecorator(2)
13+
method2(param: string): boolean {
14+
return !!param
15+
}
16+
17+
method3(@paramDecorator param: string): boolean {
18+
return !!param
19+
}
20+
21+
method4(@paramDecorator param: string, @paramDecorator param2: string): boolean {
22+
return !!param
23+
}
24+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
export class Foo {
2+
method1(param) {
3+
return !!param;
4+
}
5+
method2(param) {
6+
return !!param;
7+
}
8+
method3(param) {
9+
return !!param;
10+
}
11+
method4(param, param2) {
12+
return !!param;
13+
}
14+
}
15+
16+
babelHelpers.decorate(
17+
[
18+
methodDecorator(1),
19+
methodDecorator(2),
20+
babelHelpers.decorateParam(0, paramDecorator),
21+
babelHelpers.decorateMetadata("design:type", Function),
22+
babelHelpers.decorateMetadata("design:paramtypes", [String]),
23+
babelHelpers.decorateMetadata("design:returntype", Boolean),
24+
],
25+
Foo.prototype,
26+
"method1",
27+
null,
28+
);
29+
30+
babelHelpers.decorate(
31+
[
32+
methodDecorator(1),
33+
methodDecorator(2),
34+
babelHelpers.decorateMetadata("design:type", Function),
35+
babelHelpers.decorateMetadata("design:paramtypes", [String]),
36+
babelHelpers.decorateMetadata("design:returntype", Boolean),
37+
],
38+
Foo.prototype,
39+
"method2",
40+
null,
41+
);
42+
43+
babelHelpers.decorate(
44+
[
45+
babelHelpers.decorateParam(0, paramDecorator),
46+
babelHelpers.decorateMetadata("design:type", Function),
47+
babelHelpers.decorateMetadata("design:paramtypes", [String]),
48+
babelHelpers.decorateMetadata("design:returntype", Boolean),
49+
],
50+
Foo.prototype,
51+
"method3",
52+
null,
53+
);
54+
55+
babelHelpers.decorate(
56+
[
57+
babelHelpers.decorateParam(0, paramDecorator),
58+
babelHelpers.decorateParam(1, paramDecorator),
59+
babelHelpers.decorateMetadata("design:type", Function),
60+
babelHelpers.decorateMetadata("design:paramtypes", [String, String]),
61+
babelHelpers.decorateMetadata("design:returntype", Boolean),
62+
],
63+
Foo.prototype,
64+
"method4",
65+
null,
66+
);
Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
let Example = class Example {
2-
constructor(a) {}
2+
constructor(a) {}
33
};
4-
Example = babelHelpers.decorate([babelHelpers.decorateMetadata("design:paramtypes", [Object]), babelHelpers.decorateParam(0, dce)], Example);
4+
Example = babelHelpers.decorate(
5+
[
6+
babelHelpers.decorateParam(0, dce),
7+
babelHelpers.decorateMetadata("design:paramtypes", [Object]),
8+
],
9+
Example,
10+
);

0 commit comments

Comments
 (0)