Computed class properties (#4500)

* Support computed class property names (#4499)

** Depends on babel/babylon#121 **

* `babel-types`: Add `computed` field to `ClassProperty`

* `babel-plugin-transform-class-properties`: handle computed property names correctly

* `babel-generator`: add tests for class properties (computed/literal, static/instance)

* doc: Update babel-types with ClassProperty.computed

* chore(package): update babylon to v6.11.0

* babel-types: move ClassProperty.computed to be last builder arg
This commit is contained in:
Moti Zilberman 2016-09-26 18:46:00 +03:00 committed by Daniel Tschinder
parent a81a0d0f84
commit 03d772c2ec
14 changed files with 76 additions and 10 deletions

View File

@ -33,7 +33,7 @@
"babel-register": "^6.14.0",
"babel-traverse": "^6.14.0",
"babel-types": "^6.14.0",
"babylon": "^6.9.0",
"babylon": "^6.11.0",
"convert-source-map": "^1.1.0",
"debug": "^2.1.1",
"json5": "^0.4.0",

View File

@ -21,6 +21,6 @@
},
"devDependencies": {
"babel-helper-fixtures": "^6.9.0",
"babylon": "^6.9.0"
"babylon": "^6.11.0"
}
}

View File

@ -55,7 +55,13 @@ export function ClassProperty(node: Object) {
this.word("static");
this.space();
}
this.print(node.key, node);
if (node.computed) {
this.token("[");
this.print(node.key, node);
this.token("]");
} else {
this.print(node.key, node);
}
this.print(node.typeAnnotation, node);
if (node.value) {
this.space();

View File

@ -0,0 +1,19 @@
class Foo {
foo;
foo = 1;
"foo";
"foo" = 1;
["foo"];
["foo"] = 1;
["f" + "oo"];
["f" + "oo"] = 1;
static foo;
static foo = 1;
static "foo";
static "foo" = 1;
static ["foo"];
static ["foo"] = 1;
static ["f" + "oo"];
static ["f" + "oo"] = 1;
}

View File

@ -0,0 +1,19 @@
class Foo {
foo;
foo = 1;
"foo";
"foo" = 1;
["foo"];
["foo"] = 1;
["f" + "oo"];
["f" + "oo"] = 1;
static foo;
static foo = 1;
static "foo";
static "foo" = 1;
static ["foo"];
static ["foo"] = 1;
static ["f" + "oo"];
static ["f" + "oo"] = 1;
}

View File

@ -170,6 +170,7 @@ suites.forEach(function (testSuite) {
"exportExtensions",
"functionBind",
"classConstructorCall",
"classProperties",
],
strictMode: false,
sourceType: "module",

View File

@ -58,14 +58,15 @@ export default function ({ types: t }) {
if (!propNode.value) continue;
let isStatic = propNode.static;
let isComputed = propNode.computed || t.isLiteral(prop.key);
if (isStatic) {
nodes.push(t.expressionStatement(
t.assignmentExpression("=", t.memberExpression(ref, propNode.key), propNode.value)
t.assignmentExpression("=", t.memberExpression(ref, propNode.key, isComputed), propNode.value)
));
} else {
instanceBody.push(t.expressionStatement(
t.assignmentExpression("=", t.memberExpression(t.thisExpression(), propNode.key), propNode.value)
t.assignmentExpression("=", t.memberExpression(t.thisExpression(), propNode.key, isComputed), propNode.value)
));
}
}

View File

@ -0,0 +1,3 @@
class Foo {
[bar] = "foo";
}

View File

@ -0,0 +1,4 @@
var Foo = function Foo() {
babelHelpers.classCallCheck(this, Foo);
this[bar] = "foo";
};

View File

@ -8,7 +8,7 @@
"repository": "https://github.com/babel/babel/tree/master/packages/babel-template",
"main": "lib/index.js",
"dependencies": {
"babylon": "^6.9.0",
"babylon": "^6.11.0",
"babel-traverse": "^6.15.0",
"babel-types": "^6.15.0",
"babel-runtime": "^6.9.0",

View File

@ -12,7 +12,7 @@
"babel-messages": "^6.8.0",
"babel-runtime": "^6.9.0",
"babel-types": "^6.15.0",
"babylon": "^6.9.0",
"babylon": "^6.11.0",
"debug": "^2.2.0",
"globals": "^8.3.0",
"invariant": "^2.2.0",

View File

@ -217,7 +217,7 @@ Aliases: `Function`, `Scopable`, `BlockParent`, `FunctionParent`, `Method`
- `returnType` (default: `null`)
- `typeParameters` (default: `null`)
### t.classProperty(key, value, typeAnnotation, decorators)
### t.classProperty(key, value, typeAnnotation, decorators, computed)
See also `t.isClassProperty(node, opts)` and `t.assertClassProperty(node, opts)`.
@ -227,6 +227,7 @@ Aliases: `Flow`, `Property`
- `value` (required)
- `typeAnnotation` (required)
- `decorators` (required)
- `computed`: `boolean` (default: `false`)
### t.conditionalExpression(test, consequent, alternate)

View File

@ -1,4 +1,6 @@
import defineType from "./index";
import defineType, {
assertValueType
} from "./index";
defineType("AnyTypeAnnotation", {
aliases: ["Flow", "FlowBaseAnnotation"],
@ -42,8 +44,13 @@ defineType("ClassImplements", {
defineType("ClassProperty", {
visitor: ["key", "value", "typeAnnotation", "decorators"],
builder: ["key", "value", "typeAnnotation", "decorators", "computed"],
aliases: ["Flow", "Property"],
fields: {
computed: {
validate: assertValueType("boolean"),
default: false
}
// todo
}
});

View File

@ -100,9 +100,14 @@ export function isReferenced(node: Object, parent: Object): boolean {
return parent.name !== node;
// no: class { NODE = value; }
// yes: class { [NODE] = value; }
// yes: class { key = NODE; }
case "ClassProperty":
return parent.value === node;
if (parent.key === node) {
return parent.computed;
} else {
return parent.value === node;
}
// no: import NODE from "foo";
// no: import * as NODE from "foo";