Skip to content

Commit

Permalink
fix #1424: always generate private method names
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Jul 29, 2021
1 parent db673c3 commit f95072d
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 7 deletions.
49 changes: 49 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,55 @@
console.log((init_esm_file(), esm_file_exports).test());
```

* Fix a code generation bug for private methods ([#1424](https://github.com/evanw/esbuild/issues/1424))

This release fixes a bug where when private methods are transformed and the target environment is one that supports private methods (such as `esnext`), the member function name was uninitialized and took on the zero value by default. This resulted in the member function name becoming `__create` instead of the correct name since that's the name of the symbol at index 0. Now esbuild always generates a private method symbol even when private methods are supported, so this is no longer an issue:

```js
// Original code
class Foo {
#a() { return 'a' }
#b() { return 'b' }
static c
}

// Old output
var _a, __create, _b, __create;
var Foo = class {
constructor() {
__privateAdd(this, _a);
__privateAdd(this, _b);
}
};
_a = new WeakSet();
__create = function() {
return "a";
};
_b = new WeakSet();
__create = function() {
return "b";
};
__publicField(Foo, "c");

// New output
var _a, a_fn, _b, b_fn;
var Foo = class {
constructor() {
__privateAdd(this, _a);
__privateAdd(this, _b);
}
};
_a = new WeakSet();
a_fn = function() {
return "a";
};
_b = new WeakSet();
b_fn = function() {
return "b";
};
__publicField(Foo, "c");
```

* The CLI now stops watch and serve mode when stdin is closed ([#1449](https://github.com/evanw/esbuild/pull/1449))

To facilitate esbuild being called from the Erlang VM, esbuild's command-line interface will now exit when in `--watch` or `--serve` mode if stdin is closed. This change is necessary because the Erlang VM doesn't have an API for terminating a child process, so it instead closes stdin to indicate that the process is no longer needed.
Expand Down
22 changes: 22 additions & 0 deletions internal/bundler/bundler_lower_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1571,3 +1571,25 @@ func TestLowerTemplateObject(t *testing.T) {
},
})
}

// See https://github.com/evanw/esbuild/issues/1424 for more information
func TestLowerPrivateClassFieldStaticIssue1424(t *testing.T) {
lower_suite.expectBundled(t, bundled{
files: map[string]string{
"/entry.js": `
class T {
#a() { return 'a'; }
#b() { return 'b'; }
static c;
d() { console.log(this.#a()); }
}
new T().d();
`,
},
entryPaths: []string{"/entry.js"},
options: config.Options{
Mode: config.ModeBundle,
AbsOutputFile: "/out.js",
},
})
}
25 changes: 25 additions & 0 deletions internal/bundler/snapshots/snapshots_lower.txt
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,31 @@ class Foo {
_foo = new WeakMap();
console.log(new Foo().bar === 123);

================================================================================
TestLowerPrivateClassFieldStaticIssue1424
---------- /out.js ----------
// entry.js
var _a, a_fn, _b, b_fn;
var T = class {
constructor() {
__privateAdd(this, _a);
__privateAdd(this, _b);
}
d() {
console.log(__privateMethod(this, _a, a_fn).call(this));
}
};
_a = new WeakSet();
a_fn = function() {
return "a";
};
_b = new WeakSet();
b_fn = function() {
return "b";
};
__publicField(T, "c");
new T().d();

================================================================================
TestLowerPrivateClassMethodOrder
---------- /out.js ----------
Expand Down
12 changes: 5 additions & 7 deletions internal/js_parser/js_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2159,13 +2159,11 @@ func (p *parser) parseProperty(kind js_ast.PropertyKind, opts propertyOpts, erro
p.log.AddRangeError(&p.tracker, keyRange, fmt.Sprintf("Invalid method name %q", name))
}
private.Ref = p.declareSymbol(declare, key.Loc, name)
if p.options.unsupportedJSFeatures.Has(declare.Feature()) {
methodRef := p.newSymbol(js_ast.SymbolOther, name[1:]+suffix)
if kind == js_ast.PropertySet {
p.privateSetters[private.Ref] = methodRef
} else {
p.privateGetters[private.Ref] = methodRef
}
methodRef := p.newSymbol(js_ast.SymbolOther, name[1:]+suffix)
if kind == js_ast.PropertySet {
p.privateSetters[private.Ref] = methodRef
} else {
p.privateGetters[private.Ref] = methodRef
}
}

Expand Down

0 comments on commit f95072d

Please sign in to comment.