diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.js b/packages/babel-helper-create-class-features-plugin/src/fields.js index 68848f84e28d..083d35056bc0 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.js +++ b/packages/babel-helper-create-class-features-plugin/src/fields.js @@ -86,21 +86,28 @@ const privateNameVisitor = { const body = path.get("body.body"); const visiblePrivateNames = new Map(privateNamesMap); + const redeclared = []; for (const prop of body) { if (!prop.isPrivate()) continue; - visiblePrivateNames.delete(prop.node.key.id.name); + const { name } = prop.node.key.id; + visiblePrivateNames.delete(name); + redeclared.push(name); } // If the class doesn't redeclare any private fields, we can continue with // our overall traversal. - if (visiblePrivateNames.size === privateNamesMap.size) { + if (!redeclared.length) { return; } // This class redeclares some private field. We need to process the outer // environment with access to all the outer privates, then we can process // the inner environment with only the still-visible outer privates. - path.traverse(privateNameNestedVisitor, this); + path.get("superClass").traverse(privateNameVisitor, this); + path.get("body").traverse(privateNameNestedVisitor, { + ...this, + redeclared, + }); path.traverse(privateNameVisitor, { ...this, privateNamesMap: visiblePrivateNames, @@ -115,6 +122,13 @@ const privateNameVisitor = { // Traverses the outer portion of a class, without touching the class's inner // scope, for private names. const privateNameNestedVisitor = traverse.visitors.merge([ + { + PrivateName(path) { + const { redeclared } = this; + const { name } = path.node.id; + if (redeclared.includes(name)) path.skip(); + }, + }, { PrivateName: privateNameVisitor.PrivateName, }, diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/nested-class-computed-redeclared/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/nested-class-computed-redeclared/input.js new file mode 100644 index 000000000000..1a8d9de8e720 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/nested-class-computed-redeclared/input.js @@ -0,0 +1,14 @@ +class Foo { + #foo = 1; + + test() { + class Nested { + #foo = 2; + + [this.#foo]() { + } + } + + this.#foo; + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/nested-class-computed-redeclared/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/nested-class-computed-redeclared/output.js new file mode 100644 index 000000000000..f664abf3296a --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/nested-class-computed-redeclared/output.js @@ -0,0 +1,43 @@ +var Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + Object.defineProperty(this, _foo, { + writable: true, + value: 1 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test() { + var _babelHelpers$classPr; + + _babelHelpers$classPr = babelHelpers.classPrivateFieldLooseBase(this, _foo2)[_foo2]; + + var Nested = /*#__PURE__*/function () { + function Nested() { + babelHelpers.classCallCheck(this, Nested); + Object.defineProperty(this, _foo2, { + writable: true, + value: 2 + }); + } + + babelHelpers.createClass(Nested, [{ + key: _babelHelpers$classPr, + value: function () {} + }]); + return Nested; + }(); + + var _foo2 = babelHelpers.classPrivateFieldLooseKey("foo"); + + babelHelpers.classPrivateFieldLooseBase(this, _foo)[_foo]; + } + }]); + return Foo; +}(); + +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/nested-class-computed/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/nested-class-computed/input.js new file mode 100644 index 000000000000..7786425d1c6c --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/nested-class-computed/input.js @@ -0,0 +1,12 @@ +class Foo { + #foo = 1; + + test() { + class Nested { + [this.#foo]() { + } + } + + this.#foo; + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/nested-class-computed/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/nested-class-computed/output.js new file mode 100644 index 000000000000..57c5ed3249d1 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private-loose/nested-class-computed/output.js @@ -0,0 +1,35 @@ +var Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + Object.defineProperty(this, _foo, { + writable: true, + value: 1 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test() { + var _this = this; + + var Nested = /*#__PURE__*/function () { + function Nested() { + babelHelpers.classCallCheck(this, Nested); + } + + babelHelpers.createClass(Nested, [{ + key: babelHelpers.classPrivateFieldLooseBase(_this, _foo)[_foo], + value: function () {} + }]); + return Nested; + }(); + + babelHelpers.classPrivateFieldLooseBase(this, _foo)[_foo]; + } + }]); + return Foo; +}(); + +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class-computed-redeclared/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class-computed-redeclared/input.js new file mode 100644 index 000000000000..1a8d9de8e720 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class-computed-redeclared/input.js @@ -0,0 +1,14 @@ +class Foo { + #foo = 1; + + test() { + class Nested { + #foo = 2; + + [this.#foo]() { + } + } + + this.#foo; + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class-computed-redeclared/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class-computed-redeclared/output.js new file mode 100644 index 000000000000..c7895115ed34 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class-computed-redeclared/output.js @@ -0,0 +1,45 @@ +var Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + + _foo.set(this, { + writable: true, + value: 1 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test() { + var _babelHelpers$classPr; + + _babelHelpers$classPr = babelHelpers.classPrivateFieldGet(this, _foo2); + + var Nested = /*#__PURE__*/function () { + function Nested() { + babelHelpers.classCallCheck(this, Nested); + + _foo2.set(this, { + writable: true, + value: 2 + }); + } + + babelHelpers.createClass(Nested, [{ + key: _babelHelpers$classPr, + value: function () {} + }]); + return Nested; + }(); + + var _foo2 = new WeakMap(); + + babelHelpers.classPrivateFieldGet(this, _foo); + } + }]); + return Foo; +}(); + +var _foo = new WeakMap(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class-computed/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class-computed/input.js new file mode 100644 index 000000000000..7786425d1c6c --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class-computed/input.js @@ -0,0 +1,12 @@ +class Foo { + #foo = 1; + + test() { + class Nested { + [this.#foo]() { + } + } + + this.#foo; + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class-computed/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class-computed/output.js new file mode 100644 index 000000000000..4d06d8350652 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class-computed/output.js @@ -0,0 +1,36 @@ +var Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + + _foo.set(this, { + writable: true, + value: 1 + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test() { + var _this = this; + + var Nested = /*#__PURE__*/function () { + function Nested() { + babelHelpers.classCallCheck(this, Nested); + } + + babelHelpers.createClass(Nested, [{ + key: babelHelpers.classPrivateFieldGet(_this, _foo), + value: function () {} + }]); + return Nested; + }(); + + babelHelpers.classPrivateFieldGet(this, _foo); + } + }]); + return Foo; +}(); + +var _foo = new WeakMap();