diff --git a/CHANGELOG.md b/CHANGELOG.md index 2892b953680..ca6b44bd175 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,10 @@ Accessing layout-related properties can trigger a layout and accessing storage-related properties can throw an exception if certain privacy settings are enabled. Both of these behaviors are considered side effects. +* Fix a TypeScript parser regression ([#846](https://github.com/evanw/esbuild/issues/846)) + + Restrictions on array and object destructuring patterns in the previous release introduced a regression where arrays or objects in TypeScript code could fail to parse if they were wrapped in a double layer of parentheses. This was due to the speculative parsing of arrow function arguments. The regression has been fixed. + ## 0.8.48 * Fix some parsing edge cases ([#835](https://github.com/evanw/esbuild/issues/835)) diff --git a/internal/js_parser/js_parser.go b/internal/js_parser/js_parser.go index 515915f6976..83c6e4d98b1 100644 --- a/internal/js_parser/js_parser.go +++ b/internal/js_parser/js_parser.go @@ -2402,6 +2402,10 @@ func (p *parser) convertExprToBindingAndInitializer(expr js_ast.Expr, invalidLog return binding, initializer, invalidLog } +// Note: do not write to "p.log" in this function. Any errors due to conversion +// from expression to binding should be written to "invalidLog" instead. That +// way we can potentially keep this as an expression if it turns out it's not +// needed as a binding after all. func (p *parser) convertExprToBinding(expr js_ast.Expr, invalidLog []logger.Loc) (js_ast.Binding, []logger.Loc) { switch e := expr.Data.(type) { case *js_ast.EMissing: @@ -2412,10 +2416,10 @@ func (p *parser) convertExprToBinding(expr js_ast.Expr, invalidLog []logger.Loc) case *js_ast.EArray: if e.CommaAfterSpread.Start != 0 { - p.log.AddRangeError(&p.source, logger.Range{Loc: e.CommaAfterSpread, Len: 1}, "Unexpected \",\" after rest pattern") + invalidLog = append(invalidLog, e.CommaAfterSpread) } if e.IsParenthesized { - p.log.AddRangeError(&p.source, p.source.RangeOfOperatorBefore(expr.Loc, "("), "Unexpected \"(\" before array pattern") + invalidLog = append(invalidLog, p.source.RangeOfOperatorBefore(expr.Loc, "(").Loc) } p.markSyntaxFeature(compat.Destructuring, p.source.RangeOfOperatorAfter(expr.Loc, "[")) items := []js_ast.ArrayBinding{} @@ -2440,10 +2444,10 @@ func (p *parser) convertExprToBinding(expr js_ast.Expr, invalidLog []logger.Loc) case *js_ast.EObject: if e.CommaAfterSpread.Start != 0 { - p.log.AddRangeError(&p.source, logger.Range{Loc: e.CommaAfterSpread, Len: 1}, "Unexpected \",\" after rest pattern") + invalidLog = append(invalidLog, e.CommaAfterSpread) } if e.IsParenthesized { - p.log.AddRangeError(&p.source, p.source.RangeOfOperatorBefore(expr.Loc, "("), "Unexpected \"(\" before object pattern") + invalidLog = append(invalidLog, p.source.RangeOfOperatorBefore(expr.Loc, "(").Loc) } p.markSyntaxFeature(compat.Destructuring, p.source.RangeOfOperatorAfter(expr.Loc, "{")) properties := []js_ast.PropertyBinding{} diff --git a/internal/js_parser/js_parser_test.go b/internal/js_parser/js_parser_test.go index cab2fcbba57..27eff1b06cf 100644 --- a/internal/js_parser/js_parser_test.go +++ b/internal/js_parser/js_parser_test.go @@ -525,8 +525,8 @@ func TestDecls(t *testing.T) { expectParseError(t, "var [...x,] = []", ": error: Unexpected \",\" after rest pattern\n") expectParseError(t, "var {...x,} = {}", ": error: Unexpected \",\" after rest pattern\n") - expectParseError(t, "([...x,] = []) => {}", ": error: Unexpected \",\" after rest pattern\n") - expectParseError(t, "({...x,} = {}) => {}", ": error: Unexpected \",\" after rest pattern\n") + expectParseError(t, "([...x,] = []) => {}", ": error: Invalid binding pattern\n") + expectParseError(t, "({...x,} = {}) => {}", ": error: Invalid binding pattern\n") expectPrinted(t, "[b, ...c] = d", "[b, ...c] = d;\n") expectPrinted(t, "([b, ...c] = d)", "[b, ...c] = d;\n") @@ -554,8 +554,8 @@ func TestDecls(t *testing.T) { expectParseError(t, "({}) = {}", ": error: Invalid assignment target\n") expectParseError(t, "[([])] = [[]]", ": error: Invalid assignment target\n") expectParseError(t, "({x: ({})} = {x: {}})", ": error: Invalid assignment target\n") - expectParseError(t, "(([]) = []) => {}", ": error: Unexpected \"(\" before array pattern\n") - expectParseError(t, "(({}) = {}) => {}", ": error: Unexpected \"(\" before object pattern\n") + expectParseError(t, "(([]) = []) => {}", ": error: Invalid binding pattern\n") + expectParseError(t, "(({}) = {}) => {}", ": error: Invalid binding pattern\n") expectParseError(t, "function f(([]) = []) {}", ": error: Expected identifier but found \"(\"\n") expectParseError(t, "function f(({}) = {}) {}", ": error: Expected identifier but found \"(\"\n") diff --git a/internal/js_parser/ts_parser_test.go b/internal/js_parser/ts_parser_test.go index 1e342054204..c0cf0ce41ce 100644 --- a/internal/js_parser/ts_parser_test.go +++ b/internal/js_parser/ts_parser_test.go @@ -1080,6 +1080,15 @@ func TestTSDecl(t *testing.T) { expectParseErrorTS(t, "var a!", ": error: Expected \":\" but found end of file\n") expectParseErrorTS(t, "var a! = ", ": error: Expected \":\" but found \"=\"\n") expectParseErrorTS(t, "var a!, b", ": error: Expected \":\" but found \",\"\n") + + expectPrinted(t, "a ? ({b}) => {} : c", "a ? ({b}) => {\n} : c;\n") + expectPrinted(t, "a ? (({b}) => {}) : c", "a ? ({b}) => {\n} : c;\n") + expectPrinted(t, "a ? (({b})) : c", "a ? {b} : c;\n") + expectParseError(t, "a ? (({b})) => {} : c", ": error: Invalid binding pattern\n") + expectPrintedTS(t, "a ? ({b}) => {} : c", "a ? ({b}) => {\n} : c;\n") + expectPrintedTS(t, "a ? (({b}) => {}) : c", "a ? ({b}) => {\n} : c;\n") + expectPrintedTS(t, "a ? (({b})) : c", "a ? {b} : c;\n") + expectParseErrorTS(t, "a ? (({b})) => {} : c", ": error: Invalid binding pattern\n") } func TestTSDeclare(t *testing.T) {