Skip to content

Commit

Permalink
Allow keywords in TS qualified types (#14362)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Mar 16, 2022
1 parent dacaab1 commit 01380a6
Show file tree
Hide file tree
Showing 8 changed files with 270 additions and 61 deletions.
47 changes: 10 additions & 37 deletions packages/babel-parser/src/plugins/typescript/index.js
Expand Up @@ -560,44 +560,28 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (this.eat(tt.dot)) {
// In this instance, the entity name will actually itself be a
// qualifier, so allow it to be a reserved word as well.
node.qualifier = this.tsParseEntityName({
allowReservedEntityName: true,
allowReservedQualifiers: true,
});
node.qualifier = this.tsParseEntityName();
}
if (this.match(tt.lt)) {
node.typeParameters = this.tsParseTypeArguments();
}
return this.finishNode(node, "TSImportType");
}

tsParseEntityName({
allowReservedEntityName,
allowReservedQualifiers,
}: {
allowReservedEntityName: TokenType | boolean,
allowReservedQualifiers: boolean,
}): N.TsEntityName {
let entity: N.TsEntityName = this.parseIdentifier(
allowReservedEntityName === true ||
(allowReservedEntityName !== false &&
this.match(allowReservedEntityName)),
);
tsParseEntityName(allowReservedWords: boolean = true): N.TsEntityName {
let entity: N.TsEntityName = this.parseIdentifier(allowReservedWords);
while (this.eat(tt.dot)) {
const node: N.TsQualifiedName = this.startNodeAtNode(entity);
node.left = entity;
node.right = this.parseIdentifier(allowReservedQualifiers);
node.right = this.parseIdentifier(allowReservedWords);
entity = this.finishNode(node, "TSQualifiedName");
}
return entity;
}

tsParseTypeReference(allowConst: boolean = false): N.TsTypeReference {
tsParseTypeReference(): N.TsTypeReference {
const node: N.TsTypeReference = this.startNode();
node.typeName = this.tsParseEntityName({
allowReservedEntityName: allowConst && tt._const,
allowReservedQualifiers: true,
});
node.typeName = this.tsParseEntityName();
if (!this.hasPrecedingLineBreak() && this.match(tt.lt)) {
node.typeParameters = this.tsParseTypeArguments();
}
Expand Down Expand Up @@ -625,10 +609,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (this.match(tt._import)) {
node.exprName = this.tsParseImportType();
} else {
node.exprName = this.tsParseEntityName({
allowReservedEntityName: false,
allowReservedQualifiers: true,
});
node.exprName = this.tsParseEntityName();
}
return this.finishNode(node, "TSTypeQuery");
}
Expand Down Expand Up @@ -678,7 +659,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (this.lookahead().type !== tt._const) return null;

this.next();
const typeReference = this.tsParseTypeReference(/* allowConst */ true);
const typeReference = this.tsParseTypeReference();

// If the type reference has type parameters, then you are using it as a
// type and not as a const signifier. We'll *never* be able to find this
Expand Down Expand Up @@ -1595,12 +1576,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>

tsParseExpressionWithTypeArguments(): N.TsExpressionWithTypeArguments {
const node: N.TsExpressionWithTypeArguments = this.startNode();
// Note: TS uses parseLeftHandSideExpressionOrHigher,
// then has grammar errors later if it's not an EntityName.
node.expression = this.tsParseEntityName({
allowReservedEntityName: false,
allowReservedQualifiers: false,
});
node.expression = this.tsParseEntityName();
if (this.match(tt.lt)) {
node.typeParameters = this.tsParseTypeArguments();
}
Expand Down Expand Up @@ -1833,10 +1809,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
tsParseModuleReference(): N.TsModuleReference {
return this.tsIsExternalModuleReference()
? this.tsParseExternalModuleReference()
: this.tsParseEntityName({
allowReservedEntityName: false,
allowReservedQualifiers: false,
});
: this.tsParseEntityName(/* allowReservedWords */ false);
}

tsParseExternalModuleReference(): N.TsExternalModuleReference {
Expand Down
@@ -0,0 +1,4 @@
// These are valid TypeScript syntax (the parser doesn't produce any error),
// but they are always type-checking errors.
interface A extends this.B {}
type T = typeof var.bar;
@@ -0,0 +1,98 @@
{
"type": "File",
"start":0,"end":176,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":24,"index":176}},
"program": {
"type": "Program",
"start":0,"end":176,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":4,"column":24,"index":176}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "TSInterfaceDeclaration",
"start":122,"end":151,"loc":{"start":{"line":3,"column":0,"index":122},"end":{"line":3,"column":29,"index":151}},
"id": {
"type": "Identifier",
"start":132,"end":133,"loc":{"start":{"line":3,"column":10,"index":132},"end":{"line":3,"column":11,"index":133},"identifierName":"A"},
"name": "A"
},
"extends": [
{
"type": "TSExpressionWithTypeArguments",
"start":142,"end":148,"loc":{"start":{"line":3,"column":20,"index":142},"end":{"line":3,"column":26,"index":148}},
"expression": {
"type": "TSQualifiedName",
"start":142,"end":148,"loc":{"start":{"line":3,"column":20,"index":142},"end":{"line":3,"column":26,"index":148}},
"left": {
"type": "Identifier",
"start":142,"end":146,"loc":{"start":{"line":3,"column":20,"index":142},"end":{"line":3,"column":24,"index":146},"identifierName":"this"},
"name": "this"
},
"right": {
"type": "Identifier",
"start":147,"end":148,"loc":{"start":{"line":3,"column":25,"index":147},"end":{"line":3,"column":26,"index":148},"identifierName":"B"},
"name": "B"
}
}
}
],
"body": {
"type": "TSInterfaceBody",
"start":149,"end":151,"loc":{"start":{"line":3,"column":27,"index":149},"end":{"line":3,"column":29,"index":151}},
"body": []
},
"leadingComments": [
{
"type": "CommentLine",
"value": " These are valid TypeScript syntax (the parser doesn't produce any error),",
"start":0,"end":76,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":76,"index":76}}
},
{
"type": "CommentLine",
"value": " but they are always type-checking errors.",
"start":77,"end":121,"loc":{"start":{"line":2,"column":0,"index":77},"end":{"line":2,"column":44,"index":121}}
}
]
},
{
"type": "TSTypeAliasDeclaration",
"start":152,"end":176,"loc":{"start":{"line":4,"column":0,"index":152},"end":{"line":4,"column":24,"index":176}},
"id": {
"type": "Identifier",
"start":157,"end":158,"loc":{"start":{"line":4,"column":5,"index":157},"end":{"line":4,"column":6,"index":158},"identifierName":"T"},
"name": "T"
},
"typeAnnotation": {
"type": "TSTypeQuery",
"start":161,"end":175,"loc":{"start":{"line":4,"column":9,"index":161},"end":{"line":4,"column":23,"index":175}},
"exprName": {
"type": "TSQualifiedName",
"start":168,"end":175,"loc":{"start":{"line":4,"column":16,"index":168},"end":{"line":4,"column":23,"index":175}},
"left": {
"type": "Identifier",
"start":168,"end":171,"loc":{"start":{"line":4,"column":16,"index":168},"end":{"line":4,"column":19,"index":171},"identifierName":"var"},
"name": "var"
},
"right": {
"type": "Identifier",
"start":172,"end":175,"loc":{"start":{"line":4,"column":20,"index":172},"end":{"line":4,"column":23,"index":175},"identifierName":"bar"},
"name": "bar"
}
}
}
}
],
"directives": []
},
"comments": [
{
"type": "CommentLine",
"value": " These are valid TypeScript syntax (the parser doesn't produce any error),",
"start":0,"end":76,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":76,"index":76}}
},
{
"type": "CommentLine",
"value": " but they are always type-checking errors.",
"start":77,"end":121,"loc":{"start":{"line":2,"column":0,"index":77},"end":{"line":2,"column":44,"index":121}}
}
]
}
@@ -0,0 +1,2 @@
import X = Y.if;
import A = this.A;
@@ -0,0 +1,67 @@
{
"type": "File",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":2,"column":18,"index":35}},
"errors": [
"SyntaxError: Unexpected keyword 'if'. (1:13)",
"SyntaxError: Unexpected keyword 'this'. (2:11)"
],
"program": {
"type": "Program",
"start":0,"end":35,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":2,"column":18,"index":35}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "TSImportEqualsDeclaration",
"start":0,"end":16,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":16,"index":16}},
"importKind": "value",
"isExport": false,
"id": {
"type": "Identifier",
"start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8},"identifierName":"X"},
"name": "X"
},
"moduleReference": {
"type": "TSQualifiedName",
"start":11,"end":15,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":15,"index":15}},
"left": {
"type": "Identifier",
"start":11,"end":12,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":12,"index":12},"identifierName":"Y"},
"name": "Y"
},
"right": {
"type": "Identifier",
"start":13,"end":15,"loc":{"start":{"line":1,"column":13,"index":13},"end":{"line":1,"column":15,"index":15},"identifierName":"if"},
"name": "if"
}
}
},
{
"type": "TSImportEqualsDeclaration",
"start":17,"end":35,"loc":{"start":{"line":2,"column":0,"index":17},"end":{"line":2,"column":18,"index":35}},
"importKind": "value",
"isExport": false,
"id": {
"type": "Identifier",
"start":24,"end":25,"loc":{"start":{"line":2,"column":7,"index":24},"end":{"line":2,"column":8,"index":25},"identifierName":"A"},
"name": "A"
},
"moduleReference": {
"type": "TSQualifiedName",
"start":28,"end":34,"loc":{"start":{"line":2,"column":11,"index":28},"end":{"line":2,"column":17,"index":34}},
"left": {
"type": "Identifier",
"start":28,"end":32,"loc":{"start":{"line":2,"column":11,"index":28},"end":{"line":2,"column":15,"index":32},"identifierName":"this"},
"name": "this"
},
"right": {
"type": "Identifier",
"start":33,"end":34,"loc":{"start":{"line":2,"column":16,"index":33},"end":{"line":2,"column":17,"index":34},"identifierName":"A"},
"name": "A"
}
}
}
],
"directives": []
}
}
@@ -0,0 +1,2 @@
interface A extends T.if {}
type T = typeof this.bar;
@@ -0,0 +1,74 @@
{
"type": "File",
"start":0,"end":53,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":2,"column":25,"index":53}},
"program": {
"type": "Program",
"start":0,"end":53,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":2,"column":25,"index":53}},
"sourceType": "module",
"interpreter": null,
"body": [
{
"type": "TSInterfaceDeclaration",
"start":0,"end":27,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":27,"index":27}},
"id": {
"type": "Identifier",
"start":10,"end":11,"loc":{"start":{"line":1,"column":10,"index":10},"end":{"line":1,"column":11,"index":11},"identifierName":"A"},
"name": "A"
},
"extends": [
{
"type": "TSExpressionWithTypeArguments",
"start":20,"end":24,"loc":{"start":{"line":1,"column":20,"index":20},"end":{"line":1,"column":24,"index":24}},
"expression": {
"type": "TSQualifiedName",
"start":20,"end":24,"loc":{"start":{"line":1,"column":20,"index":20},"end":{"line":1,"column":24,"index":24}},
"left": {
"type": "Identifier",
"start":20,"end":21,"loc":{"start":{"line":1,"column":20,"index":20},"end":{"line":1,"column":21,"index":21},"identifierName":"T"},
"name": "T"
},
"right": {
"type": "Identifier",
"start":22,"end":24,"loc":{"start":{"line":1,"column":22,"index":22},"end":{"line":1,"column":24,"index":24},"identifierName":"if"},
"name": "if"
}
}
}
],
"body": {
"type": "TSInterfaceBody",
"start":25,"end":27,"loc":{"start":{"line":1,"column":25,"index":25},"end":{"line":1,"column":27,"index":27}},
"body": []
}
},
{
"type": "TSTypeAliasDeclaration",
"start":28,"end":53,"loc":{"start":{"line":2,"column":0,"index":28},"end":{"line":2,"column":25,"index":53}},
"id": {
"type": "Identifier",
"start":33,"end":34,"loc":{"start":{"line":2,"column":5,"index":33},"end":{"line":2,"column":6,"index":34},"identifierName":"T"},
"name": "T"
},
"typeAnnotation": {
"type": "TSTypeQuery",
"start":37,"end":52,"loc":{"start":{"line":2,"column":9,"index":37},"end":{"line":2,"column":24,"index":52}},
"exprName": {
"type": "TSQualifiedName",
"start":44,"end":52,"loc":{"start":{"line":2,"column":16,"index":44},"end":{"line":2,"column":24,"index":52}},
"left": {
"type": "Identifier",
"start":44,"end":48,"loc":{"start":{"line":2,"column":16,"index":44},"end":{"line":2,"column":20,"index":48},"identifierName":"this"},
"name": "this"
},
"right": {
"type": "Identifier",
"start":49,"end":52,"loc":{"start":{"line":2,"column":21,"index":49},"end":{"line":2,"column":24,"index":52},"identifierName":"bar"},
"name": "bar"
}
}
}
}
],
"directives": []
}
}

0 comments on commit 01380a6

Please sign in to comment.