diff --git a/CHANGELOG.md b/CHANGELOG.md index 00a6dcc97ad..74eede07daf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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: diff --git a/internal/js_parser/js_parser.go b/internal/js_parser/js_parser.go index 18e6c7e149c..4a660c05849 100644 --- a/internal/js_parser/js_parser.go +++ b/internal/js_parser/js_parser.go @@ -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 { @@ -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 { diff --git a/internal/js_parser/ts_parser_test.go b/internal/js_parser/ts_parser_test.go index 079f949aa7f..735f7f6bf13 100644 --- a/internal/js_parser/ts_parser_test.go +++ b/internal/js_parser/ts_parser_test.go @@ -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", ": ERROR: Transforming destructuring to the configured target environment is not supported yet\n") + expectParseErrorTargetTS(t, 5, "0 ? ({}): 0 => 0 : 0", ": ERROR: Transforming destructuring to the configured target environment is not supported yet\n") +}