Skip to content

Commit

Permalink
avoid using the alias "*" for namespace objects
Browse files Browse the repository at this point in the history
  • Loading branch information
evanw committed Mar 12, 2021
1 parent 491dd50 commit 24811f1
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 17 deletions.
33 changes: 18 additions & 15 deletions internal/bundler/linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@ type fileMeta struct {
//
// Re-exports come from other files and are the result of resolving export
// star statements (i.e. "export * from 'foo'").
resolvedExports map[string]exportData
resolvedExports map[string]exportData
resolvedExportStar *exportData

// Never iterate over "resolvedExports" directly. Instead, iterate over this
// array. Some exports in that map aren't meant to end up in generated code.
Expand Down Expand Up @@ -1248,10 +1249,10 @@ func (c *linkerContext) scanImportsAndExports() {
IsNamespaceExport: true,
}, partMeta{})

// Also add a special export called "*" so import stars can bind to it.
// This must be done in this step because it must come after CommonJS
// module discovery but before matching imports with exports.
repr.meta.resolvedExports["*"] = exportData{
// Also add a special export so import stars can bind to it. This must be
// done in this step because it must come after CommonJS module discovery
// but before matching imports with exports.
repr.meta.resolvedExportStar = &exportData{
ref: repr.ast.ExportsRef,
sourceIndex: sourceIndex,
}
Expand Down Expand Up @@ -1302,12 +1303,6 @@ func (c *linkerContext) scanImportsAndExports() {
aliases := make([]string, 0, len(repr.meta.resolvedExports))
nextAlias:
for alias, export := range repr.meta.resolvedExports {
// The automatically-generated namespace export is just for internal binding
// purposes and isn't meant to end up in generated code.
if alias == "*" {
continue
}

// Re-exporting multiple symbols with the same name causes an ambiguous
// export. These names cannot be used and should not end up in generated code.
otherRepr := c.files[export.sourceIndex].repr.(*reprJS)
Expand Down Expand Up @@ -2286,7 +2281,7 @@ func (c *linkerContext) advanceImportTracker(tracker importTracker) (importTrack

// Is this a named import of a file without any exports?
otherRepr := c.files[otherSourceIndex].repr.(*reprJS)
if namedImport.Alias != "*" && !otherRepr.ast.UsesCommonJSExports() && !otherRepr.ast.HasESMFeatures() && !otherRepr.ast.HasLazyExport {
if !namedImport.AliasIsStar && !otherRepr.ast.UsesCommonJSExports() && !otherRepr.ast.HasESMFeatures() && !otherRepr.ast.HasLazyExport {
// Just warn about it and replace the import with "undefined"
return importTracker{sourceIndex: otherSourceIndex, importRef: js_ast.InvalidRef}, importCommonJSWithoutExports, nil
}
Expand All @@ -2296,6 +2291,16 @@ func (c *linkerContext) advanceImportTracker(tracker importTracker) (importTrack
return importTracker{sourceIndex: otherSourceIndex, importRef: js_ast.InvalidRef}, importCommonJS, nil
}

// Match this import star with an export star from the imported file
if matchingExport := otherRepr.meta.resolvedExportStar; namedImport.AliasIsStar && matchingExport != nil {
// Check to see if this is a re-export of another import
return importTracker{
sourceIndex: matchingExport.sourceIndex,
importRef: matchingExport.ref,
nameLoc: matchingExport.nameLoc,
}, importFound, matchingExport.potentiallyAmbiguousExportStarRefs
}

// Match this import up with an export from the imported file
if matchingExport, ok := otherRepr.meta.resolvedExports[namedImport.Alias]; ok {
// Check to see if this is a re-export of another import
Expand Down Expand Up @@ -3813,9 +3818,7 @@ func (repr *chunkReprJS) generate(c *linkerContext, chunk *chunkInfo) func(gener
resolvedExports := fileRepr.meta.resolvedExports
aliases = make([]string, 0, len(resolvedExports))
for alias := range resolvedExports {
if alias != "*" {
aliases = append(aliases, alias)
}
aliases = append(aliases, alias)
}
}
} else {
Expand Down
6 changes: 6 additions & 0 deletions internal/js_ast/js_ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -1739,6 +1739,12 @@ type NamedImport struct {
NamespaceRef Ref
ImportRecordIndex uint32

// If true, the alias refers to the entire export namespace object of a
// module. This is no longer represented as an alias called "*" because of
// the upcoming "Arbitrary module namespace identifier names" feature:
// https://github.com/tc39/ecma262/pull/2154
AliasIsStar bool

// It's useful to flag exported imports because if they are in a TypeScript
// file, we can't tell if they are a type or a value.
IsExported bool
Expand Down
4 changes: 2 additions & 2 deletions internal/js_parser/js_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -11980,7 +11980,7 @@ func (p *parser) scanForImportsAndExports(stmts []js_ast.Stmt) (result scanForIm

if s.StarNameLoc != nil {
p.namedImports[s.NamespaceRef] = js_ast.NamedImport{
Alias: "*",
AliasIsStar: true,
AliasLoc: *s.StarNameLoc,
NamespaceRef: js_ast.InvalidRef,
ImportRecordIndex: s.ImportRecordIndex,
Expand Down Expand Up @@ -12070,7 +12070,7 @@ func (p *parser) scanForImportsAndExports(stmts []js_ast.Stmt) (result scanForIm
if s.Alias != nil {
// "export * as ns from 'path'"
p.namedImports[s.NamespaceRef] = js_ast.NamedImport{
Alias: "*",
AliasIsStar: true,
AliasLoc: s.Alias.Loc,
NamespaceRef: js_ast.InvalidRef,
ImportRecordIndex: s.ImportRecordIndex,
Expand Down

0 comments on commit 24811f1

Please sign in to comment.