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:
parent
6e39b58f8a
commit
0859535b62
@ -140,6 +140,12 @@ export function ClassMethod(node: Object) {
|
|||||||
this.print(node.body, node);
|
this.print(node.body, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function ClassPrivateMethod(node: Object) {
|
||||||
|
this._classMethodHead(node);
|
||||||
|
this.space();
|
||||||
|
this.print(node.body, node);
|
||||||
|
}
|
||||||
|
|
||||||
export function _classMethodHead(node) {
|
export function _classMethodHead(node) {
|
||||||
this.printJoin(node.decorators, node);
|
this.printJoin(node.decorators, node);
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,15 @@ class Foo {
|
|||||||
get foo() {}
|
get foo() {}
|
||||||
set foo(bar) {}
|
set foo(bar) {}
|
||||||
|
|
||||||
|
async #foo() {}
|
||||||
|
#foo() {}
|
||||||
|
get #foo() {}
|
||||||
|
set #foo(bar) {}
|
||||||
|
* #foo() {}
|
||||||
|
async * #foo() {}
|
||||||
|
get #bar() {}
|
||||||
|
set #baz(taz) {}
|
||||||
|
|
||||||
static async foo() {}
|
static async foo() {}
|
||||||
static foo() {}
|
static foo() {}
|
||||||
static ["foo"]() {}
|
static ["foo"]() {}
|
||||||
@ -52,4 +61,4 @@ class Foo {
|
|||||||
get
|
get
|
||||||
static
|
static
|
||||||
() {}
|
() {}
|
||||||
}
|
}
|
||||||
1
packages/babel-generator/test/fixtures/types/ClassBody-MethodDefinition/options.json
vendored
Normal file
1
packages/babel-generator/test/fixtures/types/ClassBody-MethodDefinition/options.json
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{ "plugins": ["classPrivateMethods", "asyncGenerators"] }
|
||||||
@ -9,6 +9,22 @@ class Foo {
|
|||||||
|
|
||||||
set foo(bar) {}
|
set foo(bar) {}
|
||||||
|
|
||||||
|
async #foo() {}
|
||||||
|
|
||||||
|
#foo() {}
|
||||||
|
|
||||||
|
get #foo() {}
|
||||||
|
|
||||||
|
set #foo(bar) {}
|
||||||
|
|
||||||
|
*#foo() {}
|
||||||
|
|
||||||
|
async *#foo() {}
|
||||||
|
|
||||||
|
get #bar() {}
|
||||||
|
|
||||||
|
set #baz(taz) {}
|
||||||
|
|
||||||
static async foo() {}
|
static async foo() {}
|
||||||
|
|
||||||
static foo() {}
|
static foo() {}
|
||||||
|
|||||||
@ -1739,3 +1739,18 @@ helpers.decorate = helper("7.1.5")`
|
|||||||
return constructor;
|
return constructor;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
helpers.classPrivateMethodGet = helper("7.1.6")`
|
||||||
|
export default function _classPrivateMethodGet(receiver, privateSet, fn) {
|
||||||
|
if (!privateSet.has(receiver)) {
|
||||||
|
throw new TypeError("attempted to get private field on non-instance");
|
||||||
|
}
|
||||||
|
return fn;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
helpers.classPrivateMethodSet = helper("7.1.6")`
|
||||||
|
export default function _classPrivateMethodSet() {
|
||||||
|
throw new TypeError("attempted to reassign private method");
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@ -39,19 +39,43 @@ export function isLoose(file, feature) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function verifyUsedFeatures(path, file) {
|
export function verifyUsedFeatures(path, file) {
|
||||||
|
if (hasDecorators(path) && !hasFeature(file, FEATURES.decorators)) {
|
||||||
|
throw path.buildCodeFrameError("Decorators are not enabled.");
|
||||||
|
}
|
||||||
|
|
||||||
if (hasFeature(file, FEATURES.decorators)) {
|
if (hasFeature(file, FEATURES.decorators)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"@babel/plugin-class-features doesn't support decorators yet.",
|
"@babel/plugin-class-features doesn't support decorators yet.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (hasFeature(file, FEATURES.privateMethods)) {
|
|
||||||
throw new Error(
|
if (path.isClassPrivateMethod()) {
|
||||||
"@babel/plugin-class-features doesn't support private methods yet.",
|
if (!hasFeature(file, FEATURES.privateMethods)) {
|
||||||
);
|
throw path.buildCodeFrameError("Class private methods are not enabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.node.static) {
|
||||||
|
throw path.buildCodeFrameError(
|
||||||
|
"@babel/plugin-class-features doesn't support class static private methods yet.",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.node.kind !== "method") {
|
||||||
|
throw path.buildCodeFrameError(
|
||||||
|
"@babel/plugin-class-features doesn't support class private accessors yet.",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasDecorators(path) && !hasFeature(file, FEATURES.decorators)) {
|
if (
|
||||||
throw path.buildCodeFrameError("Decorators are not enabled.");
|
hasFeature(file, FEATURES.privateMethods) &&
|
||||||
|
hasFeature(file, FEATURES.fields) &&
|
||||||
|
isLoose(file, FEATURES.privateMethods) !== isLoose(file, FEATURES.fields)
|
||||||
|
) {
|
||||||
|
throw path.buildCodeFrameError(
|
||||||
|
"'loose' mode configuration must be the same for both @babel/plugin-proposal-class-properties " +
|
||||||
|
"and @babel/plugin-proposal-private-methods",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.isProperty()) {
|
if (path.isProperty()) {
|
||||||
|
|||||||
@ -11,6 +11,10 @@ export function buildPrivateNamesMap(props) {
|
|||||||
privateNamesMap.set(name, {
|
privateNamesMap.set(name, {
|
||||||
id: prop.scope.generateUidIdentifier(name),
|
id: prop.scope.generateUidIdentifier(name),
|
||||||
static: !!prop.node.static,
|
static: !!prop.node.static,
|
||||||
|
method: prop.isClassPrivateMethod(),
|
||||||
|
methodId: prop.isClassPrivateMethod()
|
||||||
|
? prop.scope.generateUidIdentifier(name)
|
||||||
|
: undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -20,20 +24,22 @@ export function buildPrivateNamesMap(props) {
|
|||||||
export function buildPrivateNamesNodes(privateNamesMap, loose, state) {
|
export function buildPrivateNamesNodes(privateNamesMap, loose, state) {
|
||||||
const initNodes = [];
|
const initNodes = [];
|
||||||
|
|
||||||
for (const [name, { id, static: isStatic }] of privateNamesMap) {
|
for (const [name, value] of privateNamesMap) {
|
||||||
// In loose mode, both static and instance fields hare transpiled using a
|
// In loose mode, both static and instance fields are transpiled using a
|
||||||
// secret non-enumerable property. Hence, we also need to generate that
|
// secret non-enumerable property. Hence, we also need to generate that
|
||||||
// key (using the classPrivateFieldLooseKey helper) in loose mode.
|
// key (using the classPrivateFieldLooseKey helper).
|
||||||
// In spec mode, only instance fields need a "private name" initializer
|
// In spec mode, only instance fields need a "private name" initializer
|
||||||
// (the WeakMap), becase static fields are directly assigned to a variable
|
// because static fields are directly assigned to a variable in the
|
||||||
// in the buildPrivateStaticFieldInitSpec function.
|
// buildPrivateStaticFieldInitSpec function.
|
||||||
|
const { id, static: isStatic, method: isMethod } = value;
|
||||||
if (loose) {
|
if (loose) {
|
||||||
initNodes.push(
|
initNodes.push(
|
||||||
template.statement.ast`
|
template.statement.ast`
|
||||||
var ${id} = ${state.addHelper("classPrivateFieldLooseKey")}("${name}")
|
var ${id} = ${state.addHelper("classPrivateFieldLooseKey")}("${name}")
|
||||||
`,
|
`,
|
||||||
);
|
);
|
||||||
|
} else if (isMethod && !isStatic) {
|
||||||
|
initNodes.push(template.statement.ast`var ${id} = new WeakSet();`);
|
||||||
} else if (!isStatic) {
|
} else if (!isStatic) {
|
||||||
initNodes.push(template.statement.ast`var ${id} = new WeakMap();`);
|
initNodes.push(template.statement.ast`var ${id} = new WeakMap();`);
|
||||||
}
|
}
|
||||||
@ -42,7 +48,7 @@ export function buildPrivateNamesNodes(privateNamesMap, loose, state) {
|
|||||||
return initNodes;
|
return initNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Traverses the class scope, handling private name references. If an inner
|
// Traverses the class scope, handling private name references. If an inner
|
||||||
// class redeclares the same private name, it will hand off traversal to the
|
// class redeclares the same private name, it will hand off traversal to the
|
||||||
// restricted visitor (which doesn't traverse the inner class's inner scope).
|
// restricted visitor (which doesn't traverse the inner class's inner scope).
|
||||||
const privateNameVisitor = {
|
const privateNameVisitor = {
|
||||||
@ -61,7 +67,9 @@ const privateNameVisitor = {
|
|||||||
const body = path.get("body.body");
|
const body = path.get("body.body");
|
||||||
|
|
||||||
for (const prop of body) {
|
for (const prop of body) {
|
||||||
if (!prop.isClassPrivateProperty()) continue;
|
if (!prop.isPrivate()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!privateNamesMap.has(prop.node.key.id.name)) continue;
|
if (!privateNamesMap.has(prop.node.key.id.name)) continue;
|
||||||
|
|
||||||
// This class redeclares the private name.
|
// This class redeclares the private name.
|
||||||
@ -108,13 +116,24 @@ const privateNameHandlerSpec = {
|
|||||||
get(member) {
|
get(member) {
|
||||||
const { classRef, privateNamesMap, file } = this;
|
const { classRef, privateNamesMap, file } = this;
|
||||||
const { name } = member.node.property.id;
|
const { name } = member.node.property.id;
|
||||||
const { id, static: isStatic } = privateNamesMap.get(name);
|
const {
|
||||||
|
id,
|
||||||
|
static: isStatic,
|
||||||
|
method: isMethod,
|
||||||
|
methodId,
|
||||||
|
} = privateNamesMap.get(name);
|
||||||
|
|
||||||
if (isStatic) {
|
if (isStatic && !isMethod) {
|
||||||
return t.callExpression(
|
return t.callExpression(
|
||||||
file.addHelper("classStaticPrivateFieldSpecGet"),
|
file.addHelper("classStaticPrivateFieldSpecGet"),
|
||||||
[this.receiver(member), t.cloneNode(classRef), t.cloneNode(id)],
|
[this.receiver(member), t.cloneNode(classRef), t.cloneNode(id)],
|
||||||
);
|
);
|
||||||
|
} else if (isMethod) {
|
||||||
|
return t.callExpression(file.addHelper("classPrivateMethodGet"), [
|
||||||
|
this.receiver(member),
|
||||||
|
t.cloneNode(id),
|
||||||
|
t.cloneNode(methodId),
|
||||||
|
]);
|
||||||
} else {
|
} else {
|
||||||
return t.callExpression(file.addHelper("classPrivateFieldGet"), [
|
return t.callExpression(file.addHelper("classPrivateFieldGet"), [
|
||||||
this.receiver(member),
|
this.receiver(member),
|
||||||
@ -126,13 +145,17 @@ const privateNameHandlerSpec = {
|
|||||||
set(member, value) {
|
set(member, value) {
|
||||||
const { classRef, privateNamesMap, file } = this;
|
const { classRef, privateNamesMap, file } = this;
|
||||||
const { name } = member.node.property.id;
|
const { name } = member.node.property.id;
|
||||||
const { id, static: isStatic } = privateNamesMap.get(name);
|
const { id, static: isStatic, method: isMethod } = privateNamesMap.get(
|
||||||
|
name,
|
||||||
|
);
|
||||||
|
|
||||||
if (isStatic) {
|
if (isStatic && !isMethod) {
|
||||||
return t.callExpression(
|
return t.callExpression(
|
||||||
file.addHelper("classStaticPrivateFieldSpecSet"),
|
file.addHelper("classStaticPrivateFieldSpecSet"),
|
||||||
[this.receiver(member), t.cloneNode(classRef), t.cloneNode(id), value],
|
[this.receiver(member), t.cloneNode(classRef), t.cloneNode(id), value],
|
||||||
);
|
);
|
||||||
|
} else if (isMethod) {
|
||||||
|
return t.callExpression(file.addHelper("classPrivateMethodSet"), []);
|
||||||
} else {
|
} else {
|
||||||
return t.callExpression(file.addHelper("classPrivateFieldSet"), [
|
return t.callExpression(file.addHelper("classPrivateFieldSet"), [
|
||||||
this.receiver(member),
|
this.receiver(member),
|
||||||
@ -231,6 +254,25 @@ function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildPrivateMethodInitLoose(ref, prop, privateNamesMap) {
|
||||||
|
const { methodId, id } = 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 buildPrivateInstanceMethodInitSpec(ref, prop, privateNamesMap) {
|
||||||
|
const { id } = privateNamesMap.get(prop.node.key.id.name);
|
||||||
|
|
||||||
|
return template.statement.ast`${id}.add(${ref})`;
|
||||||
|
}
|
||||||
|
|
||||||
function buildPublicFieldInitLoose(ref, prop) {
|
function buildPublicFieldInitLoose(ref, prop) {
|
||||||
const { key, computed } = prop.node;
|
const { key, computed } = prop.node;
|
||||||
const value = prop.node.value || prop.scope.buildUndefinedNode();
|
const value = prop.node.value || prop.scope.buildUndefinedNode();
|
||||||
@ -257,6 +299,16 @@ function buildPublicFieldInitSpec(ref, prop, state) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildPrivateInstanceMethodDeclaration(prop, privateNamesMap) {
|
||||||
|
const { methodId } = privateNamesMap.get(prop.node.key.id.name);
|
||||||
|
const { params, body } = prop.node;
|
||||||
|
const methodValue = t.functionExpression(methodId, params, body);
|
||||||
|
|
||||||
|
return t.variableDeclaration("var", [
|
||||||
|
t.variableDeclarator(methodId, methodValue),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
export function buildFieldsInitNodes(
|
export function buildFieldsInitNodes(
|
||||||
ref,
|
ref,
|
||||||
props,
|
props,
|
||||||
@ -269,34 +321,34 @@ export function buildFieldsInitNodes(
|
|||||||
|
|
||||||
for (const prop of props) {
|
for (const prop of props) {
|
||||||
const isStatic = prop.node.static;
|
const isStatic = prop.node.static;
|
||||||
const isPrivate = prop.isPrivate();
|
const isPrivateField = prop.isClassPrivateProperty();
|
||||||
|
const isPrivateMethod = prop.isClassPrivateMethod();
|
||||||
|
|
||||||
// Pattern matching please
|
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case isStatic && isPrivate && loose:
|
case isStatic && isPrivateField && loose:
|
||||||
staticNodes.push(
|
staticNodes.push(
|
||||||
buildPrivateFieldInitLoose(t.cloneNode(ref), prop, privateNamesMap),
|
buildPrivateFieldInitLoose(t.cloneNode(ref), prop, privateNamesMap),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case isStatic && isPrivate && !loose:
|
case isStatic && isPrivateField && !loose:
|
||||||
staticNodes.push(
|
staticNodes.push(
|
||||||
buildPrivateStaticFieldInitSpec(prop, privateNamesMap),
|
buildPrivateStaticFieldInitSpec(prop, privateNamesMap),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case isStatic && !isPrivate && loose:
|
case isStatic && !isPrivateField && loose:
|
||||||
staticNodes.push(buildPublicFieldInitLoose(t.cloneNode(ref), prop));
|
staticNodes.push(buildPublicFieldInitLoose(t.cloneNode(ref), prop));
|
||||||
break;
|
break;
|
||||||
case isStatic && !isPrivate && !loose:
|
case isStatic && !isPrivateField && !loose:
|
||||||
staticNodes.push(
|
staticNodes.push(
|
||||||
buildPublicFieldInitSpec(t.cloneNode(ref), prop, state),
|
buildPublicFieldInitSpec(t.cloneNode(ref), prop, state),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case !isStatic && isPrivate && loose:
|
case !isStatic && isPrivateField && loose:
|
||||||
instanceNodes.push(
|
instanceNodes.push(
|
||||||
buildPrivateFieldInitLoose(t.thisExpression(), prop, privateNamesMap),
|
buildPrivateFieldInitLoose(t.thisExpression(), prop, privateNamesMap),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case !isStatic && isPrivate && !loose:
|
case !isStatic && isPrivateField && !loose:
|
||||||
instanceNodes.push(
|
instanceNodes.push(
|
||||||
buildPrivateInstanceFieldInitSpec(
|
buildPrivateInstanceFieldInitSpec(
|
||||||
t.thisExpression(),
|
t.thisExpression(),
|
||||||
@ -305,10 +357,34 @@ export function buildFieldsInitNodes(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case !isStatic && !isPrivate && loose:
|
case !isStatic && isPrivateMethod && loose:
|
||||||
|
instanceNodes.push(
|
||||||
|
buildPrivateMethodInitLoose(
|
||||||
|
t.thisExpression(),
|
||||||
|
prop,
|
||||||
|
privateNamesMap,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
staticNodes.push(
|
||||||
|
buildPrivateInstanceMethodDeclaration(prop, privateNamesMap),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case !isStatic && isPrivateMethod && !loose:
|
||||||
|
instanceNodes.push(
|
||||||
|
buildPrivateInstanceMethodInitSpec(
|
||||||
|
t.thisExpression(),
|
||||||
|
prop,
|
||||||
|
privateNamesMap,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
staticNodes.push(
|
||||||
|
buildPrivateInstanceMethodDeclaration(prop, privateNamesMap),
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case !isStatic && !isPrivateField && loose:
|
||||||
instanceNodes.push(buildPublicFieldInitLoose(t.thisExpression(), prop));
|
instanceNodes.push(buildPublicFieldInitLoose(t.thisExpression(), prop));
|
||||||
break;
|
break;
|
||||||
case !isStatic && !isPrivate && !loose:
|
case !isStatic && !isPrivateField && !loose:
|
||||||
instanceNodes.push(
|
instanceNodes.push(
|
||||||
buildPublicFieldInitSpec(t.thisExpression(), prop, state),
|
buildPublicFieldInitSpec(t.thisExpression(), prop, state),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -75,7 +75,6 @@ export default declare((api, options) => {
|
|||||||
enableFeature(this.file, FEATURES.fields, fields.loose);
|
enableFeature(this.file, FEATURES.fields, fields.loose);
|
||||||
}
|
}
|
||||||
if (privateMethods.enabled) {
|
if (privateMethods.enabled) {
|
||||||
throw new Error("Private methods are not supported yet");
|
|
||||||
enableFeature(this.file, FEATURES.privateMethods);
|
enableFeature(this.file, FEATURES.privateMethods);
|
||||||
}
|
}
|
||||||
if (decorators.enabled) {
|
if (decorators.enabled) {
|
||||||
@ -107,7 +106,7 @@ export default declare((api, options) => {
|
|||||||
computedPaths.push(path);
|
computedPaths.push(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.isClassPrivateProperty()) {
|
if (path.isPrivate()) {
|
||||||
const { name } = path.node.key.id;
|
const { name } = path.node.key.id;
|
||||||
|
|
||||||
if (privateNames.has(name)) {
|
if (privateNames.has(name)) {
|
||||||
@ -116,7 +115,7 @@ export default declare((api, options) => {
|
|||||||
privateNames.add(name);
|
privateNames.add(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.isProperty()) {
|
if (path.isProperty() || path.isClassPrivateMethod()) {
|
||||||
props.push(path);
|
props.push(path);
|
||||||
} else if (path.isClassMethod({ kind: "constructor" })) {
|
} else if (path.isClassMethod({ kind: "constructor" })) {
|
||||||
constructor = path;
|
constructor = path;
|
||||||
@ -131,7 +130,6 @@ export default declare((api, options) => {
|
|||||||
nameFunction(path);
|
nameFunction(path);
|
||||||
ref = path.scope.generateUidIdentifier("class");
|
ref = path.scope.generateUidIdentifier("class");
|
||||||
} else {
|
} else {
|
||||||
// path.isClassDeclaration() && path.node.id
|
|
||||||
ref = path.node.id;
|
ref = path.node.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
src
|
||||||
|
test
|
||||||
|
*.log
|
||||||
19
packages/babel-plugin-proposal-private-methods/README.md
Normal file
19
packages/babel-plugin-proposal-private-methods/README.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# @babel/plugin-proposal-private-methods
|
||||||
|
|
||||||
|
> This plugin transforms private class methods
|
||||||
|
|
||||||
|
See our website [@babel/plugin-proposal-private-methods](https://babeljs.io/docs/en/next/babel-plugin-proposal-private-methods.html) for more information.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Using npm:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install --save-dev @babel/plugin-proposal-private-methods
|
||||||
|
```
|
||||||
|
|
||||||
|
or using yarn:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn add @babel/plugin-proposal-private-methods --dev
|
||||||
|
```
|
||||||
25
packages/babel-plugin-proposal-private-methods/package.json
Normal file
25
packages/babel-plugin-proposal-private-methods/package.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "@babel/plugin-proposal-private-methods",
|
||||||
|
"version": "7.1.0",
|
||||||
|
"description": "This plugin transforms private class methods",
|
||||||
|
"repository": "https://github.com/babel/babel/tree/master/packages/babel-plugin-proposal-private-methods",
|
||||||
|
"license": "MIT",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"keywords": [
|
||||||
|
"babel-plugin"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/helper-plugin-utils": "^7.0.0",
|
||||||
|
"@babel/plugin-class-features": "^7.1.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@babel/core": "^7.0.0-0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.0.0",
|
||||||
|
"@babel/helper-plugin-test-runner": "^7.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
25
packages/babel-plugin-proposal-private-methods/src/index.js
Normal file
25
packages/babel-plugin-proposal-private-methods/src/index.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { declare } from "@babel/helper-plugin-utils";
|
||||||
|
import pluginClassFeatures, {
|
||||||
|
enableFeature,
|
||||||
|
FEATURES,
|
||||||
|
} from "@babel/plugin-class-features";
|
||||||
|
|
||||||
|
export default declare((api, options) => {
|
||||||
|
api.assertVersion(7);
|
||||||
|
|
||||||
|
const { loose } = options;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "proposal-private-methods",
|
||||||
|
|
||||||
|
inherits: pluginClassFeatures,
|
||||||
|
|
||||||
|
manipulateOptions(opts, parserOpts) {
|
||||||
|
parserOpts.plugins.push("classPrivateMethods");
|
||||||
|
},
|
||||||
|
|
||||||
|
pre() {
|
||||||
|
enableFeature(this.file, FEATURES.privateMethods, loose);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
@ -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);
|
||||||
@ -7,7 +7,11 @@ export default declare(api => {
|
|||||||
name: "syntax-class-properties",
|
name: "syntax-class-properties",
|
||||||
|
|
||||||
manipulateOptions(opts, parserOpts) {
|
manipulateOptions(opts, parserOpts) {
|
||||||
parserOpts.plugins.push("classProperties", "classPrivateProperties");
|
parserOpts.plugins.push(
|
||||||
|
"classProperties",
|
||||||
|
"classPrivateProperties",
|
||||||
|
"classPrivateMethods",
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@ -687,6 +687,12 @@ export function assertClassPrivateProperty(
|
|||||||
): void {
|
): void {
|
||||||
assert("ClassPrivateProperty", node, opts);
|
assert("ClassPrivateProperty", node, opts);
|
||||||
}
|
}
|
||||||
|
export function assertClassPrivateMethod(
|
||||||
|
node: Object,
|
||||||
|
opts?: Object = {},
|
||||||
|
): void {
|
||||||
|
assert("ClassPrivateMethod", node, opts);
|
||||||
|
}
|
||||||
export function assertImport(node: Object, opts?: Object = {}): void {
|
export function assertImport(node: Object, opts?: Object = {}): void {
|
||||||
assert("Import", node, opts);
|
assert("Import", node, opts);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -620,6 +620,10 @@ export function ClassPrivateProperty(...args: Array<any>): Object {
|
|||||||
return builder("ClassPrivateProperty", ...args);
|
return builder("ClassPrivateProperty", ...args);
|
||||||
}
|
}
|
||||||
export { ClassPrivateProperty as classPrivateProperty };
|
export { ClassPrivateProperty as classPrivateProperty };
|
||||||
|
export function ClassPrivateMethod(...args: Array<any>): Object {
|
||||||
|
return builder("ClassPrivateMethod", ...args);
|
||||||
|
}
|
||||||
|
export { ClassPrivateMethod as classPrivateMethod };
|
||||||
export function Import(...args: Array<any>): Object {
|
export function Import(...args: Array<any>): Object {
|
||||||
return builder("Import", ...args);
|
return builder("Import", ...args);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -87,6 +87,7 @@ defineType("ClassBody", {
|
|||||||
assertEach(
|
assertEach(
|
||||||
assertNodeType(
|
assertNodeType(
|
||||||
"ClassMethod",
|
"ClassMethod",
|
||||||
|
"ClassPrivateMethod",
|
||||||
"ClassProperty",
|
"ClassProperty",
|
||||||
"ClassPrivateProperty",
|
"ClassPrivateProperty",
|
||||||
"TSDeclareMethod",
|
"TSDeclareMethod",
|
||||||
|
|||||||
@ -5,7 +5,10 @@ import defineType, {
|
|||||||
assertValueType,
|
assertValueType,
|
||||||
chain,
|
chain,
|
||||||
} from "./utils";
|
} from "./utils";
|
||||||
import { classMethodOrPropertyCommon } from "./es2015";
|
import {
|
||||||
|
classMethodOrPropertyCommon,
|
||||||
|
classMethodOrDeclareMethodCommon,
|
||||||
|
} from "./es2015";
|
||||||
|
|
||||||
defineType("AwaitExpression", {
|
defineType("AwaitExpression", {
|
||||||
builder: ["argument"],
|
builder: ["argument"],
|
||||||
@ -131,6 +134,28 @@ defineType("ClassPrivateProperty", {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
defineType("ClassPrivateMethod", {
|
||||||
|
builder: ["kind", "key", "params", "body", "static"],
|
||||||
|
visitor: [
|
||||||
|
"key",
|
||||||
|
"params",
|
||||||
|
"body",
|
||||||
|
"decorators",
|
||||||
|
"returnType",
|
||||||
|
"typeParameters",
|
||||||
|
],
|
||||||
|
aliases: ["Method", "Private", "Function"],
|
||||||
|
fields: {
|
||||||
|
...classMethodOrDeclareMethodCommon,
|
||||||
|
key: {
|
||||||
|
validate: assertNodeType("PrivateName"),
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
validate: assertNodeType("BlockStatement"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
defineType("Import", {
|
defineType("Import", {
|
||||||
aliases: ["Expression"],
|
aliases: ["Expression"],
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2159,6 +2159,20 @@ export function isClassPrivateProperty(node: Object, opts?: Object): boolean {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
export function isClassPrivateMethod(node: Object, opts?: Object): boolean {
|
||||||
|
if (!node) return false;
|
||||||
|
|
||||||
|
const nodeType = node.type;
|
||||||
|
if (nodeType === "ClassPrivateMethod") {
|
||||||
|
if (typeof opts === "undefined") {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return shallowEqual(node, opts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
export function isImport(node: Object, opts?: Object): boolean {
|
export function isImport(node: Object, opts?: Object): boolean {
|
||||||
if (!node) return false;
|
if (!node) return false;
|
||||||
|
|
||||||
@ -3492,7 +3506,8 @@ export function isFunction(node: Object, opts?: Object): boolean {
|
|||||||
"FunctionExpression" === nodeType ||
|
"FunctionExpression" === nodeType ||
|
||||||
"ObjectMethod" === nodeType ||
|
"ObjectMethod" === nodeType ||
|
||||||
"ArrowFunctionExpression" === nodeType ||
|
"ArrowFunctionExpression" === nodeType ||
|
||||||
"ClassMethod" === nodeType
|
"ClassMethod" === nodeType ||
|
||||||
|
"ClassPrivateMethod" === nodeType
|
||||||
) {
|
) {
|
||||||
if (typeof opts === "undefined") {
|
if (typeof opts === "undefined") {
|
||||||
return true;
|
return true;
|
||||||
@ -3737,7 +3752,8 @@ export function isMethod(node: Object, opts?: Object): boolean {
|
|||||||
if (
|
if (
|
||||||
nodeType === "Method" ||
|
nodeType === "Method" ||
|
||||||
"ObjectMethod" === nodeType ||
|
"ObjectMethod" === nodeType ||
|
||||||
"ClassMethod" === nodeType
|
"ClassMethod" === nodeType ||
|
||||||
|
"ClassPrivateMethod" === nodeType
|
||||||
) {
|
) {
|
||||||
if (typeof opts === "undefined") {
|
if (typeof opts === "undefined") {
|
||||||
return true;
|
return true;
|
||||||
@ -4119,6 +4135,7 @@ export function isPrivate(node: Object, opts?: Object): boolean {
|
|||||||
if (
|
if (
|
||||||
nodeType === "Private" ||
|
nodeType === "Private" ||
|
||||||
"ClassPrivateProperty" === nodeType ||
|
"ClassPrivateProperty" === nodeType ||
|
||||||
|
"ClassPrivateMethod" === nodeType ||
|
||||||
"PrivateName" === nodeType
|
"PrivateName" === nodeType
|
||||||
) {
|
) {
|
||||||
if (typeof opts === "undefined") {
|
if (typeof opts === "undefined") {
|
||||||
|
|||||||
@ -46,6 +46,7 @@ export default function isReferenced(node: Object, parent: Object): boolean {
|
|||||||
// no: class { NODE() {} }
|
// no: class { NODE() {} }
|
||||||
// yes: class { [NODE]() {} }
|
// yes: class { [NODE]() {} }
|
||||||
case "ClassMethod":
|
case "ClassMethod":
|
||||||
|
case "ClassPrivateMethod":
|
||||||
case "ObjectMethod":
|
case "ObjectMethod":
|
||||||
if (parent.key === node) {
|
if (parent.key === node) {
|
||||||
return !!parent.computed;
|
return !!parent.computed;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user