Skip to content

Commit

Permalink
fix #2375: avoid bad es5 error when backtracking
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Jul 10, 2022
1 parent 580ad40 commit a2789bf
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 2 deletions.
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,32 @@

## Unreleased

* Fix an incorrect error in TypeScript when targeting ES5 ([#2375](https://github.com/evanw/esbuild/issues/2375))

Previously when compiling TypeScript code to ES5, esbuild could incorrectly consider the following syntax forms as a transformation error:

```ts
0 ? ([]) : 1 ? ({}) : 2;
```

The error messages looked like this:

```
✘ [ERROR] Transforming destructuring to the configured target environment ("es5") is not supported yet

example.ts:1:5:
1 │ 0 ? ([]) : 1 ? ({}) : 2;
╵ ^

✘ [ERROR] Transforming destructuring to the configured target environment ("es5") is not supported yet

example.ts:1:16:
1 │ 0 ? ([]) : 1 ? ({}) : 2;
╵ ^
```

These parenthesized literals followed by a colon look like the start of an arrow function expression followed by a TypeScript return type (e.g. `([]) : 1` could be the start of the TypeScript arrow function `([]): 1 => 1`). Unlike in JavaScript, parsing arrow functions in TypeScript requires backtracking. In this case esbuild correctly determined that this expression wasn't an arrow function after all but the check for destructuring was incorrectly not covered under the backtracking process. With this release, the error message is now only reported if the parser successfully parses an arrow function without backtracking.

* Fix generated TypeScript `enum` comments containing `*/` ([#2369](https://github.com/evanw/esbuild/issues/2369), [#2371](https://github.com/evanw/esbuild/pull/2371))

TypeScript `enum` values that are equal to a number or string literal are inlined (references to the enum are replaced with the literal value) and have a `/* ... */` comment after them with the original enum name to improve readability. However, this comment is omitted if the enum name contains the character sequence `*/` because that would end the comment early and cause a syntax error:
Expand Down
6 changes: 4 additions & 2 deletions internal/js_parser/js_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2808,7 +2808,8 @@ func (p *parser) convertExprToBinding(expr js_ast.Expr, invalidLog invalidLog) (
if e.CommaAfterSpread.Start != 0 {
invalidLog.invalidTokens = append(invalidLog.invalidTokens, logger.Range{Loc: e.CommaAfterSpread, Len: 1})
}
p.markSyntaxFeature(compat.Destructuring, p.source.RangeOfOperatorAfter(expr.Loc, "["))
invalidLog.syntaxFeatures = append(invalidLog.syntaxFeatures,
syntaxFeature{feature: compat.Destructuring, token: p.source.RangeOfOperatorAfter(expr.Loc, "[")})
items := []js_ast.ArrayBinding{}
isSpread := false
for _, item := range e.Items {
Expand All @@ -2833,7 +2834,8 @@ func (p *parser) convertExprToBinding(expr js_ast.Expr, invalidLog invalidLog) (
if e.CommaAfterSpread.Start != 0 {
invalidLog.invalidTokens = append(invalidLog.invalidTokens, logger.Range{Loc: e.CommaAfterSpread, Len: 1})
}
p.markSyntaxFeature(compat.Destructuring, p.source.RangeOfOperatorAfter(expr.Loc, "{"))
invalidLog.syntaxFeatures = append(invalidLog.syntaxFeatures,
syntaxFeature{feature: compat.Destructuring, token: p.source.RangeOfOperatorAfter(expr.Loc, "{")})
properties := []js_ast.PropertyBinding{}
for _, item := range e.Properties {
if item.Flags.Has(js_ast.PropertyIsMethod) || item.Kind == js_ast.PropertyGet || item.Kind == js_ast.PropertySet {
Expand Down
15 changes: 15 additions & 0 deletions internal/js_parser/ts_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2380,3 +2380,18 @@ func TestMangleTSStringEnumLength(t *testing.T) {
expectPrintedMangleTS(t, "enum x { y = '👯‍♂️' } z = x.y.length",
"var x = /* @__PURE__ */ ((x) => (x.y = \"👯‍♂️\", x))(x || {});\nz = 5;\n")
}

func TestTSES5(t *testing.T) {
// Errors from lowering hypothetical arrow function arguments to ES5 should
// not leak out when backtracking. This comes up when parentheses are followed
// by a colon in TypeScript because the colon could deliminate an arrow
// function return type. See: https://github.com/evanw/esbuild/issues/2375.
expectPrintedTargetTS(t, 2015, "0 ? ([]) : 0", "0 ? [] : 0;\n")
expectPrintedTargetTS(t, 2015, "0 ? ({}) : 0", "0 ? {} : 0;\n")
expectPrintedTargetTS(t, 5, "0 ? ([]) : 0", "0 ? [] : 0;\n")
expectPrintedTargetTS(t, 5, "0 ? ({}) : 0", "0 ? {} : 0;\n")
expectPrintedTargetTS(t, 2015, "0 ? ([]): 0 => 0 : 0", "0 ? ([]) => 0 : 0;\n")
expectPrintedTargetTS(t, 2015, "0 ? ({}): 0 => 0 : 0", "0 ? ({}) => 0 : 0;\n")
expectParseErrorTargetTS(t, 5, "0 ? ([]): 0 => 0 : 0", "<stdin>: ERROR: Transforming destructuring to the configured target environment is not supported yet\n")
expectParseErrorTargetTS(t, 5, "0 ? ({}): 0 => 0 : 0", "<stdin>: ERROR: Transforming destructuring to the configured target environment is not supported yet\n")
}

0 comments on commit a2789bf

Please sign in to comment.