Skip to content

Commit f82e0ad

Browse files
committed
fix #3761: this in field and accessor decorators
1 parent 46ea596 commit f82e0ad

File tree

7 files changed

+311
-235
lines changed

7 files changed

+311
-235
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
## Unreleased
44

5+
* Correct `this` in field and accessor decorators ([#3761](https://github.com/evanw/esbuild/issues/3761))
6+
7+
This release changes the value of `this` in initializers for class field and accessor decorators from the module-level `this` value to the appropriate `this` value for the decorated element (either the class or the instance). It was previously incorrect due to lack of test coverage. Here's an example of a decorator that doesn't work without this change:
8+
9+
```js
10+
const dec = () => function() { this.bar = true }
11+
class Foo { @dec static foo }
12+
console.log(Foo.bar) // Should be "true"
13+
```
14+
515
* Allow `es2023` as a target environment ([#3762](https://github.com/evanw/esbuild/issues/3762))
616

717
TypeScript recently [added `es2023`](https://github.com/microsoft/TypeScript/pull/58140) as a compilation target, so esbuild now supports this too. There is no difference between a target of `es2022` and `es2023` as far as esbuild is concerned since the 2023 edition of JavaScript doesn't introduce any new syntax features.

internal/js_parser/js_parser_lower_class.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,9 +850,16 @@ func (ctx *lowerClassContext) lowerField(
850850

851851
// Optionally call registered decorator initializers
852852
if initializerIndex != -1 {
853+
var value js_ast.Expr
854+
if prop.Flags.Has(js_ast.PropertyIsStatic) {
855+
value = ctx.nameFunc()
856+
} else {
857+
value = js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}
858+
}
853859
args := []js_ast.Expr{
854860
{Loc: loc, Data: &js_ast.EIdentifier{Ref: ctx.decoratorContextRef}},
855861
{Loc: loc, Data: &js_ast.ENumber{Value: float64((3 + 2*initializerIndex) << 1)}},
862+
value,
856863
}
857864
if _, ok := init.Data.(*js_ast.EUndefined); !ok {
858865
args = append(args, init)
@@ -1750,9 +1757,16 @@ func (ctx *lowerClassContext) processProperties(p *parser, classLoweringInfo cla
17501757

17511758
// Optionally call registered decorator initializers
17521759
if initializerIndex != -1 {
1760+
var value js_ast.Expr
1761+
if prop.Flags.Has(js_ast.PropertyIsStatic) {
1762+
value = ctx.nameFunc()
1763+
} else {
1764+
value = js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}
1765+
}
17531766
args := []js_ast.Expr{
17541767
{Loc: loc, Data: &js_ast.EIdentifier{Ref: ctx.decoratorContextRef}},
17551768
{Loc: loc, Data: &js_ast.ENumber{Value: float64((3 + 2*initializerIndex) << 1)}},
1769+
value,
17561770
}
17571771
if _, ok := init.Data.(*js_ast.EUndefined); !ok {
17581772
args = append(args, init)

internal/js_parser/js_parser_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2087,7 +2087,7 @@ _init = [, , ,];
20872087
_x_dec = [dec];
20882088
class Foo {
20892089
constructor() {
2090-
__publicField(this, "x", __runInitializers(_init, 6)), __runInitializers(_init, 9, this);
2090+
__publicField(this, "x", __runInitializers(_init, 6, this)), __runInitializers(_init, 9, this);
20912091
}
20922092
}
20932093
__decorateElement(_init, 5, "x", _x_dec, Foo);
@@ -2111,7 +2111,7 @@ _init = [, , ,];
21112111
_x_dec = [dec];
21122112
class Foo {
21132113
constructor() {
2114-
__privateAdd(this, _x, __runInitializers(_init, 6)), __runInitializers(_init, 9, this);
2114+
__privateAdd(this, _x, __runInitializers(_init, 6, this)), __runInitializers(_init, 9, this);
21152115
}
21162116
}
21172117
_x = new WeakMap();
@@ -2124,7 +2124,7 @@ _x_dec = [dec];
21242124
class Foo {
21252125
}
21262126
__decorateElement(_init, 13, "x", _x_dec, Foo);
2127-
__publicField(Foo, "x", __runInitializers(_init, 6)), __runInitializers(_init, 9, Foo);
2127+
__publicField(Foo, "x", __runInitializers(_init, 6, Foo)), __runInitializers(_init, 9, Foo);
21282128
`)
21292129
expectPrintedWithUnsupportedFeatures(t, compat.Decorators, "class Foo { @dec static x() {} }",
21302130
`var _x_dec, _init;
@@ -2145,7 +2145,7 @@ class Foo {
21452145
}
21462146
_x = new WeakMap();
21472147
__decorateElement(_init, 12, "x", _x_dec, Foo, _x);
2148-
__privateAdd(Foo, _x, __runInitializers(_init, 6)), __runInitializers(_init, 9, Foo);
2148+
__privateAdd(Foo, _x, __runInitializers(_init, 6, Foo)), __runInitializers(_init, 9, Foo);
21492149
`)
21502150

21512151
// Check ASI for "abstract"

internal/js_parser/ts_parser_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2132,7 +2132,7 @@ _init = [, , ,];
21322132
_x_dec = [dec];
21332133
class Foo {
21342134
constructor() {
2135-
__publicField(this, "x", __runInitializers(_init, 6)), __runInitializers(_init, 9, this);
2135+
__publicField(this, "x", __runInitializers(_init, 6, this)), __runInitializers(_init, 9, this);
21362136
}
21372137
}
21382138
__decorateElement(_init, 5, "x", _x_dec, Foo);
@@ -2156,7 +2156,7 @@ _init = [, , ,];
21562156
_x_dec = [dec];
21572157
class Foo {
21582158
constructor() {
2159-
__privateAdd(this, _x, __runInitializers(_init, 6)), __runInitializers(_init, 9, this);
2159+
__privateAdd(this, _x, __runInitializers(_init, 6, this)), __runInitializers(_init, 9, this);
21602160
}
21612161
}
21622162
_x = new WeakMap();
@@ -2169,7 +2169,7 @@ _x_dec = [dec];
21692169
class Foo {
21702170
}
21712171
__decorateElement(_init, 13, "x", _x_dec, Foo);
2172-
__publicField(Foo, "x", __runInitializers(_init, 6)), __runInitializers(_init, 9, Foo);
2172+
__publicField(Foo, "x", __runInitializers(_init, 6, Foo)), __runInitializers(_init, 9, Foo);
21732173
`)
21742174
expectPrintedWithUnsupportedFeaturesTS(t, compat.Decorators, "class Foo { @dec static x() {} }",
21752175
`var _x_dec, _init;
@@ -2190,7 +2190,7 @@ class Foo {
21902190
}
21912191
_x = new WeakMap();
21922192
__decorateElement(_init, 12, "x", _x_dec, Foo, _x);
2193-
__privateAdd(Foo, _x, __runInitializers(_init, 6)), __runInitializers(_init, 9, Foo);
2193+
__privateAdd(Foo, _x, __runInitializers(_init, 6, Foo)), __runInitializers(_init, 9, Foo);
21942194
`)
21952195

21962196
// Check ASI for "abstract"

internal/runtime/runtime.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,8 @@ func Source(unsupportedJSFeatures compat.JSFeature) logger.Source {
265265
var __expectFn = fn => fn !== void 0 && typeof fn !== 'function' ? __typeError('Function expected') : fn
266266
var __decoratorContext = (kind, name, done, fns) => ({ kind: __decoratorStrings[kind], name, addInitializer: fn =>
267267
done._ ? __typeError('Already initialized') : fns.push(__expectFn(fn || null)), })
268-
export var __runInitializers = (array, flags, value) => {
269-
for (var i = 0, fns = array[flags >> 1], n = fns && fns.length; i < n; i++) flags & 1 ? fns[i].call(value) : value = (0, fns[i])(value)
268+
export var __runInitializers = (array, flags, self, value) => {
269+
for (var i = 0, fns = array[flags >> 1], n = fns && fns.length; i < n; i++) flags & 1 ? fns[i].call(self) : value = fns[i].call(self, value)
270270
return value
271271
}
272272
export var __decorateElement = (array, flags, name, decorators, target, extra) => {

0 commit comments

Comments
 (0)