Skip to content

Commit

Permalink
fix #1016: parse issue with ts arrow return types
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Mar 20, 2021
1 parent 3c3a299 commit 512eb19
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 1 deletion.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## Unreleased

* Fix a TypeScript parsing edge case with arrow function return types ([#1016](https://github.com/evanw/esbuild/issues/1016))

This release fixes the following TypeScript parsing edge case:

```ts
():Array<number>=>{return [1]}
```

This was tripping up esbuild's TypeScript parser because the `>=` token was split into a `>` token and a `=` token because the `>` token is needed to close the type parameter list, but the `=` token was not being combined with the following `>` token to form a `=>` token. This is normally not an issue because there is normally a space in between the `>` and the `=>` tokens here. The issue only happened when the spaces were removed. This bug has been fixed. Now after the `>=` token is split, esbuild will expand the `=` token into the following characters if possible, which can result in a `=>`, `==`, or `===` token.

## 0.9.5

* Fix parsing of the `[dir]` placeholder ([#1013](https://github.com/evanw/esbuild/issues/1013))
Expand Down
22 changes: 22 additions & 0 deletions internal/js_lexer/js_lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ func (lexer *Lexer) ExpectLessThan(isInsideJSXElement bool) {
case TLessThanEquals:
lexer.Token = TEquals
lexer.start++
lexer.maybeExpandEquals()

case TLessThanLessThan:
lexer.Token = TLessThan
Expand Down Expand Up @@ -466,6 +467,7 @@ func (lexer *Lexer) ExpectGreaterThan(isInsideJSXElement bool) {
case TGreaterThanEquals:
lexer.Token = TEquals
lexer.start++
lexer.maybeExpandEquals()

case TGreaterThanGreaterThan:
lexer.Token = TGreaterThan
Expand All @@ -488,6 +490,26 @@ func (lexer *Lexer) ExpectGreaterThan(isInsideJSXElement bool) {
}
}

func (lexer *Lexer) maybeExpandEquals() {
switch lexer.codePoint {
case '>':
// "=" + ">" = "=>"
lexer.Token = TEqualsGreaterThan
lexer.step()

case '=':
// "=" + "=" = "=="
lexer.Token = TEqualsEquals
lexer.step()

if lexer.Token == '=' {
// "=" + "==" = "==="
lexer.Token = TEqualsEqualsEquals
lexer.step()
}
}
}

func IsIdentifier(text string) bool {
if len(text) == 0 {
return false
Expand Down
6 changes: 5 additions & 1 deletion internal/js_parser/ts_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ func TestTSTypes(t *testing.T) {
expectPrintedTS(t, "let x: A.B<X.Y<Z<T>>>", "let x;\n")
expectPrintedTS(t, "let x: A.B<X.Y<Z<T>>>=2", "let x = 2;\n")

expectPrintedTS(t, "(): A<T>=> 0", "() => 0;\n")
expectPrintedTS(t, "(): A<B<T>>=> 0", "() => 0;\n")
expectPrintedTS(t, "(): A<B<C<T>>>=> 0", "() => 0;\n")

expectPrintedTS(t, "let foo: any\n<x>y", "let foo;\ny;\n")
expectPrintedTSX(t, "let foo: any\n<x>y</x>", "let foo;\n/* @__PURE__ */ React.createElement(\"x\", null, \"y\");\n")
expectParseErrorTS(t, "let foo: (any\n<x>y)", "<stdin>: error: Expected \")\" but found \"<\"\n")
Expand Down Expand Up @@ -1472,7 +1476,7 @@ func TestTSJSX(t *testing.T) {

expectPrintedTSX(t, "const x = <Foo<T>></Foo>", "const x = /* @__PURE__ */ React.createElement(Foo, null);\n")
expectPrintedTSX(t, "const x = <Foo<T> data-foo></Foo>", "const x = /* @__PURE__ */ React.createElement(Foo, {\n \"data-foo\": true\n});\n")
expectParseErrorTSX(t, "const x = <Foo<T>=>", "<stdin>: error: Expected \">\" but found \"=\"\n")
expectParseErrorTSX(t, "const x = <Foo<T>=>", "<stdin>: error: Expected \">\" but found \"=>\"\n")

expectPrintedTS(t, "const x = <T>() => {}", "const x = () => {\n};\n")
expectPrintedTS(t, "const x = <T>(y)", "const x = y;\n")
Expand Down

0 comments on commit 512eb19

Please sign in to comment.