Skip to content

Commit

Permalink
[ts] support optional chain call with generic (#13513)
Browse files Browse the repository at this point in the history
* support optional chain call with generic

* Add testcase handling new line

* allow only call if optional chain type parameter

* use exact error message

* add transform-typescript optional-chain call test

* use exact error message

* apply feedbacks

* Fix lint error

Co-authored-by: Nicol貌 Ribaudo <nicolo.ribaudo@gmail.com>
  • Loading branch information
lala7573 and nicolo-ribaudo committed Aug 4, 2021
1 parent d5b0d9e commit 0671afc
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 5 deletions.
26 changes: 25 additions & 1 deletion packages/babel-parser/src/plugins/typescript/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2082,7 +2082,21 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.finishNode(nonNullExpression, "TSNonNullExpression");
}

let isOptionalCall = false;
if (
this.match(tt.questionDot) &&
this.lookaheadCharCode() === charCodes.lessThan
) {
if (noCalls) {
state.stop = true;
return base;
}
state.optionalChainMember = isOptionalCall = true;
this.next();
}

if (this.isRelational("<")) {
let missingParenErrorPos;
// tsTryParseAndCatch is expensive, so avoid if not necessary.
// There are number of things we are going to "maybe" parse, like type arguments on
// tagged template expressions. If any of them fail, walk it back and continue.
Expand All @@ -2105,6 +2119,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
const typeArguments = this.tsParseTypeArguments();

if (typeArguments) {
if (isOptionalCall && !this.match(tt.parenL)) {
missingParenErrorPos = this.state.pos;
this.unexpected();
}

if (!noCalls && this.eat(tt.parenL)) {
// possibleAsync always false here, because we would have handled it above.
// $FlowIgnore (won't be any undefined arguments)
Expand All @@ -2119,8 +2138,9 @@ export default (superClass: Class<Parser>): Class<Parser> =>
node.typeParameters = typeArguments;
if (state.optionalChainMember) {
// $FlowIgnore
node.optional = false;
node.optional = isOptionalCall;
}

return this.finishCallExpression(node, state.optionalChainMember);
} else if (this.match(tt.backQuote)) {
const result = this.parseTaggedTemplateExpression(
Expand All @@ -2137,6 +2157,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.unexpected();
});

if (missingParenErrorPos) {
this.unexpected(missingParenErrorPos, tt.parenL);
}

if (result) return result;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
foo?.foo<T>();
foo?.foo?.<T>();
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"type": "File",
"start":0,"end":14,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":14}},
"start":0,"end":31,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":16}},
"program": {
"type": "Program",
"start":0,"end":14,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":14}},
"start":0,"end":31,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":16}},
"sourceType": "script",
"interpreter": null,
"body": [
Expand Down Expand Up @@ -51,6 +51,51 @@
"optional": false
}
}
},
{
"type": "ExpressionStatement",
"start":15,"end":31,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":16}},
"expression": {
"type": "ChainExpression",
"start":15,"end":30,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":15}},
"expression": {
"type": "CallExpression",
"start":15,"end":30,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":15}},
"callee": {
"type": "MemberExpression",
"start":15,"end":23,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":8}},
"object": {
"type": "Identifier",
"start":15,"end":18,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":3},"identifierName":"foo"},
"name": "foo"
},
"computed": false,
"property": {
"type": "Identifier",
"start":20,"end":23,"loc":{"start":{"line":2,"column":5},"end":{"line":2,"column":8},"identifierName":"foo"},
"name": "foo"
},
"optional": true
},
"arguments": [],
"typeParameters": {
"type": "TSTypeParameterInstantiation",
"start":25,"end":28,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":13}},
"params": [
{
"type": "TSTypeReference",
"start":26,"end":27,"loc":{"start":{"line":2,"column":11},"end":{"line":2,"column":12}},
"typeName": {
"type": "Identifier",
"start":26,"end":27,"loc":{"start":{"line":2,"column":11},"end":{"line":2,"column":12},"identifierName":"T"},
"name": "T"
}
}
]
},
"optional": true
}
}
}
]
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
f?.<string>[1];
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"sourceType": "module",
"plugins": [
"typescript"
],
"throws": "Unexpected token, expected \"(\" (1:12)"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
f?.<Q>();
f?.<Q, W>();
f
?.<Q>();
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
{
"type": "File",
"start":0,"end":33,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":8}},
"program": {
"type": "Program",
"start":0,"end":33,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":8}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":9,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":9}},
"expression": {
"type": "OptionalCallExpression",
"start":0,"end":8,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":8}},
"callee": {
"type": "Identifier",
"start":0,"end":1,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":1},"identifierName":"f"},
"name": "f"
},
"arguments": [],
"typeParameters": {
"type": "TSTypeParameterInstantiation",
"start":3,"end":6,"loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":6}},
"params": [
{
"type": "TSTypeReference",
"start":4,"end":5,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5}},
"typeName": {
"type": "Identifier",
"start":4,"end":5,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":5},"identifierName":"Q"},
"name": "Q"
}
}
]
},
"optional": true
}
},
{
"type": "ExpressionStatement",
"start":10,"end":22,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":12}},
"expression": {
"type": "OptionalCallExpression",
"start":10,"end":21,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":11}},
"callee": {
"type": "Identifier",
"start":10,"end":11,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":1},"identifierName":"f"},
"name": "f"
},
"arguments": [],
"typeParameters": {
"type": "TSTypeParameterInstantiation",
"start":13,"end":19,"loc":{"start":{"line":2,"column":3},"end":{"line":2,"column":9}},
"params": [
{
"type": "TSTypeReference",
"start":14,"end":15,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":5}},
"typeName": {
"type": "Identifier",
"start":14,"end":15,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":5},"identifierName":"Q"},
"name": "Q"
}
},
{
"type": "TSTypeReference",
"start":17,"end":18,"loc":{"start":{"line":2,"column":7},"end":{"line":2,"column":8}},
"typeName": {
"type": "Identifier",
"start":17,"end":18,"loc":{"start":{"line":2,"column":7},"end":{"line":2,"column":8},"identifierName":"W"},
"name": "W"
}
}
]
},
"optional": true
}
},
{
"type": "ExpressionStatement",
"start":23,"end":33,"loc":{"start":{"line":3,"column":0},"end":{"line":4,"column":8}},
"expression": {
"type": "OptionalCallExpression",
"start":23,"end":32,"loc":{"start":{"line":3,"column":0},"end":{"line":4,"column":7}},
"callee": {
"type": "Identifier",
"start":23,"end":24,"loc":{"start":{"line":3,"column":0},"end":{"line":3,"column":1},"identifierName":"f"},
"name": "f"
},
"arguments": [],
"typeParameters": {
"type": "TSTypeParameterInstantiation",
"start":27,"end":30,"loc":{"start":{"line":4,"column":2},"end":{"line":4,"column":5}},
"params": [
{
"type": "TSTypeReference",
"start":28,"end":29,"loc":{"start":{"line":4,"column":3},"end":{"line":4,"column":4}},
"typeName": {
"type": "Identifier",
"start":28,"end":29,"loc":{"start":{"line":4,"column":3},"end":{"line":4,"column":4},"identifierName":"Q"},
"name": "Q"
}
}
]
},
"optional": true
}
}
],
"directives": []
}
}
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
x?.f<T>();
x?.f<T>();
x?.f?.<T>();
f?.<Q>();
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
x?.f();
x?.f();
x?.f?.();
f?.();

0 comments on commit 0671afc

Please sign in to comment.