From 40711afe0baa545012b813c5c7788225be9ef74c Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Mon, 19 Feb 2024 13:04:55 -0800 Subject: [PATCH] fix #3657: empty enum returns `{}` not `undefined` --- CHANGELOG.md | 20 ++++++++++++++++++++ internal/js_parser/ts_parser.go | 22 ++++++++++------------ internal/js_parser/ts_parser_test.go | 2 +- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e757ddfec3e..1937d12ad87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## Unreleased + +* Empty enums should behave like an object literal ([#3657](https://github.com/evanw/esbuild/issues/3657)) + + TypeScript allows you to create an empty enum and add properties to it at run time. While people usually use an empty object literal for this instead of a TypeScript enum, esbuild's enum transform didn't anticipate this use case and generated `undefined` instead of `{}` for an empty enum. With this release, you can now use an empty enum to generate an empty object literal. + + ```ts + // Original code + enum Foo {} + + // Old output (with --loader=ts) + var Foo = /* @__PURE__ */ ((Foo2) => { + })(Foo || {}); + + // New output (with --loader=ts) + var Foo = /* @__PURE__ */ ((Foo2) => { + return Foo2; + })(Foo || {}); + ``` + ## 0.20.1 * Fix a bug with the CSS nesting transform ([#3648](https://github.com/evanw/esbuild/issues/3648)) diff --git a/internal/js_parser/ts_parser.go b/internal/js_parser/ts_parser.go index 918437bd601..6338fa09a9a 100644 --- a/internal/js_parser/ts_parser.go +++ b/internal/js_parser/ts_parser.go @@ -1930,19 +1930,17 @@ func (p *parser) generateClosureForTypeScriptEnum( // Generate the body of the closure, including a return statement at the end stmtsInsideClosure := []js_ast.Stmt{} - if len(exprsInsideClosure) > 0 { - argExpr := js_ast.Expr{Loc: nameLoc, Data: &js_ast.EIdentifier{Ref: argRef}} - if p.options.minifySyntax { - // "a; b; return c;" => "return a, b, c;" - joined := js_ast.JoinAllWithComma(exprsInsideClosure) - joined = js_ast.JoinWithComma(joined, argExpr) - stmtsInsideClosure = append(stmtsInsideClosure, js_ast.Stmt{Loc: joined.Loc, Data: &js_ast.SReturn{ValueOrNil: joined}}) - } else { - for _, expr := range exprsInsideClosure { - stmtsInsideClosure = append(stmtsInsideClosure, js_ast.Stmt{Loc: expr.Loc, Data: &js_ast.SExpr{Value: expr}}) - } - stmtsInsideClosure = append(stmtsInsideClosure, js_ast.Stmt{Loc: argExpr.Loc, Data: &js_ast.SReturn{ValueOrNil: argExpr}}) + argExpr := js_ast.Expr{Loc: nameLoc, Data: &js_ast.EIdentifier{Ref: argRef}} + if p.options.minifySyntax { + // "a; b; return c;" => "return a, b, c;" + joined := js_ast.JoinAllWithComma(exprsInsideClosure) + joined = js_ast.JoinWithComma(joined, argExpr) + stmtsInsideClosure = append(stmtsInsideClosure, js_ast.Stmt{Loc: joined.Loc, Data: &js_ast.SReturn{ValueOrNil: joined}}) + } else { + for _, expr := range exprsInsideClosure { + stmtsInsideClosure = append(stmtsInsideClosure, js_ast.Stmt{Loc: expr.Loc, Data: &js_ast.SExpr{Value: expr}}) } + stmtsInsideClosure = append(stmtsInsideClosure, js_ast.Stmt{Loc: argExpr.Loc, Data: &js_ast.SReturn{ValueOrNil: argExpr}}) } // Try to use an arrow function if possible for compactness diff --git a/internal/js_parser/ts_parser_test.go b/internal/js_parser/ts_parser_test.go index 7660e23dcb3..41058a352fb 100644 --- a/internal/js_parser/ts_parser_test.go +++ b/internal/js_parser/ts_parser_test.go @@ -1804,7 +1804,7 @@ func TestTSDeclare(t *testing.T) { expectPrintedTS(t, "declare\nconst foo = 0", "declare;\nconst foo = 0;\n") expectPrintedTS(t, "declare\nfunction foo() {}", "declare;\nfunction foo() {\n}\n") expectPrintedTS(t, "declare\nclass Foo {}", "declare;\nclass Foo {\n}\n") - expectPrintedTS(t, "declare\nenum Foo {}", "declare;\nvar Foo = /* @__PURE__ */ ((Foo) => {\n})(Foo || {});\n") + expectPrintedTS(t, "declare\nenum Foo {}", "declare;\nvar Foo = /* @__PURE__ */ ((Foo) => {\n return Foo;\n})(Foo || {});\n") expectPrintedTS(t, "class Foo { declare \n foo }", "class Foo {\n declare;\n foo;\n}\n") expectPrintedTS(t, "declare;", "declare;\n")