Private Static Class Methods (Stage 3) (#9446)

This commit is contained in:
Tim McClure 2019-03-12 19:11:16 -04:00 committed by Nicolò Ribaudo
parent cf4bd8bb8d
commit 81c130ffc9
55 changed files with 950 additions and 20 deletions

View File

@ -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
() {}

View File

@ -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() {}

View File

@ -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.",
);
}
}

View File

@ -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:

View File

@ -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")`

View File

@ -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);
});

View File

@ -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
}
}

View File

@ -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);
});

View 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);

View File

@ -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();
}
}

View File

@ -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
});

View File

@ -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);

View File

@ -0,0 +1,7 @@
class Cl {
static #privateStaticMethod() { }
publicMethod(checked) {
return checked.#privateStaticMethod();
}
}

View File

@ -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
});

View File

@ -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);

View File

@ -0,0 +1,13 @@
let exfiltrated;
class Cl {
static #privateStaticMethod() {
return 1017;
}
constructor() {
if (exfiltrated === undefined) {
exfiltrated = Cl.#privateStaticMethod;
}
}
}

View File

@ -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
});

View File

@ -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 });

View File

@ -0,0 +1,10 @@
class Cl {
static *#foo() {
yield 2;
return 3;
}
test() {
return Cl.#foo();
}
}

View File

@ -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
});

View File

@ -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"
]
}

View File

@ -0,0 +1,9 @@
class Cl {
static #privateStaticMethod() { }
constructor() {
expect(() => Cl.#privateStaticMethod = null).toThrow(TypeError);
}
}
new Cl();

View File

@ -0,0 +1,9 @@
class Cl {
static #privateStaticMethod() { }
constructor() {
Cl.#privateStaticMethod = null;
}
}
new Cl();

View File

@ -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();

View File

@ -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);

View 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);

View File

@ -0,0 +1,13 @@
class Base {
static basePublicStaticMethod() { return 1017; }
}
class Sub extends Base {
static #subStaticPrivateMethod() {
return super.basePublicStaticMethod();
}
static check() {
Sub.#subStaticPrivateMethod();
}
}

View File

@ -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
});

View 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);

View 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();

View File

@ -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();

View File

@ -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);
});

View File

@ -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
}
}

View File

@ -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);
});

View 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);

View File

@ -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();
}
}

View File

@ -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;
};

View File

@ -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);

View File

@ -0,0 +1,7 @@
class Cl {
static #privateStaticMethod() { }
publicMethod(checked) {
return checked.#privateStaticMethod();
}
}

View File

@ -0,0 +1,8 @@
class Cl {
publicMethod(checked) {
return babelHelpers.classStaticPrivateMethodGet(checked, Cl, _privateStaticMethod).call(checked);
}
}
var _privateStaticMethod = function _privateStaticMethod() {};

View File

@ -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);

View File

@ -0,0 +1,13 @@
let exfiltrated;
class Cl {
static #privateStaticMethod() {
return 1017;
}
constructor() {
if (exfiltrated === undefined) {
exfiltrated = Cl.#privateStaticMethod;
}
}
}

View File

@ -0,0 +1,14 @@
var exfiltrated;
class Cl {
constructor() {
if (exfiltrated === undefined) {
exfiltrated = babelHelpers.classStaticPrivateMethodGet(Cl, Cl, _privateStaticMethod);
}
}
}
var _privateStaticMethod = function _privateStaticMethod() {
return 1017;
};

View File

@ -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 });

View File

@ -0,0 +1,10 @@
class Cl {
static *#foo() {
yield 2;
return 3;
}
test() {
return Cl.#foo();
}
}

View File

@ -0,0 +1,11 @@
class Cl {
test() {
return babelHelpers.classStaticPrivateMethodGet(Cl, Cl, _foo).call(Cl);
}
}
var _foo = function* _foo() {
yield 2;
return 3;
};

View File

@ -0,0 +1,14 @@
{
"plugins": [
[
"external-helpers",
{
"helperVersion": "7.1000.0"
}
],
"proposal-private-methods",
"proposal-class-properties",
"transform-block-scoping",
"syntax-class-properties"
]
}

View File

@ -0,0 +1,9 @@
class Cl {
static #privateStaticMethod() { }
constructor() {
expect(() => Cl.#privateStaticMethod = null).toThrow(TypeError);
}
}
new Cl();

View File

@ -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);

View 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);

View File

@ -0,0 +1,13 @@
class Base {
static basePublicStaticMethod() { return 1017; }
}
class Sub extends Base {
static #subStaticPrivateMethod() {
return super.basePublicStaticMethod();
}
static check() {
Sub.#subStaticPrivateMethod();
}
}

View File

@ -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);
};

View 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);

View 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();

View File

@ -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();