diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index ad8ad9ccb225..559a4b58e1f9 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -1453,7 +1453,7 @@ export default class ExpressionParser extends LValParser { if ( canBeArrow && this.shouldParseArrow() && - (arrowNode = this.parseArrow(arrowNode, exprList)) + (arrowNode = this.parseArrow(arrowNode)) ) { if (!this.isAwaitAllowed() && !this.state.maybeInAsyncArrowHead) { this.state.awaitPos = oldAwaitPos; @@ -1509,10 +1509,7 @@ export default class ExpressionParser extends LValParser { return !this.canInsertSemicolon(); } - parseArrow( - node: N.ArrowFunctionExpression, - exprList: N.Node[], // eslint-disable-line no-unused-vars - ): ?N.ArrowFunctionExpression { + parseArrow(node: N.ArrowFunctionExpression): ?N.ArrowFunctionExpression { if (this.eat(tt.arrow)) { return node; } diff --git a/packages/babel-parser/src/parser/lval.js b/packages/babel-parser/src/parser/lval.js index 19fc2f06e62b..42c094b76203 100644 --- a/packages/babel-parser/src/parser/lval.js +++ b/packages/babel-parser/src/parser/lval.js @@ -51,60 +51,10 @@ export default class LValParser extends NodeUtils { +parseDecorator: () => Decorator; */ - /** - * Check if a node can be converted to a binding identifier or binding pattern. - * https://tc39.es/ecma262/#prod-BindingIdentifier - * https://tc39.es/ecma262/#prod-BindingPattern - * Note that although a mebmer expression can serve as a LHS in the init of for loop, - * i.e. `for (a.b of []);`, it is not a binding pattern - * - * @param {Node} node - * @returns {boolean} - * @memberof LValParser - */ - isAssignable(node: Node): boolean { - switch (node.type) { - case "Identifier": - case "ObjectPattern": - case "ArrayPattern": - case "AssignmentPattern": - case "RestElement": - return true; - - case "ObjectExpression": { - const last = node.properties.length - 1; - return node.properties.every((prop, i) => { - return ( - prop.type !== "ObjectMethod" && - (i === last || prop.type === "SpreadElement") && - this.isAssignable(prop) - ); - }); - } - - case "ObjectProperty": - return this.isAssignable(node.value); - - case "SpreadElement": - return this.isAssignable(node.argument); - - case "ArrayExpression": - return node.elements.every(element => this.isAssignable(element)); - - case "AssignmentExpression": - return node.operator === "="; - - case "ParenthesizedExpression": - return this.isAssignable(node.expression); - - default: - return false; - } - } - // Convert existing expression atom to assignable pattern // if possible. - // When this one is updated, please check if `isAssignable` also needs to be updated. + // NOTE: There is a corresponding "isAssignable" method in flow.js. + // When this one is updated, please check if also that one needs to be updated. toAssignable(node: Node): Node { let parenthesized = undefined; diff --git a/packages/babel-parser/src/plugins/flow.js b/packages/babel-parser/src/plugins/flow.js index 17da0a7fe117..26ddfeaae787 100644 --- a/packages/babel-parser/src/plugins/flow.js +++ b/packages/babel-parser/src/plugins/flow.js @@ -1943,7 +1943,7 @@ export default (superClass: Class): Class => } return partition(arrows, node => - node.params.every(param => this.isAssignable(param)), + node.params.every(param => this.isAssignable(param, true)), ); } @@ -2146,12 +2146,47 @@ export default (superClass: Class): Class => } } - isAssignable(node: N.Node): boolean { + isAssignable(node: N.Node, isBinding?: boolean): boolean { switch (node.type) { + case "Identifier": + case "ObjectPattern": + case "ArrayPattern": + case "AssignmentPattern": + return true; + + case "ObjectExpression": { + const last = node.properties.length - 1; + return node.properties.every((prop, i) => { + return ( + prop.type !== "ObjectMethod" && + (i === last || prop.type === "SpreadElement") && + this.isAssignable(prop) + ); + }); + } + + case "ObjectProperty": + return this.isAssignable(node.value); + + case "SpreadElement": + return this.isAssignable(node.argument); + + case "ArrayExpression": + return node.elements.every(element => this.isAssignable(element)); + + case "AssignmentExpression": + return node.operator === "="; + + case "ParenthesizedExpression": case "TypeCastExpression": return this.isAssignable(node.expression); + + case "MemberExpression": + case "OptionalMemberExpression": + return !isBinding; + default: - return super.isAssignable(node); + return false; } } @@ -2737,10 +2772,7 @@ export default (superClass: Class): Class => } // handle return types for arrow functions - parseArrow( - node: N.ArrowFunctionExpression, - exprList: N.Node[], - ): ?N.ArrowFunctionExpression { + parseArrow(node: N.ArrowFunctionExpression): ?N.ArrowFunctionExpression { if (this.match(tt.colon)) { const result = this.tryParse(() => { const oldNoAnonFunctionType = this.state.noAnonFunctionType; @@ -2774,7 +2806,7 @@ export default (superClass: Class): Class => : null; } - return super.parseArrow(node, exprList); + return super.parseArrow(node); } shouldParseArrow(): boolean { @@ -2945,8 +2977,7 @@ export default (superClass: Class): Class => ): ?N.ArrowFunctionExpression { const node = this.startNodeAt(startPos, startLoc); this.parseFunctionParams(node); - // set exprList to `[]` as the parameters has been validated in `parseFunctionParams` - if (!this.parseArrow(node, [])) return; + if (!this.parseArrow(node)) return; return this.parseArrowExpression( node, /* params */ undefined, diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index e1f27f3ce913..b85c41371a68 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -2540,10 +2540,7 @@ export default (superClass: Class): Class => } } - parseArrow( - node: N.ArrowFunctionExpression, - exprList, - ): ?N.ArrowFunctionExpression { + parseArrow(node: N.ArrowFunctionExpression): ?N.ArrowFunctionExpression { if (this.match(tt.colon)) { // This is different from how the TS parser does it. // TS uses lookahead. The Babel Parser parses it as a parenthesized expression and converts. @@ -2553,10 +2550,6 @@ export default (superClass: Class): Class => tt.colon, ); if (this.canInsertSemicolon() || !this.match(tt.arrow)) abort(); - // check if the exprList is assignable because `: TSType` can be part of conditional expression - // i.e. we can only know `: v` is not a return type by checking that `sum(v)` can not be a pattern. - // 0 ? v => (sum(v)) : v => 0 - if (exprList.some(param => !this.isAssignable(param))) abort(); return returnType; }); @@ -2568,7 +2561,7 @@ export default (superClass: Class): Class => } } - return super.parseArrow(node, exprList); + return super.parseArrow(node); } // Allow type annotations inside of a parameter list. @@ -2587,18 +2580,6 @@ export default (superClass: Class): Class => return param; } - isAssignable(node: N.Node): boolean { - switch (node.type) { - case "TSAsExpression": - case "TSNonNullExpression": - case "TSTypeAssertion": - case "TSTypeCastExpression": - return this.isAssignable(node.expression); - default: - return super.isAssignable(node); - } - } - toAssignable(node: N.Node): N.Node { switch (node.type) { case "TSTypeCastExpression": diff --git a/packages/babel-parser/test/fixtures/typescript/arrow-function/ambiguous-ternary-arrow-return-type-typescript-issue-16241/input.ts b/packages/babel-parser/test/fixtures/typescript/arrow-function/ambiguous-ternary-arrow-return-type-typescript-issue-16241/input.ts deleted file mode 100644 index ebcb43495f37..000000000000 --- a/packages/babel-parser/test/fixtures/typescript/arrow-function/ambiguous-ternary-arrow-return-type-typescript-issue-16241/input.ts +++ /dev/null @@ -1 +0,0 @@ -0 ? v => (v) : v => 0; diff --git a/packages/babel-parser/test/fixtures/typescript/arrow-function/ambiguous-ternary-arrow-return-type-typescript-issue-16241/options.json b/packages/babel-parser/test/fixtures/typescript/arrow-function/ambiguous-ternary-arrow-return-type-typescript-issue-16241/options.json deleted file mode 100644 index 0c7f7817f9f7..000000000000 --- a/packages/babel-parser/test/fixtures/typescript/arrow-function/ambiguous-ternary-arrow-return-type-typescript-issue-16241/options.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "sourceType": "module", - "plugins": [ - "typescript" - ], - "throws": "Unexpected token, expected \":\" (1:21)" -} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/arrow-function/return-type-like-conditional/input.ts b/packages/babel-parser/test/fixtures/typescript/arrow-function/return-type-like-conditional/input.ts deleted file mode 100644 index f74bd2c8ea88..000000000000 --- a/packages/babel-parser/test/fixtures/typescript/arrow-function/return-type-like-conditional/input.ts +++ /dev/null @@ -1,4 +0,0 @@ -0 ? v => (sum += v) : v => 0; -0 ? v => (sum(v)) : v => 0; -0 ? v => (v.w) : v => 0; -0 ? v => ([ v.w ]) : v => {}; diff --git a/packages/babel-parser/test/fixtures/typescript/arrow-function/return-type-like-conditional/options.json b/packages/babel-parser/test/fixtures/typescript/arrow-function/return-type-like-conditional/options.json deleted file mode 100644 index 5047d6993fe8..000000000000 --- a/packages/babel-parser/test/fixtures/typescript/arrow-function/return-type-like-conditional/options.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "plugins": ["typescript"] -} diff --git a/packages/babel-parser/test/fixtures/typescript/arrow-function/return-type-like-conditional/output.json b/packages/babel-parser/test/fixtures/typescript/arrow-function/return-type-like-conditional/output.json deleted file mode 100644 index 08bbc5b1e9d0..000000000000 --- a/packages/babel-parser/test/fixtures/typescript/arrow-function/return-type-like-conditional/output.json +++ /dev/null @@ -1,309 +0,0 @@ -{ - "type": "File", - "start":0,"end":112,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":29}}, - "program": { - "type": "Program", - "start":0,"end":112,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":29}}, - "sourceType": "module", - "interpreter": null, - "body": [ - { - "type": "ExpressionStatement", - "start":0,"end":29,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":29}}, - "expression": { - "type": "ConditionalExpression", - "start":0,"end":28,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":28}}, - "test": { - "type": "NumericLiteral", - "start":0,"end":1,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":1}}, - "extra": { - "rawValue": 0, - "raw": "0" - }, - "value": 0 - }, - "consequent": { - "type": "ArrowFunctionExpression", - "start":4,"end":19,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":19}}, - "id": null, - "generator": false, - "async": false, - "params": [ - { - "type": "Identifier", - "start":4,"end":5,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5},"identifierName":"v"}, - "name": "v" - } - ], - "body": { - "type": "AssignmentExpression", - "start":10,"end":18,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":18}}, - "operator": "+=", - "left": { - "type": "Identifier", - "start":10,"end":13,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":13},"identifierName":"sum"}, - "name": "sum" - }, - "right": { - "type": "Identifier", - "start":17,"end":18,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":18},"identifierName":"v"}, - "name": "v" - }, - "extra": { - "parenthesized": true, - "parenStart": 9 - } - } - }, - "alternate": { - "type": "ArrowFunctionExpression", - "start":22,"end":28,"loc":{"start":{"line":1,"column":22},"end":{"line":1,"column":28}}, - "id": null, - "generator": false, - "async": false, - "params": [ - { - "type": "Identifier", - "start":22,"end":23,"loc":{"start":{"line":1,"column":22},"end":{"line":1,"column":23},"identifierName":"v"}, - "name": "v" - } - ], - "body": { - "type": "NumericLiteral", - "start":27,"end":28,"loc":{"start":{"line":1,"column":27},"end":{"line":1,"column":28}}, - "extra": { - "rawValue": 0, - "raw": "0" - }, - "value": 0 - } - } - } - }, - { - "type": "ExpressionStatement", - "start":30,"end":57,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":27}}, - "expression": { - "type": "ConditionalExpression", - "start":30,"end":56,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":26}}, - "test": { - "type": "NumericLiteral", - "start":30,"end":31,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":1}}, - "extra": { - "rawValue": 0, - "raw": "0" - }, - "value": 0 - }, - "consequent": { - "type": "ArrowFunctionExpression", - "start":34,"end":47,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":17}}, - "id": null, - "generator": false, - "async": false, - "params": [ - { - "type": "Identifier", - "start":34,"end":35,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":5},"identifierName":"v"}, - "name": "v" - } - ], - "body": { - "type": "CallExpression", - "start":40,"end":46,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":16}}, - "callee": { - "type": "Identifier", - "start":40,"end":43,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":13},"identifierName":"sum"}, - "name": "sum" - }, - "arguments": [ - { - "type": "Identifier", - "start":44,"end":45,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":15},"identifierName":"v"}, - "name": "v" - } - ], - "extra": { - "parenthesized": true, - "parenStart": 39 - } - } - }, - "alternate": { - "type": "ArrowFunctionExpression", - "start":50,"end":56,"loc":{"start":{"line":2,"column":20},"end":{"line":2,"column":26}}, - "id": null, - "generator": false, - "async": false, - "params": [ - { - "type": "Identifier", - "start":50,"end":51,"loc":{"start":{"line":2,"column":20},"end":{"line":2,"column":21},"identifierName":"v"}, - "name": "v" - } - ], - "body": { - "type": "NumericLiteral", - "start":55,"end":56,"loc":{"start":{"line":2,"column":25},"end":{"line":2,"column":26}}, - "extra": { - "rawValue": 0, - "raw": "0" - }, - "value": 0 - } - } - } - }, - { - "type": "ExpressionStatement", - "start":58,"end":82,"loc":{"start":{"line":3,"column":0},"end":{"line":3,"column":24}}, - "expression": { - "type": "ConditionalExpression", - "start":58,"end":81,"loc":{"start":{"line":3,"column":0},"end":{"line":3,"column":23}}, - "test": { - "type": "NumericLiteral", - "start":58,"end":59,"loc":{"start":{"line":3,"column":0},"end":{"line":3,"column":1}}, - "extra": { - "rawValue": 0, - "raw": "0" - }, - "value": 0 - }, - "consequent": { - "type": "ArrowFunctionExpression", - "start":62,"end":72,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":14}}, - "id": null, - "generator": false, - "async": false, - "params": [ - { - "type": "Identifier", - "start":62,"end":63,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":5},"identifierName":"v"}, - "name": "v" - } - ], - "body": { - "type": "MemberExpression", - "start":68,"end":71,"loc":{"start":{"line":3,"column":10},"end":{"line":3,"column":13}}, - "object": { - "type": "Identifier", - "start":68,"end":69,"loc":{"start":{"line":3,"column":10},"end":{"line":3,"column":11},"identifierName":"v"}, - "name": "v" - }, - "computed": false, - "property": { - "type": "Identifier", - "start":70,"end":71,"loc":{"start":{"line":3,"column":12},"end":{"line":3,"column":13},"identifierName":"w"}, - "name": "w" - }, - "extra": { - "parenthesized": true, - "parenStart": 67 - } - } - }, - "alternate": { - "type": "ArrowFunctionExpression", - "start":75,"end":81,"loc":{"start":{"line":3,"column":17},"end":{"line":3,"column":23}}, - "id": null, - "generator": false, - "async": false, - "params": [ - { - "type": "Identifier", - "start":75,"end":76,"loc":{"start":{"line":3,"column":17},"end":{"line":3,"column":18},"identifierName":"v"}, - "name": "v" - } - ], - "body": { - "type": "NumericLiteral", - "start":80,"end":81,"loc":{"start":{"line":3,"column":22},"end":{"line":3,"column":23}}, - "extra": { - "rawValue": 0, - "raw": "0" - }, - "value": 0 - } - } - } - }, - { - "type": "ExpressionStatement", - "start":83,"end":112,"loc":{"start":{"line":4,"column":0},"end":{"line":4,"column":29}}, - "expression": { - "type": "ConditionalExpression", - "start":83,"end":111,"loc":{"start":{"line":4,"column":0},"end":{"line":4,"column":28}}, - "test": { - "type": "NumericLiteral", - "start":83,"end":84,"loc":{"start":{"line":4,"column":0},"end":{"line":4,"column":1}}, - "extra": { - "rawValue": 0, - "raw": "0" - }, - "value": 0 - }, - "consequent": { - "type": "ArrowFunctionExpression", - "start":87,"end":101,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":18}}, - "id": null, - "generator": false, - "async": false, - "params": [ - { - "type": "Identifier", - "start":87,"end":88,"loc":{"start":{"line":4,"column":4},"end":{"line":4,"column":5},"identifierName":"v"}, - "name": "v" - } - ], - "body": { - "type": "ArrayExpression", - "start":93,"end":100,"loc":{"start":{"line":4,"column":10},"end":{"line":4,"column":17}}, - "elements": [ - { - "type": "MemberExpression", - "start":95,"end":98,"loc":{"start":{"line":4,"column":12},"end":{"line":4,"column":15}}, - "object": { - "type": "Identifier", - "start":95,"end":96,"loc":{"start":{"line":4,"column":12},"end":{"line":4,"column":13},"identifierName":"v"}, - "name": "v" - }, - "computed": false, - "property": { - "type": "Identifier", - "start":97,"end":98,"loc":{"start":{"line":4,"column":14},"end":{"line":4,"column":15},"identifierName":"w"}, - "name": "w" - } - } - ], - "extra": { - "parenthesized": true, - "parenStart": 92 - } - } - }, - "alternate": { - "type": "ArrowFunctionExpression", - "start":104,"end":111,"loc":{"start":{"line":4,"column":21},"end":{"line":4,"column":28}}, - "id": null, - "generator": false, - "async": false, - "params": [ - { - "type": "Identifier", - "start":104,"end":105,"loc":{"start":{"line":4,"column":21},"end":{"line":4,"column":22},"identifierName":"v"}, - "name": "v" - } - ], - "body": { - "type": "BlockStatement", - "start":109,"end":111,"loc":{"start":{"line":4,"column":26},"end":{"line":4,"column":28}}, - "body": [], - "directives": [] - } - } - } - } - ], - "directives": [] - } -} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/typescript/regression/rest-in-arrow/input.ts b/packages/babel-parser/test/fixtures/typescript/regression/rest-in-arrow/input.ts deleted file mode 100644 index 5ceec7855490..000000000000 --- a/packages/babel-parser/test/fixtures/typescript/regression/rest-in-arrow/input.ts +++ /dev/null @@ -1 +0,0 @@ -const f = (...args): void => {}; diff --git a/packages/babel-parser/test/fixtures/typescript/regression/rest-in-arrow/output.json b/packages/babel-parser/test/fixtures/typescript/regression/rest-in-arrow/output.json deleted file mode 100644 index fabbad620bdc..000000000000 --- a/packages/babel-parser/test/fixtures/typescript/regression/rest-in-arrow/output.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "type": "File", - "start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":32}}, - "program": { - "type": "Program", - "start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":32}}, - "sourceType": "module", - "interpreter": null, - "body": [ - { - "type": "VariableDeclaration", - "start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":32}}, - "declarations": [ - { - "type": "VariableDeclarator", - "start":6,"end":31,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":31}}, - "id": { - "type": "Identifier", - "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"f"}, - "name": "f" - }, - "init": { - "type": "ArrowFunctionExpression", - "start":10,"end":31,"loc":{"start":{"line":1,"column":10},"end":{"line":1,"column":31}}, - "returnType": { - "type": "TSTypeAnnotation", - "start":19,"end":25,"loc":{"start":{"line":1,"column":19},"end":{"line":1,"column":25}}, - "typeAnnotation": { - "type": "TSVoidKeyword", - "start":21,"end":25,"loc":{"start":{"line":1,"column":21},"end":{"line":1,"column":25}} - } - }, - "id": null, - "generator": false, - "async": false, - "params": [ - { - "type": "RestElement", - "start":11,"end":18,"loc":{"start":{"line":1,"column":11},"end":{"line":1,"column":18}}, - "argument": { - "type": "Identifier", - "start":14,"end":18,"loc":{"start":{"line":1,"column":14},"end":{"line":1,"column":18},"identifierName":"args"}, - "name": "args" - } - } - ], - "body": { - "type": "BlockStatement", - "start":29,"end":31,"loc":{"start":{"line":1,"column":29},"end":{"line":1,"column":31}}, - "body": [], - "directives": [] - } - } - } - ], - "kind": "const" - } - ], - "directives": [] - } -} \ No newline at end of file