Skip to content

Commit 7ece556

Browse files
committed
fix #3322: avoid temporaries before "use strict"
1 parent 900a90d commit 7ece556

3 files changed

Lines changed: 55 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,32 @@
2323

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

26+
* Avoid inserting temporary variables before `use strict` ([#3322](https://github.com/evanw/esbuild/issues/3322))
27+
28+
This release fixes a bug where esbuild could incorrectly insert automatically-generated temporary variables before `use strict` directives:
29+
30+
```js
31+
// Original code
32+
function foo() {
33+
'use strict'
34+
a.b?.c()
35+
}
36+
37+
// Old output (with --target=es6)
38+
function foo() {
39+
var _a;
40+
"use strict";
41+
(_a = a.b) == null ? void 0 : _a.c();
42+
}
43+
44+
// New output (with --target=es6)
45+
function foo() {
46+
"use strict";
47+
var _a;
48+
(_a = a.b) == null ? void 0 : _a.c();
49+
}
50+
```
51+
2652
* Adjust TypeScript `enum` output to better approximate `tsc` ([#3329](https://github.com/evanw/esbuild/issues/3329))
2753

2854
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:

internal/js_parser/js_parser.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8377,7 +8377,23 @@ func (p *parser) visitStmtsAndPrependTempRefs(stmts []js_ast.Stmt, opts prependT
83778377
}
83788378
}
83798379
if len(decls) > 0 {
8380-
stmts = append([]js_ast.Stmt{{Data: &js_ast.SLocal{Kind: js_ast.LocalVar, Decls: decls}}}, stmts...)
8380+
// Skip past leading directives and comments
8381+
split := 0
8382+
for split < len(stmts) {
8383+
switch stmts[split].Data.(type) {
8384+
case *js_ast.SComment, *js_ast.SDirective:
8385+
split++
8386+
continue
8387+
}
8388+
break
8389+
}
8390+
stmts = append(
8391+
append(
8392+
append(
8393+
[]js_ast.Stmt{},
8394+
stmts[:split]...),
8395+
js_ast.Stmt{Data: &js_ast.SLocal{Kind: js_ast.LocalVar, Decls: decls}}),
8396+
stmts[split:]...)
83818397
}
83828398

83838399
p.tempRefsToDeclare = oldTempRefs

internal/js_parser/js_parser_lower_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ func TestLowerNullishCoalescing(t *testing.T) {
9999
"function foo() {\n var _a, _b;\n if (x) {\n (_b = (_a = a()) != null ? _a : b()) != null ? _b : c();\n }\n}\n")
100100
expectPrintedTarget(t, 2019, "() => a ?? b", "() => a != null ? a : b;\n")
101101
expectPrintedTarget(t, 2019, "() => a() ?? b()", "() => {\n var _a;\n return (_a = a()) != null ? _a : b();\n};\n")
102+
103+
// Temporary variables should not come before "use strict"
104+
expectPrintedTarget(t, 2019, "function f() { /*! @license */ 'use strict'; a = b.c ?? d }",
105+
"function f() {\n /*! @license */\n \"use strict\";\n var _a;\n a = (_a = b.c) != null ? _a : d;\n}\n")
102106
}
103107

104108
func TestLowerNullishCoalescingAssign(t *testing.T) {
@@ -152,6 +156,10 @@ class Foo {
152156
}
153157
_x = new WeakMap();
154158
`)
159+
160+
// Temporary variables should not come before "use strict"
161+
expectPrintedTarget(t, 2019, "function f() { /*! @license */ 'use strict'; a.b ??= c.d }",
162+
"function f() {\n /*! @license */\n \"use strict\";\n var _a;\n (_a = a.b) != null ? _a : a.b = c.d;\n}\n")
155163
}
156164

157165
func TestLowerLogicalAssign(t *testing.T) {
@@ -704,6 +712,10 @@ func TestLowerOptionalChain(t *testing.T) {
704712
expectPrintedTarget(t, 2020, "(x?.y)``", "(x?.y)``;\n")
705713
expectPrintedTarget(t, 2019, "(x?.y)``", "var _a;\n(x == null ? void 0 : x.y).call(x, _a || (_a = __template([\"\"])));\n")
706714
expectPrintedTarget(t, 5, "(x?.y)``", "var _a;\n(x == null ? void 0 : x.y).call(x, _a || (_a = __template([\"\"])));\n")
715+
716+
// Temporary variables should not come before "use strict"
717+
expectPrintedTarget(t, 2019, "function f() { /*! @license */ 'use strict'; a.b?.c() }",
718+
"function f() {\n /*! @license */\n \"use strict\";\n var _a;\n (_a = a.b) == null ? void 0 : _a.c();\n}\n")
707719
}
708720

709721
func TestLowerOptionalCatchBinding(t *testing.T) {

0 commit comments

Comments
 (0)