diff --git a/CHANGELOG.md b/CHANGELOG.md index ec33dd576c6..5e19f6b308e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/internal/bundler/bundler_lower_test.go b/internal/bundler/bundler_lower_test.go index 972bb476493..65d1a060f47 100644 --- a/internal/bundler/bundler_lower_test.go +++ b/internal/bundler/bundler_lower_test.go @@ -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", + }, + }) +} diff --git a/internal/bundler/snapshots/snapshots_lower.txt b/internal/bundler/snapshots/snapshots_lower.txt index cd5ad682fba..80e5f692c9b 100644 --- a/internal/bundler/snapshots/snapshots_lower.txt +++ b/internal/bundler/snapshots/snapshots_lower.txt @@ -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 ---------- diff --git a/internal/js_parser/js_parser.go b/internal/js_parser/js_parser.go index 146968e8373..a82e0c65d24 100644 --- a/internal/js_parser/js_parser.go +++ b/internal/js_parser/js_parser.go @@ -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 } }