diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 79abd269e184..eb7952a3e8d9 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -628,7 +628,7 @@ export default class ExpressionParser extends LValParser { node.callee = base; node.arguments = this.parseCallExpressionArguments(tt.parenR, false); node.optional = true; - return this.finishNode(node, "OptionalCallExpression"); + return this.finishCallExpression(node, /* optional */ true); } else { node.object = base; node.property = this.parseIdentifier(true); @@ -683,11 +683,7 @@ export default class ExpressionParser extends LValParser { base.type !== "Super", node, ); - if (!state.optionalChainMember) { - this.finishCallExpression(node); - } else { - this.finishOptionalCallExpression(node); - } + this.finishCallExpression(node, state.optionalChainMember); if (state.maybeAsyncArrow && this.shouldParseAsyncArrow()) { state.stop = true; @@ -783,21 +779,10 @@ export default class ExpressionParser extends LValParser { ); } - finishCallExpression(node: N.CallExpression): N.CallExpression { - if (node.callee.type === "Import") { - if (node.arguments.length !== 1) { - this.raise(node.start, "import() requires exactly one argument"); - } - - const importArg = node.arguments[0]; - if (importArg && importArg.type === "SpreadElement") { - this.raise(importArg.start, "... is not allowed in import()"); - } - } - return this.finishNode(node, "CallExpression"); - } - - finishOptionalCallExpression(node: N.CallExpression): N.CallExpression { + finishCallExpression( + node: T, + optional: boolean, + ): T { if (node.callee.type === "Import") { if (node.arguments.length !== 1) { this.raise(node.start, "import() requires exactly one argument"); @@ -808,7 +793,10 @@ export default class ExpressionParser extends LValParser { this.raise(importArg.start, "... is not allowed in import()"); } } - return this.finishNode(node, "OptionalCallExpression"); + return this.finishNode( + node, + optional ? "OptionalCallExpression" : "CallExpression", + ); } parseCallExpressionArguments( diff --git a/packages/babel-parser/src/plugins/flow.js b/packages/babel-parser/src/plugins/flow.js index d4c815d38b45..fcdd16df61d2 100644 --- a/packages/babel-parser/src/plugins/flow.js +++ b/packages/babel-parser/src/plugins/flow.js @@ -2709,7 +2709,7 @@ export default (superClass: Class): Class => // $FlowFixMe node.arguments = this.parseCallExpressionArguments(tt.parenR, false); node.optional = true; - return this.finishNode(node, "OptionalCallExpression"); + return this.finishCallExpression(node, /* optional */ true); } else if ( !noCalls && this.shouldParseTypes() && @@ -2722,11 +2722,11 @@ export default (superClass: Class): Class => node.typeArguments = this.flowParseTypeParameterInstantiationCallOrNew(); this.expect(tt.parenL); node.arguments = this.parseCallExpressionArguments(tt.parenR, false); - if (subscriptState.optionalChainMember) { - node.optional = false; - return this.finishNode(node, "OptionalCallExpression"); - } - return this.finishNode(node, "CallExpression"); + if (subscriptState.optionalChainMember) node.optional = false; + return this.finishCallExpression( + node, + subscriptState.optionalChainMember, + ); } catch (e) { if (e instanceof SyntaxError) { this.state = state; diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index 26a6246d59e6..4dc707be7cb9 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -1655,7 +1655,7 @@ export default (superClass: Class): Class => /* possibleAsync */ false, ); node.typeParameters = typeArguments; - return this.finishCallExpression(node); + return this.finishCallExpression(node, state.optionalChainMember); } else if (this.match(tt.backQuote)) { return this.parseTaggedTemplateExpression( startPos, diff --git a/packages/babel-parser/test/fixtures/typescript/optional-chaining/type-arguments/input.ts b/packages/babel-parser/test/fixtures/typescript/optional-chaining/type-arguments/input.ts new file mode 100644 index 000000000000..731a05f63b36 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/optional-chaining/type-arguments/input.ts @@ -0,0 +1 @@ +example.inner?.greet() diff --git a/packages/babel-parser/test/fixtures/typescript/optional-chaining/type-arguments/options.json b/packages/babel-parser/test/fixtures/typescript/optional-chaining/type-arguments/options.json new file mode 100644 index 000000000000..ccc6341666b4 --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/optional-chaining/type-arguments/options.json @@ -0,0 +1,4 @@ +{ + "sourceType": "module", + "plugins": ["typescript", "optionalChaining"] +} diff --git a/packages/babel-parser/test/fixtures/typescript/optional-chaining/type-arguments/output.json b/packages/babel-parser/test/fixtures/typescript/optional-chaining/type-arguments/output.json new file mode 100644 index 000000000000..42f6c8b98b0e --- /dev/null +++ b/packages/babel-parser/test/fixtures/typescript/optional-chaining/type-arguments/output.json @@ -0,0 +1,182 @@ +{ + "type": "File", + "start": 0, + "end": 30, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 30 + } + }, + "program": { + "type": "Program", + "start": 0, + "end": 30, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 30 + } + }, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start": 0, + "end": 30, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 30 + } + }, + "expression": { + "type": "OptionalCallExpression", + "start": 0, + "end": 30, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 30 + } + }, + "callee": { + "type": "OptionalMemberExpression", + "start": 0, + "end": 20, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 20 + } + }, + "object": { + "type": "MemberExpression", + "start": 0, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 13 + } + }, + "object": { + "type": "Identifier", + "start": 0, + "end": 7, + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 7 + }, + "identifierName": "example" + }, + "name": "example" + }, + "property": { + "type": "Identifier", + "start": 8, + "end": 13, + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 1, + "column": 13 + }, + "identifierName": "inner" + }, + "name": "inner" + }, + "computed": false + }, + "property": { + "type": "Identifier", + "start": 15, + "end": 20, + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 1, + "column": 20 + }, + "identifierName": "greet" + }, + "name": "greet" + }, + "computed": false, + "optional": true + }, + "arguments": [], + "typeParameters": { + "type": "TSTypeParameterInstantiation", + "start": 20, + "end": 28, + "loc": { + "start": { + "line": 1, + "column": 20 + }, + "end": { + "line": 1, + "column": 28 + } + }, + "params": [ + { + "type": "TSStringKeyword", + "start": 21, + "end": 27, + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 27 + } + } + } + ] + } + } + } + ], + "directives": [] + } +} \ No newline at end of file