diff --git a/packages/babel-generator/src/generators/classes.js b/packages/babel-generator/src/generators/classes.js
index 1649cdee39..da1b14f78e 100644
--- a/packages/babel-generator/src/generators/classes.js
+++ b/packages/babel-generator/src/generators/classes.js
@@ -117,6 +117,21 @@ export function ClassProperty(node: Object) {
this.semicolon();
}
+export function ClassPrivateProperty(node: Object) {
+ if (node.static) {
+ this.word("static");
+ this.space();
+ }
+ this.print(node.key, node);
+ if (node.value) {
+ this.space();
+ this.token("=");
+ this.space();
+ this.print(node.value, node);
+ }
+ this.semicolon();
+}
+
export function ClassMethod(node: Object) {
this._classMethodHead(node);
this.space();
diff --git a/packages/babel-generator/src/generators/expressions.js b/packages/babel-generator/src/generators/expressions.js
index e85eec6538..2a7fc66e2e 100644
--- a/packages/babel-generator/src/generators/expressions.js
+++ b/packages/babel-generator/src/generators/expressions.js
@@ -254,3 +254,8 @@ export function MetaProperty(node: Object) {
this.token(".");
this.print(node.property, node);
}
+
+export function PrivateName(node: Object) {
+ this.token("#");
+ this.print(node.id, node);
+}
diff --git a/packages/babel-generator/test/fixtures/types/ClassBody-ClassProperty/input.js b/packages/babel-generator/test/fixtures/types/ClassBody-ClassProperty/input.js
index 41176ad01b..6256942ca5 100644
--- a/packages/babel-generator/test/fixtures/types/ClassBody-ClassProperty/input.js
+++ b/packages/babel-generator/test/fixtures/types/ClassBody-ClassProperty/input.js
@@ -26,6 +26,11 @@ class Foo {
async;
foo; bar;
foo = 0; bar = 1;
+
+ #foo;
+ #foo = 1;
+ static #foo;
+ static #foo = Foo.#foo;
}
class A1 {
diff --git a/packages/babel-generator/test/fixtures/types/ClassBody-ClassProperty/options.json b/packages/babel-generator/test/fixtures/types/ClassBody-ClassProperty/options.json
index 24551b8170..a437d2af54 100644
--- a/packages/babel-generator/test/fixtures/types/ClassBody-ClassProperty/options.json
+++ b/packages/babel-generator/test/fixtures/types/ClassBody-ClassProperty/options.json
@@ -1 +1 @@
-{ "plugins": ["classProperties"] }
\ No newline at end of file
+{ "plugins": ["classProperties", "classPrivateProperties"] }
diff --git a/packages/babel-generator/test/fixtures/types/ClassBody-ClassProperty/output.js b/packages/babel-generator/test/fixtures/types/ClassBody-ClassProperty/output.js
index 0c686caa32..905fe31bdb 100644
--- a/packages/babel-generator/test/fixtures/types/ClassBody-ClassProperty/output.js
+++ b/packages/babel-generator/test/fixtures/types/ClassBody-ClassProperty/output.js
@@ -26,6 +26,10 @@ class Foo {
bar;
foo = 0;
bar = 1;
+ #foo;
+ #foo = 1;
+ static #foo;
+ static #foo = Foo.#foo;
}
class A1 {
@@ -65,4 +69,4 @@ class A6 {
class A7 {
static get static() {}
-}
\ No newline at end of file
+}
diff --git a/packages/babel-helper-define-map/src/index.js b/packages/babel-helper-define-map/src/index.js
index 850bd51adb..ff588c1ce3 100644
--- a/packages/babel-helper-define-map/src/index.js
+++ b/packages/babel-helper-define-map/src/index.js
@@ -61,7 +61,7 @@ export function push(
key = t.toComputedKey(node, node.key);
}
- if (t.isObjectProperty(node) || t.isClassProperty(node)) {
+ if (t.isProperty(node)) {
value = node.value;
} else if (t.isObjectMethod(node) || t.isClassMethod(node)) {
value = t.functionExpression(
@@ -131,15 +131,12 @@ export function toClassObject(mutatorMap: Object): Object {
const propNode = t.objectProperty(map._key, mapNode, map._computed);
Object.keys(map).forEach(function(key) {
- let node = map[key];
+ const node = map[key];
if (key[0] === "_") return;
- const inheritNode = node;
- if (t.isClassMethod(node) || t.isClassProperty(node)) node = node.value;
-
const prop = t.objectProperty(t.identifier(key), node);
- t.inheritsComments(prop, inheritNode);
- t.removeComments(inheritNode);
+ t.inheritsComments(prop, node);
+ t.removeComments(node);
mapNode.properties.push(prop);
});
diff --git a/packages/babel-plugin-syntax-class-properties/src/index.js b/packages/babel-plugin-syntax-class-properties/src/index.js
index 8f4ee10929..fc3f176e03 100644
--- a/packages/babel-plugin-syntax-class-properties/src/index.js
+++ b/packages/babel-plugin-syntax-class-properties/src/index.js
@@ -5,7 +5,7 @@ export default declare(api => {
return {
manipulateOptions(opts, parserOpts) {
- parserOpts.plugins.push("classProperties");
+ parserOpts.plugins.push("classProperties", "classPrivateProperties");
},
};
});
diff --git a/packages/babel-plugin-transform-parameters/src/rest.js b/packages/babel-plugin-transform-parameters/src/rest.js
index aa3a8885fb..4f0817b857 100644
--- a/packages/babel-plugin-transform-parameters/src/rest.js
+++ b/packages/babel-plugin-transform-parameters/src/rest.js
@@ -46,7 +46,7 @@ const memberExpressionOptimisationVisitor = {
path.skip();
},
- "Function|ClassProperty": function(path, state) {
+ Function(path, state) {
// Detect whether any reference to rest is contained in nested functions to
// determine if deopt is necessary.
const oldNoOptimise = state.noOptimise;
diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/parameters/rest-arrow-functions/input.js b/packages/babel-plugin-transform-parameters/test/fixtures/parameters/rest-arrow-functions/input.js
index 80988d02b6..9cedf94796 100644
--- a/packages/babel-plugin-transform-parameters/test/fixtures/parameters/rest-arrow-functions/input.js
+++ b/packages/babel-plugin-transform-parameters/test/fixtures/parameters/rest-arrow-functions/input.js
@@ -33,4 +33,4 @@ var innerclassproperties = (...args) => (
static args = args;
args = args;
}
-);
\ No newline at end of file
+);
diff --git a/packages/babel-plugin-transform-react-constant-elements/test/fixtures/constant-elements/destructure/output.js b/packages/babel-plugin-transform-react-constant-elements/test/fixtures/constant-elements/destructure/output.js
index f13ad91a47..e33d215b94 100644
--- a/packages/babel-plugin-transform-react-constant-elements/test/fixtures/constant-elements/destructure/output.js
+++ b/packages/babel-plugin-transform-react-constant-elements/test/fixtures/constant-elements/destructure/output.js
@@ -1,8 +1,8 @@
class AnchorLink extends Component {
render() {
- const _props = this.props,
- isExternal = _props.isExternal,
- children = _props.children;
+ const _this$props = this.props,
+ isExternal = _this$props.isExternal,
+ children = _this$props.children;
if (isExternal) {
return {children};
diff --git a/packages/babel-traverse/src/path/conversion.js b/packages/babel-traverse/src/path/conversion.js
index ca8b144942..b192b4d9d5 100644
--- a/packages/babel-traverse/src/path/conversion.js
+++ b/packages/babel-traverse/src/path/conversion.js
@@ -163,12 +163,13 @@ function hoistFunctionEnvironment(
specCompliant = false,
allowInsertArrow = true,
) {
- const thisEnvFn = fnPath.findParent(
- p =>
+ const thisEnvFn = fnPath.findParent(p => {
+ return (
(p.isFunction() && !p.isArrowFunctionExpression()) ||
p.isProgram() ||
- p.isClassProperty({ static: false }),
- );
+ p.isClassProperty({ static: false })
+ );
+ });
const inConstructor = thisEnvFn && thisEnvFn.node.kind === "constructor";
if (thisEnvFn.isClassProperty()) {
diff --git a/packages/babel-traverse/src/scope/index.js b/packages/babel-traverse/src/scope/index.js
index a2055dd05a..4603f326e3 100644
--- a/packages/babel-traverse/src/scope/index.js
+++ b/packages/babel-traverse/src/scope/index.js
@@ -36,6 +36,10 @@ function gatherNodeParts(node: Object, parts: Array) {
for (const prop of (node.properties: Array)) {
gatherNodeParts(prop.key || prop.argument, parts);
}
+ } else if (t.isPrivateName(node)) {
+ gatherNodeParts(node.id, parts);
+ } else if (t.isThisExpression(node)) {
+ parts.push("this");
}
}
@@ -622,7 +626,7 @@ export default class Scope {
if (node.computed && !this.isPure(node.key, constantsOnly)) return false;
if (node.kind === "get" || node.kind === "set") return false;
return true;
- } else if (t.isClassProperty(node) || t.isObjectProperty(node)) {
+ } else if (t.isProperty(node)) {
if (node.computed && !this.isPure(node.key, constantsOnly)) return false;
return this.isPure(node.value, constantsOnly);
} else if (t.isUnaryExpression(node)) {
diff --git a/packages/babel-types/README.md b/packages/babel-types/README.md
index 51b2183103..aaee40e532 100644
--- a/packages/babel-types/README.md
+++ b/packages/babel-types/README.md
@@ -256,7 +256,7 @@ t.classBody(body)
See also `t.isClassBody(node, opts)` and `t.assertClassBody(node, opts)`.
- - `body`: `Array` (required)
+ - `body`: `Array` (required)
---
@@ -343,6 +343,20 @@ Aliases: `Function`, `Scopable`, `BlockParent`, `FunctionParent`, `Method`
---
+### classPrivateProperty
+```javascript
+t.classPrivateProperty(key, value)
+```
+
+See also `t.isClassPrivateProperty(node, opts)` and `t.assertClassPrivateProperty(node, opts)`.
+
+Aliases: `Property`, `Private`
+
+ - `key`: `PrivateName` (required)
+ - `value`: `Expression` (default: `null`)
+
+---
+
### classProperty
```javascript
t.classProperty(key, value, typeAnnotation, decorators, computed)
@@ -1636,6 +1650,19 @@ Aliases: `Expression`, `ExpressionWrapper`
---
+### privateName
+```javascript
+t.privateName(id)
+```
+
+See also `t.isPrivateName(node, opts)` and `t.assertPrivateName(node, opts)`.
+
+Aliases: `Private`
+
+ - `id`: `Identifier` (required)
+
+---
+
### program
```javascript
t.program(body, directives, sourceType)
diff --git a/packages/babel-types/src/asserts/generated/index.js b/packages/babel-types/src/asserts/generated/index.js
index efae53080e..bfc46770eb 100644
--- a/packages/babel-types/src/asserts/generated/index.js
+++ b/packages/babel-types/src/asserts/generated/index.js
@@ -663,6 +663,12 @@ export function assertOptionalCallExpression(
): void {
assert("OptionalCallExpression", node, opts);
}
+export function assertClassPrivateProperty(
+ node: Object,
+ opts?: Object = {},
+): void {
+ assert("ClassPrivateProperty", node, opts);
+}
export function assertImport(node: Object, opts?: Object = {}): void {
assert("Import", node, opts);
}
@@ -684,6 +690,9 @@ export function assertExportNamespaceSpecifier(
): void {
assert("ExportNamespaceSpecifier", node, opts);
}
+export function assertPrivateName(node: Object, opts?: Object = {}): void {
+ assert("PrivateName", node, opts);
+}
export function assertTSParameterProperty(
node: Object,
opts?: Object = {},
@@ -1059,6 +1068,9 @@ export function assertFlowPredicate(node: Object, opts?: Object = {}): void {
export function assertJSX(node: Object, opts?: Object = {}): void {
assert("JSX", node, opts);
}
+export function assertPrivate(node: Object, opts?: Object = {}): void {
+ assert("Private", node, opts);
+}
export function assertTSTypeElement(node: Object, opts?: Object = {}): void {
assert("TSTypeElement", node, opts);
}
diff --git a/packages/babel-types/src/builders/generated/index.js b/packages/babel-types/src/builders/generated/index.js
index 1ec3b17766..b3c07aa47d 100644
--- a/packages/babel-types/src/builders/generated/index.js
+++ b/packages/babel-types/src/builders/generated/index.js
@@ -604,6 +604,10 @@ export function OptionalCallExpression(...args: Array): Object {
return builder("OptionalCallExpression", ...args);
}
export { OptionalCallExpression as optionalCallExpression };
+export function ClassPrivateProperty(...args: Array): Object {
+ return builder("ClassPrivateProperty", ...args);
+}
+export { ClassPrivateProperty as classPrivateProperty };
export function Import(...args: Array): Object {
return builder("Import", ...args);
}
@@ -624,6 +628,10 @@ export function ExportNamespaceSpecifier(...args: Array): Object {
return builder("ExportNamespaceSpecifier", ...args);
}
export { ExportNamespaceSpecifier as exportNamespaceSpecifier };
+export function PrivateName(...args: Array): Object {
+ return builder("PrivateName", ...args);
+}
+export { PrivateName as privateName };
export function TSParameterProperty(...args: Array): Object {
return builder("TSParameterProperty", ...args);
}
diff --git a/packages/babel-types/src/constants/generated/index.js b/packages/babel-types/src/constants/generated/index.js
index ea64f77d1e..eedb7038ed 100644
--- a/packages/babel-types/src/constants/generated/index.js
+++ b/packages/babel-types/src/constants/generated/index.js
@@ -46,5 +46,6 @@ export const FLOWBASEANNOTATION_TYPES =
export const FLOWDECLARATION_TYPES = FLIPPED_ALIAS_KEYS["FlowDeclaration"];
export const FLOWPREDICATE_TYPES = FLIPPED_ALIAS_KEYS["FlowPredicate"];
export const JSX_TYPES = FLIPPED_ALIAS_KEYS["JSX"];
+export const PRIVATE_TYPES = FLIPPED_ALIAS_KEYS["Private"];
export const TSTYPEELEMENT_TYPES = FLIPPED_ALIAS_KEYS["TSTypeElement"];
export const TSTYPE_TYPES = FLIPPED_ALIAS_KEYS["TSType"];
diff --git a/packages/babel-types/src/definitions/core.js b/packages/babel-types/src/definitions/core.js
index 0bd5c2ae33..ab1e8b70b3 100644
--- a/packages/babel-types/src/definitions/core.js
+++ b/packages/babel-types/src/definitions/core.js
@@ -503,7 +503,7 @@ defineType("MemberExpression", {
},
property: {
validate: (function() {
- const normal = assertNodeType("Identifier");
+ const normal = assertNodeType("Identifier", "PrivateName");
const computed = assertNodeType("Expression");
return function(node, key, val) {
diff --git a/packages/babel-types/src/definitions/es2015.js b/packages/babel-types/src/definitions/es2015.js
index f5c67810f3..26c0d4a344 100644
--- a/packages/babel-types/src/definitions/es2015.js
+++ b/packages/babel-types/src/definitions/es2015.js
@@ -88,6 +88,7 @@ defineType("ClassBody", {
assertNodeType(
"ClassMethod",
"ClassProperty",
+ "ClassPrivateProperty",
"TSDeclareMethod",
"TSIndexSignature",
),
diff --git a/packages/babel-types/src/definitions/experimental.js b/packages/babel-types/src/definitions/experimental.js
index c9d7b1a301..7b22fa0a04 100644
--- a/packages/babel-types/src/definitions/experimental.js
+++ b/packages/babel-types/src/definitions/experimental.js
@@ -115,6 +115,21 @@ defineType("OptionalCallExpression", {
},
});
+defineType("ClassPrivateProperty", {
+ visitor: ["key", "value"],
+ builder: ["key", "value"],
+ aliases: ["Property", "Private"],
+ fields: {
+ key: {
+ validate: assertNodeType("PrivateName"),
+ },
+ value: {
+ validate: assertNodeType("Expression"),
+ optional: true,
+ },
+ },
+});
+
defineType("Import", {
aliases: ["Expression"],
});
@@ -157,3 +172,13 @@ defineType("ExportNamespaceSpecifier", {
},
},
});
+
+defineType("PrivateName", {
+ visitor: ["id"],
+ aliases: ["Private"],
+ fields: {
+ id: {
+ validate: assertNodeType("Identifier"),
+ },
+ },
+});
diff --git a/packages/babel-types/src/validators/generated/index.js b/packages/babel-types/src/validators/generated/index.js
index 874d8f6508..48729135bf 100644
--- a/packages/babel-types/src/validators/generated/index.js
+++ b/packages/babel-types/src/validators/generated/index.js
@@ -494,6 +494,9 @@ export function isOptionalMemberExpression(
export function isOptionalCallExpression(node: Object, opts?: Object): boolean {
return is("OptionalCallExpression", node, opts);
}
+export function isClassPrivateProperty(node: Object, opts?: Object): boolean {
+ return is("ClassPrivateProperty", node, opts);
+}
export function isImport(node: Object, opts?: Object): boolean {
return is("Import", node, opts);
}
@@ -512,6 +515,9 @@ export function isExportNamespaceSpecifier(
): boolean {
return is("ExportNamespaceSpecifier", node, opts);
}
+export function isPrivateName(node: Object, opts?: Object): boolean {
+ return is("PrivateName", node, opts);
+}
export function isTSParameterProperty(node: Object, opts?: Object): boolean {
return is("TSParameterProperty", node, opts);
}
@@ -821,6 +827,9 @@ export function isFlowPredicate(node: Object, opts?: Object): boolean {
export function isJSX(node: Object, opts?: Object): boolean {
return is("JSX", node, opts);
}
+export function isPrivate(node: Object, opts?: Object): boolean {
+ return is("Private", node, opts);
+}
export function isTSTypeElement(node: Object, opts?: Object): boolean {
return is("TSTypeElement", node, opts);
}
diff --git a/packages/babel-types/src/validators/isReferenced.js b/packages/babel-types/src/validators/isReferenced.js
index 1944665e9d..076bbb272d 100644
--- a/packages/babel-types/src/validators/isReferenced.js
+++ b/packages/babel-types/src/validators/isReferenced.js
@@ -76,8 +76,9 @@ export default function isReferenced(node: Object, parent: Object): boolean {
// yes: class { [NODE] = value; }
// yes: class { key = NODE; }
case "ClassProperty":
+ case "ClassPrivateProperty":
if (parent.key === node) {
- return parent.computed;
+ return !!parent.computed;
} else {
return parent.value === node;
}