Skip to content

Commit

Permalink
fix #3322: avoid temporaries before "use strict"
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Sep 13, 2023
1 parent 900a90d commit 7ece556
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 1 deletion.
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,32 @@

Note that this bug only affected code using the `local-css` loader. It did not affect code using the `css` loader.

* Avoid inserting temporary variables before `use strict` ([#3322](https://github.com/evanw/esbuild/issues/3322))

This release fixes a bug where esbuild could incorrectly insert automatically-generated temporary variables before `use strict` directives:

```js
// Original code
function foo() {
'use strict'
a.b?.c()
}

// Old output (with --target=es6)
function foo() {
var _a;
"use strict";
(_a = a.b) == null ? void 0 : _a.c();
}

// New output (with --target=es6)
function foo() {
"use strict";
var _a;
(_a = a.b) == null ? void 0 : _a.c();
}
```
* Adjust TypeScript `enum` output to better approximate `tsc` ([#3329](https://github.com/evanw/esbuild/issues/3329))
TypeScript enum values can be either number literals or string literals. Numbers create a bidirectional mapping between the name and the value but strings only create a unidirectional mapping from the name to the value. When the enum value is neither a number literal nor a string literal, TypeScript and esbuild both default to treating it as a number:
Expand Down
18 changes: 17 additions & 1 deletion internal/js_parser/js_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -8377,7 +8377,23 @@ func (p *parser) visitStmtsAndPrependTempRefs(stmts []js_ast.Stmt, opts prependT
}
}
if len(decls) > 0 {
stmts = append([]js_ast.Stmt{{Data: &js_ast.SLocal{Kind: js_ast.LocalVar, Decls: decls}}}, stmts...)
// Skip past leading directives and comments
split := 0
for split < len(stmts) {
switch stmts[split].Data.(type) {
case *js_ast.SComment, *js_ast.SDirective:
split++
continue
}
break
}
stmts = append(
append(
append(
[]js_ast.Stmt{},
stmts[:split]...),
js_ast.Stmt{Data: &js_ast.SLocal{Kind: js_ast.LocalVar, Decls: decls}}),
stmts[split:]...)
}

p.tempRefsToDeclare = oldTempRefs
Expand Down
12 changes: 12 additions & 0 deletions internal/js_parser/js_parser_lower_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ func TestLowerNullishCoalescing(t *testing.T) {
"function foo() {\n var _a, _b;\n if (x) {\n (_b = (_a = a()) != null ? _a : b()) != null ? _b : c();\n }\n}\n")
expectPrintedTarget(t, 2019, "() => a ?? b", "() => a != null ? a : b;\n")
expectPrintedTarget(t, 2019, "() => a() ?? b()", "() => {\n var _a;\n return (_a = a()) != null ? _a : b();\n};\n")

// Temporary variables should not come before "use strict"
expectPrintedTarget(t, 2019, "function f() { /*! @license */ 'use strict'; a = b.c ?? d }",
"function f() {\n /*! @license */\n \"use strict\";\n var _a;\n a = (_a = b.c) != null ? _a : d;\n}\n")
}

func TestLowerNullishCoalescingAssign(t *testing.T) {
Expand Down Expand Up @@ -152,6 +156,10 @@ class Foo {
}
_x = new WeakMap();
`)

// Temporary variables should not come before "use strict"
expectPrintedTarget(t, 2019, "function f() { /*! @license */ 'use strict'; a.b ??= c.d }",
"function f() {\n /*! @license */\n \"use strict\";\n var _a;\n (_a = a.b) != null ? _a : a.b = c.d;\n}\n")
}

func TestLowerLogicalAssign(t *testing.T) {
Expand Down Expand Up @@ -704,6 +712,10 @@ func TestLowerOptionalChain(t *testing.T) {
expectPrintedTarget(t, 2020, "(x?.y)``", "(x?.y)``;\n")
expectPrintedTarget(t, 2019, "(x?.y)``", "var _a;\n(x == null ? void 0 : x.y).call(x, _a || (_a = __template([\"\"])));\n")
expectPrintedTarget(t, 5, "(x?.y)``", "var _a;\n(x == null ? void 0 : x.y).call(x, _a || (_a = __template([\"\"])));\n")

// Temporary variables should not come before "use strict"
expectPrintedTarget(t, 2019, "function f() { /*! @license */ 'use strict'; a.b?.c() }",
"function f() {\n /*! @license */\n \"use strict\";\n var _a;\n (_a = a.b) == null ? void 0 : _a.c();\n}\n")
}

func TestLowerOptionalCatchBinding(t *testing.T) {
Expand Down

0 comments on commit 7ece556

Please sign in to comment.