Fix nested classes reference private fields (#11405)
* Fix nested classes reference private fields * Process only visible private fields when redeclaring * Comments * Skip class traversal if there are no private fields * Handle redeclared private field in computed key
This commit is contained in:
parent
aaced0156d
commit
9b48a8ead7
@ -85,24 +85,50 @@ const privateNameVisitor = {
|
||||
const { privateNamesMap } = this;
|
||||
const body = path.get("body.body");
|
||||
|
||||
const visiblePrivateNames = new Map(privateNamesMap);
|
||||
const redeclared = [];
|
||||
for (const prop of body) {
|
||||
if (!prop.isPrivate()) {
|
||||
continue;
|
||||
}
|
||||
if (!privateNamesMap.has(prop.node.key.id.name)) continue;
|
||||
|
||||
// This class redeclares the private name.
|
||||
// So, we can only evaluate the things in the outer scope.
|
||||
path.traverse(privateNameInnerVisitor, this);
|
||||
path.skip();
|
||||
break;
|
||||
if (!prop.isPrivate()) continue;
|
||||
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 (!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.get("superClass").traverse(privateNameVisitor, this);
|
||||
path.get("body").traverse(privateNameNestedVisitor, {
|
||||
...this,
|
||||
redeclared,
|
||||
});
|
||||
path.traverse(privateNameVisitor, {
|
||||
...this,
|
||||
privateNamesMap: visiblePrivateNames,
|
||||
});
|
||||
|
||||
// We'll eventually hit this class node again with the overall Class
|
||||
// Features visitor, which'll process the redeclared privates.
|
||||
path.skip();
|
||||
},
|
||||
};
|
||||
|
||||
// Traverses the outer portion of a class, without touching the class's inner
|
||||
// scope, for private names.
|
||||
const privateNameInnerVisitor = traverse.visitors.merge([
|
||||
const privateNameNestedVisitor = traverse.visitors.merge([
|
||||
{
|
||||
PrivateName(path) {
|
||||
const { redeclared } = this;
|
||||
const { name } = path.node.id;
|
||||
if (redeclared.includes(name)) path.skip();
|
||||
},
|
||||
},
|
||||
{
|
||||
PrivateName: privateNameVisitor.PrivateName,
|
||||
},
|
||||
@ -263,6 +289,8 @@ export function transformPrivateNamesUsage(
|
||||
loose,
|
||||
state,
|
||||
) {
|
||||
if (!privateNamesMap.size) return;
|
||||
|
||||
const body = path.get("body");
|
||||
|
||||
if (loose) {
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
class Foo {
|
||||
#foo = 1;
|
||||
|
||||
test() {
|
||||
class Nested {
|
||||
#foo = 2;
|
||||
|
||||
[this.#foo]() {
|
||||
}
|
||||
}
|
||||
|
||||
this.#foo;
|
||||
}
|
||||
}
|
||||
@ -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");
|
||||
@ -0,0 +1,12 @@
|
||||
class Foo {
|
||||
#foo = 1;
|
||||
|
||||
test() {
|
||||
class Nested {
|
||||
[this.#foo]() {
|
||||
}
|
||||
}
|
||||
|
||||
this.#foo;
|
||||
}
|
||||
}
|
||||
@ -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");
|
||||
@ -0,0 +1,18 @@
|
||||
class Foo {
|
||||
#foo = 1;
|
||||
#bar = 1;
|
||||
|
||||
test() {
|
||||
class Nested {
|
||||
#bar = 2;
|
||||
|
||||
test() {
|
||||
this.#foo;
|
||||
this.#bar;
|
||||
}
|
||||
}
|
||||
|
||||
this.#foo;
|
||||
this.#bar;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,49 @@
|
||||
var Foo = /*#__PURE__*/function () {
|
||||
"use strict";
|
||||
|
||||
function Foo() {
|
||||
babelHelpers.classCallCheck(this, Foo);
|
||||
Object.defineProperty(this, _foo, {
|
||||
writable: true,
|
||||
value: 1
|
||||
});
|
||||
Object.defineProperty(this, _bar, {
|
||||
writable: true,
|
||||
value: 1
|
||||
});
|
||||
}
|
||||
|
||||
babelHelpers.createClass(Foo, [{
|
||||
key: "test",
|
||||
value: function test() {
|
||||
var Nested = /*#__PURE__*/function () {
|
||||
function Nested() {
|
||||
babelHelpers.classCallCheck(this, Nested);
|
||||
Object.defineProperty(this, _bar2, {
|
||||
writable: true,
|
||||
value: 2
|
||||
});
|
||||
}
|
||||
|
||||
babelHelpers.createClass(Nested, [{
|
||||
key: "test",
|
||||
value: function test() {
|
||||
babelHelpers.classPrivateFieldLooseBase(this, _foo)[_foo];
|
||||
babelHelpers.classPrivateFieldLooseBase(this, _bar2)[_bar2];
|
||||
}
|
||||
}]);
|
||||
return Nested;
|
||||
}();
|
||||
|
||||
var _bar2 = babelHelpers.classPrivateFieldLooseKey("bar");
|
||||
|
||||
babelHelpers.classPrivateFieldLooseBase(this, _foo)[_foo];
|
||||
babelHelpers.classPrivateFieldLooseBase(this, _bar)[_bar];
|
||||
}
|
||||
}]);
|
||||
return Foo;
|
||||
}();
|
||||
|
||||
var _foo = babelHelpers.classPrivateFieldLooseKey("foo");
|
||||
|
||||
var _bar = babelHelpers.classPrivateFieldLooseKey("bar");
|
||||
@ -0,0 +1,15 @@
|
||||
class Foo {
|
||||
#foo = 1;
|
||||
|
||||
test() {
|
||||
class Nested {
|
||||
#foo = 2;
|
||||
|
||||
test() {
|
||||
this.#foo;
|
||||
}
|
||||
}
|
||||
|
||||
this.#foo;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
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 Nested = /*#__PURE__*/function () {
|
||||
function Nested() {
|
||||
babelHelpers.classCallCheck(this, Nested);
|
||||
Object.defineProperty(this, _foo2, {
|
||||
writable: true,
|
||||
value: 2
|
||||
});
|
||||
}
|
||||
|
||||
babelHelpers.createClass(Nested, [{
|
||||
key: "test",
|
||||
value: function test() {
|
||||
babelHelpers.classPrivateFieldLooseBase(this, _foo2)[_foo2];
|
||||
}
|
||||
}]);
|
||||
return Nested;
|
||||
}();
|
||||
|
||||
var _foo2 = babelHelpers.classPrivateFieldLooseKey("foo");
|
||||
|
||||
babelHelpers.classPrivateFieldLooseBase(this, _foo)[_foo];
|
||||
}
|
||||
}]);
|
||||
return Foo;
|
||||
}();
|
||||
|
||||
var _foo = babelHelpers.classPrivateFieldLooseKey("foo");
|
||||
@ -0,0 +1,13 @@
|
||||
class Foo {
|
||||
#foo = 1;
|
||||
|
||||
test() {
|
||||
class Nested {
|
||||
test() {
|
||||
this.#foo;
|
||||
}
|
||||
}
|
||||
|
||||
this.#foo;
|
||||
}
|
||||
}
|
||||
@ -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 Nested = /*#__PURE__*/function () {
|
||||
function Nested() {
|
||||
babelHelpers.classCallCheck(this, Nested);
|
||||
}
|
||||
|
||||
babelHelpers.createClass(Nested, [{
|
||||
key: "test",
|
||||
value: function test() {
|
||||
babelHelpers.classPrivateFieldLooseBase(this, _foo)[_foo];
|
||||
}
|
||||
}]);
|
||||
return Nested;
|
||||
}();
|
||||
|
||||
babelHelpers.classPrivateFieldLooseBase(this, _foo)[_foo];
|
||||
}
|
||||
}]);
|
||||
return Foo;
|
||||
}();
|
||||
|
||||
var _foo = babelHelpers.classPrivateFieldLooseKey("foo");
|
||||
@ -0,0 +1,14 @@
|
||||
class Foo {
|
||||
#foo = 1;
|
||||
|
||||
test() {
|
||||
class Nested {
|
||||
#foo = 2;
|
||||
|
||||
[this.#foo]() {
|
||||
}
|
||||
}
|
||||
|
||||
this.#foo;
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
@ -0,0 +1,12 @@
|
||||
class Foo {
|
||||
#foo = 1;
|
||||
|
||||
test() {
|
||||
class Nested {
|
||||
[this.#foo]() {
|
||||
}
|
||||
}
|
||||
|
||||
this.#foo;
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
@ -0,0 +1,18 @@
|
||||
class Foo {
|
||||
#foo = 1;
|
||||
#bar = 1;
|
||||
|
||||
test() {
|
||||
class Nested {
|
||||
#bar = 2;
|
||||
|
||||
test() {
|
||||
this.#foo;
|
||||
this.#bar;
|
||||
}
|
||||
}
|
||||
|
||||
this.#foo;
|
||||
this.#bar;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
var Foo = /*#__PURE__*/function () {
|
||||
"use strict";
|
||||
|
||||
function Foo() {
|
||||
babelHelpers.classCallCheck(this, Foo);
|
||||
|
||||
_foo.set(this, {
|
||||
writable: true,
|
||||
value: 1
|
||||
});
|
||||
|
||||
_bar.set(this, {
|
||||
writable: true,
|
||||
value: 1
|
||||
});
|
||||
}
|
||||
|
||||
babelHelpers.createClass(Foo, [{
|
||||
key: "test",
|
||||
value: function test() {
|
||||
var Nested = /*#__PURE__*/function () {
|
||||
function Nested() {
|
||||
babelHelpers.classCallCheck(this, Nested);
|
||||
|
||||
_bar2.set(this, {
|
||||
writable: true,
|
||||
value: 2
|
||||
});
|
||||
}
|
||||
|
||||
babelHelpers.createClass(Nested, [{
|
||||
key: "test",
|
||||
value: function test() {
|
||||
babelHelpers.classPrivateFieldGet(this, _foo);
|
||||
babelHelpers.classPrivateFieldGet(this, _bar2);
|
||||
}
|
||||
}]);
|
||||
return Nested;
|
||||
}();
|
||||
|
||||
var _bar2 = new WeakMap();
|
||||
|
||||
babelHelpers.classPrivateFieldGet(this, _foo);
|
||||
babelHelpers.classPrivateFieldGet(this, _bar);
|
||||
}
|
||||
}]);
|
||||
return Foo;
|
||||
}();
|
||||
|
||||
var _foo = new WeakMap();
|
||||
|
||||
var _bar = new WeakMap();
|
||||
@ -0,0 +1,15 @@
|
||||
class Foo {
|
||||
#foo = 1;
|
||||
|
||||
test() {
|
||||
class Nested {
|
||||
#foo = 2;
|
||||
|
||||
test() {
|
||||
this.#foo;
|
||||
}
|
||||
}
|
||||
|
||||
this.#foo;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
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 Nested = /*#__PURE__*/function () {
|
||||
function Nested() {
|
||||
babelHelpers.classCallCheck(this, Nested);
|
||||
|
||||
_foo2.set(this, {
|
||||
writable: true,
|
||||
value: 2
|
||||
});
|
||||
}
|
||||
|
||||
babelHelpers.createClass(Nested, [{
|
||||
key: "test",
|
||||
value: function test() {
|
||||
babelHelpers.classPrivateFieldGet(this, _foo2);
|
||||
}
|
||||
}]);
|
||||
return Nested;
|
||||
}();
|
||||
|
||||
var _foo2 = new WeakMap();
|
||||
|
||||
babelHelpers.classPrivateFieldGet(this, _foo);
|
||||
}
|
||||
}]);
|
||||
return Foo;
|
||||
}();
|
||||
|
||||
var _foo = new WeakMap();
|
||||
13
packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class/input.js
vendored
Normal file
13
packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class/input.js
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
class Foo {
|
||||
#foo = 1;
|
||||
|
||||
test() {
|
||||
class Nested {
|
||||
test() {
|
||||
this.#foo;
|
||||
}
|
||||
}
|
||||
|
||||
this.#foo;
|
||||
}
|
||||
}
|
||||
36
packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class/output.js
vendored
Normal file
36
packages/babel-plugin-proposal-class-properties/test/fixtures/private/nested-class/output.js
vendored
Normal file
@ -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 Nested = /*#__PURE__*/function () {
|
||||
function Nested() {
|
||||
babelHelpers.classCallCheck(this, Nested);
|
||||
}
|
||||
|
||||
babelHelpers.createClass(Nested, [{
|
||||
key: "test",
|
||||
value: function test() {
|
||||
babelHelpers.classPrivateFieldGet(this, _foo);
|
||||
}
|
||||
}]);
|
||||
return Nested;
|
||||
}();
|
||||
|
||||
babelHelpers.classPrivateFieldGet(this, _foo);
|
||||
}
|
||||
}]);
|
||||
return Foo;
|
||||
}();
|
||||
|
||||
var _foo = new WeakMap();
|
||||
Loading…
x
Reference in New Issue
Block a user