diff --git a/src/index.js b/src/index.js index 09a5c40cbe..84770971a9 100755 --- a/src/index.js +++ b/src/index.js @@ -47,6 +47,11 @@ const parserClassCache: { [key: string]: Class } = {}; /** Get a Parser class with plugins applied. */ function getParserClass(pluginsFromOptions: $ReadOnlyArray): Class { + + if (pluginsFromOptions.indexOf("decorators") >= 0 && pluginsFromOptions.indexOf("decorators2") >= 0) { + throw new Error("Cannot use decorators and decorators2 plugin together"); + } + // Filter out just the plugins that have an actual mixin associated with them. let pluginList = pluginsFromOptions.filter((p) => p === "estree" || p === "flow" || p === "jsx"); diff --git a/src/parser/expression.js b/src/parser/expression.js index 16ca598bbd..3aaa2faf08 100644 --- a/src/parser/expression.js +++ b/src/parser/expression.js @@ -857,8 +857,16 @@ export default class ExpressionParser extends LValParser { if (this.eat(tt.braceR)) break; } - while (this.match(tt.at)) { - decorators.push(this.parseDecorator()); + if (this.match(tt.at)) { + if (this.hasPlugin("decorators2")) { + this.raise(this.state.start, "Stage 2 decorators disallow object literal property decorators"); + } else { + // we needn't check if decorators (stage 0) plugin is enabled since it's checked by + // the call to this.parseDecorator + while (this.match(tt.at)) { + decorators.push(this.parseDecorator()); + } + } } let prop = this.startNode(), isGenerator = false, isAsync = false, startPos, startLoc; diff --git a/src/parser/lval.js b/src/parser/lval.js index d3fcd02900..3c88a5b1c0 100644 --- a/src/parser/lval.js +++ b/src/parser/lval.js @@ -187,6 +187,9 @@ export default class LValParser extends NodeUtils { break; } else { const decorators = []; + if (this.match(tt.at) && this.hasPlugin("decorators2")) { + this.raise(this.state.start, "Stage 2 decorators cannot be used to decorate parameters"); + } while (this.match(tt.at)) { decorators.push(this.parseDecorator()); } diff --git a/src/parser/statement.js b/src/parser/statement.js index 610f7b4f53..2cbfa3b52c 100644 --- a/src/parser/statement.js +++ b/src/parser/statement.js @@ -152,11 +152,18 @@ export default class StatementParser extends ExpressionParser { takeDecorators(node: N.HasDecorators): void { if (this.state.decorators.length) { node.decorators = this.state.decorators; + if (this.hasPlugin("decorators2")) { + this.resetStartLocationFromNode(node, this.state.decorators[0]); + } this.state.decorators = []; } } parseDecorators(allowExport?: boolean): void { + if (this.hasPlugin("decorators2")) { + allowExport = false; + } + while (this.match(tt.at)) { const decorator = this.parseDecorator(); this.state.decorators.push(decorator); @@ -172,12 +179,38 @@ export default class StatementParser extends ExpressionParser { } parseDecorator(): N.Decorator { - if (!this.hasPlugin("decorators")) { + if (!(this.hasPlugin("decorators") || this.hasPlugin("decorators2"))) { this.unexpected(); } + const node = this.startNode(); this.next(); - node.expression = this.parseMaybeAssign(); + + if (this.hasPlugin("decorators2")) { + const startPos = this.state.start; + const startLoc = this.state.startLoc; + let expr = this.parseIdentifier(false); + + while (this.eat(tt.dot)) { + const node = this.startNodeAt(startPos, startLoc); + node.object = expr; + node.property = this.parseIdentifier(true); + node.computed = false; + expr = this.finishNode(node, "MemberExpression"); + } + + if (this.eat(tt.parenL)) { + const node = this.startNodeAt(startPos, startLoc); + node.callee = expr; + node.arguments = this.parseCallExpressionArguments(tt.parenR, false); + expr = this.finishNode(node, "CallExpression"); + this.toReferencedList(expr.arguments); + } + + node.expression = expr; + } else { + node.expression = this.parseMaybeAssign(); + } return this.finishNode(node, "Decorator"); } @@ -679,10 +712,17 @@ export default class StatementParser extends ExpressionParser { // steal the decorators if there are any if (decorators.length) { member.decorators = decorators; + if (this.hasPlugin("decorators2")) { + this.resetStartLocationFromNode(member, decorators[0]); + } decorators = []; } this.parseClassMember(classBody, member, state); + + if (this.hasPlugin("decorators2") && member.kind != "method" && member.decorators && member.decorators.length > 0) { + this.raise(member.start, "Stage 2 decorators may only be used with a class or a class method"); + } } if (decorators.length) { @@ -750,6 +790,7 @@ export default class StatementParser extends ExpressionParser { if (!methodOrProp.computed && methodOrProp.static && (methodOrProp.key.name === "prototype" || methodOrProp.key.value === "prototype")) { this.raise(methodOrProp.key.start, "Classes may not have static property named prototype"); } + if (this.isClassMethod()) { // a normal method if (this.isNonstaticConstructor(method)) { diff --git a/test/fixtures/experimental/decorators-2/class-decorator-call-expr/actual.js b/test/fixtures/experimental/decorators-2/class-decorator-call-expr/actual.js new file mode 100644 index 0000000000..8f69136200 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/class-decorator-call-expr/actual.js @@ -0,0 +1,2 @@ +@foo('bar') +class Foo {} diff --git a/test/fixtures/experimental/decorators-2/class-decorator-call-expr/expected.json b/test/fixtures/experimental/decorators-2/class-decorator-call-expr/expected.json new file mode 100644 index 0000000000..26d8fca5be --- /dev/null +++ b/test/fixtures/experimental/decorators-2/class-decorator-call-expr/expected.json @@ -0,0 +1,154 @@ +{ + "type": "File", + "start": 0, + "end": 24, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 12 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 24, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 12 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ClassDeclaration", + "start": 0, + "end": 24, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 12 + } + }, + "decorators": [ + { + "type": "Decorator", + "start": 0, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "expression": { + "type": "CallExpression", + "start": 1, + "end": 11, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 11 + } + }, + "callee": { + "type": "Identifier", + "start": 1, + "end": 4, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 4 + }, + "identifierName": "foo" + }, + "name": "foo" + }, + "arguments": [ + { + "type": "StringLiteral", + "start": 5, + "end": 10, + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 10 + } + }, + "extra": { + "rawValue": "bar", + "raw": "'bar'" + }, + "value": "bar" + } + ] + } + } + ], + "id": { + "type": "Identifier", + "start": 18, + "end": 21, + "loc": { + "start": { + "line": 2, + "column": 6 + }, + "end": { + "line": 2, + "column": 9 + }, + "identifierName": "Foo" + }, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 22, + "end": 24, + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 2, + "column": 12 + } + }, + "body": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/decorators-2/class-decorator/actual.js b/test/fixtures/experimental/decorators-2/class-decorator/actual.js new file mode 100644 index 0000000000..b1d1c0dd75 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/class-decorator/actual.js @@ -0,0 +1,4 @@ +@abc +class Foo { + +} diff --git a/test/fixtures/experimental/decorators-2/class-decorator/expected.json b/test/fixtures/experimental/decorators-2/class-decorator/expected.json new file mode 100644 index 0000000000..b0570136eb --- /dev/null +++ b/test/fixtures/experimental/decorators-2/class-decorator/expected.json @@ -0,0 +1,117 @@ +{ + "type": "File", + "start": 0, + "end": 19, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 19, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ClassDeclaration", + "start": 0, + "end": 19, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "decorators": [ + { + "type": "Decorator", + "start": 0, + "end": 4, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 4 + } + }, + "expression": { + "type": "Identifier", + "start": 1, + "end": 4, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 4 + }, + "identifierName": "abc" + }, + "name": "abc" + } + } + ], + "id": { + "type": "Identifier", + "start": 11, + "end": 14, + "loc": { + "start": { + "line": 2, + "column": 6 + }, + "end": { + "line": 2, + "column": 9 + }, + "identifierName": "Foo" + }, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 15, + "end": 19, + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "body": [] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/decorators-2/class-expression/actual.js b/test/fixtures/experimental/decorators-2/class-expression/actual.js new file mode 100644 index 0000000000..b8695c19cd --- /dev/null +++ b/test/fixtures/experimental/decorators-2/class-expression/actual.js @@ -0,0 +1,6 @@ +var foo = @dec class Bar { + @baz + bam() { + f(); + } +} diff --git a/test/fixtures/experimental/decorators-2/class-expression/expected.json b/test/fixtures/experimental/decorators-2/class-expression/expected.json new file mode 100644 index 0000000000..af3ed887d2 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/class-expression/expected.json @@ -0,0 +1,308 @@ +{ + "type": "File", + "start": 0, + "end": 58, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 58, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "VariableDeclaration", + "start": 0, + "end": 58, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "declarations": [ + { + "type": "VariableDeclarator", + "start": 4, + "end": 58, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 4, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 4 + }, + "end": { + "line": 1, + "column": 7 + }, + "identifierName": "foo" + }, + "name": "foo" + }, + "init": { + "type": "ClassExpression", + "start": 10, + "end": 58, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "decorators": [ + { + "type": "Decorator", + "start": 10, + "end": 14, + "loc": { + "start": { + "line": 1, + "column": 10 + }, + "end": { + "line": 1, + "column": 14 + } + }, + "expression": { + "type": "Identifier", + "start": 11, + "end": 14, + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 14 + }, + "identifierName": "dec" + }, + "name": "dec" + } + } + ], + "id": { + "type": "Identifier", + "start": 21, + "end": 24, + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 24 + }, + "identifierName": "Bar" + }, + "name": "Bar" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 25, + "end": 58, + "loc": { + "start": { + "line": 1, + "column": 25 + }, + "end": { + "line": 6, + "column": 1 + } + }, + "body": [ + { + "type": "ClassMethod", + "start": 29, + "end": 56, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 5, + "column": 3 + } + }, + "decorators": [ + { + "type": "Decorator", + "start": 29, + "end": 33, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 6 + } + }, + "expression": { + "type": "Identifier", + "start": 30, + "end": 33, + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 6 + }, + "identifierName": "baz" + }, + "name": "baz" + } + } + ], + "static": false, + "computed": false, + "key": { + "type": "Identifier", + "start": 36, + "end": 39, + "loc": { + "start": { + "line": 3, + "column": 2 + }, + "end": { + "line": 3, + "column": 5 + }, + "identifierName": "bam" + }, + "name": "bam" + }, + "kind": "method", + "id": null, + "generator": false, + "expression": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 42, + "end": 56, + "loc": { + "start": { + "line": 3, + "column": 8 + }, + "end": { + "line": 5, + "column": 3 + } + }, + "body": [ + { + "type": "ExpressionStatement", + "start": 48, + "end": 52, + "loc": { + "start": { + "line": 4, + "column": 4 + }, + "end": { + "line": 4, + "column": 8 + } + }, + "expression": { + "type": "CallExpression", + "start": 48, + "end": 51, + "loc": { + "start": { + "line": 4, + "column": 4 + }, + "end": { + "line": 4, + "column": 7 + } + }, + "callee": { + "type": "Identifier", + "start": 48, + "end": 49, + "loc": { + "start": { + "line": 4, + "column": 4 + }, + "end": { + "line": 4, + "column": 5 + }, + "identifierName": "f" + }, + "name": "f" + }, + "arguments": [] + } + } + ], + "directives": [] + } + } + ] + } + } + } + ], + "kind": "var" + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/decorators-2/class-generator/actual.js b/test/fixtures/experimental/decorators-2/class-generator/actual.js new file mode 100644 index 0000000000..65db374bbc --- /dev/null +++ b/test/fixtures/experimental/decorators-2/class-generator/actual.js @@ -0,0 +1,3 @@ +class A { + @dec *m(){} +} diff --git a/test/fixtures/experimental/decorators-2/class-generator/expected.json b/test/fixtures/experimental/decorators-2/class-generator/expected.json new file mode 100644 index 0000000000..87b73b717a --- /dev/null +++ b/test/fixtures/experimental/decorators-2/class-generator/expected.json @@ -0,0 +1,175 @@ +{ + "type": "File", + "start": 0, + "end": 25, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 25, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ClassDeclaration", + "start": 0, + "end": 25, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 6, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + }, + "identifierName": "A" + }, + "name": "A" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 8, + "end": 25, + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 3, + "column": 1 + } + }, + "body": [ + { + "type": "ClassMethod", + "start": 12, + "end": 23, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 13 + } + }, + "decorators": [ + { + "type": "Decorator", + "start": 12, + "end": 16, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 6 + } + }, + "expression": { + "type": "Identifier", + "start": 13, + "end": 16, + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 6 + }, + "identifierName": "dec" + }, + "name": "dec" + } + } + ], + "static": false, + "kind": "method", + "computed": false, + "key": { + "type": "Identifier", + "start": 18, + "end": 19, + "loc": { + "start": { + "line": 2, + "column": 8 + }, + "end": { + "line": 2, + "column": 9 + }, + "identifierName": "m" + }, + "name": "m" + }, + "id": null, + "generator": true, + "expression": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 21, + "end": 23, + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 13 + } + }, + "body": [], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/decorators-2/complex-expr/actual.js b/test/fixtures/experimental/decorators-2/complex-expr/actual.js new file mode 100644 index 0000000000..fb98deaf3d --- /dev/null +++ b/test/fixtures/experimental/decorators-2/complex-expr/actual.js @@ -0,0 +1,4 @@ +class A { + @a.b.c.d(e, f) + m(){} +} diff --git a/test/fixtures/experimental/decorators-2/complex-expr/expected.json b/test/fixtures/experimental/decorators-2/complex-expr/expected.json new file mode 100644 index 0000000000..b048d367ee --- /dev/null +++ b/test/fixtures/experimental/decorators-2/complex-expr/expected.json @@ -0,0 +1,325 @@ +{ + "type": "File", + "start": 0, + "end": 36, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 36, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ClassDeclaration", + "start": 0, + "end": 36, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 6, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + }, + "identifierName": "A" + }, + "name": "A" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 8, + "end": 36, + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "body": [ + { + "type": "ClassMethod", + "start": 12, + "end": 34, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 3, + "column": 7 + } + }, + "decorators": [ + { + "type": "Decorator", + "start": 12, + "end": 26, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "expression": { + "type": "CallExpression", + "start": 13, + "end": 26, + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "callee": { + "type": "MemberExpression", + "start": 13, + "end": 20, + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 10 + } + }, + "object": { + "type": "MemberExpression", + "start": 13, + "end": 18, + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 8 + } + }, + "object": { + "type": "MemberExpression", + "start": 13, + "end": 16, + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 6 + } + }, + "object": { + "type": "Identifier", + "start": 13, + "end": 14, + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 4 + }, + "identifierName": "a" + }, + "name": "a" + }, + "property": { + "type": "Identifier", + "start": 15, + "end": 16, + "loc": { + "start": { + "line": 2, + "column": 5 + }, + "end": { + "line": 2, + "column": 6 + }, + "identifierName": "b" + }, + "name": "b" + }, + "computed": false + }, + "property": { + "type": "Identifier", + "start": 17, + "end": 18, + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + }, + "identifierName": "c" + }, + "name": "c" + }, + "computed": false + }, + "property": { + "type": "Identifier", + "start": 19, + "end": 20, + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 10 + }, + "identifierName": "d" + }, + "name": "d" + }, + "computed": false + }, + "arguments": [ + { + "type": "Identifier", + "start": 21, + "end": 22, + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 12 + }, + "identifierName": "e" + }, + "name": "e" + }, + { + "type": "Identifier", + "start": 24, + "end": 25, + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 15 + }, + "identifierName": "f" + }, + "name": "f" + } + ] + } + } + ], + "static": false, + "computed": false, + "key": { + "type": "Identifier", + "start": 29, + "end": 30, + "loc": { + "start": { + "line": 3, + "column": 2 + }, + "end": { + "line": 3, + "column": 3 + }, + "identifierName": "m" + }, + "name": "m" + }, + "kind": "method", + "id": null, + "generator": false, + "expression": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 32, + "end": 34, + "loc": { + "start": { + "line": 3, + "column": 5 + }, + "end": { + "line": 3, + "column": 7 + } + }, + "body": [], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/decorators-2/export-decorated-class/actual.js b/test/fixtures/experimental/decorators-2/export-decorated-class/actual.js new file mode 100644 index 0000000000..80ba64f71a --- /dev/null +++ b/test/fixtures/experimental/decorators-2/export-decorated-class/actual.js @@ -0,0 +1,2 @@ +export default +@bar class Foo { } diff --git a/test/fixtures/experimental/decorators-2/export-decorated-class/expected.json b/test/fixtures/experimental/decorators-2/export-decorated-class/expected.json new file mode 100644 index 0000000000..bbfcc7fcca --- /dev/null +++ b/test/fixtures/experimental/decorators-2/export-decorated-class/expected.json @@ -0,0 +1,132 @@ +{ + "type": "File", + "start": 0, + "end": 34, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 18 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 34, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 18 + } + }, + "sourceType": "module", + "body": [ + { + "type": "ExportDefaultDeclaration", + "start": 0, + "end": 34, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 2, + "column": 18 + } + }, + "declaration": { + "type": "ClassExpression", + "start": 16, + "end": 34, + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 18 + } + }, + "decorators": [ + { + "type": "Decorator", + "start": 16, + "end": 20, + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 4 + } + }, + "expression": { + "type": "Identifier", + "start": 17, + "end": 20, + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 4 + }, + "identifierName": "bar" + }, + "name": "bar" + } + } + ], + "id": { + "type": "Identifier", + "start": 27, + "end": 30, + "loc": { + "start": { + "line": 2, + "column": 11 + }, + "end": { + "line": 2, + "column": 14 + }, + "identifierName": "Foo" + }, + "name": "Foo" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 31, + "end": 34, + "loc": { + "start": { + "line": 2, + "column": 15 + }, + "end": { + "line": 2, + "column": 18 + } + }, + "body": [] + } + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/decorators-2/export-decorated-class/options.json b/test/fixtures/experimental/decorators-2/export-decorated-class/options.json new file mode 100644 index 0000000000..2104ca4328 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/export-decorated-class/options.json @@ -0,0 +1,3 @@ +{ + "sourceType": "module" +} diff --git a/test/fixtures/experimental/decorators-2/no-class-method-parameter/actual.js b/test/fixtures/experimental/decorators-2/no-class-method-parameter/actual.js new file mode 100644 index 0000000000..6ebf34c91e --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-class-method-parameter/actual.js @@ -0,0 +1,3 @@ +class Foo { + constructor(@foo x) {} +} diff --git a/test/fixtures/experimental/decorators-2/no-class-method-parameter/options.json b/test/fixtures/experimental/decorators-2/no-class-method-parameter/options.json new file mode 100644 index 0000000000..7b4e6dc626 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-class-method-parameter/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Stage 2 decorators cannot be used to decorate parameters (2:14)" +} diff --git a/test/fixtures/experimental/decorators-2/no-class-property/actual.js b/test/fixtures/experimental/decorators-2/no-class-property/actual.js new file mode 100644 index 0000000000..9225da7c2c --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-class-property/actual.js @@ -0,0 +1,3 @@ +class A { + @dec name = 0 +} diff --git a/test/fixtures/experimental/decorators-2/no-class-property/options.json b/test/fixtures/experimental/decorators-2/no-class-property/options.json new file mode 100644 index 0000000000..024e2be712 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-class-property/options.json @@ -0,0 +1,4 @@ +{ + "plugins": ["classProperties", "decorators2"], + "throws": "Stage 2 decorators may only be used with a class or a class method (2:2)" +} diff --git a/test/fixtures/experimental/decorators-2/no-computed-decorator-member/actual.js b/test/fixtures/experimental/decorators-2/no-computed-decorator-member/actual.js new file mode 100644 index 0000000000..f261291097 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-computed-decorator-member/actual.js @@ -0,0 +1,6 @@ +class Foo { + @bar[bizz] + abc() { + + } +} diff --git a/test/fixtures/experimental/decorators-2/no-computed-decorator-member/options.json b/test/fixtures/experimental/decorators-2/no-computed-decorator-member/options.json new file mode 100644 index 0000000000..999cde36f6 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-computed-decorator-member/options.json @@ -0,0 +1,4 @@ +{ + "plugins": ["decorators2", "classProperties"], + "throws": "Stage 2 decorators may only be used with a class or a class method (2:2)" +} diff --git a/test/fixtures/experimental/decorators-2/no-constructor-decorators/actual.js b/test/fixtures/experimental/decorators-2/no-constructor-decorators/actual.js new file mode 100644 index 0000000000..4387084bbf --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-constructor-decorators/actual.js @@ -0,0 +1,4 @@ +class Foo { + @abc + constructor(){} +} diff --git a/test/fixtures/experimental/decorators-2/no-constructor-decorators/options.json b/test/fixtures/experimental/decorators-2/no-constructor-decorators/options.json new file mode 100644 index 0000000000..a26ed7cacb --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-constructor-decorators/options.json @@ -0,0 +1,3 @@ +{ + "throws": "You can't attach decorators to a class constructor (2:2)" +} diff --git a/test/fixtures/experimental/decorators-2/no-export-decorators-on-class/actual.js b/test/fixtures/experimental/decorators-2/no-export-decorators-on-class/actual.js new file mode 100644 index 0000000000..51804c6056 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-export-decorators-on-class/actual.js @@ -0,0 +1,2 @@ +@foo +export default class {} \ No newline at end of file diff --git a/test/fixtures/experimental/decorators-2/no-export-decorators-on-class/options.json b/test/fixtures/experimental/decorators-2/no-export-decorators-on-class/options.json new file mode 100644 index 0000000000..43922816e1 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-export-decorators-on-class/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "throws": "Leading decorators must be attached to a class declaration (2:0)" +} diff --git a/test/fixtures/experimental/decorators-2/no-function-parameters/actual.js b/test/fixtures/experimental/decorators-2/no-function-parameters/actual.js new file mode 100644 index 0000000000..857c046452 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-function-parameters/actual.js @@ -0,0 +1 @@ +function func(@foo x) {} diff --git a/test/fixtures/experimental/decorators-2/no-function-parameters/options.json b/test/fixtures/experimental/decorators-2/no-function-parameters/options.json new file mode 100644 index 0000000000..6637fc7f83 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-function-parameters/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Stage 2 decorators cannot be used to decorate parameters (1:14)" +} diff --git a/test/fixtures/experimental/decorators-2/no-object-method-parameters/actual.js b/test/fixtures/experimental/decorators-2/no-object-method-parameters/actual.js new file mode 100644 index 0000000000..a1aed846a9 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-object-method-parameters/actual.js @@ -0,0 +1,3 @@ +var obj = { + method(@foo x) {} +}; diff --git a/test/fixtures/experimental/decorators-2/no-object-method-parameters/options.json b/test/fixtures/experimental/decorators-2/no-object-method-parameters/options.json new file mode 100644 index 0000000000..b173069693 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-object-method-parameters/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Stage 2 decorators cannot be used to decorate parameters (2:9)" +} diff --git a/test/fixtures/experimental/decorators-2/no-object-methods/actual.js b/test/fixtures/experimental/decorators-2/no-object-methods/actual.js new file mode 100644 index 0000000000..51a3b5373e --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-object-methods/actual.js @@ -0,0 +1,5 @@ +var o = { + @baz + foo() { + } +} diff --git a/test/fixtures/experimental/decorators-2/no-object-methods/options.json b/test/fixtures/experimental/decorators-2/no-object-methods/options.json new file mode 100644 index 0000000000..7dd4ed9e28 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-object-methods/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Stage 2 decorators disallow object literal property decorators (2:2)" +} diff --git a/test/fixtures/experimental/decorators-2/no-private-property/actual.js b/test/fixtures/experimental/decorators-2/no-private-property/actual.js new file mode 100644 index 0000000000..2c1a455e62 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-private-property/actual.js @@ -0,0 +1,3 @@ +class A { + @dec #name = 0 +} diff --git a/test/fixtures/experimental/decorators-2/no-private-property/options.json b/test/fixtures/experimental/decorators-2/no-private-property/options.json new file mode 100644 index 0000000000..14c752698a --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-private-property/options.json @@ -0,0 +1,4 @@ +{ + "plugins": ["classProperties", "classPrivateProperties", "decorators2"], + "throws": "Stage 2 decorators may only be used with a class or a class method (2:2)" +} diff --git a/test/fixtures/experimental/decorators-2/no-semi/actual.js b/test/fixtures/experimental/decorators-2/no-semi/actual.js new file mode 100644 index 0000000000..6138e9c6f9 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-semi/actual.js @@ -0,0 +1,4 @@ +class A { + @a; + m(){} +} diff --git a/test/fixtures/experimental/decorators-2/no-semi/options.json b/test/fixtures/experimental/decorators-2/no-semi/options.json new file mode 100644 index 0000000000..ffac21b695 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-semi/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Decorators must not be followed by a semicolon (2:5)" +} diff --git a/test/fixtures/experimental/decorators-2/no-static-property/actual.js b/test/fixtures/experimental/decorators-2/no-static-property/actual.js new file mode 100644 index 0000000000..2fcc5057bd --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-static-property/actual.js @@ -0,0 +1,3 @@ +class A { + @dec static name = 0 +} diff --git a/test/fixtures/experimental/decorators-2/no-static-property/options.json b/test/fixtures/experimental/decorators-2/no-static-property/options.json new file mode 100644 index 0000000000..024e2be712 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/no-static-property/options.json @@ -0,0 +1,4 @@ +{ + "plugins": ["classProperties", "decorators2"], + "throws": "Stage 2 decorators may only be used with a class or a class method (2:2)" +} diff --git a/test/fixtures/experimental/decorators-2/on-computed-name-method/actual.js b/test/fixtures/experimental/decorators-2/on-computed-name-method/actual.js new file mode 100644 index 0000000000..39663850c3 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/on-computed-name-method/actual.js @@ -0,0 +1,4 @@ +class A { + @dec + ['name'](){} +} diff --git a/test/fixtures/experimental/decorators-2/on-computed-name-method/expected.json b/test/fixtures/experimental/decorators-2/on-computed-name-method/expected.json new file mode 100644 index 0000000000..7e9968743f --- /dev/null +++ b/test/fixtures/experimental/decorators-2/on-computed-name-method/expected.json @@ -0,0 +1,178 @@ +{ + "type": "File", + "start": 0, + "end": 33, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 33, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "sourceType": "script", + "body": [ + { + "type": "ClassDeclaration", + "start": 0, + "end": 33, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "id": { + "type": "Identifier", + "start": 6, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + }, + "identifierName": "A" + }, + "name": "A" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start": 8, + "end": 33, + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 4, + "column": 1 + } + }, + "body": [ + { + "type": "ClassMethod", + "start": 12, + "end": 31, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 3, + "column": 14 + } + }, + "decorators": [ + { + "type": "Decorator", + "start": 12, + "end": 16, + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 6 + } + }, + "expression": { + "type": "Identifier", + "start": 13, + "end": 16, + "loc": { + "start": { + "line": 2, + "column": 3 + }, + "end": { + "line": 2, + "column": 6 + }, + "identifierName": "dec" + }, + "name": "dec" + } + } + ], + "static": false, + "computed": true, + "key": { + "type": "StringLiteral", + "start": 20, + "end": 26, + "loc": { + "start": { + "line": 3, + "column": 3 + }, + "end": { + "line": 3, + "column": 9 + } + }, + "extra": { + "rawValue": "name", + "raw": "'name'" + }, + "value": "name" + }, + "kind": "method", + "id": null, + "generator": false, + "expression": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start": 29, + "end": 31, + "loc": { + "start": { + "line": 3, + "column": 12 + }, + "end": { + "line": 3, + "column": 14 + } + }, + "body": [], + "directives": [] + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/test/fixtures/experimental/decorators-2/options.json b/test/fixtures/experimental/decorators-2/options.json new file mode 100644 index 0000000000..607159a010 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["decorators2"] +} diff --git a/test/fixtures/experimental/decorators-2/plugin-conflict/actual.js b/test/fixtures/experimental/decorators-2/plugin-conflict/actual.js new file mode 100644 index 0000000000..68f513e2af --- /dev/null +++ b/test/fixtures/experimental/decorators-2/plugin-conflict/actual.js @@ -0,0 +1,2 @@ +// we don't need any source code for this error to trigger, +// it should trigger just because both old and new decorator plugins exist together diff --git a/test/fixtures/experimental/decorators-2/plugin-conflict/options.json b/test/fixtures/experimental/decorators-2/plugin-conflict/options.json new file mode 100644 index 0000000000..3e9d38f259 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/plugin-conflict/options.json @@ -0,0 +1,4 @@ +{ + "plugins": ["decorators", "decorators2"], + "throws": "Cannot use decorators and decorators2 plugin together" +} diff --git a/test/fixtures/experimental/decorators-2/restricted-1/actual.js b/test/fixtures/experimental/decorators-2/restricted-1/actual.js new file mode 100644 index 0000000000..cf35085f86 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/restricted-1/actual.js @@ -0,0 +1,2 @@ +@(bar.baz) +class Foo {} diff --git a/test/fixtures/experimental/decorators-2/restricted-1/options.json b/test/fixtures/experimental/decorators-2/restricted-1/options.json new file mode 100644 index 0000000000..b5b75f4187 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/restricted-1/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Unexpected token (1:1)" +} diff --git a/test/fixtures/experimental/decorators-2/restricted-2/actual.js b/test/fixtures/experimental/decorators-2/restricted-2/actual.js new file mode 100644 index 0000000000..8402c20e30 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/restricted-2/actual.js @@ -0,0 +1,2 @@ +@foo().bar +class Baz {} diff --git a/test/fixtures/experimental/decorators-2/restricted-2/options.json b/test/fixtures/experimental/decorators-2/restricted-2/options.json new file mode 100644 index 0000000000..9fc4104fb3 --- /dev/null +++ b/test/fixtures/experimental/decorators-2/restricted-2/options.json @@ -0,0 +1,3 @@ +{ + "throws": "Leading decorators must be attached to a class declaration (1:6)" +}