From e09acfc42fc7f145dbc4832f098830a194877b78 Mon Sep 17 00:00:00 2001 From: Evan Wallace Date: Sun, 3 Apr 2022 21:55:25 -0400 Subject: [PATCH] reuse default name in `export default class` --- .../bundler/snapshots/snapshots_lower.txt | 84 +++++++++---------- internal/js_parser/js_parser.go | 62 ++++++++------ internal/js_parser/js_parser_lower.go | 8 +- 3 files changed, 78 insertions(+), 76 deletions(-) diff --git a/internal/bundler/snapshots/snapshots_lower.txt b/internal/bundler/snapshots/snapshots_lower.txt index cf98d8df6d8..a6fe431b07e 100644 --- a/internal/bundler/snapshots/snapshots_lower.txt +++ b/internal/bundler/snapshots/snapshots_lower.txt @@ -1525,36 +1525,36 @@ var foo4_default = class extends x { }; // bar1.js -var _default = class extends x { +var _bar1_default = class extends x { }; -var default2 = _default; -__publicField(default2, "bar1", () => __async(_default, null, function* () { - return __superStaticGet(_default, "foo").call(this, "bar1"); +var bar1_default = _bar1_default; +__publicField(bar1_default, "bar1", () => __async(_bar1_default, null, function* () { + return __superStaticGet(_bar1_default, "foo").call(this, "bar1"); })); // bar2.js -var _default2 = class extends x { +var _bar2_default = class extends x { }; -var default2 = _default2; -__publicField(default2, "bar2", () => __async(_default2, null, function* () { - return () => __superStaticGet(_default2, "foo").call(this, "bar2"); +var bar2_default = _bar2_default; +__publicField(bar2_default, "bar2", () => __async(_bar2_default, null, function* () { + return () => __superStaticGet(_bar2_default, "foo").call(this, "bar2"); })); // bar3.js -var _default3 = class extends x { +var _bar3_default = class extends x { }; -var default2 = _default3; -__publicField(default2, "bar3", () => () => __async(_default3, null, function* () { - return __superStaticGet(_default3, "foo").call(this, "bar3"); +var bar3_default = _bar3_default; +__publicField(bar3_default, "bar3", () => () => __async(_bar3_default, null, function* () { + return __superStaticGet(_bar3_default, "foo").call(this, "bar3"); })); // bar4.js -var _default4 = class extends x { +var _bar4_default = class extends x { }; -var default2 = _default4; -__publicField(default2, "bar4", () => __async(_default4, null, function* () { - return () => __async(_default4, null, function* () { - return __superStaticGet(_default4, "foo").call(this, "bar4"); +var bar4_default = _bar4_default; +__publicField(bar4_default, "bar4", () => __async(_bar4_default, null, function* () { + return () => __async(_bar4_default, null, function* () { + return __superStaticGet(_bar4_default, "foo").call(this, "bar4"); }); })); @@ -1591,10 +1591,10 @@ var outer_default = function() { }); }(); export { - _default as bar1, - _default2 as bar2, - _default3 as bar3, - _default4 as bar4, + bar1_default as bar1, + bar2_default as bar2, + bar3_default as bar3, + bar4_default as bar4, baz1_default as baz1, baz2_default as baz2, foo1_default as foo1, @@ -1657,36 +1657,36 @@ var foo4_default = class extends x { }; // bar1.js -var _default = class extends x { +var _bar1_default = class extends x { }; -var default2 = _default; -__publicField(default2, "bar1", () => __async(_default, null, function* () { - return __superStaticSet(_default, "foo", "bar1"); +var bar1_default = _bar1_default; +__publicField(bar1_default, "bar1", () => __async(_bar1_default, null, function* () { + return __superStaticSet(_bar1_default, "foo", "bar1"); })); // bar2.js -var _default2 = class extends x { +var _bar2_default = class extends x { }; -var default2 = _default2; -__publicField(default2, "bar2", () => __async(_default2, null, function* () { - return () => __superStaticSet(_default2, "foo", "bar2"); +var bar2_default = _bar2_default; +__publicField(bar2_default, "bar2", () => __async(_bar2_default, null, function* () { + return () => __superStaticSet(_bar2_default, "foo", "bar2"); })); // bar3.js -var _default3 = class extends x { +var _bar3_default = class extends x { }; -var default2 = _default3; -__publicField(default2, "bar3", () => () => __async(_default3, null, function* () { - return __superStaticSet(_default3, "foo", "bar3"); +var bar3_default = _bar3_default; +__publicField(bar3_default, "bar3", () => () => __async(_bar3_default, null, function* () { + return __superStaticSet(_bar3_default, "foo", "bar3"); })); // bar4.js -var _default4 = class extends x { +var _bar4_default = class extends x { }; -var default2 = _default4; -__publicField(default2, "bar4", () => __async(_default4, null, function* () { - return () => __async(_default4, null, function* () { - return __superStaticSet(_default4, "foo", "bar4"); +var bar4_default = _bar4_default; +__publicField(bar4_default, "bar4", () => __async(_bar4_default, null, function* () { + return () => __async(_bar4_default, null, function* () { + return __superStaticSet(_bar4_default, "foo", "bar4"); }); })); @@ -1723,10 +1723,10 @@ var outer_default = function() { }); }(); export { - _default as bar1, - _default2 as bar2, - _default3 as bar3, - _default4 as bar4, + bar1_default as bar1, + bar2_default as bar2, + bar3_default as bar3, + bar4_default as bar4, baz1_default as baz1, baz2_default as baz2, foo1_default as foo1, diff --git a/internal/js_parser/js_parser.go b/internal/js_parser/js_parser.go index d9062b154e7..1354884dd8e 100644 --- a/internal/js_parser/js_parser.go +++ b/internal/js_parser/js_parser.go @@ -5876,7 +5876,8 @@ func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt { // The default name is lazily generated only if no other name is present createDefaultName := func() js_ast.LocRef { - defaultName := js_ast.LocRef{Loc: defaultLoc, Ref: p.newSymbol(js_ast.SymbolOther, p.source.IdentifierName+"_default")} + // This must be named "default" for when "--keep-names" is active + defaultName := js_ast.LocRef{Loc: defaultLoc, Ref: p.newSymbol(js_ast.SymbolOther, "default")} p.currentScope.Generated = append(p.currentScope.Generated, defaultName.Ref) return defaultName } @@ -8980,6 +8981,8 @@ func (p *parser) visitAndAppendStmt(stmts []js_ast.Stmt, stmt js_ast.Stmt) []js_ } } + stmts = append(stmts, stmt) + case *js_ast.SFunction: // If we need to preserve the name but there is no name, generate a name var name string @@ -9001,19 +9004,26 @@ func (p *parser) visitAndAppendStmt(stmts []js_ast.Stmt, stmt js_ast.Stmt) []js_ stmts = append(stmts, p.keepStmtSymbolName(s2.Fn.Name.Loc, s2.Fn.Name.Ref, name)) } - return stmts - case *js_ast.SClass: - result := p.visitClass(s.Value.Loc, &s2.Class, true /* isDefaultExport */) + result := p.visitClass(s.Value.Loc, &s2.Class, s.DefaultName.Ref) // Lower class field syntax for browsers that don't support it classStmts, _ := p.lowerClass(stmt, js_ast.Expr{}, result) - return append(stmts, classStmts...) + + stmts = append(stmts, classStmts...) default: panic("Internal error") } + // Use a more friendly name than "default" now that "--keep-names" has + // been applied and has made sure to enforce the name "default" + if p.symbols[s.DefaultName.Ref.InnerIndex].OriginalName == "default" { + p.symbols[s.DefaultName.Ref.InnerIndex].OriginalName = p.source.IdentifierName + "_default" + } + + return stmts + case *js_ast.SExportEquals: // "module.exports = value" stmts = append(stmts, js_ast.AssignStmt( @@ -9580,7 +9590,7 @@ func (p *parser) visitAndAppendStmt(stmts []js_ast.Stmt, stmt js_ast.Stmt) []js_ return stmts case *js_ast.SClass: - result := p.visitClass(stmt.Loc, &s.Class, false /* isDefaultExport */) + result := p.visitClass(stmt.Loc, &s.Class, js_ast.InvalidRef) // Remove the export flag inside a namespace wasExportInsideNamespace := s.IsExport && p.enclosingNamespaceArgRef != nil @@ -10105,7 +10115,7 @@ type visitClassResult struct { superCtorRef js_ast.Ref } -func (p *parser) visitClass(nameScopeLoc logger.Loc, class *js_ast.Class, isDefaultExport bool) (result visitClassResult) { +func (p *parser) visitClass(nameScopeLoc logger.Loc, class *js_ast.Class, defaultNameRef js_ast.Ref) (result visitClassResult) { tsDecoratorScope := p.currentScope class.TSDecorators = p.visitTSDecorators(class.TSDecorators, tsDecoratorScope) @@ -10182,19 +10192,6 @@ func (p *parser) visitClass(nameScopeLoc logger.Loc, class *js_ast.Class, isDefa oldSuperCtorRef := p.superCtorRef p.superCtorRef = result.superCtorRef - var classNameRef js_ast.Ref - if class.Name != nil { - classNameRef = class.Name.Ref - } else { - // Generate a name if one doesn't already exist. This is necessary for - // handling "this" in static class property initializers. - name := "this" - if isDefaultExport { - name = "default" // This is important for "--keep-names" - } - classNameRef = p.newSymbol(js_ast.SymbolOther, name) - } - // Insert a shadowing name that spans the whole class, which matches // JavaScript's semantics. The class body (and extends clause) "captures" the // original value of the name. This matters for class statements because the @@ -10202,12 +10199,18 @@ func (p *parser) visitClass(nameScopeLoc logger.Loc, class *js_ast.Class, isDefa // must be the original value of the name, not the re-assigned value. // Use "const" for this symbol to match JavaScript run-time semantics. You // are not allowed to assign to this symbol (it throws a TypeError). - name := p.symbols[classNameRef.InnerIndex].OriginalName - result.shadowRef = p.newSymbol(js_ast.SymbolConst, "_"+name) - p.recordDeclaredSymbol(result.shadowRef) if class.Name != nil { + name := p.symbols[class.Name.Ref.InnerIndex].OriginalName + result.shadowRef = p.newSymbol(js_ast.SymbolConst, "_"+name) p.currentScope.Members[name] = js_ast.ScopeMember{Loc: class.Name.Loc, Ref: result.shadowRef} + } else { + name := "_this" + if defaultNameRef != js_ast.InvalidRef { + name = "_" + p.source.IdentifierName + "_default" + } + result.shadowRef = p.newSymbol(js_ast.SymbolConst, name) } + p.recordDeclaredSymbol(result.shadowRef) if class.ExtendsOrNil.Data != nil { class.ExtendsOrNil = p.visitExpr(class.ExtendsOrNil) @@ -10377,10 +10380,15 @@ func (p *parser) visitClass(nameScopeLoc logger.Loc, class *js_ast.Class, isDefa } else if class.Name == nil { // If there was originally no class name but something inside needed one // (e.g. there was a static property initializer that referenced "this"), - // store our generated name so the class expression ends up with a name. + // populate the class name. If this is an "export default class" statement, + // use the existing default name so that things will work as expected if + // this is turned into a regular class statement later on. + classNameRef := defaultNameRef + if classNameRef == js_ast.InvalidRef { + classNameRef = p.newSymbol(js_ast.SymbolOther, "this") + p.recordDeclaredSymbol(classNameRef) + } class.Name = &js_ast.LocRef{Loc: nameScopeLoc, Ref: classNameRef} - p.currentScope.Generated = append(p.currentScope.Generated, classNameRef) - p.recordDeclaredSymbol(classNameRef) } return @@ -13508,7 +13516,7 @@ func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprO } case *js_ast.EClass: - result := p.visitClass(expr.Loc, &e.Class, false /* isDefaultExport */) + result := p.visitClass(expr.Loc, &e.Class, js_ast.InvalidRef) // Lower class field syntax for browsers that don't support it _, expr = p.lowerClass(js_ast.Stmt{}, expr, result) diff --git a/internal/js_parser/js_parser_lower.go b/internal/js_parser/js_parser_lower.go index 69074455716..57368d87ad3 100644 --- a/internal/js_parser/js_parser_lower.go +++ b/internal/js_parser/js_parser_lower.go @@ -2061,13 +2061,6 @@ func (p *parser) lowerClass(stmt js_ast.Stmt, expr js_ast.Expr, result visitClas class = &s2.Class defaultName = s.DefaultName kind = classKindExportDefaultStmt - - // The shadowing name inside the class expression should be the same as - // the default export name - if result.shadowRef != js_ast.InvalidRef { - p.mergeSymbols(result.shadowRef, defaultName.Ref) - } - if class.Name != nil { nameToKeep = p.symbols[class.Name.Ref.InnerIndex].OriginalName } else { @@ -2691,6 +2684,7 @@ func (p *parser) lowerClass(stmt js_ast.Stmt, expr js_ast.Expr, result visitClas ValueOrNil: init, }}, }}) + p.recordUsage(nameRef) } else { switch kind { case classKindStmt: