Skip to content

Commit

Permalink
[ts] Allow ...<...> followed by newline or binary operator
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Jun 10, 2022
1 parent a5dacd9 commit 2d85950
Show file tree
Hide file tree
Showing 11 changed files with 958 additions and 60 deletions.
32 changes: 12 additions & 20 deletions packages/babel-parser/src/plugins/typescript/index.js
Expand Up @@ -13,7 +13,6 @@ import {
type TokenType,
tokenIsTemplate,
tokenCanStartExpression,
tokenIsBinaryOperator,
} from "../../tokenizer/types";
import { types as tc } from "../../tokenizer/context";
import * as N from "../../types";
Expand Down Expand Up @@ -66,12 +65,6 @@ function assert(x: boolean): void {
}
}

function tsTokenCanStartExpression(token: TokenType) {
// tsc considers binary operators as "can start expression" tokens:
// https://github.com/microsoft/TypeScript/blob/eca1b4/src/compiler/parser.ts#L4260-L4266
return tokenCanStartExpression(token) || tokenIsBinaryOperator(token);
}

type ParsingContext =
| "EnumMembers"
| "HeritageClauseElement"
Expand Down Expand Up @@ -2429,11 +2422,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}

const typeArguments = this.tsParseTypeArgumentsInExpression();
if (!typeArguments) throw this.unexpected();
if (!typeArguments) return;

if (isOptionalCall && !this.match(tt.parenL)) {
missingParenErrorLoc = this.state.curPosition();
throw this.unexpected();
return;
}

if (tokenIsTemplate(this.state.type)) {
Expand Down Expand Up @@ -2469,19 +2462,18 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.finishCallExpression(node, state.optionalChainMember);
}

// TODO: This doesn't exactly match what TS does when it comes to ASI.
// For example,
// a<b>
// if (0);
// is not valid TS code (https://github.com/microsoft/TypeScript/issues/48654)
// However, it should correctly parse anything that is correctly parsed by TS.
const tokenType = this.state.type;
if (
tsTokenCanStartExpression(this.state.type) &&
this.state.type !== tt.parenL
// a<b>>c is not (a<b>)>c, but a<(b>>c)
tokenType === tt.gt ||
// a<b>c is (a<b)>c
(tokenType !== tt.parenL &&
tokenCanStartExpression(tokenType) &&
!this.hasPrecedingLineBreak())
) {
// Bail out. We have something like a<b>c, which is not an expression with
// type arguments but an (a < b) > c comparison.
throw this.unexpected();
// Bail out. a<b>... is not an expression with
// type arguments but an (a < b) > ... comparison.
return;
}

const node: N.TsInstantiationExpression = this.startNodeAt(
Expand Down
@@ -0,0 +1,40 @@
const x5 = f<true>
let yy = 0;

const x6 = f<true>
interface I {}

let x10 = f<true>
this.bar()

let x11 = f<true>
function bar() {}

let x12 = f<true>
class C {}

let x13 = f<true>
bar()

let x14 = f<true>
void bar()

class C1 {
static specialFoo = f<string>
static bar = 123
}

class C2 {
public specialFoo = f<string>
public bar = 123
}

class C3 {
private specialFoo = f<string>
private bar = 123
}

class C4 {
protected specialFoo = f<string>
protected bar = 123
}

0 comments on commit 2d85950

Please sign in to comment.