[ts] support optional chain call with generic (#13513)
* 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>
This commit is contained in:
parent
d5b0d9e33d
commit
0671afcf87
@ -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.
|
||||
@ -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)
|
||||
@ -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(
|
||||
@ -2137,6 +2157,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
||||
this.unexpected();
|
||||
});
|
||||
|
||||
if (missingParenErrorPos) {
|
||||
this.unexpected(missingParenErrorPos, tt.parenL);
|
||||
}
|
||||
|
||||
if (result) return result;
|
||||
}
|
||||
|
||||
|
||||
@ -1 +1,2 @@
|
||||
foo?.foo<T>();
|
||||
foo?.foo?.<T>();
|
||||
|
||||
@ -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": [
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -0,0 +1 @@
|
||||
f?.<string>[1];
|
||||
@ -0,0 +1,7 @@
|
||||
{
|
||||
"sourceType": "module",
|
||||
"plugins": [
|
||||
"typescript"
|
||||
],
|
||||
"throws": "Unexpected token, expected \"(\" (1:12)"
|
||||
}
|
||||
4
packages/babel-parser/test/fixtures/typescript/type-arguments/call-optional-chain/input.ts
vendored
Normal file
4
packages/babel-parser/test/fixtures/typescript/type-arguments/call-optional-chain/input.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
f?.<Q>();
|
||||
f?.<Q, W>();
|
||||
f
|
||||
?.<Q>();
|
||||
112
packages/babel-parser/test/fixtures/typescript/type-arguments/call-optional-chain/output.json
vendored
Normal file
112
packages/babel-parser/test/fixtures/typescript/type-arguments/call-optional-chain/output.json
vendored
Normal file
@ -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": []
|
||||
}
|
||||
}
|
||||
@ -1 +1,3 @@
|
||||
x?.f<T>();
|
||||
x?.f?.<T>();
|
||||
f?.<Q>();
|
||||
|
||||
@ -1 +1,3 @@
|
||||
x?.f();
|
||||
x?.f?.();
|
||||
f?.();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user