Private class methods stage 3 (#8654)
* Add private method syntax support * Add private method spec support * Add private method loose support * Throw error if static private method is used * Add more isStatic & isMethod checks * Remove `writable:false` from private method inits `writable` is false by default. * Add private method func obj equality check * Throw if private accessor is used * Add check for fields === private method loose mode * Throw buildCodeFrameErrors instead of Errors * Move obj destructuring inside for loop * Remove "computed" from ClassPrivateMethod type def
This commit is contained in:
committed by
Justin Ridgewell
parent
6e39b58f8a
commit
0859535b62
@@ -0,0 +1,11 @@
|
||||
class Foo {
|
||||
constructor() {
|
||||
this.publicField = this.#privateMethod();
|
||||
}
|
||||
|
||||
#privateMethod() {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
|
||||
expect((new Foo).publicField).toEqual(42);
|
||||
@@ -0,0 +1,9 @@
|
||||
class Foo {
|
||||
constructor() {
|
||||
this.publicField = this.#privateMethod();
|
||||
}
|
||||
|
||||
#privateMethod() {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
var Foo = function Foo() {
|
||||
"use strict";
|
||||
|
||||
babelHelpers.classCallCheck(this, Foo);
|
||||
Object.defineProperty(this, _privateMethod, {
|
||||
value: _privateMethod2
|
||||
});
|
||||
this.publicField = babelHelpers.classPrivateFieldLooseBase(this, _privateMethod)[_privateMethod]();
|
||||
};
|
||||
|
||||
var _privateMethod = babelHelpers.classPrivateFieldLooseKey("privateMethod");
|
||||
|
||||
var _privateMethod2 = function _privateMethod2() {
|
||||
return 42;
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
class Foo {
|
||||
constructor(status) {
|
||||
this.status = status;
|
||||
expect(() => this.#getStatus = null).toThrow(TypeError);
|
||||
}
|
||||
|
||||
#getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
getCurrentStatus() {
|
||||
return this.#getStatus();
|
||||
}
|
||||
|
||||
setCurrentStatus(newStatus) {
|
||||
this.status = newStatus;
|
||||
}
|
||||
|
||||
getFakeStatus(fakeStatus) {
|
||||
const getStatus = this.#getStatus;
|
||||
return function () {
|
||||
return getStatus.call({ status: fakeStatus });
|
||||
};
|
||||
}
|
||||
|
||||
getFakeStatusFunc() {
|
||||
return {
|
||||
status: 'fake-status',
|
||||
getFakeStatus: this.#getStatus,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const f = new Foo('inactive');
|
||||
expect(f.getCurrentStatus()).toBe('inactive');
|
||||
|
||||
f.setCurrentStatus('new-status');
|
||||
expect(f.getCurrentStatus()).toBe('new-status');
|
||||
|
||||
expect(f.getFakeStatus('fake')()).toBe('fake');
|
||||
expect(f.getFakeStatusFunc().getFakeStatus()).toBe('fake-status');
|
||||
@@ -0,0 +1,31 @@
|
||||
class Foo {
|
||||
constructor(status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
#getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
getCurrentStatus() {
|
||||
return this.#getStatus();
|
||||
}
|
||||
|
||||
setCurrentStatus(newStatus) {
|
||||
this.status = newStatus;
|
||||
}
|
||||
|
||||
getFakeStatus(fakeStatus) {
|
||||
const fakeGetStatus = this.#getStatus;
|
||||
return function() {
|
||||
return fakeGetStatus.call({ status: fakeStatus });
|
||||
};
|
||||
}
|
||||
|
||||
getFakeStatusFunc() {
|
||||
return {
|
||||
status: 'fake-status',
|
||||
getFakeStatus: this.#getStatus,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
var Foo =
|
||||
/*#__PURE__*/
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
function Foo(status) {
|
||||
babelHelpers.classCallCheck(this, Foo);
|
||||
Object.defineProperty(this, _getStatus, {
|
||||
value: _getStatus2
|
||||
});
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
babelHelpers.createClass(Foo, [{
|
||||
key: "getCurrentStatus",
|
||||
value: function getCurrentStatus() {
|
||||
return babelHelpers.classPrivateFieldLooseBase(this, _getStatus)[_getStatus]();
|
||||
}
|
||||
}, {
|
||||
key: "setCurrentStatus",
|
||||
value: function setCurrentStatus(newStatus) {
|
||||
this.status = newStatus;
|
||||
}
|
||||
}, {
|
||||
key: "getFakeStatus",
|
||||
value: function getFakeStatus(fakeStatus) {
|
||||
var fakeGetStatus = babelHelpers.classPrivateFieldLooseBase(this, _getStatus)[_getStatus];
|
||||
|
||||
return function () {
|
||||
return fakeGetStatus.call({
|
||||
status: fakeStatus
|
||||
});
|
||||
};
|
||||
}
|
||||
}, {
|
||||
key: "getFakeStatusFunc",
|
||||
value: function getFakeStatusFunc() {
|
||||
return {
|
||||
status: 'fake-status',
|
||||
getFakeStatus: babelHelpers.classPrivateFieldLooseBase(this, _getStatus)[_getStatus]
|
||||
};
|
||||
}
|
||||
}]);
|
||||
return Foo;
|
||||
}();
|
||||
|
||||
var _getStatus = babelHelpers.classPrivateFieldLooseKey("getStatus");
|
||||
|
||||
var _getStatus2 = function _getStatus2() {
|
||||
return this.status;
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
let exfiltrated;
|
||||
class Foo {
|
||||
#privateMethod() {}
|
||||
|
||||
constructor() {
|
||||
if (exfiltrated === undefined) {
|
||||
exfiltrated = this.#privateMethod;
|
||||
}
|
||||
expect(exfiltrated).toStrictEqual(this.#privateMethod);
|
||||
}
|
||||
}
|
||||
|
||||
new Foo();
|
||||
// check for private method function object equality
|
||||
new Foo();
|
||||
@@ -0,0 +1,10 @@
|
||||
let exfiltrated;
|
||||
class Foo {
|
||||
#privateMethod() {}
|
||||
|
||||
constructor() {
|
||||
if (exfiltrated === undefined) {
|
||||
exfiltrated = this.#privateMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
var exfiltrated;
|
||||
|
||||
var Foo = function Foo() {
|
||||
"use strict";
|
||||
|
||||
babelHelpers.classCallCheck(this, Foo);
|
||||
Object.defineProperty(this, _privateMethod, {
|
||||
value: _privateMethod2
|
||||
});
|
||||
|
||||
if (exfiltrated === undefined) {
|
||||
exfiltrated = babelHelpers.classPrivateFieldLooseBase(this, _privateMethod)[_privateMethod];
|
||||
}
|
||||
};
|
||||
|
||||
var _privateMethod = babelHelpers.classPrivateFieldLooseKey("privateMethod");
|
||||
|
||||
var _privateMethod2 = function _privateMethod2() {};
|
||||
15
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-loose/options.json
vendored
Normal file
15
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-loose/options.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"plugins": [
|
||||
[
|
||||
"external-helpers",
|
||||
{
|
||||
"helperVersion": "7.1.6"
|
||||
}
|
||||
],
|
||||
["proposal-private-methods", { "loose": true }],
|
||||
["proposal-class-properties", { "loose": true }],
|
||||
"transform-classes",
|
||||
"transform-block-scoping",
|
||||
"syntax-class-properties"
|
||||
]
|
||||
}
|
||||
11
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/assignment/exec.js
vendored
Normal file
11
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/assignment/exec.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
class Foo {
|
||||
constructor() {
|
||||
this.publicField = this.#privateMethod();
|
||||
}
|
||||
|
||||
#privateMethod() {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
|
||||
expect((new Foo).publicField).toEqual(42);
|
||||
@@ -0,0 +1,9 @@
|
||||
class Foo {
|
||||
constructor() {
|
||||
this.publicField = this.#privateMethod();
|
||||
}
|
||||
|
||||
#privateMethod() {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
15
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/assignment/output.js
vendored
Normal file
15
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/assignment/output.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
var Foo = function Foo() {
|
||||
"use strict";
|
||||
|
||||
babelHelpers.classCallCheck(this, Foo);
|
||||
|
||||
_privateMethod.add(this);
|
||||
|
||||
this.publicField = babelHelpers.classPrivateMethodGet(this, _privateMethod, _privateMethod2).call(this);
|
||||
};
|
||||
|
||||
var _privateMethod = new WeakSet();
|
||||
|
||||
var _privateMethod2 = function _privateMethod2() {
|
||||
return 42;
|
||||
};
|
||||
41
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/context/exec.js
vendored
Normal file
41
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/context/exec.js
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
class Foo {
|
||||
constructor(status) {
|
||||
this.status = status;
|
||||
expect(() => this.#getStatus = null).toThrow(TypeError);
|
||||
}
|
||||
|
||||
#getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
getCurrentStatus() {
|
||||
return this.#getStatus();
|
||||
}
|
||||
|
||||
setCurrentStatus(newStatus) {
|
||||
this.status = newStatus;
|
||||
}
|
||||
|
||||
getFakeStatus(fakeStatus) {
|
||||
const getStatus = this.#getStatus;
|
||||
return function () {
|
||||
return getStatus.call({ status: fakeStatus });
|
||||
};
|
||||
}
|
||||
|
||||
getFakeStatusFunc() {
|
||||
return {
|
||||
status: 'fake-status',
|
||||
getFakeStatus: this.#getStatus,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const f = new Foo('inactive');
|
||||
expect(f.getCurrentStatus()).toBe('inactive');
|
||||
|
||||
f.setCurrentStatus('new-status');
|
||||
expect(f.getCurrentStatus()).toBe('new-status');
|
||||
|
||||
expect(f.getFakeStatus('fake')()).toBe('fake');
|
||||
expect(f.getFakeStatusFunc().getFakeStatus()).toBe('fake-status');
|
||||
31
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/context/input.js
vendored
Normal file
31
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/context/input.js
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
class Foo {
|
||||
constructor(status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
#getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
getCurrentStatus() {
|
||||
return this.#getStatus();
|
||||
}
|
||||
|
||||
setCurrentStatus(newStatus) {
|
||||
this.status = newStatus;
|
||||
}
|
||||
|
||||
getFakeStatus(fakeStatus) {
|
||||
const fakeGetStatus = this.#getStatus;
|
||||
return function() {
|
||||
return fakeGetStatus.call({ status: fakeStatus });
|
||||
};
|
||||
}
|
||||
|
||||
getFakeStatusFunc() {
|
||||
return {
|
||||
status: 'fake-status',
|
||||
getFakeStatus: this.#getStatus,
|
||||
};
|
||||
}
|
||||
}
|
||||
50
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/context/output.js
vendored
Normal file
50
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/context/output.js
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
var Foo =
|
||||
/*#__PURE__*/
|
||||
function () {
|
||||
"use strict";
|
||||
|
||||
function Foo(status) {
|
||||
babelHelpers.classCallCheck(this, Foo);
|
||||
|
||||
_getStatus.add(this);
|
||||
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
babelHelpers.createClass(Foo, [{
|
||||
key: "getCurrentStatus",
|
||||
value: function getCurrentStatus() {
|
||||
return babelHelpers.classPrivateMethodGet(this, _getStatus, _getStatus2).call(this);
|
||||
}
|
||||
}, {
|
||||
key: "setCurrentStatus",
|
||||
value: function setCurrentStatus(newStatus) {
|
||||
this.status = newStatus;
|
||||
}
|
||||
}, {
|
||||
key: "getFakeStatus",
|
||||
value: function getFakeStatus(fakeStatus) {
|
||||
var fakeGetStatus = babelHelpers.classPrivateMethodGet(this, _getStatus, _getStatus2);
|
||||
return function () {
|
||||
return fakeGetStatus.call({
|
||||
status: fakeStatus
|
||||
});
|
||||
};
|
||||
}
|
||||
}, {
|
||||
key: "getFakeStatusFunc",
|
||||
value: function getFakeStatusFunc() {
|
||||
return {
|
||||
status: 'fake-status',
|
||||
getFakeStatus: babelHelpers.classPrivateMethodGet(this, _getStatus, _getStatus2)
|
||||
};
|
||||
}
|
||||
}]);
|
||||
return Foo;
|
||||
}();
|
||||
|
||||
var _getStatus = new WeakSet();
|
||||
|
||||
var _getStatus2 = function _getStatus2() {
|
||||
return this.status;
|
||||
};
|
||||
15
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/exfiltrated/exec.js
vendored
Normal file
15
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/exfiltrated/exec.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
let exfiltrated;
|
||||
class Foo {
|
||||
#privateMethod() {}
|
||||
|
||||
constructor() {
|
||||
if (exfiltrated === undefined) {
|
||||
exfiltrated = this.#privateMethod;
|
||||
}
|
||||
expect(exfiltrated).toStrictEqual(this.#privateMethod);
|
||||
}
|
||||
}
|
||||
|
||||
new Foo();
|
||||
// check for private method function object equality
|
||||
new Foo();
|
||||
10
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/exfiltrated/input.js
vendored
Normal file
10
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/exfiltrated/input.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
let exfiltrated;
|
||||
class Foo {
|
||||
#privateMethod() {}
|
||||
|
||||
constructor() {
|
||||
if (exfiltrated === undefined) {
|
||||
exfiltrated = this.#privateMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
var exfiltrated;
|
||||
|
||||
var Foo = function Foo() {
|
||||
"use strict";
|
||||
|
||||
babelHelpers.classCallCheck(this, Foo);
|
||||
|
||||
_privateMethod.add(this);
|
||||
|
||||
if (exfiltrated === undefined) {
|
||||
exfiltrated = babelHelpers.classPrivateMethodGet(this, _privateMethod, _privateMethod2);
|
||||
}
|
||||
};
|
||||
|
||||
var _privateMethod = new WeakSet();
|
||||
|
||||
var _privateMethod2 = function _privateMethod2() {};
|
||||
15
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/options.json
vendored
Normal file
15
packages/babel-plugin-proposal-private-methods/test/fixtures/private-method/options.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"plugins": [
|
||||
[
|
||||
"external-helpers",
|
||||
{
|
||||
"helperVersion": "7.1.6"
|
||||
}
|
||||
],
|
||||
"proposal-private-methods",
|
||||
"proposal-class-properties",
|
||||
"transform-classes",
|
||||
"transform-block-scoping",
|
||||
"syntax-class-properties"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import runner from "@babel/helper-plugin-test-runner";
|
||||
|
||||
runner(__dirname);
|
||||
Reference in New Issue
Block a user