Private Properties phase 1 (#7666)

* Private Properties phase 1

Co-authored-by: CodingItWrong

* Private fields are optional

* Docs update
This commit is contained in:
Justin Ridgewell 2018-04-05 11:17:34 +01:00 committed by GitHub
parent 01f4c2368e
commit 43040a4181
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 138 additions and 23 deletions

View File

@ -117,6 +117,21 @@ export function ClassProperty(node: Object) {
this.semicolon(); 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) { export function ClassMethod(node: Object) {
this._classMethodHead(node); this._classMethodHead(node);
this.space(); this.space();

View File

@ -254,3 +254,8 @@ export function MetaProperty(node: Object) {
this.token("."); this.token(".");
this.print(node.property, node); this.print(node.property, node);
} }
export function PrivateName(node: Object) {
this.token("#");
this.print(node.id, node);
}

View File

@ -26,6 +26,11 @@ class Foo {
async; async;
foo; bar; foo; bar;
foo = 0; bar = 1; foo = 0; bar = 1;
#foo;
#foo = 1;
static #foo;
static #foo = Foo.#foo;
} }
class A1 { class A1 {

View File

@ -1 +1 @@
{ "plugins": ["classProperties"] } { "plugins": ["classProperties", "classPrivateProperties"] }

View File

@ -26,6 +26,10 @@ class Foo {
bar; bar;
foo = 0; foo = 0;
bar = 1; bar = 1;
#foo;
#foo = 1;
static #foo;
static #foo = Foo.#foo;
} }
class A1 { class A1 {
@ -65,4 +69,4 @@ class A6 {
class A7 { class A7 {
static get static() {} static get static() {}
} }

View File

@ -61,7 +61,7 @@ export function push(
key = t.toComputedKey(node, node.key); key = t.toComputedKey(node, node.key);
} }
if (t.isObjectProperty(node) || t.isClassProperty(node)) { if (t.isProperty(node)) {
value = node.value; value = node.value;
} else if (t.isObjectMethod(node) || t.isClassMethod(node)) { } else if (t.isObjectMethod(node) || t.isClassMethod(node)) {
value = t.functionExpression( value = t.functionExpression(
@ -131,15 +131,12 @@ export function toClassObject(mutatorMap: Object): Object {
const propNode = t.objectProperty(map._key, mapNode, map._computed); const propNode = t.objectProperty(map._key, mapNode, map._computed);
Object.keys(map).forEach(function(key) { Object.keys(map).forEach(function(key) {
let node = map[key]; const node = map[key];
if (key[0] === "_") return; 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); const prop = t.objectProperty(t.identifier(key), node);
t.inheritsComments(prop, inheritNode); t.inheritsComments(prop, node);
t.removeComments(inheritNode); t.removeComments(node);
mapNode.properties.push(prop); mapNode.properties.push(prop);
}); });

View File

@ -5,7 +5,7 @@ export default declare(api => {
return { return {
manipulateOptions(opts, parserOpts) { manipulateOptions(opts, parserOpts) {
parserOpts.plugins.push("classProperties"); parserOpts.plugins.push("classProperties", "classPrivateProperties");
}, },
}; };
}); });

View File

@ -46,7 +46,7 @@ const memberExpressionOptimisationVisitor = {
path.skip(); path.skip();
}, },
"Function|ClassProperty": function(path, state) { Function(path, state) {
// Detect whether any reference to rest is contained in nested functions to // Detect whether any reference to rest is contained in nested functions to
// determine if deopt is necessary. // determine if deopt is necessary.
const oldNoOptimise = state.noOptimise; const oldNoOptimise = state.noOptimise;

View File

@ -33,4 +33,4 @@ var innerclassproperties = (...args) => (
static args = args; static args = args;
args = args; args = args;
} }
); );

View File

@ -1,8 +1,8 @@
class AnchorLink extends Component { class AnchorLink extends Component {
render() { render() {
const _props = this.props, const _this$props = this.props,
isExternal = _props.isExternal, isExternal = _this$props.isExternal,
children = _props.children; children = _this$props.children;
if (isExternal) { if (isExternal) {
return <a>{children}</a>; return <a>{children}</a>;

View File

@ -163,12 +163,13 @@ function hoistFunctionEnvironment(
specCompliant = false, specCompliant = false,
allowInsertArrow = true, allowInsertArrow = true,
) { ) {
const thisEnvFn = fnPath.findParent( const thisEnvFn = fnPath.findParent(p => {
p => return (
(p.isFunction() && !p.isArrowFunctionExpression()) || (p.isFunction() && !p.isArrowFunctionExpression()) ||
p.isProgram() || p.isProgram() ||
p.isClassProperty({ static: false }), p.isClassProperty({ static: false })
); );
});
const inConstructor = thisEnvFn && thisEnvFn.node.kind === "constructor"; const inConstructor = thisEnvFn && thisEnvFn.node.kind === "constructor";
if (thisEnvFn.isClassProperty()) { if (thisEnvFn.isClassProperty()) {

View File

@ -36,6 +36,10 @@ function gatherNodeParts(node: Object, parts: Array) {
for (const prop of (node.properties: Array)) { for (const prop of (node.properties: Array)) {
gatherNodeParts(prop.key || prop.argument, parts); 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.computed && !this.isPure(node.key, constantsOnly)) return false;
if (node.kind === "get" || node.kind === "set") return false; if (node.kind === "get" || node.kind === "set") return false;
return true; 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; if (node.computed && !this.isPure(node.key, constantsOnly)) return false;
return this.isPure(node.value, constantsOnly); return this.isPure(node.value, constantsOnly);
} else if (t.isUnaryExpression(node)) { } else if (t.isUnaryExpression(node)) {

View File

@ -256,7 +256,7 @@ t.classBody(body)
See also `t.isClassBody(node, opts)` and `t.assertClassBody(node, opts)`. See also `t.isClassBody(node, opts)` and `t.assertClassBody(node, opts)`.
- `body`: `Array<ClassMethod | ClassProperty | TSDeclareMethod | TSIndexSignature>` (required) - `body`: `Array<ClassMethod | ClassProperty | ClassPrivateProperty | TSDeclareMethod | TSIndexSignature>` (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 ### classProperty
```javascript ```javascript
t.classProperty(key, value, typeAnnotation, decorators, computed) 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 ### program
```javascript ```javascript
t.program(body, directives, sourceType) t.program(body, directives, sourceType)

View File

@ -663,6 +663,12 @@ export function assertOptionalCallExpression(
): void { ): void {
assert("OptionalCallExpression", node, opts); assert("OptionalCallExpression", node, opts);
} }
export function assertClassPrivateProperty(
node: Object,
opts?: Object = {},
): void {
assert("ClassPrivateProperty", 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);
} }
@ -684,6 +690,9 @@ export function assertExportNamespaceSpecifier(
): void { ): void {
assert("ExportNamespaceSpecifier", node, opts); assert("ExportNamespaceSpecifier", node, opts);
} }
export function assertPrivateName(node: Object, opts?: Object = {}): void {
assert("PrivateName", node, opts);
}
export function assertTSParameterProperty( export function assertTSParameterProperty(
node: Object, node: Object,
opts?: Object = {}, opts?: Object = {},
@ -1059,6 +1068,9 @@ export function assertFlowPredicate(node: Object, opts?: Object = {}): void {
export function assertJSX(node: Object, opts?: Object = {}): void { export function assertJSX(node: Object, opts?: Object = {}): void {
assert("JSX", node, opts); assert("JSX", node, opts);
} }
export function assertPrivate(node: Object, opts?: Object = {}): void {
assert("Private", node, opts);
}
export function assertTSTypeElement(node: Object, opts?: Object = {}): void { export function assertTSTypeElement(node: Object, opts?: Object = {}): void {
assert("TSTypeElement", node, opts); assert("TSTypeElement", node, opts);
} }

View File

@ -604,6 +604,10 @@ export function OptionalCallExpression(...args: Array<any>): Object {
return builder("OptionalCallExpression", ...args); return builder("OptionalCallExpression", ...args);
} }
export { OptionalCallExpression as optionalCallExpression }; export { OptionalCallExpression as optionalCallExpression };
export function ClassPrivateProperty(...args: Array<any>): Object {
return builder("ClassPrivateProperty", ...args);
}
export { ClassPrivateProperty as classPrivateProperty };
export function Import(...args: Array<any>): Object { export function Import(...args: Array<any>): Object {
return builder("Import", ...args); return builder("Import", ...args);
} }
@ -624,6 +628,10 @@ export function ExportNamespaceSpecifier(...args: Array<any>): Object {
return builder("ExportNamespaceSpecifier", ...args); return builder("ExportNamespaceSpecifier", ...args);
} }
export { ExportNamespaceSpecifier as exportNamespaceSpecifier }; export { ExportNamespaceSpecifier as exportNamespaceSpecifier };
export function PrivateName(...args: Array<any>): Object {
return builder("PrivateName", ...args);
}
export { PrivateName as privateName };
export function TSParameterProperty(...args: Array<any>): Object { export function TSParameterProperty(...args: Array<any>): Object {
return builder("TSParameterProperty", ...args); return builder("TSParameterProperty", ...args);
} }

View File

@ -46,5 +46,6 @@ export const FLOWBASEANNOTATION_TYPES =
export const FLOWDECLARATION_TYPES = FLIPPED_ALIAS_KEYS["FlowDeclaration"]; export const FLOWDECLARATION_TYPES = FLIPPED_ALIAS_KEYS["FlowDeclaration"];
export const FLOWPREDICATE_TYPES = FLIPPED_ALIAS_KEYS["FlowPredicate"]; export const FLOWPREDICATE_TYPES = FLIPPED_ALIAS_KEYS["FlowPredicate"];
export const JSX_TYPES = FLIPPED_ALIAS_KEYS["JSX"]; 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 TSTYPEELEMENT_TYPES = FLIPPED_ALIAS_KEYS["TSTypeElement"];
export const TSTYPE_TYPES = FLIPPED_ALIAS_KEYS["TSType"]; export const TSTYPE_TYPES = FLIPPED_ALIAS_KEYS["TSType"];

View File

@ -503,7 +503,7 @@ defineType("MemberExpression", {
}, },
property: { property: {
validate: (function() { validate: (function() {
const normal = assertNodeType("Identifier"); const normal = assertNodeType("Identifier", "PrivateName");
const computed = assertNodeType("Expression"); const computed = assertNodeType("Expression");
return function(node, key, val) { return function(node, key, val) {

View File

@ -88,6 +88,7 @@ defineType("ClassBody", {
assertNodeType( assertNodeType(
"ClassMethod", "ClassMethod",
"ClassProperty", "ClassProperty",
"ClassPrivateProperty",
"TSDeclareMethod", "TSDeclareMethod",
"TSIndexSignature", "TSIndexSignature",
), ),

View File

@ -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", { defineType("Import", {
aliases: ["Expression"], aliases: ["Expression"],
}); });
@ -157,3 +172,13 @@ defineType("ExportNamespaceSpecifier", {
}, },
}, },
}); });
defineType("PrivateName", {
visitor: ["id"],
aliases: ["Private"],
fields: {
id: {
validate: assertNodeType("Identifier"),
},
},
});

View File

@ -494,6 +494,9 @@ export function isOptionalMemberExpression(
export function isOptionalCallExpression(node: Object, opts?: Object): boolean { export function isOptionalCallExpression(node: Object, opts?: Object): boolean {
return is("OptionalCallExpression", node, opts); 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 { export function isImport(node: Object, opts?: Object): boolean {
return is("Import", node, opts); return is("Import", node, opts);
} }
@ -512,6 +515,9 @@ export function isExportNamespaceSpecifier(
): boolean { ): boolean {
return is("ExportNamespaceSpecifier", node, opts); 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 { export function isTSParameterProperty(node: Object, opts?: Object): boolean {
return is("TSParameterProperty", node, opts); 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 { export function isJSX(node: Object, opts?: Object): boolean {
return is("JSX", node, opts); 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 { export function isTSTypeElement(node: Object, opts?: Object): boolean {
return is("TSTypeElement", node, opts); return is("TSTypeElement", node, opts);
} }

View File

@ -76,8 +76,9 @@ export default function isReferenced(node: Object, parent: Object): boolean {
// yes: class { [NODE] = value; } // yes: class { [NODE] = value; }
// yes: class { key = NODE; } // yes: class { key = NODE; }
case "ClassProperty": case "ClassProperty":
case "ClassPrivateProperty":
if (parent.key === node) { if (parent.key === node) {
return parent.computed; return !!parent.computed;
} else { } else {
return parent.value === node; return parent.value === node;
} }