From 80d99b4d4e7ebb7f7136ad35163329375173ed2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Tue, 1 Oct 2019 11:40:42 +0200 Subject: [PATCH] Do not allow member expressions to start async arrows (#10332) * Do not allow member expressions to start async arrows * Boolean -> boolean --- .../babel-parser/src/parser/expression.js | 20 +- packages/babel-parser/src/plugins/flow.js | 2 - .../src/plugins/typescript/index.js | 10 +- packages/babel-parser/src/types.js | 1 + .../flow/regression/issue-10314/input.js | 3 + .../flow/regression/issue-10314/output.json | 198 ++++++++++++++++++ 6 files changed, 210 insertions(+), 24 deletions(-) create mode 100644 packages/babel-parser/test/fixtures/flow/regression/issue-10314/input.js create mode 100644 packages/babel-parser/test/fixtures/flow/regression/issue-10314/output.json diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index f7e75bfe5ea3..8dcf3aabef05 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -578,21 +578,16 @@ export default class ExpressionParser extends LValParser { startLoc: Position, noCalls?: ?boolean, ): N.Expression { - const maybeAsyncArrow = this.atPossibleAsync(base); - const state = { optionalChainMember: false, + maybeAsyncArrow: this.atPossibleAsync(base), stop: false, }; do { - base = this.parseSubscript( - base, - startPos, - startLoc, - noCalls, - state, - maybeAsyncArrow, - ); + base = this.parseSubscript(base, startPos, startLoc, noCalls, state); + + // After parsing a subscript, this isn't "async" for sure. + state.maybeAsyncArrow = false; } while (!state.stop); return base; } @@ -607,7 +602,6 @@ export default class ExpressionParser extends LValParser { startLoc: Position, noCalls: ?boolean, state: N.ParseSubscriptState, - maybeAsyncArrow: boolean, ): N.Expression { if (!noCalls && this.eat(tt.doubleColon)) { const node = this.startNodeAt(startPos, startLoc); @@ -695,7 +689,7 @@ export default class ExpressionParser extends LValParser { node.arguments = this.parseCallExpressionArguments( tt.parenR, - maybeAsyncArrow, + state.maybeAsyncArrow, base.type === "Import", base.type !== "Super", ); @@ -705,7 +699,7 @@ export default class ExpressionParser extends LValParser { this.finishOptionalCallExpression(node); } - if (maybeAsyncArrow && this.shouldParseAsyncArrow()) { + if (state.maybeAsyncArrow && this.shouldParseAsyncArrow()) { state.stop = true; this.checkCommaAfterRestFromSpread(); diff --git a/packages/babel-parser/src/plugins/flow.js b/packages/babel-parser/src/plugins/flow.js index 024a21baa5ab..da11a4eccc0f 100644 --- a/packages/babel-parser/src/plugins/flow.js +++ b/packages/babel-parser/src/plugins/flow.js @@ -2634,7 +2634,6 @@ export default (superClass: Class): Class => startLoc: Position, noCalls: ?boolean, subscriptState: N.ParseSubscriptState, - maybeAsyncArrow: boolean, ): N.Expression { if (this.match(tt.questionDot) && this.isLookaheadRelational("<")) { this.expectPlugin("optionalChaining"); @@ -2687,7 +2686,6 @@ export default (superClass: Class): Class => startLoc, noCalls, subscriptState, - maybeAsyncArrow, ); } diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 5d6922d329eb..3ac78d17474a 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -1568,7 +1568,6 @@ export default (superClass: Class): Class => startLoc: Position, noCalls: ?boolean, state: N.ParseSubscriptState, - maybeAsyncArrow: boolean, ): N.Expression { if (!this.hasPrecedingLineBreak() && this.match(tt.bang)) { this.state.exprAllowed = false; @@ -1631,14 +1630,7 @@ export default (superClass: Class): Class => if (result) return result; } - return super.parseSubscript( - base, - startPos, - startLoc, - noCalls, - state, - maybeAsyncArrow, - ); + return super.parseSubscript(base, startPos, startLoc, noCalls, state); } parseNewArguments(node: N.NewExpression): void { diff --git a/packages/babel-parser/src/types.js b/packages/babel-parser/src/types.js index 2c5992d2ba6c..8560da3a3f73 100644 --- a/packages/babel-parser/src/types.js +++ b/packages/babel-parser/src/types.js @@ -1447,5 +1447,6 @@ export type Placeholder = NodeBase & { export type ParseSubscriptState = { optionalChainMember: boolean, + maybeAsyncArrow: boolean, stop: boolean, }; diff --git a/packages/babel-parser/test/fixtures/flow/regression/issue-10314/input.js b/packages/babel-parser/test/fixtures/flow/regression/issue-10314/input.js new file mode 100644 index 000000000000..3c830a898f38 --- /dev/null +++ b/packages/babel-parser/test/fixtures/flow/regression/issue-10314/input.js @@ -0,0 +1,3 @@ +// @flow + +true ? async.waterfall() : null; diff --git a/packages/babel-parser/test/fixtures/flow/regression/issue-10314/output.json b/packages/babel-parser/test/fixtures/flow/regression/issue-10314/output.json new file mode 100644 index 000000000000..3742c1bbf74d --- /dev/null +++ b/packages/babel-parser/test/fixtures/flow/regression/issue-10314/output.json @@ -0,0 +1,198 @@ +{ + "type": "File", + "start": 0, + "end": 42, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 32 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 42, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 3, + "column": 32 + } + }, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 10, + "end": 42, + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 32 + } + }, + "expression": { + "type": "ConditionalExpression", + "start": 10, + "end": 41, + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 31 + } + }, + "test": { + "type": "BooleanLiteral", + "start": 10, + "end": 14, + "loc": { + "start": { + "line": 3, + "column": 0 + }, + "end": { + "line": 3, + "column": 4 + } + }, + "value": true + }, + "consequent": { + "type": "CallExpression", + "start": 17, + "end": 34, + "loc": { + "start": { + "line": 3, + "column": 7 + }, + "end": { + "line": 3, + "column": 24 + } + }, + "callee": { + "type": "MemberExpression", + "start": 17, + "end": 32, + "loc": { + "start": { + "line": 3, + "column": 7 + }, + "end": { + "line": 3, + "column": 22 + } + }, + "object": { + "type": "Identifier", + "start": 17, + "end": 22, + "loc": { + "start": { + "line": 3, + "column": 7 + }, + "end": { + "line": 3, + "column": 12 + }, + "identifierName": "async" + }, + "name": "async" + }, + "property": { + "type": "Identifier", + "start": 23, + "end": 32, + "loc": { + "start": { + "line": 3, + "column": 13 + }, + "end": { + "line": 3, + "column": 22 + }, + "identifierName": "waterfall" + }, + "name": "waterfall" + }, + "computed": false + }, + "arguments": [] + }, + "alternate": { + "type": "NullLiteral", + "start": 37, + "end": 41, + "loc": { + "start": { + "line": 3, + "column": 27 + }, + "end": { + "line": 3, + "column": 31 + } + } + } + }, + "leadingComments": [ + { + "type": "CommentLine", + "value": " @flow", + "start": 0, + "end": 8, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 8 + } + } + } + ] + } + ], + "directives": [] + }, + "comments": [ + { + "type": "CommentLine", + "value": " @flow", + "start": 0, + "end": 8, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 8 + } + } + } + ] +} \ No newline at end of file