Skip to content

Commit

Permalink
fix #2914: do not emit computed declare fields
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Feb 13, 2023
1 parent 29d5a9b commit 429d073
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 7 deletions.
33 changes: 33 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,39 @@

## Unreleased

* Fix TypeScript code translation for certain computed `declare` class fields ([#2914](https://github.com/evanw/esbuild/issues/2914))

In TypeScript, the key of a computed `declare` class field should only be preserved if there are no decorators for that field. Previously esbuild always preserved the key, but esbuild will now remove the key to match the output of the TypeScript compiler:

```ts
// Original code
declare function dec(a: any, b: any): any
declare const removeMe: unique symbol
declare const keepMe: unique symbol
class X {
declare [removeMe]: any
@dec declare [keepMe]: any
}

// Old output
var _a;
class X {
}
removeMe, _a = keepMe;
__decorateClass([
dec
], X.prototype, _a, 2);

// New output
var _a;
class X {
}
_a = keepMe;
__decorateClass([
dec
], X.prototype, _a, 2);
```

* Fix a crash with path resolution error generation ([#2913](https://github.com/evanw/esbuild/issues/2913))

In certain situations, a module containing an invalid import path could previously cause esbuild to crash when it attempts to generate a more helpful error message. This crash has been fixed.
Expand Down
4 changes: 2 additions & 2 deletions internal/bundler_tests/snapshots/snapshots_ts.txt
Expand Up @@ -232,7 +232,7 @@ TestTSDeclareClassFields
// define-false/index.ts
var Foo = class {
};
() => null, c, () => null, d, () => null, C, () => null, D;
() => null, c, () => null, C;
(() => new Foo())();

// define-true/index.ts
Expand All @@ -243,7 +243,7 @@ var Bar = class {
__publicField(this, _a);
}
};
_a = (() => null, c), () => null, d, _b = (() => null, C), () => null, D;
_a = (() => null, c), _b = (() => null, C);
__publicField(Bar, "A");
__publicField(Bar, _b);
(() => new Bar())();
Expand Down
9 changes: 6 additions & 3 deletions internal/js_parser/js_parser.go
Expand Up @@ -2061,13 +2061,16 @@ func (p *parser) parseProperty(startLoc logger.Loc, kind js_ast.PropertyKind, op
scopeIndex := len(p.scopesInOrder)

if prop, ok := p.parseProperty(startLoc, kind, opts, nil); ok &&
prop.Kind == js_ast.PropertyNormal && prop.ValueOrNil.Data == nil {
prop.Kind == js_ast.PropertyNormal && prop.ValueOrNil.Data == nil && len(opts.tsDecorators) > 0 {
// If this is a well-formed class field with the "declare" keyword,
// keep the declaration to preserve its side-effects, which may
// include the computed key and/or the TypeScript decorators:
// only keep the declaration to preserve its side-effects when
// there are TypeScript decorators present:
//
// class Foo {
// // Remove this
// declare [(console.log('side effect 1'), 'foo')]
//
// // Keep this
// @decorator(console.log('side effect 2')) declare bar
// }
//
Expand Down
4 changes: 2 additions & 2 deletions internal/js_parser/ts_parser_test.go
Expand Up @@ -2512,7 +2512,7 @@ func TestTSNoAmbiguousLessThan(t *testing.T) {
"<stdin>: ERROR: Unexpected \"=\"\n")
}

func TestClassSideEffectOrder(t *testing.T) {
func TestTSClassSideEffectOrder(t *testing.T) {
// The order of computed property side effects must not change
expectPrintedTS(t, `class Foo {
[a()]() {}
Expand Down Expand Up @@ -2541,7 +2541,7 @@ Foo[_b] = 1;
`)
}

func TestMangleTSStringEnumLength(t *testing.T) {
func TestTSMangleStringEnumLength(t *testing.T) {
expectPrintedTS(t, "enum x { y = '' } z = x.y.length",
"var x = /* @__PURE__ */ ((x) => {\n x[\"y\"] = \"\";\n return x;\n})(x || {});\nz = \"\" /* y */.length;\n")

Expand Down

0 comments on commit 429d073

Please sign in to comment.