Private Static Class Methods (Stage 3) (#9446)
This commit is contained in:
parent
cf4bd8bb8d
commit
81c130ffc9
@ -20,6 +20,16 @@ class Foo {
|
||||
static get foo() {}
|
||||
static set foo(bar) {}
|
||||
static static() {}
|
||||
static * foo() {}
|
||||
static async * foo() {}
|
||||
|
||||
static #foo() {}
|
||||
static async #foo() {}
|
||||
static ["foo"]() {}
|
||||
static get #foo() {}
|
||||
static set #foo(taz) {}
|
||||
static * #foo() {}
|
||||
static async * #foo() {}
|
||||
|
||||
get
|
||||
() {}
|
||||
|
||||
@ -37,6 +37,24 @@ class Foo {
|
||||
|
||||
static static() {}
|
||||
|
||||
static *foo() {}
|
||||
|
||||
static async *foo() {}
|
||||
|
||||
static #foo() {}
|
||||
|
||||
static async #foo() {}
|
||||
|
||||
static ["foo"]() {}
|
||||
|
||||
static get #foo() {}
|
||||
|
||||
static set #foo(taz) {}
|
||||
|
||||
static *#foo() {}
|
||||
|
||||
static async *#foo() {}
|
||||
|
||||
get() {}
|
||||
|
||||
set() {}
|
||||
|
||||
@ -67,9 +67,9 @@ export function verifyUsedFeatures(path, file) {
|
||||
throw path.buildCodeFrameError("Class private methods are not enabled.");
|
||||
}
|
||||
|
||||
if (path.node.static) {
|
||||
if (path.node.static && path.node.kind !== "method") {
|
||||
throw path.buildCodeFrameError(
|
||||
"@babel/plugin-class-features doesn't support class static private methods yet.",
|
||||
"@babel/plugin-class-features doesn't support class static private accessors yet.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ export function buildPrivateNamesMap(props) {
|
||||
update.getId = prop.scope.generateUidIdentifier(`get_${name}`);
|
||||
} else if (prop.node.kind === "set") {
|
||||
update.setId = prop.scope.generateUidIdentifier(`set_${name}`);
|
||||
} else if (prop.node.kind === "method" && isMethod && isInstance) {
|
||||
} else if (prop.node.kind === "method") {
|
||||
update.methodId = prop.scope.generateUidIdentifier(name);
|
||||
}
|
||||
privateNamesMap.set(name, update);
|
||||
@ -141,12 +141,18 @@ const privateNameHandlerSpec = {
|
||||
setId,
|
||||
} = privateNamesMap.get(name);
|
||||
|
||||
if (isStatic && !isMethod) {
|
||||
return t.callExpression(
|
||||
file.addHelper("classStaticPrivateFieldSpecGet"),
|
||||
[this.receiver(member), t.cloneNode(classRef), t.cloneNode(id)],
|
||||
);
|
||||
if (isStatic) {
|
||||
const helperName = isMethod
|
||||
? "classStaticPrivateMethodGet"
|
||||
: "classStaticPrivateFieldSpecGet";
|
||||
|
||||
return t.callExpression(file.addHelper(helperName), [
|
||||
this.receiver(member),
|
||||
t.cloneNode(classRef),
|
||||
t.cloneNode(id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (isMethod) {
|
||||
if (getId || setId) {
|
||||
return t.callExpression(file.addHelper("classPrivateFieldGet"), [
|
||||
@ -176,11 +182,17 @@ const privateNameHandlerSpec = {
|
||||
setId,
|
||||
} = privateNamesMap.get(name);
|
||||
|
||||
if (isStatic && !isMethod) {
|
||||
return t.callExpression(
|
||||
file.addHelper("classStaticPrivateFieldSpecSet"),
|
||||
[this.receiver(member), t.cloneNode(classRef), t.cloneNode(id), value],
|
||||
);
|
||||
if (isStatic) {
|
||||
const helperName = isMethod
|
||||
? "classStaticPrivateMethodSet"
|
||||
: "classStaticPrivateFieldSpecSet";
|
||||
|
||||
return t.callExpression(file.addHelper(helperName), [
|
||||
this.receiver(member),
|
||||
t.cloneNode(classRef),
|
||||
t.cloneNode(id),
|
||||
value,
|
||||
]);
|
||||
}
|
||||
if (isMethod) {
|
||||
if (setId) {
|
||||
@ -403,14 +415,28 @@ function buildPublicFieldInitSpec(ref, prop, state) {
|
||||
);
|
||||
}
|
||||
|
||||
function buildPrivateInstanceMethodDeclaration(prop, privateNamesMap) {
|
||||
function buildPrivateStaticMethodInitLoose(ref, prop, state, privateNamesMap) {
|
||||
const { id, methodId } = privateNamesMap.get(prop.node.key.id.name);
|
||||
return template.statement.ast`
|
||||
Object.defineProperty(${ref}, ${id}, {
|
||||
// configurable is false by default
|
||||
// enumerable is false by default
|
||||
// writable is false by default
|
||||
value: ${methodId.name}
|
||||
});
|
||||
`;
|
||||
}
|
||||
|
||||
function buildPrivateMethodDeclaration(prop, privateNamesMap, loose = false) {
|
||||
const privateName = privateNamesMap.get(prop.node.key.id.name);
|
||||
const {
|
||||
id,
|
||||
methodId,
|
||||
getId,
|
||||
setId,
|
||||
getterDeclared,
|
||||
setterDeclared,
|
||||
static: isStatic,
|
||||
} = privateName;
|
||||
const { params, body, generator, async } = prop.node;
|
||||
const methodValue = t.functionExpression(
|
||||
@ -441,6 +467,14 @@ function buildPrivateInstanceMethodDeclaration(prop, privateNamesMap) {
|
||||
t.variableDeclarator(setId, methodValue),
|
||||
]);
|
||||
}
|
||||
if (isStatic && !loose) {
|
||||
return t.variableDeclaration("var", [
|
||||
t.variableDeclarator(
|
||||
id,
|
||||
t.functionExpression(id, params, body, generator, async),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
return t.variableDeclaration("var", [
|
||||
t.variableDeclarator(methodId, methodValue),
|
||||
@ -472,8 +506,9 @@ function replaceThisContext(path, ref, superRef, file, loose) {
|
||||
});
|
||||
replacer.isStatic = true;
|
||||
replacer.replace();
|
||||
|
||||
path.traverse(thisContextVisitor, state);
|
||||
if (path.isProperty()) {
|
||||
path.traverse(thisContextVisitor, state);
|
||||
}
|
||||
return state.needsClassRef;
|
||||
}
|
||||
|
||||
@ -497,7 +532,7 @@ export function buildFieldsInitNodes(
|
||||
const isField = prop.isProperty();
|
||||
const isMethod = !isField;
|
||||
|
||||
if (isStatic && isField) {
|
||||
if (isStatic) {
|
||||
const replaced = replaceThisContext(prop, ref, superRef, state, loose);
|
||||
needsClassRef = needsClassRef || replaced;
|
||||
}
|
||||
@ -548,7 +583,7 @@ export function buildFieldsInitNodes(
|
||||
),
|
||||
);
|
||||
staticNodes.push(
|
||||
buildPrivateInstanceMethodDeclaration(prop, privateNamesMap),
|
||||
buildPrivateMethodDeclaration(prop, privateNamesMap, loose),
|
||||
);
|
||||
break;
|
||||
case isInstance && isPrivate && isMethod && !loose:
|
||||
@ -560,7 +595,27 @@ export function buildFieldsInitNodes(
|
||||
),
|
||||
);
|
||||
staticNodes.push(
|
||||
buildPrivateInstanceMethodDeclaration(prop, privateNamesMap),
|
||||
buildPrivateMethodDeclaration(prop, privateNamesMap, loose),
|
||||
);
|
||||
break;
|
||||
case isStatic && isPrivate && isMethod && !loose:
|
||||
needsClassRef = true;
|
||||
staticNodes.push(
|
||||
buildPrivateMethodDeclaration(prop, privateNamesMap, loose),
|
||||
);
|
||||
break;
|
||||
case isStatic && isPrivate && isMethod && loose:
|
||||
needsClassRef = true;
|
||||
staticNodes.push(
|
||||
buildPrivateMethodDeclaration(prop, privateNamesMap, loose),
|
||||
);
|
||||
staticNodes.push(
|
||||
buildPrivateStaticMethodInitLoose(
|
||||
t.cloneNode(ref),
|
||||
prop,
|
||||
state,
|
||||
privateNamesMap,
|
||||
),
|
||||
);
|
||||
break;
|
||||
case isInstance && isPublic && isField && loose:
|
||||
|
||||
@ -1102,7 +1102,21 @@ helpers.classStaticPrivateFieldSpecSet = helper("7.0.2")`
|
||||
descriptor.value = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
`;
|
||||
|
||||
helpers.classStaticPrivateMethodGet = helper("7.3.2")`
|
||||
export default function _classStaticPrivateMethodGet(receiver, classConstructor, method) {
|
||||
if (receiver !== classConstructor) {
|
||||
throw new TypeError("Private static access of wrong provenance");
|
||||
}
|
||||
return method;
|
||||
}
|
||||
`;
|
||||
|
||||
helpers.classStaticPrivateMethodSet = helper("7.3.2")`
|
||||
export default function _classStaticPrivateMethodSet() {
|
||||
throw new TypeError("attempted to set read only static private field");
|
||||
}
|
||||
`;
|
||||
|
||||
helpers.decorate = helper("7.1.5")`
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
class Cl {
|
||||
static async #privateStaticMethod() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
test() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
}
|
||||
|
||||
return new Cl().test().then(val => {
|
||||
expect(val).toBe(2);
|
||||
});
|
||||
@ -0,0 +1,18 @@
|
||||
{
|
||||
"minNodeVersion": "8.0.0",
|
||||
"plugins": [
|
||||
[
|
||||
"external-helpers",
|
||||
{
|
||||
"helperVersion": "7.1000.0"
|
||||
}
|
||||
],
|
||||
"proposal-private-methods",
|
||||
"proposal-class-properties",
|
||||
"transform-block-scoping",
|
||||
"syntax-class-properties"
|
||||
],
|
||||
"parserOpts": {
|
||||
"allowReturnOutsideFunction": true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
class Cl {
|
||||
test() {
|
||||
return babelHelpers.classStaticPrivateMethodGet(Cl, Cl, _privateStaticMethod).call(Cl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _privateStaticMethod = async function _privateStaticMethod() {
|
||||
return 2;
|
||||
};
|
||||
|
||||
return new Cl().test().then(val => {
|
||||
expect(val).toBe(2);
|
||||
});
|
||||
@ -0,0 +1,33 @@
|
||||
const privateStaticValue = 1017;
|
||||
|
||||
class Cl {
|
||||
static staticMethod2() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
static #privateStaticMethod() {
|
||||
return privateStaticValue;
|
||||
}
|
||||
|
||||
static staticMethod() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
static privateStaticMethod() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
publicMethod() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.instanceField = Cl.#privateStaticMethod();
|
||||
}
|
||||
}
|
||||
|
||||
expect((new Cl).publicMethod()).toEqual(privateStaticValue);
|
||||
// expect((new Cl).instanceField).toEqual(privateStaticValue);
|
||||
// expect(Cl.privateStaticMethod()).toEqual(privateStaticValue);
|
||||
// expect(Cl.staticMethod()).toEqual(privateStaticValue);
|
||||
// expect(Cl.staticMethod2()).toEqual(privateStaticValue);
|
||||
@ -0,0 +1,25 @@
|
||||
class Cl {
|
||||
static staticMethod2() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
static #privateStaticMethod() {
|
||||
return 1017;
|
||||
}
|
||||
|
||||
static staticMethod() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
static privateStaticMethod() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
publicMethod() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.instanceField = Cl.#privateStaticMethod();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
class Cl {
|
||||
static staticMethod2() {
|
||||
return babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod]();
|
||||
}
|
||||
|
||||
static staticMethod() {
|
||||
return babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod]();
|
||||
}
|
||||
|
||||
static privateStaticMethod() {
|
||||
return babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod]();
|
||||
}
|
||||
|
||||
publicMethod() {
|
||||
return babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod]();
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.instanceField = babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod]();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _privateStaticMethod = babelHelpers.classPrivateFieldLooseKey("privateStaticMethod");
|
||||
|
||||
var _privateStaticMethod2 = function _privateStaticMethod2() {
|
||||
return 1017;
|
||||
};
|
||||
|
||||
Object.defineProperty(Cl, _privateStaticMethod, {
|
||||
value: _privateStaticMethod2
|
||||
});
|
||||
@ -0,0 +1,12 @@
|
||||
class Cl {
|
||||
static #privateStaticMethod() {
|
||||
return 1017;
|
||||
}
|
||||
|
||||
publicMethod(checked) {
|
||||
return checked.#privateStaticMethod();
|
||||
}
|
||||
}
|
||||
|
||||
const cl = new Cl();
|
||||
expect(cl.publicMethod(Cl)).toBe(1017);
|
||||
@ -0,0 +1,7 @@
|
||||
class Cl {
|
||||
static #privateStaticMethod() { }
|
||||
|
||||
publicMethod(checked) {
|
||||
return checked.#privateStaticMethod();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
class Cl {
|
||||
publicMethod(checked) {
|
||||
return babelHelpers.classPrivateFieldLooseBase(checked, _privateStaticMethod)[_privateStaticMethod]();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _privateStaticMethod = babelHelpers.classPrivateFieldLooseKey("privateStaticMethod");
|
||||
|
||||
var _privateStaticMethod2 = function _privateStaticMethod2() {};
|
||||
|
||||
Object.defineProperty(Cl, _privateStaticMethod, {
|
||||
value: _privateStaticMethod2
|
||||
});
|
||||
@ -0,0 +1,20 @@
|
||||
let exfiltrated;
|
||||
|
||||
class Cl {
|
||||
static #privateStaticMethod() {
|
||||
return 1017;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
if (exfiltrated === undefined) {
|
||||
exfiltrated = Cl.#privateStaticMethod;
|
||||
}
|
||||
expect(exfiltrated).toStrictEqual(Cl.#privateStaticMethod);
|
||||
}
|
||||
}
|
||||
|
||||
new Cl();
|
||||
// check for private method function object equality
|
||||
new Cl();
|
||||
|
||||
expect(exfiltrated()).toEqual(1017);
|
||||
@ -0,0 +1,13 @@
|
||||
let exfiltrated;
|
||||
|
||||
class Cl {
|
||||
static #privateStaticMethod() {
|
||||
return 1017;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
if (exfiltrated === undefined) {
|
||||
exfiltrated = Cl.#privateStaticMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
var exfiltrated;
|
||||
|
||||
class Cl {
|
||||
constructor() {
|
||||
if (exfiltrated === undefined) {
|
||||
exfiltrated = babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _privateStaticMethod = babelHelpers.classPrivateFieldLooseKey("privateStaticMethod");
|
||||
|
||||
var _privateStaticMethod2 = function _privateStaticMethod2() {
|
||||
return 1017;
|
||||
};
|
||||
|
||||
Object.defineProperty(Cl, _privateStaticMethod, {
|
||||
value: _privateStaticMethod2
|
||||
});
|
||||
@ -0,0 +1,14 @@
|
||||
class Cl {
|
||||
static *#foo() {
|
||||
yield 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
test() {
|
||||
return Cl.#foo();
|
||||
}
|
||||
}
|
||||
|
||||
const val = new Cl().test();
|
||||
expect(val.next()).toEqual({ value: 2, done: false });
|
||||
expect(val.next()).toEqual({ value: 3, done: true });
|
||||
@ -0,0 +1,10 @@
|
||||
class Cl {
|
||||
static *#foo() {
|
||||
yield 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
test() {
|
||||
return Cl.#foo();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
class Cl {
|
||||
test() {
|
||||
return babelHelpers.classPrivateFieldLooseBase(Cl, _foo)[_foo]();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _foo = babelHelpers.classPrivateFieldLooseKey("foo");
|
||||
|
||||
var _foo2 = function* _foo2() {
|
||||
yield 2;
|
||||
return 3;
|
||||
};
|
||||
|
||||
Object.defineProperty(Cl, _foo, {
|
||||
value: _foo2
|
||||
});
|
||||
@ -0,0 +1,14 @@
|
||||
{
|
||||
"plugins": [
|
||||
[
|
||||
"external-helpers",
|
||||
{
|
||||
"helperVersion": "7.1000.0"
|
||||
}
|
||||
],
|
||||
["proposal-private-methods", { "loose": true }],
|
||||
["proposal-class-properties", { "loose": true }],
|
||||
"transform-block-scoping",
|
||||
"syntax-class-properties"
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
class Cl {
|
||||
static #privateStaticMethod() { }
|
||||
|
||||
constructor() {
|
||||
expect(() => Cl.#privateStaticMethod = null).toThrow(TypeError);
|
||||
}
|
||||
}
|
||||
|
||||
new Cl();
|
||||
@ -0,0 +1,9 @@
|
||||
class Cl {
|
||||
static #privateStaticMethod() { }
|
||||
|
||||
constructor() {
|
||||
Cl.#privateStaticMethod = null;
|
||||
}
|
||||
}
|
||||
|
||||
new Cl();
|
||||
@ -0,0 +1,15 @@
|
||||
class Cl {
|
||||
constructor() {
|
||||
babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod] = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _privateStaticMethod = babelHelpers.classPrivateFieldLooseKey("privateStaticMethod");
|
||||
|
||||
var _privateStaticMethod2 = function _privateStaticMethod2() {};
|
||||
|
||||
Object.defineProperty(Cl, _privateStaticMethod, {
|
||||
value: _privateStaticMethod2
|
||||
});
|
||||
new Cl();
|
||||
@ -0,0 +1,17 @@
|
||||
class Cl {
|
||||
static #privateMethodA() {
|
||||
const i = 40;
|
||||
return i;
|
||||
}
|
||||
|
||||
static #privateMethodB() {
|
||||
const i = 2;
|
||||
return i;
|
||||
}
|
||||
|
||||
publicMethod() {
|
||||
return Cl.#privateMethodA() + Cl.#privateMethodB();
|
||||
}
|
||||
}
|
||||
|
||||
expect((new Cl).publicMethod()).toEqual(42);
|
||||
@ -0,0 +1,15 @@
|
||||
class Base {
|
||||
static basePublicStaticMethod() { return 1017; }
|
||||
}
|
||||
|
||||
class Sub extends Base {
|
||||
static #subStaticPrivateMethod() {
|
||||
return super.basePublicStaticMethod();
|
||||
}
|
||||
|
||||
static check() {
|
||||
return Sub.#subStaticPrivateMethod();
|
||||
}
|
||||
}
|
||||
|
||||
expect(Sub.check()).toEqual(1017);
|
||||
@ -0,0 +1,13 @@
|
||||
class Base {
|
||||
static basePublicStaticMethod() { return 1017; }
|
||||
}
|
||||
|
||||
class Sub extends Base {
|
||||
static #subStaticPrivateMethod() {
|
||||
return super.basePublicStaticMethod();
|
||||
}
|
||||
|
||||
static check() {
|
||||
Sub.#subStaticPrivateMethod();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
class Base {
|
||||
static basePublicStaticMethod() {
|
||||
return 1017;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Sub extends Base {
|
||||
static check() {
|
||||
babelHelpers.classPrivateFieldLooseBase(Sub, _subStaticPrivateMethod)[_subStaticPrivateMethod]();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _subStaticPrivateMethod = babelHelpers.classPrivateFieldLooseKey("subStaticPrivateMethod");
|
||||
|
||||
var _subStaticPrivateMethod2 = function _subStaticPrivateMethod2() {
|
||||
return Base.basePublicStaticMethod.call(this);
|
||||
};
|
||||
|
||||
Object.defineProperty(Sub, _subStaticPrivateMethod, {
|
||||
value: _subStaticPrivateMethod2
|
||||
});
|
||||
@ -0,0 +1,18 @@
|
||||
class A {
|
||||
static get a() { return 1 }
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
static get b() { return 2 }
|
||||
|
||||
static #getA() { return super.a }
|
||||
static #getB() { return this.b }
|
||||
|
||||
static extract() {
|
||||
return [this.#getA, this.#getB];
|
||||
}
|
||||
}
|
||||
|
||||
const [getA, getB] = B.extract();
|
||||
expect(getA.call({ a: 3 })).toBe(1);
|
||||
expect(getB.call({ b: 4 })).toBe(4);
|
||||
@ -0,0 +1,16 @@
|
||||
class A {
|
||||
static get a() { return 1 }
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
static get b() { return 2 }
|
||||
|
||||
static #getA() { return super.a }
|
||||
static #getB() { return this.b }
|
||||
|
||||
static extract() {
|
||||
return [this.#getA, this.#getB];
|
||||
}
|
||||
}
|
||||
|
||||
const [getA, getB] = B.extract();
|
||||
@ -0,0 +1,38 @@
|
||||
class A {
|
||||
static get a() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
static get b() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
static extract() {
|
||||
return [babelHelpers.classPrivateFieldLooseBase(this, _getA)[_getA], babelHelpers.classPrivateFieldLooseBase(this, _getB)[_getB]];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _getA = babelHelpers.classPrivateFieldLooseKey("getA");
|
||||
|
||||
var _getB = babelHelpers.classPrivateFieldLooseKey("getB");
|
||||
|
||||
var _getA2 = function _getA2() {
|
||||
return A.a;
|
||||
};
|
||||
|
||||
Object.defineProperty(B, _getA, {
|
||||
value: _getA2
|
||||
});
|
||||
|
||||
var _getB2 = function _getB2() {
|
||||
return this.b;
|
||||
};
|
||||
|
||||
Object.defineProperty(B, _getB, {
|
||||
value: _getB2
|
||||
});
|
||||
var [getA, getB] = B.extract();
|
||||
@ -0,0 +1,13 @@
|
||||
class Cl {
|
||||
static async #privateStaticMethod() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
test() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
}
|
||||
|
||||
return new Cl().test().then(val => {
|
||||
expect(val).toBe(2);
|
||||
});
|
||||
@ -0,0 +1,18 @@
|
||||
{
|
||||
"minNodeVersion": "8.0.0",
|
||||
"plugins": [
|
||||
[
|
||||
"external-helpers",
|
||||
{
|
||||
"helperVersion": "7.1000.0"
|
||||
}
|
||||
],
|
||||
"proposal-private-methods",
|
||||
"proposal-class-properties",
|
||||
"transform-block-scoping",
|
||||
"syntax-class-properties"
|
||||
],
|
||||
"parserOpts": {
|
||||
"allowReturnOutsideFunction": true
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
class Cl {
|
||||
test() {
|
||||
return babelHelpers.classStaticPrivateMethodGet(Cl, Cl, _privateStaticMethod).call(Cl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _privateStaticMethod = async function _privateStaticMethod() {
|
||||
return 2;
|
||||
};
|
||||
|
||||
return new Cl().test().then(val => {
|
||||
expect(val).toBe(2);
|
||||
});
|
||||
33
packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method/basic/exec.js
vendored
Normal file
33
packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method/basic/exec.js
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
const privateStaticValue = 1017;
|
||||
|
||||
class Cl {
|
||||
static staticMethod2() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
static #privateStaticMethod() {
|
||||
return privateStaticValue;
|
||||
}
|
||||
|
||||
static staticMethod() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
static privateStaticMethod() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
publicMethod() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.instanceField = Cl.#privateStaticMethod();
|
||||
}
|
||||
}
|
||||
|
||||
expect((new Cl).publicMethod()).toEqual(privateStaticValue);
|
||||
expect((new Cl).instanceField).toEqual(privateStaticValue);
|
||||
expect(Cl.privateStaticMethod()).toEqual(privateStaticValue);
|
||||
expect(Cl.staticMethod()).toEqual(privateStaticValue);
|
||||
expect(Cl.staticMethod2()).toEqual(privateStaticValue);
|
||||
@ -0,0 +1,25 @@
|
||||
class Cl {
|
||||
static staticMethod2() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
static #privateStaticMethod() {
|
||||
return 1017;
|
||||
}
|
||||
|
||||
static staticMethod() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
static privateStaticMethod() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
publicMethod() {
|
||||
return Cl.#privateStaticMethod();
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.instanceField = Cl.#privateStaticMethod();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
class Cl {
|
||||
static staticMethod2() {
|
||||
return babelHelpers.classStaticPrivateMethodGet(Cl, Cl, _privateStaticMethod).call(Cl);
|
||||
}
|
||||
|
||||
static staticMethod() {
|
||||
return babelHelpers.classStaticPrivateMethodGet(Cl, Cl, _privateStaticMethod).call(Cl);
|
||||
}
|
||||
|
||||
static privateStaticMethod() {
|
||||
return babelHelpers.classStaticPrivateMethodGet(Cl, Cl, _privateStaticMethod).call(Cl);
|
||||
}
|
||||
|
||||
publicMethod() {
|
||||
return babelHelpers.classStaticPrivateMethodGet(Cl, Cl, _privateStaticMethod).call(Cl);
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.instanceField = babelHelpers.classStaticPrivateMethodGet(Cl, Cl, _privateStaticMethod).call(Cl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _privateStaticMethod = function _privateStaticMethod() {
|
||||
return 1017;
|
||||
};
|
||||
@ -0,0 +1,12 @@
|
||||
class Cl {
|
||||
static #privateStaticMethod() {
|
||||
return 1017;
|
||||
}
|
||||
|
||||
publicMethod(checked) {
|
||||
return checked.#privateStaticMethod();
|
||||
}
|
||||
}
|
||||
|
||||
const cl = new Cl();
|
||||
expect(cl.publicMethod(Cl)).toBe(1017);
|
||||
@ -0,0 +1,7 @@
|
||||
class Cl {
|
||||
static #privateStaticMethod() { }
|
||||
|
||||
publicMethod(checked) {
|
||||
return checked.#privateStaticMethod();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
class Cl {
|
||||
publicMethod(checked) {
|
||||
return babelHelpers.classStaticPrivateMethodGet(checked, Cl, _privateStaticMethod).call(checked);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _privateStaticMethod = function _privateStaticMethod() {};
|
||||
@ -0,0 +1,20 @@
|
||||
let exfiltrated;
|
||||
|
||||
class Cl {
|
||||
static #privateStaticMethod() {
|
||||
return 1017;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
if (exfiltrated === undefined) {
|
||||
exfiltrated = Cl.#privateStaticMethod;
|
||||
}
|
||||
expect(exfiltrated).toStrictEqual(Cl.#privateStaticMethod);
|
||||
}
|
||||
}
|
||||
|
||||
new Cl();
|
||||
// check for private method function object equality
|
||||
new Cl();
|
||||
|
||||
expect(exfiltrated()).toEqual(1017);
|
||||
@ -0,0 +1,13 @@
|
||||
let exfiltrated;
|
||||
|
||||
class Cl {
|
||||
static #privateStaticMethod() {
|
||||
return 1017;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
if (exfiltrated === undefined) {
|
||||
exfiltrated = Cl.#privateStaticMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
var exfiltrated;
|
||||
|
||||
class Cl {
|
||||
constructor() {
|
||||
if (exfiltrated === undefined) {
|
||||
exfiltrated = babelHelpers.classStaticPrivateMethodGet(Cl, Cl, _privateStaticMethod);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _privateStaticMethod = function _privateStaticMethod() {
|
||||
return 1017;
|
||||
};
|
||||
@ -0,0 +1,14 @@
|
||||
class Cl {
|
||||
static *#foo() {
|
||||
yield 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
test() {
|
||||
return Cl.#foo();
|
||||
}
|
||||
}
|
||||
|
||||
const val = new Cl().test();
|
||||
expect(val.next()).toEqual({ value: 2, done: false });
|
||||
expect(val.next()).toEqual({ value: 3, done: true });
|
||||
@ -0,0 +1,10 @@
|
||||
class Cl {
|
||||
static *#foo() {
|
||||
yield 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
test() {
|
||||
return Cl.#foo();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
class Cl {
|
||||
test() {
|
||||
return babelHelpers.classStaticPrivateMethodGet(Cl, Cl, _foo).call(Cl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _foo = function* _foo() {
|
||||
yield 2;
|
||||
return 3;
|
||||
};
|
||||
14
packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method/options.json
vendored
Normal file
14
packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method/options.json
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"plugins": [
|
||||
[
|
||||
"external-helpers",
|
||||
{
|
||||
"helperVersion": "7.1000.0"
|
||||
}
|
||||
],
|
||||
"proposal-private-methods",
|
||||
"proposal-class-properties",
|
||||
"transform-block-scoping",
|
||||
"syntax-class-properties"
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
class Cl {
|
||||
static #privateStaticMethod() { }
|
||||
|
||||
constructor() {
|
||||
expect(() => Cl.#privateStaticMethod = null).toThrow(TypeError);
|
||||
}
|
||||
}
|
||||
|
||||
new Cl();
|
||||
@ -0,0 +1,17 @@
|
||||
class Cl {
|
||||
static #privateMethodA() {
|
||||
const i = 40;
|
||||
return i;
|
||||
}
|
||||
|
||||
static #privateMethodB() {
|
||||
const i = 2;
|
||||
return i;
|
||||
}
|
||||
|
||||
publicMethod() {
|
||||
return Cl.#privateMethodA() + Cl.#privateMethodB();
|
||||
}
|
||||
}
|
||||
|
||||
expect((new Cl).publicMethod()).toEqual(42);
|
||||
15
packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method/super/exec.js
vendored
Normal file
15
packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method/super/exec.js
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
class Base {
|
||||
static basePublicStaticMethod() { return 1017; }
|
||||
}
|
||||
|
||||
class Sub extends Base {
|
||||
static #subStaticPrivateMethod() {
|
||||
return super.basePublicStaticMethod();
|
||||
}
|
||||
|
||||
static check() {
|
||||
return Sub.#subStaticPrivateMethod();
|
||||
}
|
||||
}
|
||||
|
||||
expect(Sub.check()).toEqual(1017);
|
||||
@ -0,0 +1,13 @@
|
||||
class Base {
|
||||
static basePublicStaticMethod() { return 1017; }
|
||||
}
|
||||
|
||||
class Sub extends Base {
|
||||
static #subStaticPrivateMethod() {
|
||||
return super.basePublicStaticMethod();
|
||||
}
|
||||
|
||||
static check() {
|
||||
Sub.#subStaticPrivateMethod();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
class Base {
|
||||
static basePublicStaticMethod() {
|
||||
return 1017;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Sub extends Base {
|
||||
static check() {
|
||||
babelHelpers.classStaticPrivateMethodGet(Sub, Sub, _subStaticPrivateMethod).call(Sub);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _subStaticPrivateMethod = function _subStaticPrivateMethod() {
|
||||
return babelHelpers.get(babelHelpers.getPrototypeOf(Sub), "basePublicStaticMethod", this).call(this);
|
||||
};
|
||||
18
packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method/this/exec.js
vendored
Normal file
18
packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method/this/exec.js
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
class A {
|
||||
static get a() { return 1 }
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
static get b() { return 2 }
|
||||
|
||||
static #getA() { return super.a }
|
||||
static #getB() { return this.b }
|
||||
|
||||
static extract() {
|
||||
return [this.#getA, this.#getB];
|
||||
}
|
||||
}
|
||||
|
||||
const [getA, getB] = B.extract();
|
||||
expect(getA.call({ a: 3 })).toBe(1);
|
||||
expect(getB.call({ b: 4 })).toBe(4);
|
||||
16
packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method/this/input.js
vendored
Normal file
16
packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method/this/input.js
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
class A {
|
||||
static get a() { return 1 }
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
static get b() { return 2 }
|
||||
|
||||
static #getA() { return super.a }
|
||||
static #getB() { return this.b }
|
||||
|
||||
static extract() {
|
||||
return [this.#getA, this.#getB];
|
||||
}
|
||||
}
|
||||
|
||||
const [getA, getB] = B.extract();
|
||||
@ -0,0 +1,27 @@
|
||||
class A {
|
||||
static get a() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
static get b() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
static extract() {
|
||||
return [babelHelpers.classStaticPrivateMethodGet(this, B, _getA), babelHelpers.classStaticPrivateMethodGet(this, B, _getB)];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var _getA = function _getA() {
|
||||
return babelHelpers.get(babelHelpers.getPrototypeOf(B), "a", this);
|
||||
};
|
||||
|
||||
var _getB = function _getB() {
|
||||
return this.b;
|
||||
};
|
||||
|
||||
var [getA, getB] = B.extract();
|
||||
Loading…
x
Reference in New Issue
Block a user