make parsing of decorators stateless - fixes shuhei/babel-angular2-app#4

This commit is contained in:
Sebastian McKenzie
2015-04-13 08:26:51 -07:00
parent 31b4468514
commit 5f8667eaa7
3 changed files with 174 additions and 9 deletions

View File

@@ -509,22 +509,24 @@ pp.parseTemplate = function() {
pp.parseObj = function(isPattern, refShorthandDefaultPos) {
let node = this.startNode(), first = true, propHash = {}
node.properties = []
let decorators = []
this.next()
while (!this.eat(tt.braceR)) {
if (!first) {
this.expect(tt.comma)
if (this.afterTrailingComma(tt.braceR)) break
} else first = false
while (this.type === tt.at) {
this.decorators.push(this.parseDecorator())
decorators.push(this.parseDecorator())
}
let prop = this.startNode(), isGenerator = false, isAsync = false, start
if (decorators.length) {
prop.decorators = decorators
decorators = []
}
if (this.options.features["es7.objectRestSpread"] && this.type === tt.ellipsis) {
prop = this.parseSpread()
prop.type = "SpreadProperty"
this.takeDecorators(prop)
node.properties.push(prop)
continue
}
@@ -550,10 +552,9 @@ pp.parseObj = function(isPattern, refShorthandDefaultPos) {
}
this.parseObjPropValue(prop, start, isGenerator, isAsync, isPattern, refShorthandDefaultPos);
this.checkPropClash(prop, propHash)
this.takeDecorators(prop)
node.properties.push(this.finishNode(prop, "Property"))
}
if (this.decorators.length) {
if (decorators.length) {
this.raise(this.start, "You have trailing decorators with no property");
}
return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression")

View File

@@ -471,14 +471,18 @@ pp.parseClass = function(node, isStatement) {
var classBody = this.startNode()
classBody.body = []
this.expect(tt.braceL)
let decorators = []
while (!this.eat(tt.braceR)) {
if (this.eat(tt.semi)) continue
if (this.type === tt.at) {
this.decorators.push(this.parseDecorator())
decorators.push(this.parseDecorator())
continue
}
var method = this.startNode()
this.takeDecorators(method)
if (decorators.length) {
method.decorators = decorators
decorators = []
}
var isGenerator = this.eat(tt.star), isAsync = false
this.parsePropertyName(method)
if (this.type !== tt.parenL && !method.computed && method.key.type === "Identifier" &&
@@ -517,7 +521,7 @@ pp.parseClass = function(node, isStatement) {
}
this.parseClassMethod(classBody, method, isGenerator, isAsync)
}
if (this.decorators.length) {
if (decorators.length) {
this.raise(this.start, "You have trailing decorators with no method");
}
node.body = this.finishNode(classBody, "ClassBody")

View File

@@ -2461,6 +2461,166 @@ test("class Foo { @foo @bar bar() {} }", {
features: { "es7.decorators": true }
});
test('@foo({ @bar foo: "bar" }) @bar class Foo {}', {
"start": 0,
"body": [{
"start": 31,
"decorators": [{
"start": 0,
"expression": {
"start": 1,
"callee": {
"start": 1,
"name": "foo",
"type": "Identifier",
"end": 4
},
"arguments": [{
"start": 5,
"properties": [{
"start": 12,
"decorators": [{
"start": 7,
"expression": {
"start": 8,
"name": "bar",
"type": "Identifier",
"end": 11
},
"type": "Decorator",
"end": 11
}],
"method": false,
"shorthand": false,
"computed": false,
"key": {
"start": 12,
"name": "foo",
"type": "Identifier",
"end": 15
},
"value": {
"start": 17,
"value": "bar",
"raw": "\"bar\"",
"type": "Literal",
"end": 22
},
"kind": "init",
"type": "Property",
"end": 22
}],
"type": "ObjectExpression",
"end": 24
}],
"type": "CallExpression",
"end": 25
},
"type": "Decorator",
"end": 25
},
{
"start": 26,
"expression": {
"start": 27,
"name": "bar",
"type": "Identifier",
"end": 30
},
"type": "Decorator",
"end": 30
}],
"id": {
"start": 37,
"name": "Foo",
"type": "Identifier",
"end": 40
},
"superClass": null,
"body": {
"start": 41,
"body": [],
"type": "ClassBody",
"end": 43
},
"type": "ClassDeclaration",
"end": 43
}],
"sourceType": "script",
"type": "Program",
"end": 43
}, {
ecmaVersion: 6,
features: { "es7.decorators": true }
});
test('@bar class Foo extends @foo class Bar {} {}', {
"start": 0,
"body": [{
"start": 5,
"decorators": [{
"start": 0,
"expression": {
"start": 1,
"name": "bar",
"type": "Identifier",
"end": 4
},
"type": "Decorator",
"end": 4
}],
"id": {
"start": 11,
"name": "Foo",
"type": "Identifier",
"end": 14
},
"superClass": {
"start": 28,
"decorators": [{
"start": 23,
"expression": {
"start": 24,
"name": "foo",
"type": "Identifier",
"end": 27
},
"type": "Decorator",
"end": 27
}],
"id": {
"start": 34,
"name": "Bar",
"type": "Identifier",
"end": 37
},
"superClass": null,
"body": {
"start": 38,
"body": [],
"type": "ClassBody",
"end": 40
},
"type": "ClassExpression",
"end": 40
},
"body": {
"start": 41,
"body": [],
"type": "ClassBody",
"end": 43
},
"type": "ClassDeclaration",
"end": 43
}],
"sourceType": "script",
"type": "Program",
"end": 43
}, {
ecmaVersion: 6,
features: { "es7.decorators": true }
});
testFail("@foo function bar() {}", "Leading decorators must be attached to a class declaration (1:5)", {
ecmaVersion: 6,
features: { "es7.decorators": true }