github.com/evanw/esbuild@v0.21.4/internal/linker/linker.go (about)

     1  package linker
     2  
     3  // This package implements the second phase of the bundling operation that
     4  // generates the output files when given a module graph. It has been split off
     5  // into separate package to allow two linkers to cleanly exist in the same code
     6  // base. This will be useful when rewriting the linker because the new one can
     7  // be off by default to minimize disruption, but can still be enabled by anyone
     8  // to assist in giving feedback on the rewrite.
     9  
    10  import (
    11  	"bytes"
    12  	"encoding/base64"
    13  	"encoding/binary"
    14  	"fmt"
    15  	"hash"
    16  	"path"
    17  	"sort"
    18  	"strconv"
    19  	"strings"
    20  	"sync"
    21  
    22  	"github.com/evanw/esbuild/internal/ast"
    23  	"github.com/evanw/esbuild/internal/bundler"
    24  	"github.com/evanw/esbuild/internal/compat"
    25  	"github.com/evanw/esbuild/internal/config"
    26  	"github.com/evanw/esbuild/internal/css_ast"
    27  	"github.com/evanw/esbuild/internal/css_lexer"
    28  	"github.com/evanw/esbuild/internal/css_parser"
    29  	"github.com/evanw/esbuild/internal/css_printer"
    30  	"github.com/evanw/esbuild/internal/fs"
    31  	"github.com/evanw/esbuild/internal/graph"
    32  	"github.com/evanw/esbuild/internal/helpers"
    33  	"github.com/evanw/esbuild/internal/js_ast"
    34  	"github.com/evanw/esbuild/internal/js_lexer"
    35  	"github.com/evanw/esbuild/internal/js_printer"
    36  	"github.com/evanw/esbuild/internal/logger"
    37  	"github.com/evanw/esbuild/internal/renamer"
    38  	"github.com/evanw/esbuild/internal/resolver"
    39  	"github.com/evanw/esbuild/internal/runtime"
    40  	"github.com/evanw/esbuild/internal/sourcemap"
    41  	"github.com/evanw/esbuild/internal/xxhash"
    42  )
    43  
    44  type linkerContext struct {
    45  	options *config.Options
    46  	timer   *helpers.Timer
    47  	log     logger.Log
    48  	fs      fs.FS
    49  	res     *resolver.Resolver
    50  	graph   graph.LinkerGraph
    51  	chunks  []chunkInfo
    52  
    53  	// This helps avoid an infinite loop when matching imports to exports
    54  	cycleDetector []importTracker
    55  
    56  	// This represents the parallel computation of source map related data.
    57  	// Calling this will block until the computation is done. The resulting value
    58  	// is shared between threads and must be treated as immutable.
    59  	dataForSourceMaps func() []bundler.DataForSourceMap
    60  
    61  	// This is passed to us from the bundling phase
    62  	uniqueKeyPrefix      string
    63  	uniqueKeyPrefixBytes []byte // This is just "uniqueKeyPrefix" in byte form
    64  
    65  	// Property mangling results go here
    66  	mangledProps map[ast.Ref]string
    67  
    68  	// We may need to refer to the CommonJS "module" symbol for exports
    69  	unboundModuleRef ast.Ref
    70  
    71  	// We may need to refer to the "__esm" and/or "__commonJS" runtime symbols
    72  	cjsRuntimeRef ast.Ref
    73  	esmRuntimeRef ast.Ref
    74  }
    75  
    76  type partRange struct {
    77  	sourceIndex    uint32
    78  	partIndexBegin uint32
    79  	partIndexEnd   uint32
    80  }
    81  
    82  type chunkInfo struct {
    83  	// This is a random string and is used to represent the output path of this
    84  	// chunk before the final output path has been computed.
    85  	uniqueKey string
    86  
    87  	filesWithPartsInChunk map[uint32]bool
    88  	entryBits             helpers.BitSet
    89  
    90  	// For code splitting
    91  	crossChunkImports []chunkImport
    92  
    93  	// This is the representation-specific information
    94  	chunkRepr chunkRepr
    95  
    96  	// This is the final path of this chunk relative to the output directory, but
    97  	// without the substitution of the final hash (since it hasn't been computed).
    98  	finalTemplate []config.PathTemplate
    99  
   100  	// This is the final path of this chunk relative to the output directory. It
   101  	// is the substitution of the final hash into "finalTemplate".
   102  	finalRelPath string
   103  
   104  	// If non-empty, this chunk needs to generate an external legal comments file.
   105  	externalLegalComments []byte
   106  
   107  	// This contains the hash for just this chunk without including information
   108  	// from the hashes of other chunks. Later on in the linking process, the
   109  	// final hash for this chunk will be constructed by merging the isolated
   110  	// hashes of all transitive dependencies of this chunk. This is separated
   111  	// into two phases like this to handle cycles in the chunk import graph.
   112  	waitForIsolatedHash func() []byte
   113  
   114  	// Other fields relating to the output file for this chunk
   115  	jsonMetadataChunkCallback func(finalOutputSize int) helpers.Joiner
   116  	outputSourceMap           sourcemap.SourceMapPieces
   117  
   118  	// When this chunk is initially generated in isolation, the output pieces
   119  	// will contain slices of the output with the unique keys of other chunks
   120  	// omitted.
   121  	intermediateOutput intermediateOutput
   122  
   123  	// This information is only useful if "isEntryPoint" is true
   124  	entryPointBit uint   // An index into "c.graph.EntryPoints"
   125  	sourceIndex   uint32 // An index into "c.sources"
   126  	isEntryPoint  bool
   127  
   128  	isExecutable bool
   129  }
   130  
   131  type chunkImport struct {
   132  	chunkIndex uint32
   133  	importKind ast.ImportKind
   134  }
   135  
   136  type outputPieceIndexKind uint8
   137  
   138  const (
   139  	outputPieceNone outputPieceIndexKind = iota
   140  	outputPieceAssetIndex
   141  	outputPieceChunkIndex
   142  )
   143  
   144  // This is a chunk of source code followed by a reference to another chunk. For
   145  // example, the file "@import 'CHUNK0001'; body { color: black; }" would be
   146  // represented by two pieces, one with the data "@import '" and another with the
   147  // data "'; body { color: black; }". The first would have the chunk index 1 and
   148  // the second would have an invalid chunk index.
   149  type outputPiece struct {
   150  	data []byte
   151  
   152  	// Note: The "kind" may be "outputPieceNone" in which case there is one piece
   153  	// with data and no chunk index. For example, the chunk may not contain any
   154  	// imports.
   155  	index uint32
   156  	kind  outputPieceIndexKind
   157  }
   158  
   159  type intermediateOutput struct {
   160  	// If the chunk has references to other chunks, then "pieces" contains the
   161  	// contents of the chunk and "joiner" should not be used. Another joiner
   162  	// will have to be constructed later when merging the pieces together.
   163  	pieces []outputPiece
   164  
   165  	// If the chunk doesn't have any references to other chunks, then "pieces" is
   166  	// nil and "joiner" contains the contents of the chunk. This is more efficient
   167  	// because it avoids doing a join operation twice.
   168  	joiner helpers.Joiner
   169  }
   170  
   171  type chunkRepr interface{ isChunk() }
   172  
   173  func (*chunkReprJS) isChunk()  {}
   174  func (*chunkReprCSS) isChunk() {}
   175  
   176  type chunkReprJS struct {
   177  	filesInChunkInOrder []uint32
   178  	partsInChunkInOrder []partRange
   179  
   180  	// For code splitting
   181  	exportsToOtherChunks   map[ast.Ref]string
   182  	importsFromOtherChunks map[uint32]crossChunkImportItemArray
   183  	crossChunkPrefixStmts  []js_ast.Stmt
   184  	crossChunkSuffixStmts  []js_ast.Stmt
   185  
   186  	cssChunkIndex uint32
   187  	hasCSSChunk   bool
   188  }
   189  
   190  type chunkReprCSS struct {
   191  	importsInChunkInOrder []cssImportOrder
   192  }
   193  
   194  type externalImportCSS struct {
   195  	path                   logger.Path
   196  	conditions             []css_ast.ImportConditions
   197  	conditionImportRecords []ast.ImportRecord
   198  }
   199  
   200  // Returns a log where "log.HasErrors()" only returns true if any errors have
   201  // been logged since this call. This is useful when there have already been
   202  // errors logged by other linkers that share the same log.
   203  func wrappedLog(log logger.Log) logger.Log {
   204  	var mutex sync.Mutex
   205  	var hasErrors bool
   206  	addMsg := log.AddMsg
   207  
   208  	log.AddMsg = func(msg logger.Msg) {
   209  		if msg.Kind == logger.Error {
   210  			mutex.Lock()
   211  			defer mutex.Unlock()
   212  			hasErrors = true
   213  		}
   214  		addMsg(msg)
   215  	}
   216  
   217  	log.HasErrors = func() bool {
   218  		mutex.Lock()
   219  		defer mutex.Unlock()
   220  		return hasErrors
   221  	}
   222  
   223  	return log
   224  }
   225  
   226  func Link(
   227  	options *config.Options,
   228  	timer *helpers.Timer,
   229  	log logger.Log,
   230  	fs fs.FS,
   231  	res *resolver.Resolver,
   232  	inputFiles []graph.InputFile,
   233  	entryPoints []graph.EntryPoint,
   234  	uniqueKeyPrefix string,
   235  	reachableFiles []uint32,
   236  	dataForSourceMaps func() []bundler.DataForSourceMap,
   237  ) []graph.OutputFile {
   238  	timer.Begin("Link")
   239  	defer timer.End("Link")
   240  
   241  	log = wrappedLog(log)
   242  
   243  	timer.Begin("Clone linker graph")
   244  	c := linkerContext{
   245  		options:              options,
   246  		timer:                timer,
   247  		log:                  log,
   248  		fs:                   fs,
   249  		res:                  res,
   250  		dataForSourceMaps:    dataForSourceMaps,
   251  		uniqueKeyPrefix:      uniqueKeyPrefix,
   252  		uniqueKeyPrefixBytes: []byte(uniqueKeyPrefix),
   253  		graph: graph.CloneLinkerGraph(
   254  			inputFiles,
   255  			reachableFiles,
   256  			entryPoints,
   257  			options.CodeSplitting,
   258  		),
   259  	}
   260  	timer.End("Clone linker graph")
   261  
   262  	// Use a smaller version of these functions if we don't need profiler names
   263  	runtimeRepr := c.graph.Files[runtime.SourceIndex].InputFile.Repr.(*graph.JSRepr)
   264  	if c.options.ProfilerNames {
   265  		c.cjsRuntimeRef = runtimeRepr.AST.NamedExports["__commonJS"].Ref
   266  		c.esmRuntimeRef = runtimeRepr.AST.NamedExports["__esm"].Ref
   267  	} else {
   268  		c.cjsRuntimeRef = runtimeRepr.AST.NamedExports["__commonJSMin"].Ref
   269  		c.esmRuntimeRef = runtimeRepr.AST.NamedExports["__esmMin"].Ref
   270  	}
   271  
   272  	var additionalFiles []graph.OutputFile
   273  	for _, entryPoint := range entryPoints {
   274  		file := &c.graph.Files[entryPoint.SourceIndex].InputFile
   275  		switch repr := file.Repr.(type) {
   276  		case *graph.JSRepr:
   277  			// Loaders default to CommonJS when they are the entry point and the output
   278  			// format is not ESM-compatible since that avoids generating the ESM-to-CJS
   279  			// machinery.
   280  			if repr.AST.HasLazyExport && (c.options.Mode == config.ModePassThrough ||
   281  				(c.options.Mode == config.ModeConvertFormat && !c.options.OutputFormat.KeepESMImportExportSyntax())) {
   282  				repr.AST.ExportsKind = js_ast.ExportsCommonJS
   283  			}
   284  
   285  			// Entry points with ES6 exports must generate an exports object when
   286  			// targeting non-ES6 formats. Note that the IIFE format only needs this
   287  			// when the global name is present, since that's the only way the exports
   288  			// can actually be observed externally.
   289  			if repr.AST.ExportKeyword.Len > 0 && (options.OutputFormat == config.FormatCommonJS ||
   290  				(options.OutputFormat == config.FormatIIFE && len(options.GlobalName) > 0)) {
   291  				repr.AST.UsesExportsRef = true
   292  				repr.Meta.ForceIncludeExportsForEntryPoint = true
   293  			}
   294  
   295  		case *graph.CopyRepr:
   296  			// If an entry point uses the copy loader, then copy the file manually
   297  			// here. Other uses of the copy loader will automatically be included
   298  			// along with the corresponding bundled chunk but that doesn't happen
   299  			// for entry points.
   300  			additionalFiles = append(additionalFiles, file.AdditionalFiles...)
   301  		}
   302  	}
   303  
   304  	// Allocate a new unbound symbol called "module" in case we need it later
   305  	if c.options.OutputFormat == config.FormatCommonJS {
   306  		c.unboundModuleRef = c.graph.GenerateNewSymbol(runtime.SourceIndex, ast.SymbolUnbound, "module")
   307  	} else {
   308  		c.unboundModuleRef = ast.InvalidRef
   309  	}
   310  
   311  	c.scanImportsAndExports()
   312  
   313  	// Stop now if there were errors
   314  	if c.log.HasErrors() {
   315  		c.options.ExclusiveMangleCacheUpdate(func(map[string]interface{}, map[string]bool) {
   316  			// Always do this so that we don't cause other entry points when there are errors
   317  		})
   318  		return []graph.OutputFile{}
   319  	}
   320  
   321  	c.treeShakingAndCodeSplitting()
   322  
   323  	if c.options.Mode == config.ModePassThrough {
   324  		for _, entryPoint := range c.graph.EntryPoints() {
   325  			c.preventExportsFromBeingRenamed(entryPoint.SourceIndex)
   326  		}
   327  	}
   328  
   329  	c.computeChunks()
   330  	c.computeCrossChunkDependencies()
   331  
   332  	// Merge mangled properties before chunks are generated since the names must
   333  	// be consistent across all chunks, or the generated code will break
   334  	c.timer.Begin("Waiting for mangle cache")
   335  	c.options.ExclusiveMangleCacheUpdate(func(
   336  		mangleCache map[string]interface{},
   337  		cssUsedLocalNames map[string]bool,
   338  	) {
   339  		c.timer.End("Waiting for mangle cache")
   340  		c.mangleProps(mangleCache)
   341  		c.mangleLocalCSS(cssUsedLocalNames)
   342  	})
   343  
   344  	// Make sure calls to "ast.FollowSymbols()" in parallel goroutines after this
   345  	// won't hit concurrent map mutation hazards
   346  	ast.FollowAllSymbols(c.graph.Symbols)
   347  
   348  	return c.generateChunksInParallel(additionalFiles)
   349  }
   350  
   351  func (c *linkerContext) mangleProps(mangleCache map[string]interface{}) {
   352  	c.timer.Begin("Mangle props")
   353  	defer c.timer.End("Mangle props")
   354  
   355  	mangledProps := make(map[ast.Ref]string)
   356  	c.mangledProps = mangledProps
   357  
   358  	// Reserve all JS keywords
   359  	reservedProps := make(map[string]bool)
   360  	for keyword := range js_lexer.Keywords {
   361  		reservedProps[keyword] = true
   362  	}
   363  
   364  	// Reserve all target properties in the cache
   365  	for original, remapped := range mangleCache {
   366  		if remapped == false {
   367  			reservedProps[original] = true
   368  		} else {
   369  			reservedProps[remapped.(string)] = true
   370  		}
   371  	}
   372  
   373  	// Merge all mangled property symbols together
   374  	freq := ast.CharFreq{}
   375  	mergedProps := make(map[string]ast.Ref)
   376  	for _, sourceIndex := range c.graph.ReachableFiles {
   377  		// Don't mangle anything in the runtime code
   378  		if sourceIndex == runtime.SourceIndex {
   379  			continue
   380  		}
   381  
   382  		// For each file
   383  		if repr, ok := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr); ok {
   384  			// Reserve all non-mangled properties
   385  			for prop := range repr.AST.ReservedProps {
   386  				reservedProps[prop] = true
   387  			}
   388  
   389  			// Merge each mangled property with other ones of the same name
   390  			for name, ref := range repr.AST.MangledProps {
   391  				if existing, ok := mergedProps[name]; ok {
   392  					ast.MergeSymbols(c.graph.Symbols, ref, existing)
   393  				} else {
   394  					mergedProps[name] = ref
   395  				}
   396  			}
   397  
   398  			// Include this file's frequency histogram, which affects the mangled names
   399  			if repr.AST.CharFreq != nil {
   400  				freq.Include(repr.AST.CharFreq)
   401  			}
   402  		}
   403  	}
   404  
   405  	// Sort by use count (note: does not currently account for live vs. dead code)
   406  	sorted := make(renamer.StableSymbolCountArray, 0, len(mergedProps))
   407  	stableSourceIndices := c.graph.StableSourceIndices
   408  	for _, ref := range mergedProps {
   409  		sorted = append(sorted, renamer.StableSymbolCount{
   410  			StableSourceIndex: stableSourceIndices[ref.SourceIndex],
   411  			Ref:               ref,
   412  			Count:             c.graph.Symbols.Get(ref).UseCountEstimate,
   413  		})
   414  	}
   415  	sort.Sort(sorted)
   416  
   417  	// Assign names in order of use count
   418  	minifier := ast.DefaultNameMinifierJS.ShuffleByCharFreq(freq)
   419  	nextName := 0
   420  	for _, symbolCount := range sorted {
   421  		symbol := c.graph.Symbols.Get(symbolCount.Ref)
   422  
   423  		// Don't change existing mappings
   424  		if existing, ok := mangleCache[symbol.OriginalName]; ok {
   425  			if existing != false {
   426  				mangledProps[symbolCount.Ref] = existing.(string)
   427  			}
   428  			continue
   429  		}
   430  
   431  		// Generate a new name
   432  		name := minifier.NumberToMinifiedName(nextName)
   433  		nextName++
   434  
   435  		// Avoid reserved properties
   436  		for reservedProps[name] {
   437  			name = minifier.NumberToMinifiedName(nextName)
   438  			nextName++
   439  		}
   440  
   441  		// Track the new mapping
   442  		if mangleCache != nil {
   443  			mangleCache[symbol.OriginalName] = name
   444  		}
   445  		mangledProps[symbolCount.Ref] = name
   446  	}
   447  }
   448  
   449  func (c *linkerContext) mangleLocalCSS(usedLocalNames map[string]bool) {
   450  	c.timer.Begin("Mangle local CSS")
   451  	defer c.timer.End("Mangle local CSS")
   452  
   453  	mangledProps := c.mangledProps
   454  	globalNames := make(map[string]bool)
   455  	localNames := make(map[ast.Ref]struct{})
   456  
   457  	// Collect all local and global CSS names
   458  	freq := ast.CharFreq{}
   459  	for _, sourceIndex := range c.graph.ReachableFiles {
   460  		if repr, ok := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.CSSRepr); ok {
   461  			for innerIndex, symbol := range c.graph.Symbols.SymbolsForSource[sourceIndex] {
   462  				if symbol.Kind == ast.SymbolGlobalCSS {
   463  					globalNames[symbol.OriginalName] = true
   464  				} else {
   465  					ref := ast.Ref{SourceIndex: sourceIndex, InnerIndex: uint32(innerIndex)}
   466  					ref = ast.FollowSymbols(c.graph.Symbols, ref)
   467  					localNames[ref] = struct{}{}
   468  				}
   469  			}
   470  
   471  			// Include this file's frequency histogram, which affects the mangled names
   472  			if repr.AST.CharFreq != nil {
   473  				freq.Include(repr.AST.CharFreq)
   474  			}
   475  		}
   476  	}
   477  
   478  	// Sort by use count (note: does not currently account for live vs. dead code)
   479  	sorted := make(renamer.StableSymbolCountArray, 0, len(localNames))
   480  	stableSourceIndices := c.graph.StableSourceIndices
   481  	for ref := range localNames {
   482  		sorted = append(sorted, renamer.StableSymbolCount{
   483  			StableSourceIndex: stableSourceIndices[ref.SourceIndex],
   484  			Ref:               ref,
   485  			Count:             c.graph.Symbols.Get(ref).UseCountEstimate,
   486  		})
   487  	}
   488  	sort.Sort(sorted)
   489  
   490  	// Rename all local names to avoid collisions
   491  	if c.options.MinifyIdentifiers {
   492  		minifier := ast.DefaultNameMinifierCSS.ShuffleByCharFreq(freq)
   493  		nextName := 0
   494  
   495  		for _, symbolCount := range sorted {
   496  			name := minifier.NumberToMinifiedName(nextName)
   497  			for globalNames[name] || usedLocalNames[name] {
   498  				nextName++
   499  				name = minifier.NumberToMinifiedName(nextName)
   500  			}
   501  
   502  			// Turn this local name into a global one
   503  			mangledProps[symbolCount.Ref] = name
   504  			usedLocalNames[name] = true
   505  		}
   506  	} else {
   507  		nameCounts := make(map[string]uint32)
   508  
   509  		for _, symbolCount := range sorted {
   510  			symbol := c.graph.Symbols.Get(symbolCount.Ref)
   511  			name := fmt.Sprintf("%s_%s", c.graph.Files[symbolCount.Ref.SourceIndex].InputFile.Source.IdentifierName, symbol.OriginalName)
   512  
   513  			// If the name is already in use, generate a new name by appending a number
   514  			if globalNames[name] || usedLocalNames[name] {
   515  				// To avoid O(n^2) behavior, the number must start off being the number
   516  				// that we used last time there was a collision with this name. Otherwise
   517  				// if there are many collisions with the same name, each name collision
   518  				// would have to increment the counter past all previous name collisions
   519  				// which is a O(n^2) time algorithm.
   520  				tries, ok := nameCounts[name]
   521  				if !ok {
   522  					tries = 1
   523  				}
   524  				prefix := name
   525  
   526  				// Keep incrementing the number until the name is unused
   527  				for {
   528  					tries++
   529  					name = prefix + strconv.Itoa(int(tries))
   530  
   531  					// Make sure this new name is unused
   532  					if !globalNames[name] && !usedLocalNames[name] {
   533  						// Store the count so we can start here next time instead of starting
   534  						// from 1. This means we avoid O(n^2) behavior.
   535  						nameCounts[prefix] = tries
   536  						break
   537  					}
   538  				}
   539  			}
   540  
   541  			// Turn this local name into a global one
   542  			mangledProps[symbolCount.Ref] = name
   543  			usedLocalNames[name] = true
   544  		}
   545  	}
   546  }
   547  
   548  // Currently the automatic chunk generation algorithm should by construction
   549  // never generate chunks that import each other since files are allocated to
   550  // chunks based on which entry points they are reachable from.
   551  //
   552  // This will change in the future when we allow manual chunk labels. But before
   553  // we allow manual chunk labels, we'll need to rework module initialization to
   554  // allow code splitting chunks to be lazily-initialized.
   555  //
   556  // Since that work hasn't been finished yet, cycles in the chunk import graph
   557  // can cause initialization bugs. So let's forbid these cycles for now to guard
   558  // against code splitting bugs that could cause us to generate buggy chunks.
   559  func (c *linkerContext) enforceNoCyclicChunkImports() {
   560  	var validate func(int, map[int]int) bool
   561  
   562  	// DFS memoization with 3-colors, more space efficient
   563  	// 0: white (unvisited), 1: gray (visiting), 2: black (visited)
   564  	colors := make(map[int]int)
   565  	validate = func(chunkIndex int, colors map[int]int) bool {
   566  		if colors[chunkIndex] == 1 {
   567  			c.log.AddError(nil, logger.Range{}, "Internal error: generated chunks contain a circular import")
   568  			return true
   569  		}
   570  
   571  		if colors[chunkIndex] == 2 {
   572  			return false
   573  		}
   574  
   575  		colors[chunkIndex] = 1
   576  
   577  		for _, chunkImport := range c.chunks[chunkIndex].crossChunkImports {
   578  			// Ignore cycles caused by dynamic "import()" expressions. These are fine
   579  			// because they don't necessarily cause initialization order issues and
   580  			// they don't indicate a bug in our chunk generation algorithm. They arise
   581  			// normally in real code (e.g. two files that import each other).
   582  			if chunkImport.importKind != ast.ImportDynamic {
   583  
   584  				// Recursively validate otherChunkIndex
   585  				if validate(int(chunkImport.chunkIndex), colors) {
   586  					return true
   587  				}
   588  			}
   589  		}
   590  
   591  		colors[chunkIndex] = 2
   592  		return false
   593  	}
   594  
   595  	for i := range c.chunks {
   596  		if validate(i, colors) {
   597  			break
   598  		}
   599  	}
   600  }
   601  
   602  func (c *linkerContext) generateChunksInParallel(additionalFiles []graph.OutputFile) []graph.OutputFile {
   603  	c.timer.Begin("Generate chunks")
   604  	defer c.timer.End("Generate chunks")
   605  
   606  	// Generate each chunk on a separate goroutine. When a chunk needs to
   607  	// reference the path of another chunk, it will use a temporary path called
   608  	// the "uniqueKey" since the final path hasn't been computed yet (and is
   609  	// in general uncomputable at this point because paths have hashes that
   610  	// include information about chunk dependencies, and chunk dependencies
   611  	// can be cyclic due to dynamic imports).
   612  	generateWaitGroup := sync.WaitGroup{}
   613  	generateWaitGroup.Add(len(c.chunks))
   614  	for chunkIndex := range c.chunks {
   615  		switch c.chunks[chunkIndex].chunkRepr.(type) {
   616  		case *chunkReprJS:
   617  			go c.generateChunkJS(chunkIndex, &generateWaitGroup)
   618  		case *chunkReprCSS:
   619  			go c.generateChunkCSS(chunkIndex, &generateWaitGroup)
   620  		}
   621  	}
   622  	c.enforceNoCyclicChunkImports()
   623  	generateWaitGroup.Wait()
   624  
   625  	// Compute the final hashes of each chunk, then use those to create the final
   626  	// paths of each chunk. This can technically be done in parallel but it
   627  	// probably doesn't matter so much because we're not hashing that much data.
   628  	visited := make([]uint32, len(c.chunks))
   629  	var finalBytes []byte
   630  	for chunkIndex := range c.chunks {
   631  		chunk := &c.chunks[chunkIndex]
   632  		var hashSubstitution *string
   633  
   634  		// Only wait for the hash if necessary
   635  		if config.HasPlaceholder(chunk.finalTemplate, config.HashPlaceholder) {
   636  			// Compute the final hash using the isolated hashes of the dependencies
   637  			hash := xxhash.New()
   638  			c.appendIsolatedHashesForImportedChunks(hash, uint32(chunkIndex), visited, ^uint32(chunkIndex))
   639  			finalBytes = hash.Sum(finalBytes[:0])
   640  			finalString := bundler.HashForFileName(finalBytes)
   641  			hashSubstitution = &finalString
   642  		}
   643  
   644  		// Render the last remaining placeholder in the template
   645  		chunk.finalRelPath = config.TemplateToString(config.SubstituteTemplate(chunk.finalTemplate, config.PathPlaceholders{
   646  			Hash: hashSubstitution,
   647  		}))
   648  	}
   649  
   650  	// Generate the final output files by joining file pieces together and
   651  	// substituting the temporary paths for the final paths. This substitution
   652  	// can be done in parallel for each chunk.
   653  	c.timer.Begin("Generate final output files")
   654  	var resultsWaitGroup sync.WaitGroup
   655  	results := make([][]graph.OutputFile, len(c.chunks))
   656  	resultsWaitGroup.Add(len(c.chunks))
   657  	for chunkIndex, chunk := range c.chunks {
   658  		go func(chunkIndex int, chunk chunkInfo) {
   659  			var outputFiles []graph.OutputFile
   660  
   661  			// Each file may optionally contain additional files to be copied to the
   662  			// output directory. This is used by the "file" and "copy" loaders.
   663  			var commentPrefix string
   664  			var commentSuffix string
   665  			switch chunkRepr := chunk.chunkRepr.(type) {
   666  			case *chunkReprJS:
   667  				for _, sourceIndex := range chunkRepr.filesInChunkInOrder {
   668  					outputFiles = append(outputFiles, c.graph.Files[sourceIndex].InputFile.AdditionalFiles...)
   669  				}
   670  				commentPrefix = "//"
   671  
   672  			case *chunkReprCSS:
   673  				for _, entry := range chunkRepr.importsInChunkInOrder {
   674  					if entry.kind == cssImportSourceIndex {
   675  						outputFiles = append(outputFiles, c.graph.Files[entry.sourceIndex].InputFile.AdditionalFiles...)
   676  					}
   677  				}
   678  				commentPrefix = "/*"
   679  				commentSuffix = " */"
   680  			}
   681  
   682  			// Path substitution for the chunk itself
   683  			finalRelDir := c.fs.Dir(chunk.finalRelPath)
   684  			outputContentsJoiner, outputSourceMapShifts := c.substituteFinalPaths(chunk.intermediateOutput,
   685  				func(finalRelPathForImport string) string {
   686  					return c.pathBetweenChunks(finalRelDir, finalRelPathForImport)
   687  				})
   688  
   689  			// Generate the optional legal comments file for this chunk
   690  			if chunk.externalLegalComments != nil {
   691  				finalRelPathForLegalComments := chunk.finalRelPath + ".LEGAL.txt"
   692  
   693  				// Link the file to the legal comments
   694  				if c.options.LegalComments == config.LegalCommentsLinkedWithComment {
   695  					importPath := c.pathBetweenChunks(finalRelDir, finalRelPathForLegalComments)
   696  					importPath = strings.TrimPrefix(importPath, "./")
   697  					outputContentsJoiner.EnsureNewlineAtEnd()
   698  					outputContentsJoiner.AddString("/*! For license information please see ")
   699  					outputContentsJoiner.AddString(importPath)
   700  					outputContentsJoiner.AddString(" */\n")
   701  				}
   702  
   703  				// Write the external legal comments file
   704  				outputFiles = append(outputFiles, graph.OutputFile{
   705  					AbsPath:  c.fs.Join(c.options.AbsOutputDir, finalRelPathForLegalComments),
   706  					Contents: chunk.externalLegalComments,
   707  					JSONMetadataChunk: fmt.Sprintf(
   708  						"{\n      \"imports\": [],\n      \"exports\": [],\n      \"inputs\": {},\n      \"bytes\": %d\n    }", len(chunk.externalLegalComments)),
   709  				})
   710  			}
   711  
   712  			// Generate the optional source map for this chunk
   713  			if c.options.SourceMap != config.SourceMapNone && chunk.outputSourceMap.HasContent() {
   714  				outputSourceMap := chunk.outputSourceMap.Finalize(outputSourceMapShifts)
   715  				finalRelPathForSourceMap := chunk.finalRelPath + ".map"
   716  
   717  				// Potentially write a trailing source map comment
   718  				switch c.options.SourceMap {
   719  				case config.SourceMapLinkedWithComment:
   720  					importPath := c.pathBetweenChunks(finalRelDir, finalRelPathForSourceMap)
   721  					importPath = strings.TrimPrefix(importPath, "./")
   722  					outputContentsJoiner.EnsureNewlineAtEnd()
   723  					outputContentsJoiner.AddString(commentPrefix)
   724  					outputContentsJoiner.AddString("# sourceMappingURL=")
   725  					outputContentsJoiner.AddString(importPath)
   726  					outputContentsJoiner.AddString(commentSuffix)
   727  					outputContentsJoiner.AddString("\n")
   728  
   729  				case config.SourceMapInline, config.SourceMapInlineAndExternal:
   730  					outputContentsJoiner.EnsureNewlineAtEnd()
   731  					outputContentsJoiner.AddString(commentPrefix)
   732  					outputContentsJoiner.AddString("# sourceMappingURL=data:application/json;base64,")
   733  					outputContentsJoiner.AddString(base64.StdEncoding.EncodeToString(outputSourceMap))
   734  					outputContentsJoiner.AddString(commentSuffix)
   735  					outputContentsJoiner.AddString("\n")
   736  				}
   737  
   738  				// Potentially write the external source map file
   739  				switch c.options.SourceMap {
   740  				case config.SourceMapLinkedWithComment, config.SourceMapInlineAndExternal, config.SourceMapExternalWithoutComment:
   741  					outputFiles = append(outputFiles, graph.OutputFile{
   742  						AbsPath:  c.fs.Join(c.options.AbsOutputDir, finalRelPathForSourceMap),
   743  						Contents: outputSourceMap,
   744  						JSONMetadataChunk: fmt.Sprintf(
   745  							"{\n      \"imports\": [],\n      \"exports\": [],\n      \"inputs\": {},\n      \"bytes\": %d\n    }", len(outputSourceMap)),
   746  					})
   747  				}
   748  			}
   749  
   750  			// Finalize the output contents
   751  			outputContents := outputContentsJoiner.Done()
   752  
   753  			// Path substitution for the JSON metadata
   754  			var jsonMetadataChunk string
   755  			if c.options.NeedsMetafile {
   756  				jsonMetadataChunkPieces := c.breakJoinerIntoPieces(chunk.jsonMetadataChunkCallback(len(outputContents)))
   757  				jsonMetadataChunkBytes, _ := c.substituteFinalPaths(jsonMetadataChunkPieces, func(finalRelPathForImport string) string {
   758  					return resolver.PrettyPath(c.fs, logger.Path{Text: c.fs.Join(c.options.AbsOutputDir, finalRelPathForImport), Namespace: "file"})
   759  				})
   760  				jsonMetadataChunk = string(jsonMetadataChunkBytes.Done())
   761  			}
   762  
   763  			// Generate the output file for this chunk
   764  			outputFiles = append(outputFiles, graph.OutputFile{
   765  				AbsPath:           c.fs.Join(c.options.AbsOutputDir, chunk.finalRelPath),
   766  				Contents:          outputContents,
   767  				JSONMetadataChunk: jsonMetadataChunk,
   768  				IsExecutable:      chunk.isExecutable,
   769  			})
   770  
   771  			results[chunkIndex] = outputFiles
   772  			resultsWaitGroup.Done()
   773  		}(chunkIndex, chunk)
   774  	}
   775  	resultsWaitGroup.Wait()
   776  	c.timer.End("Generate final output files")
   777  
   778  	// Merge the output files from the different goroutines together in order
   779  	outputFilesLen := len(additionalFiles)
   780  	for _, result := range results {
   781  		outputFilesLen += len(result)
   782  	}
   783  	outputFiles := make([]graph.OutputFile, 0, outputFilesLen)
   784  	outputFiles = append(outputFiles, additionalFiles...)
   785  	for _, result := range results {
   786  		outputFiles = append(outputFiles, result...)
   787  	}
   788  	return outputFiles
   789  }
   790  
   791  // Given a set of output pieces (i.e. a buffer already divided into the spans
   792  // between import paths), substitute the final import paths in and then join
   793  // everything into a single byte buffer.
   794  func (c *linkerContext) substituteFinalPaths(
   795  	intermediateOutput intermediateOutput,
   796  	modifyPath func(string) string,
   797  ) (j helpers.Joiner, shifts []sourcemap.SourceMapShift) {
   798  	// Optimization: If there can be no substitutions, just reuse the initial
   799  	// joiner that was used when generating the intermediate chunk output
   800  	// instead of creating another one and copying the whole file into it.
   801  	if intermediateOutput.pieces == nil {
   802  		return intermediateOutput.joiner, []sourcemap.SourceMapShift{{}}
   803  	}
   804  
   805  	var shift sourcemap.SourceMapShift
   806  	shifts = make([]sourcemap.SourceMapShift, 0, len(intermediateOutput.pieces))
   807  	shifts = append(shifts, shift)
   808  
   809  	for _, piece := range intermediateOutput.pieces {
   810  		var dataOffset sourcemap.LineColumnOffset
   811  		j.AddBytes(piece.data)
   812  		dataOffset.AdvanceBytes(piece.data)
   813  		shift.Before.Add(dataOffset)
   814  		shift.After.Add(dataOffset)
   815  
   816  		switch piece.kind {
   817  		case outputPieceAssetIndex:
   818  			file := c.graph.Files[piece.index]
   819  			if len(file.InputFile.AdditionalFiles) != 1 {
   820  				panic("Internal error")
   821  			}
   822  			relPath, _ := c.fs.Rel(c.options.AbsOutputDir, file.InputFile.AdditionalFiles[0].AbsPath)
   823  
   824  			// Make sure to always use forward slashes, even on Windows
   825  			relPath = strings.ReplaceAll(relPath, "\\", "/")
   826  
   827  			importPath := modifyPath(relPath)
   828  			j.AddString(importPath)
   829  			shift.Before.AdvanceString(file.InputFile.UniqueKeyForAdditionalFile)
   830  			shift.After.AdvanceString(importPath)
   831  			shifts = append(shifts, shift)
   832  
   833  		case outputPieceChunkIndex:
   834  			chunk := c.chunks[piece.index]
   835  			importPath := modifyPath(chunk.finalRelPath)
   836  			j.AddString(importPath)
   837  			shift.Before.AdvanceString(chunk.uniqueKey)
   838  			shift.After.AdvanceString(importPath)
   839  			shifts = append(shifts, shift)
   840  		}
   841  	}
   842  
   843  	return
   844  }
   845  
   846  func (c *linkerContext) accurateFinalByteCount(output intermediateOutput, chunkFinalRelDir string) int {
   847  	count := 0
   848  
   849  	// Note: The paths generated here must match "substituteFinalPaths" above
   850  	for _, piece := range output.pieces {
   851  		count += len(piece.data)
   852  
   853  		switch piece.kind {
   854  		case outputPieceAssetIndex:
   855  			file := c.graph.Files[piece.index]
   856  			if len(file.InputFile.AdditionalFiles) != 1 {
   857  				panic("Internal error")
   858  			}
   859  			relPath, _ := c.fs.Rel(c.options.AbsOutputDir, file.InputFile.AdditionalFiles[0].AbsPath)
   860  
   861  			// Make sure to always use forward slashes, even on Windows
   862  			relPath = strings.ReplaceAll(relPath, "\\", "/")
   863  
   864  			importPath := c.pathBetweenChunks(chunkFinalRelDir, relPath)
   865  			count += len(importPath)
   866  
   867  		case outputPieceChunkIndex:
   868  			chunk := c.chunks[piece.index]
   869  			importPath := c.pathBetweenChunks(chunkFinalRelDir, chunk.finalRelPath)
   870  			count += len(importPath)
   871  		}
   872  	}
   873  
   874  	return count
   875  }
   876  
   877  func (c *linkerContext) pathBetweenChunks(fromRelDir string, toRelPath string) string {
   878  	// Join with the public path if it has been configured
   879  	if c.options.PublicPath != "" {
   880  		return joinWithPublicPath(c.options.PublicPath, toRelPath)
   881  	}
   882  
   883  	// Otherwise, return a relative path
   884  	relPath, ok := c.fs.Rel(fromRelDir, toRelPath)
   885  	if !ok {
   886  		c.log.AddError(nil, logger.Range{},
   887  			fmt.Sprintf("Cannot traverse from directory %q to chunk %q", fromRelDir, toRelPath))
   888  		return ""
   889  	}
   890  
   891  	// Make sure to always use forward slashes, even on Windows
   892  	relPath = strings.ReplaceAll(relPath, "\\", "/")
   893  
   894  	// Make sure the relative path doesn't start with a name, since that could
   895  	// be interpreted as a package path instead of a relative path
   896  	if !strings.HasPrefix(relPath, "./") && !strings.HasPrefix(relPath, "../") {
   897  		relPath = "./" + relPath
   898  	}
   899  
   900  	return relPath
   901  }
   902  
   903  func (c *linkerContext) computeCrossChunkDependencies() {
   904  	c.timer.Begin("Compute cross-chunk dependencies")
   905  	defer c.timer.End("Compute cross-chunk dependencies")
   906  
   907  	if !c.options.CodeSplitting {
   908  		// No need to compute cross-chunk dependencies if there can't be any
   909  		return
   910  	}
   911  
   912  	type chunkMeta struct {
   913  		imports        map[ast.Ref]bool
   914  		exports        map[ast.Ref]bool
   915  		dynamicImports map[int]bool
   916  	}
   917  
   918  	chunkMetas := make([]chunkMeta, len(c.chunks))
   919  
   920  	// For each chunk, see what symbols it uses from other chunks. Do this in
   921  	// parallel because it's the most expensive part of this function.
   922  	waitGroup := sync.WaitGroup{}
   923  	waitGroup.Add(len(c.chunks))
   924  	for chunkIndex, chunk := range c.chunks {
   925  		go func(chunkIndex int, chunk chunkInfo) {
   926  			chunkMeta := &chunkMetas[chunkIndex]
   927  			imports := make(map[ast.Ref]bool)
   928  			chunkMeta.imports = imports
   929  			chunkMeta.exports = make(map[ast.Ref]bool)
   930  
   931  			// Go over each file in this chunk
   932  			for sourceIndex := range chunk.filesWithPartsInChunk {
   933  				// Go over each part in this file that's marked for inclusion in this chunk
   934  				switch repr := c.graph.Files[sourceIndex].InputFile.Repr.(type) {
   935  				case *graph.JSRepr:
   936  					for partIndex, partMeta := range repr.AST.Parts {
   937  						if !partMeta.IsLive {
   938  							continue
   939  						}
   940  						part := &repr.AST.Parts[partIndex]
   941  
   942  						// Rewrite external dynamic imports to point to the chunk for that entry point
   943  						for _, importRecordIndex := range part.ImportRecordIndices {
   944  							record := &repr.AST.ImportRecords[importRecordIndex]
   945  							if record.SourceIndex.IsValid() && c.isExternalDynamicImport(record, sourceIndex) {
   946  								otherChunkIndex := c.graph.Files[record.SourceIndex.GetIndex()].EntryPointChunkIndex
   947  								record.Path.Text = c.chunks[otherChunkIndex].uniqueKey
   948  								record.SourceIndex = ast.Index32{}
   949  								record.Flags |= ast.ShouldNotBeExternalInMetafile | ast.ContainsUniqueKey
   950  
   951  								// Track this cross-chunk dynamic import so we make sure to
   952  								// include its hash when we're calculating the hashes of all
   953  								// dependencies of this chunk.
   954  								if int(otherChunkIndex) != chunkIndex {
   955  									if chunkMeta.dynamicImports == nil {
   956  										chunkMeta.dynamicImports = make(map[int]bool)
   957  									}
   958  									chunkMeta.dynamicImports[int(otherChunkIndex)] = true
   959  								}
   960  							}
   961  						}
   962  
   963  						// Remember what chunk each top-level symbol is declared in. Symbols
   964  						// with multiple declarations such as repeated "var" statements with
   965  						// the same name should already be marked as all being in a single
   966  						// chunk. In that case this will overwrite the same value below which
   967  						// is fine.
   968  						for _, declared := range part.DeclaredSymbols {
   969  							if declared.IsTopLevel {
   970  								c.graph.Symbols.Get(declared.Ref).ChunkIndex = ast.MakeIndex32(uint32(chunkIndex))
   971  							}
   972  						}
   973  
   974  						// Record each symbol used in this part. This will later be matched up
   975  						// with our map of which chunk a given symbol is declared in to
   976  						// determine if the symbol needs to be imported from another chunk.
   977  						for ref := range part.SymbolUses {
   978  							symbol := c.graph.Symbols.Get(ref)
   979  
   980  							// Ignore unbound symbols, which don't have declarations
   981  							if symbol.Kind == ast.SymbolUnbound {
   982  								continue
   983  							}
   984  
   985  							// Ignore symbols that are going to be replaced by undefined
   986  							if symbol.ImportItemStatus == ast.ImportItemMissing {
   987  								continue
   988  							}
   989  
   990  							// If this is imported from another file, follow the import
   991  							// reference and reference the symbol in that file instead
   992  							if importData, ok := repr.Meta.ImportsToBind[ref]; ok {
   993  								ref = importData.Ref
   994  								symbol = c.graph.Symbols.Get(ref)
   995  							} else if repr.Meta.Wrap == graph.WrapCJS && ref != repr.AST.WrapperRef {
   996  								// The only internal symbol that wrapped CommonJS files export
   997  								// is the wrapper itself.
   998  								continue
   999  							}
  1000  
  1001  							// If this is an ES6 import from a CommonJS file, it will become a
  1002  							// property access off the namespace symbol instead of a bare
  1003  							// identifier. In that case we want to pull in the namespace symbol
  1004  							// instead. The namespace symbol stores the result of "require()".
  1005  							if symbol.NamespaceAlias != nil {
  1006  								ref = symbol.NamespaceAlias.NamespaceRef
  1007  							}
  1008  
  1009  							// We must record this relationship even for symbols that are not
  1010  							// imports. Due to code splitting, the definition of a symbol may
  1011  							// be moved to a separate chunk than the use of a symbol even if
  1012  							// the definition and use of that symbol are originally from the
  1013  							// same source file.
  1014  							imports[ref] = true
  1015  						}
  1016  					}
  1017  				}
  1018  			}
  1019  
  1020  			// Include the exports if this is an entry point chunk
  1021  			if chunk.isEntryPoint {
  1022  				if repr, ok := c.graph.Files[chunk.sourceIndex].InputFile.Repr.(*graph.JSRepr); ok {
  1023  					if repr.Meta.Wrap != graph.WrapCJS {
  1024  						for _, alias := range repr.Meta.SortedAndFilteredExportAliases {
  1025  							export := repr.Meta.ResolvedExports[alias]
  1026  							targetRef := export.Ref
  1027  
  1028  							// If this is an import, then target what the import points to
  1029  							if importData, ok := c.graph.Files[export.SourceIndex].InputFile.Repr.(*graph.JSRepr).Meta.ImportsToBind[targetRef]; ok {
  1030  								targetRef = importData.Ref
  1031  							}
  1032  
  1033  							// If this is an ES6 import from a CommonJS file, it will become a
  1034  							// property access off the namespace symbol instead of a bare
  1035  							// identifier. In that case we want to pull in the namespace symbol
  1036  							// instead. The namespace symbol stores the result of "require()".
  1037  							if symbol := c.graph.Symbols.Get(targetRef); symbol.NamespaceAlias != nil {
  1038  								targetRef = symbol.NamespaceAlias.NamespaceRef
  1039  							}
  1040  
  1041  							imports[targetRef] = true
  1042  						}
  1043  					}
  1044  
  1045  					// Ensure "exports" is included if the current output format needs it
  1046  					if repr.Meta.ForceIncludeExportsForEntryPoint {
  1047  						imports[repr.AST.ExportsRef] = true
  1048  					}
  1049  
  1050  					// Include the wrapper if present
  1051  					if repr.Meta.Wrap != graph.WrapNone {
  1052  						imports[repr.AST.WrapperRef] = true
  1053  					}
  1054  				}
  1055  			}
  1056  
  1057  			waitGroup.Done()
  1058  		}(chunkIndex, chunk)
  1059  	}
  1060  	waitGroup.Wait()
  1061  
  1062  	// Mark imported symbols as exported in the chunk from which they are declared
  1063  	for chunkIndex := range c.chunks {
  1064  		chunk := &c.chunks[chunkIndex]
  1065  		chunkRepr, ok := chunk.chunkRepr.(*chunkReprJS)
  1066  		if !ok {
  1067  			continue
  1068  		}
  1069  		chunkMeta := chunkMetas[chunkIndex]
  1070  
  1071  		// Find all uses in this chunk of symbols from other chunks
  1072  		chunkRepr.importsFromOtherChunks = make(map[uint32]crossChunkImportItemArray)
  1073  		for importRef := range chunkMeta.imports {
  1074  			// Ignore uses that aren't top-level symbols
  1075  			if otherChunkIndex := c.graph.Symbols.Get(importRef).ChunkIndex; otherChunkIndex.IsValid() {
  1076  				if otherChunkIndex := otherChunkIndex.GetIndex(); otherChunkIndex != uint32(chunkIndex) {
  1077  					chunkRepr.importsFromOtherChunks[otherChunkIndex] =
  1078  						append(chunkRepr.importsFromOtherChunks[otherChunkIndex], crossChunkImportItem{ref: importRef})
  1079  					chunkMetas[otherChunkIndex].exports[importRef] = true
  1080  				}
  1081  			}
  1082  		}
  1083  
  1084  		// If this is an entry point, make sure we import all chunks belonging to
  1085  		// this entry point, even if there are no imports. We need to make sure
  1086  		// these chunks are evaluated for their side effects too.
  1087  		if chunk.isEntryPoint {
  1088  			for otherChunkIndex, otherChunk := range c.chunks {
  1089  				if _, ok := otherChunk.chunkRepr.(*chunkReprJS); ok && chunkIndex != otherChunkIndex && otherChunk.entryBits.HasBit(chunk.entryPointBit) {
  1090  					imports := chunkRepr.importsFromOtherChunks[uint32(otherChunkIndex)]
  1091  					chunkRepr.importsFromOtherChunks[uint32(otherChunkIndex)] = imports
  1092  				}
  1093  			}
  1094  		}
  1095  
  1096  		// Make sure we also track dynamic cross-chunk imports. These need to be
  1097  		// tracked so we count them as dependencies of this chunk for the purpose
  1098  		// of hash calculation.
  1099  		if chunkMeta.dynamicImports != nil {
  1100  			sortedDynamicImports := make([]int, 0, len(chunkMeta.dynamicImports))
  1101  			for chunkIndex := range chunkMeta.dynamicImports {
  1102  				sortedDynamicImports = append(sortedDynamicImports, chunkIndex)
  1103  			}
  1104  			sort.Ints(sortedDynamicImports)
  1105  			for _, chunkIndex := range sortedDynamicImports {
  1106  				chunk.crossChunkImports = append(chunk.crossChunkImports, chunkImport{
  1107  					importKind: ast.ImportDynamic,
  1108  					chunkIndex: uint32(chunkIndex),
  1109  				})
  1110  			}
  1111  		}
  1112  	}
  1113  
  1114  	// Generate cross-chunk exports. These must be computed before cross-chunk
  1115  	// imports because of export alias renaming, which must consider all export
  1116  	// aliases simultaneously to avoid collisions.
  1117  	for chunkIndex := range c.chunks {
  1118  		chunk := &c.chunks[chunkIndex]
  1119  		chunkRepr, ok := chunk.chunkRepr.(*chunkReprJS)
  1120  		if !ok {
  1121  			continue
  1122  		}
  1123  
  1124  		chunkRepr.exportsToOtherChunks = make(map[ast.Ref]string)
  1125  		switch c.options.OutputFormat {
  1126  		case config.FormatESModule:
  1127  			r := renamer.ExportRenamer{}
  1128  			var items []js_ast.ClauseItem
  1129  			for _, export := range c.sortedCrossChunkExportItems(chunkMetas[chunkIndex].exports) {
  1130  				var alias string
  1131  				if c.options.MinifyIdentifiers {
  1132  					alias = r.NextMinifiedName()
  1133  				} else {
  1134  					alias = r.NextRenamedName(c.graph.Symbols.Get(export.Ref).OriginalName)
  1135  				}
  1136  				items = append(items, js_ast.ClauseItem{Name: ast.LocRef{Ref: export.Ref}, Alias: alias})
  1137  				chunkRepr.exportsToOtherChunks[export.Ref] = alias
  1138  			}
  1139  			if len(items) > 0 {
  1140  				chunkRepr.crossChunkSuffixStmts = []js_ast.Stmt{{Data: &js_ast.SExportClause{
  1141  					Items: items,
  1142  				}}}
  1143  			}
  1144  
  1145  		default:
  1146  			panic("Internal error")
  1147  		}
  1148  	}
  1149  
  1150  	// Generate cross-chunk imports. These must be computed after cross-chunk
  1151  	// exports because the export aliases must already be finalized so they can
  1152  	// be embedded in the generated import statements.
  1153  	for chunkIndex := range c.chunks {
  1154  		chunk := &c.chunks[chunkIndex]
  1155  		chunkRepr, ok := chunk.chunkRepr.(*chunkReprJS)
  1156  		if !ok {
  1157  			continue
  1158  		}
  1159  
  1160  		var crossChunkPrefixStmts []js_ast.Stmt
  1161  
  1162  		for _, crossChunkImport := range c.sortedCrossChunkImports(chunkRepr.importsFromOtherChunks) {
  1163  			switch c.options.OutputFormat {
  1164  			case config.FormatESModule:
  1165  				var items []js_ast.ClauseItem
  1166  				for _, item := range crossChunkImport.sortedImportItems {
  1167  					items = append(items, js_ast.ClauseItem{Name: ast.LocRef{Ref: item.ref}, Alias: item.exportAlias})
  1168  				}
  1169  				importRecordIndex := uint32(len(chunk.crossChunkImports))
  1170  				chunk.crossChunkImports = append(chunk.crossChunkImports, chunkImport{
  1171  					importKind: ast.ImportStmt,
  1172  					chunkIndex: crossChunkImport.chunkIndex,
  1173  				})
  1174  				if len(items) > 0 {
  1175  					// "import {a, b} from './chunk.js'"
  1176  					crossChunkPrefixStmts = append(crossChunkPrefixStmts, js_ast.Stmt{Data: &js_ast.SImport{
  1177  						Items:             &items,
  1178  						ImportRecordIndex: importRecordIndex,
  1179  					}})
  1180  				} else {
  1181  					// "import './chunk.js'"
  1182  					crossChunkPrefixStmts = append(crossChunkPrefixStmts, js_ast.Stmt{Data: &js_ast.SImport{
  1183  						ImportRecordIndex: importRecordIndex,
  1184  					}})
  1185  				}
  1186  
  1187  			default:
  1188  				panic("Internal error")
  1189  			}
  1190  		}
  1191  
  1192  		chunkRepr.crossChunkPrefixStmts = crossChunkPrefixStmts
  1193  	}
  1194  }
  1195  
  1196  type crossChunkImport struct {
  1197  	sortedImportItems crossChunkImportItemArray
  1198  	chunkIndex        uint32
  1199  }
  1200  
  1201  // This type is just so we can use Go's native sort function
  1202  type crossChunkImportArray []crossChunkImport
  1203  
  1204  func (a crossChunkImportArray) Len() int          { return len(a) }
  1205  func (a crossChunkImportArray) Swap(i int, j int) { a[i], a[j] = a[j], a[i] }
  1206  
  1207  func (a crossChunkImportArray) Less(i int, j int) bool {
  1208  	return a[i].chunkIndex < a[j].chunkIndex
  1209  }
  1210  
  1211  // Sort cross-chunk imports by chunk name for determinism
  1212  func (c *linkerContext) sortedCrossChunkImports(importsFromOtherChunks map[uint32]crossChunkImportItemArray) crossChunkImportArray {
  1213  	result := make(crossChunkImportArray, 0, len(importsFromOtherChunks))
  1214  
  1215  	for otherChunkIndex, importItems := range importsFromOtherChunks {
  1216  		// Sort imports from a single chunk by alias for determinism
  1217  		otherChunk := &c.chunks[otherChunkIndex]
  1218  		exportsToOtherChunks := otherChunk.chunkRepr.(*chunkReprJS).exportsToOtherChunks
  1219  		for i, item := range importItems {
  1220  			importItems[i].exportAlias = exportsToOtherChunks[item.ref]
  1221  		}
  1222  		sort.Sort(importItems)
  1223  		result = append(result, crossChunkImport{
  1224  			chunkIndex:        otherChunkIndex,
  1225  			sortedImportItems: importItems,
  1226  		})
  1227  	}
  1228  
  1229  	sort.Sort(result)
  1230  	return result
  1231  }
  1232  
  1233  type crossChunkImportItem struct {
  1234  	exportAlias string
  1235  	ref         ast.Ref
  1236  }
  1237  
  1238  // This type is just so we can use Go's native sort function
  1239  type crossChunkImportItemArray []crossChunkImportItem
  1240  
  1241  func (a crossChunkImportItemArray) Len() int          { return len(a) }
  1242  func (a crossChunkImportItemArray) Swap(i int, j int) { a[i], a[j] = a[j], a[i] }
  1243  
  1244  func (a crossChunkImportItemArray) Less(i int, j int) bool {
  1245  	return a[i].exportAlias < a[j].exportAlias
  1246  }
  1247  
  1248  // The sort order here is arbitrary but needs to be consistent between builds.
  1249  // The InnerIndex should be stable because the parser for a single file is
  1250  // single-threaded and deterministically assigns out InnerIndex values
  1251  // sequentially. But the SourceIndex should be unstable because the main thread
  1252  // assigns out source index values sequentially to newly-discovered dependencies
  1253  // in a multi-threaded producer/consumer relationship. So instead we use the
  1254  // index of the source in the DFS order over all entry points for stability.
  1255  type stableRef struct {
  1256  	StableSourceIndex uint32
  1257  	Ref               ast.Ref
  1258  }
  1259  
  1260  // This type is just so we can use Go's native sort function
  1261  type stableRefArray []stableRef
  1262  
  1263  func (a stableRefArray) Len() int          { return len(a) }
  1264  func (a stableRefArray) Swap(i int, j int) { a[i], a[j] = a[j], a[i] }
  1265  func (a stableRefArray) Less(i int, j int) bool {
  1266  	ai, aj := a[i], a[j]
  1267  	return ai.StableSourceIndex < aj.StableSourceIndex ||
  1268  		(ai.StableSourceIndex == aj.StableSourceIndex && ai.Ref.InnerIndex < aj.Ref.InnerIndex)
  1269  }
  1270  
  1271  // Sort cross-chunk exports by chunk name for determinism
  1272  func (c *linkerContext) sortedCrossChunkExportItems(exportRefs map[ast.Ref]bool) stableRefArray {
  1273  	result := make(stableRefArray, 0, len(exportRefs))
  1274  	for ref := range exportRefs {
  1275  		result = append(result, stableRef{
  1276  			StableSourceIndex: c.graph.StableSourceIndices[ref.SourceIndex],
  1277  			Ref:               ref,
  1278  		})
  1279  	}
  1280  	sort.Sort(result)
  1281  	return result
  1282  }
  1283  
  1284  func (c *linkerContext) scanImportsAndExports() {
  1285  	c.timer.Begin("Scan imports and exports")
  1286  	defer c.timer.End("Scan imports and exports")
  1287  
  1288  	// Step 1: Figure out what modules must be CommonJS
  1289  	c.timer.Begin("Step 1")
  1290  	for _, sourceIndex := range c.graph.ReachableFiles {
  1291  		file := &c.graph.Files[sourceIndex]
  1292  		additionalFiles := file.InputFile.AdditionalFiles
  1293  
  1294  		switch repr := file.InputFile.Repr.(type) {
  1295  		case *graph.CSSRepr:
  1296  			// Inline URLs for non-CSS files into the CSS file
  1297  			for importRecordIndex := range repr.AST.ImportRecords {
  1298  				if record := &repr.AST.ImportRecords[importRecordIndex]; record.SourceIndex.IsValid() {
  1299  					otherFile := &c.graph.Files[record.SourceIndex.GetIndex()]
  1300  					if otherRepr, ok := otherFile.InputFile.Repr.(*graph.JSRepr); ok {
  1301  						record.Path.Text = otherRepr.AST.URLForCSS
  1302  						record.Path.Namespace = ""
  1303  						record.SourceIndex = ast.Index32{}
  1304  						if otherFile.InputFile.Loader == config.LoaderEmpty {
  1305  							record.Flags |= ast.WasLoadedWithEmptyLoader
  1306  						} else {
  1307  							record.Flags |= ast.ShouldNotBeExternalInMetafile
  1308  						}
  1309  						if strings.Contains(otherRepr.AST.URLForCSS, c.uniqueKeyPrefix) {
  1310  							record.Flags |= ast.ContainsUniqueKey
  1311  						}
  1312  
  1313  						// Copy the additional files to the output directory
  1314  						additionalFiles = append(additionalFiles, otherFile.InputFile.AdditionalFiles...)
  1315  					}
  1316  				} else if record.CopySourceIndex.IsValid() {
  1317  					otherFile := &c.graph.Files[record.CopySourceIndex.GetIndex()]
  1318  					if otherRepr, ok := otherFile.InputFile.Repr.(*graph.CopyRepr); ok {
  1319  						record.Path.Text = otherRepr.URLForCode
  1320  						record.Path.Namespace = ""
  1321  						record.CopySourceIndex = ast.Index32{}
  1322  						record.Flags |= ast.ShouldNotBeExternalInMetafile | ast.ContainsUniqueKey
  1323  
  1324  						// Copy the additional files to the output directory
  1325  						additionalFiles = append(additionalFiles, otherFile.InputFile.AdditionalFiles...)
  1326  					}
  1327  				}
  1328  			}
  1329  
  1330  			// Validate cross-file "composes: ... from" named imports
  1331  			for _, composes := range repr.AST.Composes {
  1332  				for _, name := range composes.ImportedNames {
  1333  					if record := repr.AST.ImportRecords[name.ImportRecordIndex]; record.SourceIndex.IsValid() {
  1334  						otherFile := &c.graph.Files[record.SourceIndex.GetIndex()]
  1335  						if otherRepr, ok := otherFile.InputFile.Repr.(*graph.CSSRepr); ok {
  1336  							if _, ok := otherRepr.AST.LocalScope[name.Alias]; !ok {
  1337  								if global, ok := otherRepr.AST.GlobalScope[name.Alias]; ok {
  1338  									var hint string
  1339  									if otherFile.InputFile.Loader == config.LoaderCSS {
  1340  										hint = fmt.Sprintf("Use the \"local-css\" loader for %q to enable local names.", otherFile.InputFile.Source.PrettyPath)
  1341  									} else {
  1342  										hint = fmt.Sprintf("Use the \":local\" selector to change %q into a local name.", name.Alias)
  1343  									}
  1344  									c.log.AddErrorWithNotes(file.LineColumnTracker(),
  1345  										css_lexer.RangeOfIdentifier(file.InputFile.Source, name.AliasLoc),
  1346  										fmt.Sprintf("Cannot use global name %q with \"composes\"", name.Alias),
  1347  										[]logger.MsgData{
  1348  											otherFile.LineColumnTracker().MsgData(
  1349  												css_lexer.RangeOfIdentifier(otherFile.InputFile.Source, global.Loc),
  1350  												fmt.Sprintf("The global name %q is defined here:", name.Alias),
  1351  											),
  1352  											{Text: hint},
  1353  										})
  1354  								} else {
  1355  									c.log.AddError(file.LineColumnTracker(),
  1356  										css_lexer.RangeOfIdentifier(file.InputFile.Source, name.AliasLoc),
  1357  										fmt.Sprintf("The name %q never appears in %q",
  1358  											name.Alias, otherFile.InputFile.Source.PrettyPath))
  1359  								}
  1360  							}
  1361  						}
  1362  					}
  1363  				}
  1364  			}
  1365  
  1366  			c.validateComposesFromProperties(file, repr)
  1367  
  1368  		case *graph.JSRepr:
  1369  			for importRecordIndex := range repr.AST.ImportRecords {
  1370  				record := &repr.AST.ImportRecords[importRecordIndex]
  1371  				if !record.SourceIndex.IsValid() {
  1372  					if record.CopySourceIndex.IsValid() {
  1373  						otherFile := &c.graph.Files[record.CopySourceIndex.GetIndex()]
  1374  						if otherRepr, ok := otherFile.InputFile.Repr.(*graph.CopyRepr); ok {
  1375  							record.Path.Text = otherRepr.URLForCode
  1376  							record.Path.Namespace = ""
  1377  							record.CopySourceIndex = ast.Index32{}
  1378  							record.Flags |= ast.ShouldNotBeExternalInMetafile | ast.ContainsUniqueKey
  1379  
  1380  							// Copy the additional files to the output directory
  1381  							additionalFiles = append(additionalFiles, otherFile.InputFile.AdditionalFiles...)
  1382  						}
  1383  					}
  1384  					continue
  1385  				}
  1386  
  1387  				otherFile := &c.graph.Files[record.SourceIndex.GetIndex()]
  1388  				otherRepr := otherFile.InputFile.Repr.(*graph.JSRepr)
  1389  
  1390  				switch record.Kind {
  1391  				case ast.ImportStmt:
  1392  					// Importing using ES6 syntax from a file without any ES6 syntax
  1393  					// causes that module to be considered CommonJS-style, even if it
  1394  					// doesn't have any CommonJS exports.
  1395  					//
  1396  					// That means the ES6 imports will become undefined instead of
  1397  					// causing errors. This is for compatibility with older CommonJS-
  1398  					// style bundlers.
  1399  					//
  1400  					// We emit a warning in this case but try to avoid turning the module
  1401  					// into a CommonJS module if possible. This is possible with named
  1402  					// imports (the module stays an ECMAScript module but the imports are
  1403  					// rewritten with undefined) but is not possible with star or default
  1404  					// imports:
  1405  					//
  1406  					//   import * as ns from './empty-file'
  1407  					//   import defVal from './empty-file'
  1408  					//   console.log(ns, defVal)
  1409  					//
  1410  					// In that case the module *is* considered a CommonJS module because
  1411  					// the namespace object must be created.
  1412  					if (record.Flags.Has(ast.ContainsImportStar) || record.Flags.Has(ast.ContainsDefaultAlias)) &&
  1413  						otherRepr.AST.ExportsKind == js_ast.ExportsNone && !otherRepr.AST.HasLazyExport {
  1414  						otherRepr.Meta.Wrap = graph.WrapCJS
  1415  						otherRepr.AST.ExportsKind = js_ast.ExportsCommonJS
  1416  					}
  1417  
  1418  				case ast.ImportRequire:
  1419  					// Files that are imported with require() must be wrapped so that
  1420  					// they can be lazily-evaluated
  1421  					if otherRepr.AST.ExportsKind == js_ast.ExportsESM {
  1422  						otherRepr.Meta.Wrap = graph.WrapESM
  1423  					} else {
  1424  						otherRepr.Meta.Wrap = graph.WrapCJS
  1425  						otherRepr.AST.ExportsKind = js_ast.ExportsCommonJS
  1426  					}
  1427  
  1428  				case ast.ImportDynamic:
  1429  					if !c.options.CodeSplitting {
  1430  						// If we're not splitting, then import() is just a require() that
  1431  						// returns a promise, so the imported file must also be wrapped
  1432  						if otherRepr.AST.ExportsKind == js_ast.ExportsESM {
  1433  							otherRepr.Meta.Wrap = graph.WrapESM
  1434  						} else {
  1435  							otherRepr.Meta.Wrap = graph.WrapCJS
  1436  							otherRepr.AST.ExportsKind = js_ast.ExportsCommonJS
  1437  						}
  1438  					}
  1439  				}
  1440  			}
  1441  
  1442  			// If the output format doesn't have an implicit CommonJS wrapper, any file
  1443  			// that uses CommonJS features will need to be wrapped, even though the
  1444  			// resulting wrapper won't be invoked by other files. An exception is made
  1445  			// for entry point files in CommonJS format (or when in pass-through mode).
  1446  			if repr.AST.ExportsKind == js_ast.ExportsCommonJS && (!file.IsEntryPoint() ||
  1447  				c.options.OutputFormat == config.FormatIIFE || c.options.OutputFormat == config.FormatESModule) {
  1448  				repr.Meta.Wrap = graph.WrapCJS
  1449  			}
  1450  		}
  1451  
  1452  		file.InputFile.AdditionalFiles = additionalFiles
  1453  	}
  1454  	c.timer.End("Step 1")
  1455  
  1456  	// Step 2: Propagate dynamic export status for export star statements that
  1457  	// are re-exports from a module whose exports are not statically analyzable.
  1458  	// In this case the export star must be evaluated at run time instead of at
  1459  	// bundle time.
  1460  	c.timer.Begin("Step 2")
  1461  	for _, sourceIndex := range c.graph.ReachableFiles {
  1462  		repr, ok := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr)
  1463  		if !ok {
  1464  			continue
  1465  		}
  1466  
  1467  		if repr.Meta.Wrap != graph.WrapNone {
  1468  			c.recursivelyWrapDependencies(sourceIndex)
  1469  		}
  1470  
  1471  		if len(repr.AST.ExportStarImportRecords) > 0 {
  1472  			visited := make(map[uint32]bool)
  1473  			c.hasDynamicExportsDueToExportStar(sourceIndex, visited)
  1474  		}
  1475  
  1476  		// Even if the output file is CommonJS-like, we may still need to wrap
  1477  		// CommonJS-style files. Any file that imports a CommonJS-style file will
  1478  		// cause that file to need to be wrapped. This is because the import
  1479  		// method, whatever it is, will need to invoke the wrapper. Note that
  1480  		// this can include entry points (e.g. an entry point that imports a file
  1481  		// that imports that entry point).
  1482  		for _, record := range repr.AST.ImportRecords {
  1483  			if record.SourceIndex.IsValid() {
  1484  				otherRepr := c.graph.Files[record.SourceIndex.GetIndex()].InputFile.Repr.(*graph.JSRepr)
  1485  				if otherRepr.AST.ExportsKind == js_ast.ExportsCommonJS {
  1486  					c.recursivelyWrapDependencies(record.SourceIndex.GetIndex())
  1487  				}
  1488  			}
  1489  		}
  1490  	}
  1491  	c.timer.End("Step 2")
  1492  
  1493  	// Step 3: Resolve "export * from" statements. This must be done after we
  1494  	// discover all modules that can have dynamic exports because export stars
  1495  	// are ignored for those modules.
  1496  	c.timer.Begin("Step 3")
  1497  	exportStarStack := make([]uint32, 0, 32)
  1498  	for _, sourceIndex := range c.graph.ReachableFiles {
  1499  		repr, ok := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr)
  1500  		if !ok {
  1501  			continue
  1502  		}
  1503  
  1504  		// Expression-style loaders defer code generation until linking. Code
  1505  		// generation is done here because at this point we know that the
  1506  		// "ExportsKind" field has its final value and will not be changed.
  1507  		if repr.AST.HasLazyExport {
  1508  			c.generateCodeForLazyExport(sourceIndex)
  1509  		}
  1510  
  1511  		// Propagate exports for export star statements
  1512  		if len(repr.AST.ExportStarImportRecords) > 0 {
  1513  			c.addExportsForExportStar(repr.Meta.ResolvedExports, sourceIndex, exportStarStack)
  1514  		}
  1515  
  1516  		// Also add a special export so import stars can bind to it. This must be
  1517  		// done in this step because it must come after CommonJS module discovery
  1518  		// but before matching imports with exports.
  1519  		repr.Meta.ResolvedExportStar = &graph.ExportData{
  1520  			Ref:         repr.AST.ExportsRef,
  1521  			SourceIndex: sourceIndex,
  1522  		}
  1523  	}
  1524  	c.timer.End("Step 3")
  1525  
  1526  	// Step 4: Match imports with exports. This must be done after we process all
  1527  	// export stars because imports can bind to export star re-exports.
  1528  	c.timer.Begin("Step 4")
  1529  	for _, sourceIndex := range c.graph.ReachableFiles {
  1530  		file := &c.graph.Files[sourceIndex]
  1531  		repr, ok := file.InputFile.Repr.(*graph.JSRepr)
  1532  		if !ok {
  1533  			continue
  1534  		}
  1535  
  1536  		if len(repr.AST.NamedImports) > 0 {
  1537  			c.matchImportsWithExportsForFile(uint32(sourceIndex))
  1538  		}
  1539  
  1540  		// If we're exporting as CommonJS and this file was originally CommonJS,
  1541  		// then we'll be using the actual CommonJS "exports" and/or "module"
  1542  		// symbols. In that case make sure to mark them as such so they don't
  1543  		// get minified.
  1544  		if file.IsEntryPoint() && repr.AST.ExportsKind == js_ast.ExportsCommonJS && repr.Meta.Wrap == graph.WrapNone &&
  1545  			(c.options.OutputFormat == config.FormatPreserve || c.options.OutputFormat == config.FormatCommonJS) {
  1546  			exportsRef := ast.FollowSymbols(c.graph.Symbols, repr.AST.ExportsRef)
  1547  			moduleRef := ast.FollowSymbols(c.graph.Symbols, repr.AST.ModuleRef)
  1548  			c.graph.Symbols.Get(exportsRef).Kind = ast.SymbolUnbound
  1549  			c.graph.Symbols.Get(moduleRef).Kind = ast.SymbolUnbound
  1550  		} else if repr.Meta.ForceIncludeExportsForEntryPoint || repr.AST.ExportsKind != js_ast.ExportsCommonJS {
  1551  			repr.Meta.NeedsExportsVariable = true
  1552  		}
  1553  
  1554  		// Create the wrapper part for wrapped files. This is needed by a later step.
  1555  		c.createWrapperForFile(uint32(sourceIndex))
  1556  	}
  1557  	c.timer.End("Step 4")
  1558  
  1559  	// Step 5: Create namespace exports for every file. This is always necessary
  1560  	// for CommonJS files, and is also necessary for other files if they are
  1561  	// imported using an import star statement.
  1562  	c.timer.Begin("Step 5")
  1563  	waitGroup := sync.WaitGroup{}
  1564  	for _, sourceIndex := range c.graph.ReachableFiles {
  1565  		repr, ok := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr)
  1566  		if !ok {
  1567  			continue
  1568  		}
  1569  
  1570  		// This is the slowest step and is also parallelizable, so do this in parallel.
  1571  		waitGroup.Add(1)
  1572  		go func(sourceIndex uint32, repr *graph.JSRepr) {
  1573  			// Now that all exports have been resolved, sort and filter them to create
  1574  			// something we can iterate over later.
  1575  			aliases := make([]string, 0, len(repr.Meta.ResolvedExports))
  1576  		nextAlias:
  1577  			for alias, export := range repr.Meta.ResolvedExports {
  1578  				otherFile := &c.graph.Files[export.SourceIndex].InputFile
  1579  				otherRepr := otherFile.Repr.(*graph.JSRepr)
  1580  
  1581  				// Re-exporting multiple symbols with the same name causes an ambiguous
  1582  				// export. These names cannot be used and should not end up in generated code.
  1583  				if len(export.PotentiallyAmbiguousExportStarRefs) > 0 {
  1584  					mainRef := export.Ref
  1585  					mainLoc := export.NameLoc
  1586  					if imported, ok := otherRepr.Meta.ImportsToBind[export.Ref]; ok {
  1587  						mainRef = imported.Ref
  1588  						mainLoc = imported.NameLoc
  1589  					}
  1590  
  1591  					for _, ambiguousExport := range export.PotentiallyAmbiguousExportStarRefs {
  1592  						ambiguousFile := &c.graph.Files[ambiguousExport.SourceIndex].InputFile
  1593  						ambiguousRepr := ambiguousFile.Repr.(*graph.JSRepr)
  1594  						ambiguousRef := ambiguousExport.Ref
  1595  						ambiguousLoc := ambiguousExport.NameLoc
  1596  						if imported, ok := ambiguousRepr.Meta.ImportsToBind[ambiguousExport.Ref]; ok {
  1597  							ambiguousRef = imported.Ref
  1598  							ambiguousLoc = imported.NameLoc
  1599  						}
  1600  
  1601  						if mainRef != ambiguousRef {
  1602  							file := &c.graph.Files[sourceIndex].InputFile
  1603  							otherTracker := logger.MakeLineColumnTracker(&otherFile.Source)
  1604  							ambiguousTracker := logger.MakeLineColumnTracker(&ambiguousFile.Source)
  1605  							c.log.AddIDWithNotes(logger.MsgID_Bundler_AmbiguousReexport, logger.Debug, nil, logger.Range{},
  1606  								fmt.Sprintf("Re-export of %q in %q is ambiguous and has been removed", alias, file.Source.PrettyPath),
  1607  								[]logger.MsgData{
  1608  									otherTracker.MsgData(js_lexer.RangeOfIdentifier(otherFile.Source, mainLoc),
  1609  										fmt.Sprintf("One definition of %q comes from %q here:", alias, otherFile.Source.PrettyPath)),
  1610  									ambiguousTracker.MsgData(js_lexer.RangeOfIdentifier(ambiguousFile.Source, ambiguousLoc),
  1611  										fmt.Sprintf("Another definition of %q comes from %q here:", alias, ambiguousFile.Source.PrettyPath)),
  1612  								},
  1613  							)
  1614  							continue nextAlias
  1615  						}
  1616  					}
  1617  				}
  1618  
  1619  				// Ignore re-exported imports in TypeScript files that failed to be
  1620  				// resolved. These are probably just type-only imports so the best thing to
  1621  				// do is to silently omit them from the export list.
  1622  				if otherRepr.Meta.IsProbablyTypeScriptType[export.Ref] {
  1623  					continue
  1624  				}
  1625  
  1626  				if c.options.OutputFormat == config.FormatESModule && c.options.UnsupportedJSFeatures.Has(compat.ArbitraryModuleNamespaceNames) && c.graph.Files[sourceIndex].IsEntryPoint() {
  1627  					c.maybeForbidArbitraryModuleNamespaceIdentifier("export", export.SourceIndex, export.NameLoc, alias)
  1628  				}
  1629  
  1630  				aliases = append(aliases, alias)
  1631  			}
  1632  			sort.Strings(aliases)
  1633  			repr.Meta.SortedAndFilteredExportAliases = aliases
  1634  
  1635  			// Export creation uses "sortedAndFilteredExportAliases" so this must
  1636  			// come second after we fill in that array
  1637  			c.createExportsForFile(uint32(sourceIndex))
  1638  
  1639  			// Each part tracks the other parts it depends on within this file
  1640  			localDependencies := make(map[uint32]uint32)
  1641  			parts := repr.AST.Parts
  1642  			namedImports := repr.AST.NamedImports
  1643  			graph := c.graph
  1644  			for partIndex := range parts {
  1645  				part := &parts[partIndex]
  1646  
  1647  				// Now that all files have been parsed, determine which property
  1648  				// accesses off of imported symbols are inlined enum values and
  1649  				// which ones aren't
  1650  				for ref, properties := range part.ImportSymbolPropertyUses {
  1651  					use := part.SymbolUses[ref]
  1652  
  1653  					// Rare path: this import is a TypeScript enum
  1654  					if importData, ok := repr.Meta.ImportsToBind[ref]; ok {
  1655  						if symbol := graph.Symbols.Get(importData.Ref); symbol.Kind == ast.SymbolTSEnum {
  1656  							if enum, ok := graph.TSEnums[importData.Ref]; ok {
  1657  								foundNonInlinedEnum := false
  1658  								for name, propertyUse := range properties {
  1659  									if _, ok := enum[name]; !ok {
  1660  										foundNonInlinedEnum = true
  1661  										use.CountEstimate += propertyUse.CountEstimate
  1662  									}
  1663  								}
  1664  								if foundNonInlinedEnum {
  1665  									part.SymbolUses[ref] = use
  1666  								}
  1667  							}
  1668  							continue
  1669  						}
  1670  					}
  1671  
  1672  					// Common path: this import isn't a TypeScript enum
  1673  					for _, propertyUse := range properties {
  1674  						use.CountEstimate += propertyUse.CountEstimate
  1675  					}
  1676  					part.SymbolUses[ref] = use
  1677  				}
  1678  
  1679  				// Also determine which function calls will be inlined (and so should
  1680  				// not count as uses), and which ones will not be (and so should count
  1681  				// as uses)
  1682  				for ref, callUse := range part.SymbolCallUses {
  1683  					use := part.SymbolUses[ref]
  1684  
  1685  					// Find the symbol that was called
  1686  					symbol := graph.Symbols.Get(ref)
  1687  					if symbol.Kind == ast.SymbolImport {
  1688  						if importData, ok := repr.Meta.ImportsToBind[ref]; ok {
  1689  							symbol = graph.Symbols.Get(importData.Ref)
  1690  						}
  1691  					}
  1692  					flags := symbol.Flags
  1693  
  1694  					// Rare path: this is a function that will be inlined
  1695  					if (flags & (ast.IsEmptyFunction | ast.CouldPotentiallyBeMutated)) == ast.IsEmptyFunction {
  1696  						// Every call will be inlined
  1697  						continue
  1698  					} else if (flags & (ast.IsIdentityFunction | ast.CouldPotentiallyBeMutated)) == ast.IsIdentityFunction {
  1699  						// Every single-argument call will be inlined as long as it's not a spread
  1700  						callUse.CallCountEstimate -= callUse.SingleArgNonSpreadCallCountEstimate
  1701  						if callUse.CallCountEstimate == 0 {
  1702  							continue
  1703  						}
  1704  					}
  1705  
  1706  					// Common path: this isn't a function that will be inlined
  1707  					use.CountEstimate += callUse.CallCountEstimate
  1708  					part.SymbolUses[ref] = use
  1709  				}
  1710  
  1711  				// Now that we know this, we can determine cross-part dependencies
  1712  				for ref := range part.SymbolUses {
  1713  
  1714  					// Rare path: this import is an inlined const value
  1715  					if graph.ConstValues != nil {
  1716  						if importData, ok := repr.Meta.ImportsToBind[ref]; ok {
  1717  							if _, isConstValue := graph.ConstValues[importData.Ref]; isConstValue {
  1718  								delete(part.SymbolUses, importData.Ref)
  1719  								continue
  1720  							}
  1721  						}
  1722  					}
  1723  
  1724  					for _, otherPartIndex := range repr.TopLevelSymbolToParts(ref) {
  1725  						if oldPartIndex, ok := localDependencies[otherPartIndex]; !ok || oldPartIndex != uint32(partIndex) {
  1726  							localDependencies[otherPartIndex] = uint32(partIndex)
  1727  							part.Dependencies = append(part.Dependencies, js_ast.Dependency{
  1728  								SourceIndex: sourceIndex,
  1729  								PartIndex:   otherPartIndex,
  1730  							})
  1731  						}
  1732  					}
  1733  
  1734  					// Also map from imports to parts that use them
  1735  					if namedImport, ok := namedImports[ref]; ok {
  1736  						namedImport.LocalPartsWithUses = append(namedImport.LocalPartsWithUses, uint32(partIndex))
  1737  						namedImports[ref] = namedImport
  1738  					}
  1739  				}
  1740  			}
  1741  
  1742  			waitGroup.Done()
  1743  		}(sourceIndex, repr)
  1744  	}
  1745  	waitGroup.Wait()
  1746  	c.timer.End("Step 5")
  1747  
  1748  	// Step 6: Bind imports to exports. This adds non-local dependencies on the
  1749  	// parts that declare the export to all parts that use the import. Also
  1750  	// generate wrapper parts for wrapped files.
  1751  	c.timer.Begin("Step 6")
  1752  	for _, sourceIndex := range c.graph.ReachableFiles {
  1753  		file := &c.graph.Files[sourceIndex]
  1754  		repr, ok := file.InputFile.Repr.(*graph.JSRepr)
  1755  		if !ok {
  1756  			continue
  1757  		}
  1758  
  1759  		// Pre-generate symbols for re-exports CommonJS symbols in case they
  1760  		// are necessary later. This is done now because the symbols map cannot be
  1761  		// mutated later due to parallelism.
  1762  		if file.IsEntryPoint() && c.options.OutputFormat == config.FormatESModule {
  1763  			copies := make([]ast.Ref, len(repr.Meta.SortedAndFilteredExportAliases))
  1764  			for i, alias := range repr.Meta.SortedAndFilteredExportAliases {
  1765  				copies[i] = c.graph.GenerateNewSymbol(sourceIndex, ast.SymbolOther, "export_"+alias)
  1766  			}
  1767  			repr.Meta.CJSExportCopies = copies
  1768  		}
  1769  
  1770  		// Use "init_*" for ESM wrappers instead of "require_*"
  1771  		if repr.Meta.Wrap == graph.WrapESM {
  1772  			c.graph.Symbols.Get(repr.AST.WrapperRef).OriginalName = "init_" + file.InputFile.Source.IdentifierName
  1773  		}
  1774  
  1775  		// If this isn't CommonJS, then rename the unused "exports" and "module"
  1776  		// variables to avoid them causing the identically-named variables in
  1777  		// actual CommonJS files from being renamed. This is purely about
  1778  		// aesthetics and is not about correctness. This is done here because by
  1779  		// this point, we know the CommonJS status will not change further.
  1780  		if repr.Meta.Wrap != graph.WrapCJS && repr.AST.ExportsKind != js_ast.ExportsCommonJS {
  1781  			name := file.InputFile.Source.IdentifierName
  1782  			c.graph.Symbols.Get(repr.AST.ExportsRef).OriginalName = name + "_exports"
  1783  			c.graph.Symbols.Get(repr.AST.ModuleRef).OriginalName = name + "_module"
  1784  		}
  1785  
  1786  		// Include the "__export" symbol from the runtime if it was used in the
  1787  		// previous step. The previous step can't do this because it's running in
  1788  		// parallel and can't safely mutate the "importsToBind" map of another file.
  1789  		if repr.Meta.NeedsExportSymbolFromRuntime {
  1790  			runtimeRepr := c.graph.Files[runtime.SourceIndex].InputFile.Repr.(*graph.JSRepr)
  1791  			exportRef := runtimeRepr.AST.ModuleScope.Members["__export"].Ref
  1792  			c.graph.GenerateSymbolImportAndUse(sourceIndex, js_ast.NSExportPartIndex, exportRef, 1, runtime.SourceIndex)
  1793  		}
  1794  
  1795  		for importRef, importData := range repr.Meta.ImportsToBind {
  1796  			resolvedRepr := c.graph.Files[importData.SourceIndex].InputFile.Repr.(*graph.JSRepr)
  1797  			partsDeclaringSymbol := resolvedRepr.TopLevelSymbolToParts(importData.Ref)
  1798  
  1799  			for _, partIndex := range repr.AST.NamedImports[importRef].LocalPartsWithUses {
  1800  				part := &repr.AST.Parts[partIndex]
  1801  
  1802  				// Depend on the file containing the imported symbol
  1803  				for _, resolvedPartIndex := range partsDeclaringSymbol {
  1804  					part.Dependencies = append(part.Dependencies, js_ast.Dependency{
  1805  						SourceIndex: importData.SourceIndex,
  1806  						PartIndex:   resolvedPartIndex,
  1807  					})
  1808  				}
  1809  
  1810  				// Also depend on any files that re-exported this symbol in between the
  1811  				// file containing the import and the file containing the imported symbol
  1812  				part.Dependencies = append(part.Dependencies, importData.ReExports...)
  1813  			}
  1814  
  1815  			// Merge these symbols so they will share the same name
  1816  			ast.MergeSymbols(c.graph.Symbols, importRef, importData.Ref)
  1817  		}
  1818  
  1819  		// If this is an entry point, depend on all exports so they are included
  1820  		if file.IsEntryPoint() {
  1821  			var dependencies []js_ast.Dependency
  1822  
  1823  			for _, alias := range repr.Meta.SortedAndFilteredExportAliases {
  1824  				export := repr.Meta.ResolvedExports[alias]
  1825  				targetSourceIndex := export.SourceIndex
  1826  				targetRef := export.Ref
  1827  
  1828  				// If this is an import, then target what the import points to
  1829  				targetRepr := c.graph.Files[targetSourceIndex].InputFile.Repr.(*graph.JSRepr)
  1830  				if importData, ok := targetRepr.Meta.ImportsToBind[targetRef]; ok {
  1831  					targetSourceIndex = importData.SourceIndex
  1832  					targetRef = importData.Ref
  1833  					targetRepr = c.graph.Files[targetSourceIndex].InputFile.Repr.(*graph.JSRepr)
  1834  					dependencies = append(dependencies, importData.ReExports...)
  1835  				}
  1836  
  1837  				// Pull in all declarations of this symbol
  1838  				for _, partIndex := range targetRepr.TopLevelSymbolToParts(targetRef) {
  1839  					dependencies = append(dependencies, js_ast.Dependency{
  1840  						SourceIndex: targetSourceIndex,
  1841  						PartIndex:   partIndex,
  1842  					})
  1843  				}
  1844  			}
  1845  
  1846  			// Ensure "exports" is included if the current output format needs it
  1847  			if repr.Meta.ForceIncludeExportsForEntryPoint {
  1848  				dependencies = append(dependencies, js_ast.Dependency{
  1849  					SourceIndex: sourceIndex,
  1850  					PartIndex:   js_ast.NSExportPartIndex,
  1851  				})
  1852  			}
  1853  
  1854  			// Include the wrapper if present
  1855  			if repr.Meta.Wrap != graph.WrapNone {
  1856  				dependencies = append(dependencies, js_ast.Dependency{
  1857  					SourceIndex: sourceIndex,
  1858  					PartIndex:   repr.Meta.WrapperPartIndex.GetIndex(),
  1859  				})
  1860  			}
  1861  
  1862  			// Represent these constraints with a dummy part
  1863  			entryPointPartIndex := c.graph.AddPartToFile(sourceIndex, js_ast.Part{
  1864  				Dependencies:         dependencies,
  1865  				CanBeRemovedIfUnused: false,
  1866  			})
  1867  			repr.Meta.EntryPointPartIndex = ast.MakeIndex32(entryPointPartIndex)
  1868  
  1869  			// Pull in the "__toCommonJS" symbol if we need it due to being an entry point
  1870  			if repr.Meta.ForceIncludeExportsForEntryPoint {
  1871  				c.graph.GenerateRuntimeSymbolImportAndUse(sourceIndex, entryPointPartIndex, "__toCommonJS", 1)
  1872  			}
  1873  		}
  1874  
  1875  		// Encode import-specific constraints in the dependency graph
  1876  		for partIndex, part := range repr.AST.Parts {
  1877  			toESMUses := uint32(0)
  1878  			toCommonJSUses := uint32(0)
  1879  			runtimeRequireUses := uint32(0)
  1880  
  1881  			// Imports of wrapped files must depend on the wrapper
  1882  			for _, importRecordIndex := range part.ImportRecordIndices {
  1883  				record := &repr.AST.ImportRecords[importRecordIndex]
  1884  
  1885  				// Don't follow external imports (this includes import() expressions)
  1886  				if !record.SourceIndex.IsValid() || c.isExternalDynamicImport(record, sourceIndex) {
  1887  					// This is an external import. Check if it will be a "require()" call.
  1888  					if record.Kind == ast.ImportRequire || !c.options.OutputFormat.KeepESMImportExportSyntax() ||
  1889  						(record.Kind == ast.ImportDynamic && c.options.UnsupportedJSFeatures.Has(compat.DynamicImport)) {
  1890  						// We should use "__require" instead of "require" if we're not
  1891  						// generating a CommonJS output file, since it won't exist otherwise
  1892  						if config.ShouldCallRuntimeRequire(c.options.Mode, c.options.OutputFormat) {
  1893  							record.Flags |= ast.CallRuntimeRequire
  1894  							runtimeRequireUses++
  1895  						}
  1896  
  1897  						// If this wasn't originally a "require()" call, then we may need
  1898  						// to wrap this in a call to the "__toESM" wrapper to convert from
  1899  						// CommonJS semantics to ESM semantics.
  1900  						//
  1901  						// Unfortunately this adds some additional code since the conversion
  1902  						// is somewhat complex. As an optimization, we can avoid this if the
  1903  						// following things are true:
  1904  						//
  1905  						// - The import is an ES module statement (e.g. not an "import()" expression)
  1906  						// - The ES module namespace object must not be captured
  1907  						// - The "default" and "__esModule" exports must not be accessed
  1908  						//
  1909  						if record.Kind != ast.ImportRequire &&
  1910  							(record.Kind != ast.ImportStmt ||
  1911  								record.Flags.Has(ast.ContainsImportStar) ||
  1912  								record.Flags.Has(ast.ContainsDefaultAlias) ||
  1913  								record.Flags.Has(ast.ContainsESModuleAlias)) {
  1914  							record.Flags |= ast.WrapWithToESM
  1915  							toESMUses++
  1916  						}
  1917  					}
  1918  					continue
  1919  				}
  1920  
  1921  				otherSourceIndex := record.SourceIndex.GetIndex()
  1922  				otherRepr := c.graph.Files[otherSourceIndex].InputFile.Repr.(*graph.JSRepr)
  1923  
  1924  				if otherRepr.Meta.Wrap != graph.WrapNone {
  1925  					// Depend on the automatically-generated require wrapper symbol
  1926  					wrapperRef := otherRepr.AST.WrapperRef
  1927  					c.graph.GenerateSymbolImportAndUse(sourceIndex, uint32(partIndex), wrapperRef, 1, otherSourceIndex)
  1928  
  1929  					// This is an ES6 import of a CommonJS module, so it needs the
  1930  					// "__toESM" wrapper as long as it's not a bare "require()"
  1931  					if record.Kind != ast.ImportRequire && otherRepr.AST.ExportsKind == js_ast.ExportsCommonJS {
  1932  						record.Flags |= ast.WrapWithToESM
  1933  						toESMUses++
  1934  					}
  1935  
  1936  					// If this is an ESM wrapper, also depend on the exports object
  1937  					// since the final code will contain an inline reference to it.
  1938  					// This must be done for "require()" and "import()" expressions
  1939  					// but does not need to be done for "import" statements since
  1940  					// those just cause us to reference the exports directly.
  1941  					if otherRepr.Meta.Wrap == graph.WrapESM && record.Kind != ast.ImportStmt {
  1942  						c.graph.GenerateSymbolImportAndUse(sourceIndex, uint32(partIndex), otherRepr.AST.ExportsRef, 1, otherSourceIndex)
  1943  
  1944  						// If this is a "require()" call, then we should add the
  1945  						// "__esModule" marker to behave as if the module was converted
  1946  						// from ESM to CommonJS. This is done via a wrapper instead of
  1947  						// by modifying the exports object itself because the same ES
  1948  						// module may be simultaneously imported and required, and the
  1949  						// importing code should not see "__esModule" while the requiring
  1950  						// code should see "__esModule". This is an extremely complex
  1951  						// and subtle set of bundler interop issues. See for example
  1952  						// https://github.com/evanw/esbuild/issues/1591.
  1953  						if record.Kind == ast.ImportRequire {
  1954  							record.Flags |= ast.WrapWithToCJS
  1955  							toCommonJSUses++
  1956  						}
  1957  					}
  1958  				} else if record.Kind == ast.ImportStmt && otherRepr.AST.ExportsKind == js_ast.ExportsESMWithDynamicFallback {
  1959  					// This is an import of a module that has a dynamic export fallback
  1960  					// object. In that case we need to depend on that object in case
  1961  					// something ends up needing to use it later. This could potentially
  1962  					// be omitted in some cases with more advanced analysis if this
  1963  					// dynamic export fallback object doesn't end up being needed.
  1964  					c.graph.GenerateSymbolImportAndUse(sourceIndex, uint32(partIndex), otherRepr.AST.ExportsRef, 1, otherSourceIndex)
  1965  				}
  1966  			}
  1967  
  1968  			// If there's an ES6 import of a non-ES6 module, then we're going to need the
  1969  			// "__toESM" symbol from the runtime to wrap the result of "require()"
  1970  			c.graph.GenerateRuntimeSymbolImportAndUse(sourceIndex, uint32(partIndex), "__toESM", toESMUses)
  1971  
  1972  			// If there's a CommonJS require of an ES6 module, then we're going to need the
  1973  			// "__toCommonJS" symbol from the runtime to wrap the exports object
  1974  			c.graph.GenerateRuntimeSymbolImportAndUse(sourceIndex, uint32(partIndex), "__toCommonJS", toCommonJSUses)
  1975  
  1976  			// If there are unbundled calls to "require()" and we're not generating
  1977  			// code for node, then substitute a "__require" wrapper for "require".
  1978  			c.graph.GenerateRuntimeSymbolImportAndUse(sourceIndex, uint32(partIndex), "__require", runtimeRequireUses)
  1979  
  1980  			// If there's an ES6 export star statement of a non-ES6 module, then we're
  1981  			// going to need the "__reExport" symbol from the runtime
  1982  			reExportUses := uint32(0)
  1983  			for _, importRecordIndex := range repr.AST.ExportStarImportRecords {
  1984  				record := &repr.AST.ImportRecords[importRecordIndex]
  1985  
  1986  				// Is this export star evaluated at run time?
  1987  				happensAtRunTime := !record.SourceIndex.IsValid() && (!file.IsEntryPoint() || !c.options.OutputFormat.KeepESMImportExportSyntax())
  1988  				if record.SourceIndex.IsValid() {
  1989  					otherSourceIndex := record.SourceIndex.GetIndex()
  1990  					otherRepr := c.graph.Files[otherSourceIndex].InputFile.Repr.(*graph.JSRepr)
  1991  					if otherSourceIndex != sourceIndex && otherRepr.AST.ExportsKind.IsDynamic() {
  1992  						happensAtRunTime = true
  1993  					}
  1994  					if otherRepr.AST.ExportsKind == js_ast.ExportsESMWithDynamicFallback {
  1995  						// This looks like "__reExport(exports_a, exports_b)". Make sure to
  1996  						// pull in the "exports_b" symbol into this export star. This matters
  1997  						// in code splitting situations where the "export_b" symbol might live
  1998  						// in a different chunk than this export star.
  1999  						c.graph.GenerateSymbolImportAndUse(sourceIndex, uint32(partIndex), otherRepr.AST.ExportsRef, 1, otherSourceIndex)
  2000  					}
  2001  				}
  2002  				if happensAtRunTime {
  2003  					// Depend on this file's "exports" object for the first argument to "__reExport"
  2004  					c.graph.GenerateSymbolImportAndUse(sourceIndex, uint32(partIndex), repr.AST.ExportsRef, 1, sourceIndex)
  2005  					record.Flags |= ast.CallsRunTimeReExportFn
  2006  					repr.AST.UsesExportsRef = true
  2007  					reExportUses++
  2008  				}
  2009  			}
  2010  			c.graph.GenerateRuntimeSymbolImportAndUse(sourceIndex, uint32(partIndex), "__reExport", reExportUses)
  2011  		}
  2012  	}
  2013  	c.timer.End("Step 6")
  2014  }
  2015  
  2016  func (c *linkerContext) validateComposesFromProperties(rootFile *graph.LinkerFile, rootRepr *graph.CSSRepr) {
  2017  	for _, local := range rootRepr.AST.LocalSymbols {
  2018  		type propertyInFile struct {
  2019  			file *graph.LinkerFile
  2020  			loc  logger.Loc
  2021  		}
  2022  
  2023  		visited := make(map[ast.Ref]bool)
  2024  		properties := make(map[string]propertyInFile)
  2025  		var visit func(*graph.LinkerFile, *graph.CSSRepr, ast.Ref)
  2026  
  2027  		visit = func(file *graph.LinkerFile, repr *graph.CSSRepr, ref ast.Ref) {
  2028  			if visited[ref] {
  2029  				return
  2030  			}
  2031  			visited[ref] = true
  2032  
  2033  			composes, ok := repr.AST.Composes[ref]
  2034  			if !ok {
  2035  				return
  2036  			}
  2037  
  2038  			for _, name := range composes.ImportedNames {
  2039  				if record := repr.AST.ImportRecords[name.ImportRecordIndex]; record.SourceIndex.IsValid() {
  2040  					otherFile := &c.graph.Files[record.SourceIndex.GetIndex()]
  2041  					if otherRepr, ok := otherFile.InputFile.Repr.(*graph.CSSRepr); ok {
  2042  						if otherName, ok := otherRepr.AST.LocalScope[name.Alias]; ok {
  2043  							visit(otherFile, otherRepr, otherName.Ref)
  2044  						}
  2045  					}
  2046  				}
  2047  			}
  2048  
  2049  			for _, name := range composes.Names {
  2050  				visit(file, repr, name.Ref)
  2051  			}
  2052  
  2053  			// Warn about cross-file composition with the same CSS properties
  2054  			for keyText, keyLoc := range composes.Properties {
  2055  				property, ok := properties[keyText]
  2056  				if !ok {
  2057  					properties[keyText] = propertyInFile{file, keyLoc}
  2058  					continue
  2059  				}
  2060  				if property.file == file || property.file == nil {
  2061  					continue
  2062  				}
  2063  
  2064  				localOriginalName := c.graph.Symbols.Get(local.Ref).OriginalName
  2065  				c.log.AddMsgID(logger.MsgID_CSS_UndefinedComposesFrom, logger.Msg{
  2066  					Kind: logger.Warning,
  2067  					Data: rootFile.LineColumnTracker().MsgData(
  2068  						css_lexer.RangeOfIdentifier(rootFile.InputFile.Source, local.Loc),
  2069  						fmt.Sprintf("The value of %q in the %q class is undefined", keyText, localOriginalName),
  2070  					),
  2071  					Notes: []logger.MsgData{
  2072  						property.file.LineColumnTracker().MsgData(
  2073  							css_lexer.RangeOfIdentifier(property.file.InputFile.Source, property.loc),
  2074  							fmt.Sprintf("The first definition of %q is here:", keyText),
  2075  						),
  2076  						file.LineColumnTracker().MsgData(
  2077  							css_lexer.RangeOfIdentifier(file.InputFile.Source, keyLoc),
  2078  							fmt.Sprintf("The second definition of %q is here:", keyText),
  2079  						),
  2080  						{Text: fmt.Sprintf("The specification of \"composes\" does not define an order when class declarations from separate files are composed together. "+
  2081  							"The value of the %q property for %q may change unpredictably as the code is edited. "+
  2082  							"Make sure that all definitions of %q for %q are in a single file.", keyText, localOriginalName, keyText, localOriginalName)},
  2083  					},
  2084  				})
  2085  
  2086  				// Don't warn more than once
  2087  				property.file = nil
  2088  				properties[keyText] = property
  2089  			}
  2090  		}
  2091  
  2092  		visit(rootFile, rootRepr, local.Ref)
  2093  	}
  2094  }
  2095  
  2096  func (c *linkerContext) generateCodeForLazyExport(sourceIndex uint32) {
  2097  	file := &c.graph.Files[sourceIndex]
  2098  	repr := file.InputFile.Repr.(*graph.JSRepr)
  2099  
  2100  	// Grab the lazy expression
  2101  	if len(repr.AST.Parts) < 1 {
  2102  		panic("Internal error")
  2103  	}
  2104  	part := &repr.AST.Parts[len(repr.AST.Parts)-1]
  2105  	if len(part.Stmts) != 1 {
  2106  		panic("Internal error")
  2107  	}
  2108  	lazyValue := part.Stmts[0].Data.(*js_ast.SLazyExport).Value
  2109  
  2110  	// If this JavaScript file is a stub from a CSS file, populate the exports of
  2111  	// this JavaScript stub with the local names from that CSS file. This is done
  2112  	// now instead of earlier because we need the whole bundle to be present.
  2113  	if repr.CSSSourceIndex.IsValid() {
  2114  		cssSourceIndex := repr.CSSSourceIndex.GetIndex()
  2115  		if css, ok := c.graph.Files[cssSourceIndex].InputFile.Repr.(*graph.CSSRepr); ok {
  2116  			exports := js_ast.EObject{}
  2117  
  2118  			for _, local := range css.AST.LocalSymbols {
  2119  				value := js_ast.Expr{Loc: local.Loc, Data: &js_ast.ENameOfSymbol{Ref: local.Ref}}
  2120  				visited := map[ast.Ref]bool{local.Ref: true}
  2121  				var parts []js_ast.TemplatePart
  2122  				var visitName func(*graph.CSSRepr, ast.Ref)
  2123  				var visitComposes func(*graph.CSSRepr, ast.Ref)
  2124  
  2125  				visitName = func(repr *graph.CSSRepr, ref ast.Ref) {
  2126  					if !visited[ref] {
  2127  						visited[ref] = true
  2128  						visitComposes(repr, ref)
  2129  						parts = append(parts, js_ast.TemplatePart{
  2130  							Value:      js_ast.Expr{Data: &js_ast.ENameOfSymbol{Ref: ref}},
  2131  							TailCooked: []uint16{' '},
  2132  						})
  2133  					}
  2134  				}
  2135  
  2136  				visitComposes = func(repr *graph.CSSRepr, ref ast.Ref) {
  2137  					if composes, ok := repr.AST.Composes[ref]; ok {
  2138  						for _, name := range composes.ImportedNames {
  2139  							if record := repr.AST.ImportRecords[name.ImportRecordIndex]; record.SourceIndex.IsValid() {
  2140  								otherFile := &c.graph.Files[record.SourceIndex.GetIndex()]
  2141  								if otherRepr, ok := otherFile.InputFile.Repr.(*graph.CSSRepr); ok {
  2142  									if otherName, ok := otherRepr.AST.LocalScope[name.Alias]; ok {
  2143  										visitName(otherRepr, otherName.Ref)
  2144  									}
  2145  								}
  2146  							}
  2147  						}
  2148  
  2149  						for _, name := range composes.Names {
  2150  							visitName(repr, name.Ref)
  2151  						}
  2152  					}
  2153  				}
  2154  
  2155  				visitComposes(css, local.Ref)
  2156  
  2157  				if len(parts) > 0 {
  2158  					value.Data = &js_ast.ETemplate{Parts: append(parts, js_ast.TemplatePart{Value: value})}
  2159  				}
  2160  
  2161  				exports.Properties = append(exports.Properties, js_ast.Property{
  2162  					Key:        js_ast.Expr{Loc: local.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(c.graph.Symbols.Get(local.Ref).OriginalName)}},
  2163  					ValueOrNil: value,
  2164  				})
  2165  			}
  2166  
  2167  			lazyValue.Data = &exports
  2168  		}
  2169  	}
  2170  
  2171  	// Use "module.exports = value" for CommonJS-style modules
  2172  	if repr.AST.ExportsKind == js_ast.ExportsCommonJS {
  2173  		part.Stmts = []js_ast.Stmt{js_ast.AssignStmt(
  2174  			js_ast.Expr{Loc: lazyValue.Loc, Data: &js_ast.EDot{
  2175  				Target:  js_ast.Expr{Loc: lazyValue.Loc, Data: &js_ast.EIdentifier{Ref: repr.AST.ModuleRef}},
  2176  				Name:    "exports",
  2177  				NameLoc: lazyValue.Loc,
  2178  			}},
  2179  			lazyValue,
  2180  		)}
  2181  		c.graph.GenerateSymbolImportAndUse(sourceIndex, 0, repr.AST.ModuleRef, 1, sourceIndex)
  2182  		return
  2183  	}
  2184  
  2185  	// Otherwise, generate ES6 export statements. These are added as additional
  2186  	// parts so they can be tree shaken individually.
  2187  	part.Stmts = nil
  2188  
  2189  	// Generate a new symbol and link the export into the graph for tree shaking
  2190  	generateExport := func(loc logger.Loc, name string, alias string) (ast.Ref, uint32) {
  2191  		ref := c.graph.GenerateNewSymbol(sourceIndex, ast.SymbolOther, name)
  2192  		partIndex := c.graph.AddPartToFile(sourceIndex, js_ast.Part{
  2193  			DeclaredSymbols:      []js_ast.DeclaredSymbol{{Ref: ref, IsTopLevel: true}},
  2194  			CanBeRemovedIfUnused: true,
  2195  		})
  2196  		c.graph.GenerateSymbolImportAndUse(sourceIndex, partIndex, repr.AST.ModuleRef, 1, sourceIndex)
  2197  		repr.Meta.TopLevelSymbolToPartsOverlay[ref] = []uint32{partIndex}
  2198  		repr.Meta.ResolvedExports[alias] = graph.ExportData{
  2199  			Ref:         ref,
  2200  			NameLoc:     loc,
  2201  			SourceIndex: sourceIndex,
  2202  		}
  2203  		return ref, partIndex
  2204  	}
  2205  
  2206  	// Unwrap JSON objects into separate top-level variables. This improves tree-
  2207  	// shaking by letting you only import part of a JSON file.
  2208  	//
  2209  	// But don't do this for files loaded via "with { type: 'json' }" as that
  2210  	// behavior is specified to not export anything except for the "default"
  2211  	// export: https://github.com/tc39/proposal-json-modules
  2212  	if object, ok := lazyValue.Data.(*js_ast.EObject); ok && file.InputFile.Loader != config.LoaderWithTypeJSON {
  2213  		for _, property := range object.Properties {
  2214  			if str, ok := property.Key.Data.(*js_ast.EString); ok &&
  2215  				(!file.IsEntryPoint() || js_ast.IsIdentifierUTF16(str.Value) ||
  2216  					!c.options.UnsupportedJSFeatures.Has(compat.ArbitraryModuleNamespaceNames)) {
  2217  				if name := helpers.UTF16ToString(str.Value); name != "default" {
  2218  					ref, partIndex := generateExport(property.Key.Loc, name, name)
  2219  
  2220  					// This initializes the generated variable with a copy of the property
  2221  					// value, which is INCORRECT for values that are objects/arrays because
  2222  					// they will have separate object identity. This is fixed up later in
  2223  					// "generateCodeForFileInChunkJS" by changing the object literal to
  2224  					// reference this generated variable instead.
  2225  					//
  2226  					// Changing the object literal is deferred until that point instead of
  2227  					// doing it now because we only want to do this for top-level variables
  2228  					// that actually end up being used, and we don't know which ones will
  2229  					// end up actually being used at this point (since import binding hasn't
  2230  					// happened yet). So we need to wait until after tree shaking happens.
  2231  					repr.AST.Parts[partIndex].Stmts = []js_ast.Stmt{{Loc: property.Key.Loc, Data: &js_ast.SLocal{
  2232  						IsExport: true,
  2233  						Decls: []js_ast.Decl{{
  2234  							Binding:    js_ast.Binding{Loc: property.Key.Loc, Data: &js_ast.BIdentifier{Ref: ref}},
  2235  							ValueOrNil: property.ValueOrNil,
  2236  						}},
  2237  					}}}
  2238  				}
  2239  			}
  2240  		}
  2241  	}
  2242  
  2243  	// Generate the default export
  2244  	ref, partIndex := generateExport(lazyValue.Loc, file.InputFile.Source.IdentifierName+"_default", "default")
  2245  	repr.AST.Parts[partIndex].Stmts = []js_ast.Stmt{{Loc: lazyValue.Loc, Data: &js_ast.SExportDefault{
  2246  		DefaultName: ast.LocRef{Loc: lazyValue.Loc, Ref: ref},
  2247  		Value:       js_ast.Stmt{Loc: lazyValue.Loc, Data: &js_ast.SExpr{Value: lazyValue}},
  2248  	}}}
  2249  }
  2250  
  2251  func (c *linkerContext) createExportsForFile(sourceIndex uint32) {
  2252  	////////////////////////////////////////////////////////////////////////////////
  2253  	// WARNING: This method is run in parallel over all files. Do not mutate data
  2254  	// for other files within this method or you will create a data race.
  2255  	////////////////////////////////////////////////////////////////////////////////
  2256  
  2257  	file := &c.graph.Files[sourceIndex]
  2258  	repr := file.InputFile.Repr.(*graph.JSRepr)
  2259  
  2260  	// Generate a getter per export
  2261  	properties := []js_ast.Property{}
  2262  	nsExportDependencies := []js_ast.Dependency{}
  2263  	nsExportSymbolUses := make(map[ast.Ref]js_ast.SymbolUse)
  2264  	for _, alias := range repr.Meta.SortedAndFilteredExportAliases {
  2265  		export := repr.Meta.ResolvedExports[alias]
  2266  
  2267  		// If this is an export of an import, reference the symbol that the import
  2268  		// was eventually resolved to. We need to do this because imports have
  2269  		// already been resolved by this point, so we can't generate a new import
  2270  		// and have that be resolved later.
  2271  		if importData, ok := c.graph.Files[export.SourceIndex].InputFile.Repr.(*graph.JSRepr).Meta.ImportsToBind[export.Ref]; ok {
  2272  			export.Ref = importData.Ref
  2273  			export.SourceIndex = importData.SourceIndex
  2274  			nsExportDependencies = append(nsExportDependencies, importData.ReExports...)
  2275  		}
  2276  
  2277  		// Exports of imports need EImportIdentifier in case they need to be re-
  2278  		// written to a property access later on
  2279  		var value js_ast.Expr
  2280  		if c.graph.Symbols.Get(export.Ref).NamespaceAlias != nil {
  2281  			value = js_ast.Expr{Data: &js_ast.EImportIdentifier{Ref: export.Ref}}
  2282  		} else {
  2283  			value = js_ast.Expr{Data: &js_ast.EIdentifier{Ref: export.Ref}}
  2284  		}
  2285  
  2286  		// Add a getter property
  2287  		var getter js_ast.Expr
  2288  		body := js_ast.FnBody{Block: js_ast.SBlock{Stmts: []js_ast.Stmt{{Loc: value.Loc, Data: &js_ast.SReturn{ValueOrNil: value}}}}}
  2289  		if c.options.UnsupportedJSFeatures.Has(compat.Arrow) {
  2290  			getter = js_ast.Expr{Data: &js_ast.EFunction{Fn: js_ast.Fn{Body: body}}}
  2291  		} else {
  2292  			getter = js_ast.Expr{Data: &js_ast.EArrow{PreferExpr: true, Body: body}}
  2293  		}
  2294  		properties = append(properties, js_ast.Property{
  2295  			Key:        js_ast.Expr{Data: &js_ast.EString{Value: helpers.StringToUTF16(alias)}},
  2296  			ValueOrNil: getter,
  2297  		})
  2298  		nsExportSymbolUses[export.Ref] = js_ast.SymbolUse{CountEstimate: 1}
  2299  
  2300  		// Make sure the part that declares the export is included
  2301  		for _, partIndex := range c.graph.Files[export.SourceIndex].InputFile.Repr.(*graph.JSRepr).TopLevelSymbolToParts(export.Ref) {
  2302  			// Use a non-local dependency since this is likely from a different
  2303  			// file if it came in through an export star
  2304  			nsExportDependencies = append(nsExportDependencies, js_ast.Dependency{
  2305  				SourceIndex: export.SourceIndex,
  2306  				PartIndex:   partIndex,
  2307  			})
  2308  		}
  2309  	}
  2310  
  2311  	declaredSymbols := []js_ast.DeclaredSymbol{}
  2312  	var nsExportStmts []js_ast.Stmt
  2313  
  2314  	// Prefix this part with "var exports = {}" if this isn't a CommonJS entry point
  2315  	if repr.Meta.NeedsExportsVariable {
  2316  		nsExportStmts = append(nsExportStmts, js_ast.Stmt{Data: &js_ast.SLocal{Decls: []js_ast.Decl{{
  2317  			Binding:    js_ast.Binding{Data: &js_ast.BIdentifier{Ref: repr.AST.ExportsRef}},
  2318  			ValueOrNil: js_ast.Expr{Data: &js_ast.EObject{}},
  2319  		}}}})
  2320  		declaredSymbols = append(declaredSymbols, js_ast.DeclaredSymbol{
  2321  			Ref:        repr.AST.ExportsRef,
  2322  			IsTopLevel: true,
  2323  		})
  2324  	}
  2325  
  2326  	// "__export(exports, { foo: () => foo })"
  2327  	exportRef := ast.InvalidRef
  2328  	if len(properties) > 0 {
  2329  		runtimeRepr := c.graph.Files[runtime.SourceIndex].InputFile.Repr.(*graph.JSRepr)
  2330  		exportRef = runtimeRepr.AST.ModuleScope.Members["__export"].Ref
  2331  		nsExportStmts = append(nsExportStmts, js_ast.Stmt{Data: &js_ast.SExpr{Value: js_ast.Expr{Data: &js_ast.ECall{
  2332  			Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: exportRef}},
  2333  			Args: []js_ast.Expr{
  2334  				{Data: &js_ast.EIdentifier{Ref: repr.AST.ExportsRef}},
  2335  				{Data: &js_ast.EObject{
  2336  					Properties: properties,
  2337  				}},
  2338  			},
  2339  		}}}})
  2340  
  2341  		// Make sure this file depends on the "__export" symbol
  2342  		for _, partIndex := range runtimeRepr.TopLevelSymbolToParts(exportRef) {
  2343  			nsExportDependencies = append(nsExportDependencies, js_ast.Dependency{
  2344  				SourceIndex: runtime.SourceIndex,
  2345  				PartIndex:   partIndex,
  2346  			})
  2347  		}
  2348  
  2349  		// Make sure the CommonJS closure, if there is one, includes "exports"
  2350  		repr.AST.UsesExportsRef = true
  2351  	}
  2352  
  2353  	// Decorate "module.exports" with the "__esModule" flag to indicate that
  2354  	// we used to be an ES module. This is done by wrapping the exports object
  2355  	// instead of by mutating the exports object because other modules in the
  2356  	// bundle (including the entry point module) may do "import * as" to get
  2357  	// access to the exports object and should NOT see the "__esModule" flag.
  2358  	if repr.Meta.ForceIncludeExportsForEntryPoint &&
  2359  		c.options.OutputFormat == config.FormatCommonJS {
  2360  
  2361  		runtimeRepr := c.graph.Files[runtime.SourceIndex].InputFile.Repr.(*graph.JSRepr)
  2362  		toCommonJSRef := runtimeRepr.AST.NamedExports["__toCommonJS"].Ref
  2363  
  2364  		// "module.exports = __toCommonJS(exports);"
  2365  		nsExportStmts = append(nsExportStmts, js_ast.AssignStmt(
  2366  			js_ast.Expr{Data: &js_ast.EDot{
  2367  				Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: c.unboundModuleRef}},
  2368  				Name:   "exports",
  2369  			}},
  2370  
  2371  			js_ast.Expr{Data: &js_ast.ECall{
  2372  				Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: toCommonJSRef}},
  2373  				Args:   []js_ast.Expr{{Data: &js_ast.EIdentifier{Ref: repr.AST.ExportsRef}}},
  2374  			}},
  2375  		))
  2376  	}
  2377  
  2378  	// No need to generate a part if it'll be empty
  2379  	if len(nsExportStmts) > 0 {
  2380  		// Initialize the part that was allocated for us earlier. The information
  2381  		// here will be used after this during tree shaking.
  2382  		repr.AST.Parts[js_ast.NSExportPartIndex] = js_ast.Part{
  2383  			Stmts:           nsExportStmts,
  2384  			SymbolUses:      nsExportSymbolUses,
  2385  			Dependencies:    nsExportDependencies,
  2386  			DeclaredSymbols: declaredSymbols,
  2387  
  2388  			// This can be removed if nothing uses it
  2389  			CanBeRemovedIfUnused: true,
  2390  
  2391  			// Make sure this is trimmed if unused even if tree shaking is disabled
  2392  			ForceTreeShaking: true,
  2393  		}
  2394  
  2395  		// Pull in the "__export" symbol if it was used
  2396  		if exportRef != ast.InvalidRef {
  2397  			repr.Meta.NeedsExportSymbolFromRuntime = true
  2398  		}
  2399  	}
  2400  }
  2401  
  2402  func (c *linkerContext) createWrapperForFile(sourceIndex uint32) {
  2403  	repr := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr)
  2404  
  2405  	switch repr.Meta.Wrap {
  2406  	// If this is a CommonJS file, we're going to need to generate a wrapper
  2407  	// for the CommonJS closure. That will end up looking something like this:
  2408  	//
  2409  	//   var require_foo = __commonJS((exports, module) => {
  2410  	//     ...
  2411  	//   });
  2412  	//
  2413  	// However, that generation is special-cased for various reasons and is
  2414  	// done later on. Still, we're going to need to ensure that this file
  2415  	// both depends on the "__commonJS" symbol and declares the "require_foo"
  2416  	// symbol. Instead of special-casing this during the reachablity analysis
  2417  	// below, we just append a dummy part to the end of the file with these
  2418  	// dependencies and let the general-purpose reachablity analysis take care
  2419  	// of it.
  2420  	case graph.WrapCJS:
  2421  		runtimeRepr := c.graph.Files[runtime.SourceIndex].InputFile.Repr.(*graph.JSRepr)
  2422  		commonJSParts := runtimeRepr.TopLevelSymbolToParts(c.cjsRuntimeRef)
  2423  
  2424  		// Generate the dummy part
  2425  		dependencies := make([]js_ast.Dependency, len(commonJSParts))
  2426  		for i, partIndex := range commonJSParts {
  2427  			dependencies[i] = js_ast.Dependency{
  2428  				SourceIndex: runtime.SourceIndex,
  2429  				PartIndex:   partIndex,
  2430  			}
  2431  		}
  2432  		partIndex := c.graph.AddPartToFile(sourceIndex, js_ast.Part{
  2433  			SymbolUses: map[ast.Ref]js_ast.SymbolUse{
  2434  				repr.AST.WrapperRef: {CountEstimate: 1},
  2435  			},
  2436  			DeclaredSymbols: []js_ast.DeclaredSymbol{
  2437  				{Ref: repr.AST.ExportsRef, IsTopLevel: true},
  2438  				{Ref: repr.AST.ModuleRef, IsTopLevel: true},
  2439  				{Ref: repr.AST.WrapperRef, IsTopLevel: true},
  2440  			},
  2441  			Dependencies: dependencies,
  2442  		})
  2443  		repr.Meta.WrapperPartIndex = ast.MakeIndex32(partIndex)
  2444  		c.graph.GenerateSymbolImportAndUse(sourceIndex, partIndex, c.cjsRuntimeRef, 1, runtime.SourceIndex)
  2445  
  2446  	// If this is a lazily-initialized ESM file, we're going to need to
  2447  	// generate a wrapper for the ESM closure. That will end up looking
  2448  	// something like this:
  2449  	//
  2450  	//   var init_foo = __esm(() => {
  2451  	//     ...
  2452  	//   });
  2453  	//
  2454  	// This depends on the "__esm" symbol and declares the "init_foo" symbol
  2455  	// for similar reasons to the CommonJS closure above.
  2456  	case graph.WrapESM:
  2457  		runtimeRepr := c.graph.Files[runtime.SourceIndex].InputFile.Repr.(*graph.JSRepr)
  2458  		esmParts := runtimeRepr.TopLevelSymbolToParts(c.esmRuntimeRef)
  2459  
  2460  		// Generate the dummy part
  2461  		dependencies := make([]js_ast.Dependency, len(esmParts))
  2462  		for i, partIndex := range esmParts {
  2463  			dependencies[i] = js_ast.Dependency{
  2464  				SourceIndex: runtime.SourceIndex,
  2465  				PartIndex:   partIndex,
  2466  			}
  2467  		}
  2468  		partIndex := c.graph.AddPartToFile(sourceIndex, js_ast.Part{
  2469  			SymbolUses: map[ast.Ref]js_ast.SymbolUse{
  2470  				repr.AST.WrapperRef: {CountEstimate: 1},
  2471  			},
  2472  			DeclaredSymbols: []js_ast.DeclaredSymbol{
  2473  				{Ref: repr.AST.WrapperRef, IsTopLevel: true},
  2474  			},
  2475  			Dependencies: dependencies,
  2476  		})
  2477  		repr.Meta.WrapperPartIndex = ast.MakeIndex32(partIndex)
  2478  		c.graph.GenerateSymbolImportAndUse(sourceIndex, partIndex, c.esmRuntimeRef, 1, runtime.SourceIndex)
  2479  	}
  2480  }
  2481  
  2482  func (c *linkerContext) matchImportsWithExportsForFile(sourceIndex uint32) {
  2483  	file := &c.graph.Files[sourceIndex]
  2484  	repr := file.InputFile.Repr.(*graph.JSRepr)
  2485  
  2486  	// Sort imports for determinism. Otherwise our unit tests will randomly
  2487  	// fail sometimes when error messages are reordered.
  2488  	sortedImportRefs := make([]int, 0, len(repr.AST.NamedImports))
  2489  	for ref := range repr.AST.NamedImports {
  2490  		sortedImportRefs = append(sortedImportRefs, int(ref.InnerIndex))
  2491  	}
  2492  	sort.Ints(sortedImportRefs)
  2493  
  2494  	// Pair imports with their matching exports
  2495  	for _, innerIndex := range sortedImportRefs {
  2496  		// Re-use memory for the cycle detector
  2497  		c.cycleDetector = c.cycleDetector[:0]
  2498  
  2499  		importRef := ast.Ref{SourceIndex: sourceIndex, InnerIndex: uint32(innerIndex)}
  2500  		result, reExports := c.matchImportWithExport(importTracker{sourceIndex: sourceIndex, importRef: importRef}, nil)
  2501  		switch result.kind {
  2502  		case matchImportIgnore:
  2503  
  2504  		case matchImportNormal:
  2505  			repr.Meta.ImportsToBind[importRef] = graph.ImportData{
  2506  				ReExports:   reExports,
  2507  				SourceIndex: result.sourceIndex,
  2508  				Ref:         result.ref,
  2509  			}
  2510  
  2511  		case matchImportNamespace:
  2512  			c.graph.Symbols.Get(importRef).NamespaceAlias = &ast.NamespaceAlias{
  2513  				NamespaceRef: result.namespaceRef,
  2514  				Alias:        result.alias,
  2515  			}
  2516  
  2517  		case matchImportNormalAndNamespace:
  2518  			repr.Meta.ImportsToBind[importRef] = graph.ImportData{
  2519  				ReExports:   reExports,
  2520  				SourceIndex: result.sourceIndex,
  2521  				Ref:         result.ref,
  2522  			}
  2523  
  2524  			c.graph.Symbols.Get(importRef).NamespaceAlias = &ast.NamespaceAlias{
  2525  				NamespaceRef: result.namespaceRef,
  2526  				Alias:        result.alias,
  2527  			}
  2528  
  2529  		case matchImportCycle:
  2530  			namedImport := repr.AST.NamedImports[importRef]
  2531  			c.log.AddError(file.LineColumnTracker(), js_lexer.RangeOfIdentifier(file.InputFile.Source, namedImport.AliasLoc),
  2532  				fmt.Sprintf("Detected cycle while resolving import %q", namedImport.Alias))
  2533  
  2534  		case matchImportProbablyTypeScriptType:
  2535  			repr.Meta.IsProbablyTypeScriptType[importRef] = true
  2536  
  2537  		case matchImportAmbiguous:
  2538  			namedImport := repr.AST.NamedImports[importRef]
  2539  			r := js_lexer.RangeOfIdentifier(file.InputFile.Source, namedImport.AliasLoc)
  2540  			var notes []logger.MsgData
  2541  
  2542  			// Provide the locations of both ambiguous exports if possible
  2543  			if result.nameLoc.Start != 0 && result.otherNameLoc.Start != 0 {
  2544  				a := c.graph.Files[result.sourceIndex]
  2545  				b := c.graph.Files[result.otherSourceIndex]
  2546  				ra := js_lexer.RangeOfIdentifier(a.InputFile.Source, result.nameLoc)
  2547  				rb := js_lexer.RangeOfIdentifier(b.InputFile.Source, result.otherNameLoc)
  2548  				notes = []logger.MsgData{
  2549  					a.LineColumnTracker().MsgData(ra, "One matching export is here:"),
  2550  					b.LineColumnTracker().MsgData(rb, "Another matching export is here:"),
  2551  				}
  2552  			}
  2553  
  2554  			symbol := c.graph.Symbols.Get(importRef)
  2555  			if symbol.ImportItemStatus == ast.ImportItemGenerated {
  2556  				// This is a warning instead of an error because although it appears
  2557  				// to be a named import, it's actually an automatically-generated
  2558  				// named import that was originally a property access on an import
  2559  				// star namespace object. Normally this property access would just
  2560  				// resolve to undefined at run-time instead of failing at binding-
  2561  				// time, so we emit a warning and rewrite the value to the literal
  2562  				// "undefined" instead of emitting an error.
  2563  				symbol.ImportItemStatus = ast.ImportItemMissing
  2564  				msg := fmt.Sprintf("Import %q will always be undefined because there are multiple matching exports", namedImport.Alias)
  2565  				c.log.AddIDWithNotes(logger.MsgID_Bundler_ImportIsUndefined, logger.Warning, file.LineColumnTracker(), r, msg, notes)
  2566  			} else {
  2567  				msg := fmt.Sprintf("Ambiguous import %q has multiple matching exports", namedImport.Alias)
  2568  				c.log.AddErrorWithNotes(file.LineColumnTracker(), r, msg, notes)
  2569  			}
  2570  		}
  2571  	}
  2572  }
  2573  
  2574  type matchImportKind uint8
  2575  
  2576  const (
  2577  	// The import is either external or undefined
  2578  	matchImportIgnore matchImportKind = iota
  2579  
  2580  	// "sourceIndex" and "ref" are in use
  2581  	matchImportNormal
  2582  
  2583  	// "namespaceRef" and "alias" are in use
  2584  	matchImportNamespace
  2585  
  2586  	// Both "matchImportNormal" and "matchImportNamespace"
  2587  	matchImportNormalAndNamespace
  2588  
  2589  	// The import could not be evaluated due to a cycle
  2590  	matchImportCycle
  2591  
  2592  	// The import is missing but came from a TypeScript file
  2593  	matchImportProbablyTypeScriptType
  2594  
  2595  	// The import resolved to multiple symbols via "export * from"
  2596  	matchImportAmbiguous
  2597  )
  2598  
  2599  type matchImportResult struct {
  2600  	alias            string
  2601  	kind             matchImportKind
  2602  	namespaceRef     ast.Ref
  2603  	sourceIndex      uint32
  2604  	nameLoc          logger.Loc // Optional, goes with sourceIndex, ignore if zero
  2605  	otherSourceIndex uint32
  2606  	otherNameLoc     logger.Loc // Optional, goes with otherSourceIndex, ignore if zero
  2607  	ref              ast.Ref
  2608  }
  2609  
  2610  func (c *linkerContext) matchImportWithExport(
  2611  	tracker importTracker, reExportsIn []js_ast.Dependency,
  2612  ) (result matchImportResult, reExports []js_ast.Dependency) {
  2613  	var ambiguousResults []matchImportResult
  2614  	reExports = reExportsIn
  2615  
  2616  loop:
  2617  	for {
  2618  		// Make sure we avoid infinite loops trying to resolve cycles:
  2619  		//
  2620  		//   // foo.js
  2621  		//   export {a as b} from './foo.js'
  2622  		//   export {b as c} from './foo.js'
  2623  		//   export {c as a} from './foo.js'
  2624  		//
  2625  		// This uses a O(n^2) array scan instead of a O(n) map because the vast
  2626  		// majority of cases have one or two elements and Go arrays are cheap to
  2627  		// reuse without allocating.
  2628  		for _, previousTracker := range c.cycleDetector {
  2629  			if tracker == previousTracker {
  2630  				result = matchImportResult{kind: matchImportCycle}
  2631  				break loop
  2632  			}
  2633  		}
  2634  		c.cycleDetector = append(c.cycleDetector, tracker)
  2635  
  2636  		// Resolve the import by one step
  2637  		nextTracker, status, potentiallyAmbiguousExportStarRefs := c.advanceImportTracker(tracker)
  2638  		switch status {
  2639  		case importCommonJS, importCommonJSWithoutExports, importExternal, importDisabled:
  2640  			if status == importExternal && c.options.OutputFormat.KeepESMImportExportSyntax() {
  2641  				// Imports from external modules should not be converted to CommonJS
  2642  				// if the output format preserves the original ES6 import statements
  2643  				break
  2644  			}
  2645  
  2646  			// If it's a CommonJS or external file, rewrite the import to a
  2647  			// property access. Don't do this if the namespace reference is invalid
  2648  			// though. This is the case for star imports, where the import is the
  2649  			// namespace.
  2650  			trackerFile := &c.graph.Files[tracker.sourceIndex]
  2651  			namedImport := trackerFile.InputFile.Repr.(*graph.JSRepr).AST.NamedImports[tracker.importRef]
  2652  			if namedImport.NamespaceRef != ast.InvalidRef {
  2653  				if result.kind == matchImportNormal {
  2654  					result.kind = matchImportNormalAndNamespace
  2655  					result.namespaceRef = namedImport.NamespaceRef
  2656  					result.alias = namedImport.Alias
  2657  				} else {
  2658  					result = matchImportResult{
  2659  						kind:         matchImportNamespace,
  2660  						namespaceRef: namedImport.NamespaceRef,
  2661  						alias:        namedImport.Alias,
  2662  					}
  2663  				}
  2664  			}
  2665  
  2666  			// Warn about importing from a file that is known to not have any exports
  2667  			if status == importCommonJSWithoutExports {
  2668  				symbol := c.graph.Symbols.Get(tracker.importRef)
  2669  				symbol.ImportItemStatus = ast.ImportItemMissing
  2670  				kind := logger.Warning
  2671  				if helpers.IsInsideNodeModules(trackerFile.InputFile.Source.KeyPath.Text) {
  2672  					kind = logger.Debug
  2673  				}
  2674  				c.log.AddID(logger.MsgID_Bundler_ImportIsUndefined, kind,
  2675  					trackerFile.LineColumnTracker(),
  2676  					js_lexer.RangeOfIdentifier(trackerFile.InputFile.Source, namedImport.AliasLoc),
  2677  					fmt.Sprintf("Import %q will always be undefined because the file %q has no exports",
  2678  						namedImport.Alias, c.graph.Files[nextTracker.sourceIndex].InputFile.Source.PrettyPath))
  2679  			}
  2680  
  2681  		case importDynamicFallback:
  2682  			// If it's a file with dynamic export fallback, rewrite the import to a property access
  2683  			trackerFile := &c.graph.Files[tracker.sourceIndex]
  2684  			namedImport := trackerFile.InputFile.Repr.(*graph.JSRepr).AST.NamedImports[tracker.importRef]
  2685  			if result.kind == matchImportNormal {
  2686  				result.kind = matchImportNormalAndNamespace
  2687  				result.namespaceRef = nextTracker.importRef
  2688  				result.alias = namedImport.Alias
  2689  			} else {
  2690  				result = matchImportResult{
  2691  					kind:         matchImportNamespace,
  2692  					namespaceRef: nextTracker.importRef,
  2693  					alias:        namedImport.Alias,
  2694  				}
  2695  			}
  2696  
  2697  		case importNoMatch:
  2698  			symbol := c.graph.Symbols.Get(tracker.importRef)
  2699  			trackerFile := &c.graph.Files[tracker.sourceIndex]
  2700  			namedImport := trackerFile.InputFile.Repr.(*graph.JSRepr).AST.NamedImports[tracker.importRef]
  2701  			r := js_lexer.RangeOfIdentifier(trackerFile.InputFile.Source, namedImport.AliasLoc)
  2702  
  2703  			// Report mismatched imports and exports
  2704  			if symbol.ImportItemStatus == ast.ImportItemGenerated {
  2705  				// This is not an error because although it appears to be a named
  2706  				// import, it's actually an automatically-generated named import
  2707  				// that was originally a property access on an import star
  2708  				// namespace object:
  2709  				//
  2710  				//   import * as ns from 'foo'
  2711  				//   const undefinedValue = ns.notAnExport
  2712  				//
  2713  				// If this code wasn't bundled, this property access would just resolve
  2714  				// to undefined at run-time instead of failing at binding-time, so we
  2715  				// emit rewrite the value to the literal "undefined" instead of
  2716  				// emitting an error.
  2717  				symbol.ImportItemStatus = ast.ImportItemMissing
  2718  
  2719  				// Don't emit a log message if this symbol isn't used, since then the
  2720  				// log message isn't helpful. This can happen with "import" assignment
  2721  				// statements in TypeScript code since they are ambiguously either a
  2722  				// type or a value. We consider them to be a type if they aren't used.
  2723  				//
  2724  				//   import * as ns from 'foo'
  2725  				//
  2726  				//   // There's no warning here because this is dead code
  2727  				//   if (false) ns.notAnExport
  2728  				//
  2729  				//   // There's no warning here because this is never used
  2730  				//   import unused = ns.notAnExport
  2731  				//
  2732  				if symbol.UseCountEstimate > 0 {
  2733  					nextFile := &c.graph.Files[nextTracker.sourceIndex].InputFile
  2734  					msg := logger.Msg{
  2735  						Kind: logger.Warning,
  2736  						Data: trackerFile.LineColumnTracker().MsgData(r, fmt.Sprintf(
  2737  							"Import %q will always be undefined because there is no matching export in %q",
  2738  							namedImport.Alias, nextFile.Source.PrettyPath)),
  2739  					}
  2740  					if helpers.IsInsideNodeModules(trackerFile.InputFile.Source.KeyPath.Text) {
  2741  						msg.Kind = logger.Debug
  2742  					}
  2743  					c.maybeCorrectObviousTypo(nextFile.Repr.(*graph.JSRepr), namedImport.Alias, &msg)
  2744  					c.log.AddMsgID(logger.MsgID_Bundler_ImportIsUndefined, msg)
  2745  				}
  2746  			} else {
  2747  				nextFile := &c.graph.Files[nextTracker.sourceIndex].InputFile
  2748  				msg := logger.Msg{
  2749  					Kind: logger.Error,
  2750  					Data: trackerFile.LineColumnTracker().MsgData(r, fmt.Sprintf(
  2751  						"No matching export in %q for import %q",
  2752  						nextFile.Source.PrettyPath, namedImport.Alias)),
  2753  				}
  2754  				c.maybeCorrectObviousTypo(nextFile.Repr.(*graph.JSRepr), namedImport.Alias, &msg)
  2755  				c.log.AddMsg(msg)
  2756  			}
  2757  
  2758  		case importProbablyTypeScriptType:
  2759  			// Omit this import from any namespace export code we generate for
  2760  			// import star statements (i.e. "import * as ns from 'path'")
  2761  			result = matchImportResult{kind: matchImportProbablyTypeScriptType}
  2762  
  2763  		case importFound:
  2764  			// If there are multiple ambiguous results due to use of "export * from"
  2765  			// statements, trace them all to see if they point to different things.
  2766  			for _, ambiguousTracker := range potentiallyAmbiguousExportStarRefs {
  2767  				// If this is a re-export of another import, follow the import
  2768  				if _, ok := c.graph.Files[ambiguousTracker.SourceIndex].InputFile.Repr.(*graph.JSRepr).AST.NamedImports[ambiguousTracker.Ref]; ok {
  2769  					// Save and restore the cycle detector to avoid mixing information
  2770  					oldCycleDetector := c.cycleDetector
  2771  					ambiguousResult, newReExportFiles := c.matchImportWithExport(importTracker{
  2772  						sourceIndex: ambiguousTracker.SourceIndex,
  2773  						importRef:   ambiguousTracker.Ref,
  2774  					}, reExports)
  2775  					c.cycleDetector = oldCycleDetector
  2776  					ambiguousResults = append(ambiguousResults, ambiguousResult)
  2777  					reExports = newReExportFiles
  2778  				} else {
  2779  					ambiguousResults = append(ambiguousResults, matchImportResult{
  2780  						kind:        matchImportNormal,
  2781  						sourceIndex: ambiguousTracker.SourceIndex,
  2782  						ref:         ambiguousTracker.Ref,
  2783  						nameLoc:     ambiguousTracker.NameLoc,
  2784  					})
  2785  				}
  2786  			}
  2787  
  2788  			// Defer the actual binding of this import until after we generate
  2789  			// namespace export code for all files. This has to be done for all
  2790  			// import-to-export matches, not just the initial import to the final
  2791  			// export, since all imports and re-exports must be merged together
  2792  			// for correctness.
  2793  			result = matchImportResult{
  2794  				kind:        matchImportNormal,
  2795  				sourceIndex: nextTracker.sourceIndex,
  2796  				ref:         nextTracker.importRef,
  2797  				nameLoc:     nextTracker.nameLoc,
  2798  			}
  2799  
  2800  			// Depend on the statement(s) that declared this import symbol in the
  2801  			// original file
  2802  			for _, resolvedPartIndex := range c.graph.Files[tracker.sourceIndex].InputFile.Repr.(*graph.JSRepr).TopLevelSymbolToParts(tracker.importRef) {
  2803  				reExports = append(reExports, js_ast.Dependency{
  2804  					SourceIndex: tracker.sourceIndex,
  2805  					PartIndex:   resolvedPartIndex,
  2806  				})
  2807  			}
  2808  
  2809  			// If this is a re-export of another import, continue for another
  2810  			// iteration of the loop to resolve that import as well
  2811  			if _, ok := c.graph.Files[nextTracker.sourceIndex].InputFile.Repr.(*graph.JSRepr).AST.NamedImports[nextTracker.importRef]; ok {
  2812  				tracker = nextTracker
  2813  				continue
  2814  			}
  2815  
  2816  		default:
  2817  			panic("Internal error")
  2818  		}
  2819  
  2820  		// Stop now if we didn't explicitly "continue" above
  2821  		break
  2822  	}
  2823  
  2824  	// If there is a potential ambiguity, all results must be the same
  2825  	for _, ambiguousResult := range ambiguousResults {
  2826  		if ambiguousResult != result {
  2827  			if result.kind == matchImportNormal && ambiguousResult.kind == matchImportNormal &&
  2828  				result.nameLoc.Start != 0 && ambiguousResult.nameLoc.Start != 0 {
  2829  				return matchImportResult{
  2830  					kind:             matchImportAmbiguous,
  2831  					sourceIndex:      result.sourceIndex,
  2832  					nameLoc:          result.nameLoc,
  2833  					otherSourceIndex: ambiguousResult.sourceIndex,
  2834  					otherNameLoc:     ambiguousResult.nameLoc,
  2835  				}, nil
  2836  			}
  2837  			return matchImportResult{kind: matchImportAmbiguous}, nil
  2838  		}
  2839  	}
  2840  
  2841  	return
  2842  }
  2843  
  2844  func (c *linkerContext) maybeForbidArbitraryModuleNamespaceIdentifier(kind string, sourceIndex uint32, loc logger.Loc, alias string) {
  2845  	if !js_ast.IsIdentifier(alias) {
  2846  		file := &c.graph.Files[sourceIndex]
  2847  		where := config.PrettyPrintTargetEnvironment(c.options.OriginalTargetEnv, c.options.UnsupportedJSFeatureOverridesMask)
  2848  		c.log.AddError(file.LineColumnTracker(), file.InputFile.Source.RangeOfString(loc), fmt.Sprintf(
  2849  			"Using the string %q as an %s name is not supported in %s", alias, kind, where))
  2850  	}
  2851  }
  2852  
  2853  // Attempt to correct an import name with a typo
  2854  func (c *linkerContext) maybeCorrectObviousTypo(repr *graph.JSRepr, name string, msg *logger.Msg) {
  2855  	if repr.Meta.ResolvedExportTypos == nil {
  2856  		valid := make([]string, 0, len(repr.Meta.ResolvedExports))
  2857  		for alias := range repr.Meta.ResolvedExports {
  2858  			valid = append(valid, alias)
  2859  		}
  2860  		sort.Strings(valid)
  2861  		typos := helpers.MakeTypoDetector(valid)
  2862  		repr.Meta.ResolvedExportTypos = &typos
  2863  	}
  2864  
  2865  	if corrected, ok := repr.Meta.ResolvedExportTypos.MaybeCorrectTypo(name); ok {
  2866  		msg.Data.Location.Suggestion = corrected
  2867  		export := repr.Meta.ResolvedExports[corrected]
  2868  		importedFile := &c.graph.Files[export.SourceIndex]
  2869  		text := fmt.Sprintf("Did you mean to import %q instead?", corrected)
  2870  		var note logger.MsgData
  2871  		if export.NameLoc.Start == 0 {
  2872  			// Don't report a source location for definitions without one. This can
  2873  			// happen with automatically-generated exports from non-JavaScript files.
  2874  			note.Text = text
  2875  		} else {
  2876  			var r logger.Range
  2877  			if importedFile.InputFile.Loader.IsCSS() {
  2878  				r = css_lexer.RangeOfIdentifier(importedFile.InputFile.Source, export.NameLoc)
  2879  			} else {
  2880  				r = js_lexer.RangeOfIdentifier(importedFile.InputFile.Source, export.NameLoc)
  2881  			}
  2882  			note = importedFile.LineColumnTracker().MsgData(r, text)
  2883  		}
  2884  		msg.Notes = append(msg.Notes, note)
  2885  	}
  2886  }
  2887  
  2888  func (c *linkerContext) recursivelyWrapDependencies(sourceIndex uint32) {
  2889  	repr := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr)
  2890  	if repr.Meta.DidWrapDependencies {
  2891  		return
  2892  	}
  2893  	repr.Meta.DidWrapDependencies = true
  2894  
  2895  	// Never wrap the runtime file since it always comes first
  2896  	if sourceIndex == runtime.SourceIndex {
  2897  		return
  2898  	}
  2899  
  2900  	// This module must be wrapped
  2901  	if repr.Meta.Wrap == graph.WrapNone {
  2902  		if repr.AST.ExportsKind == js_ast.ExportsCommonJS {
  2903  			repr.Meta.Wrap = graph.WrapCJS
  2904  		} else {
  2905  			repr.Meta.Wrap = graph.WrapESM
  2906  		}
  2907  	}
  2908  
  2909  	// All dependencies must also be wrapped
  2910  	for _, record := range repr.AST.ImportRecords {
  2911  		if record.SourceIndex.IsValid() {
  2912  			c.recursivelyWrapDependencies(record.SourceIndex.GetIndex())
  2913  		}
  2914  	}
  2915  }
  2916  
  2917  func (c *linkerContext) hasDynamicExportsDueToExportStar(sourceIndex uint32, visited map[uint32]bool) bool {
  2918  	// Terminate the traversal now if this file already has dynamic exports
  2919  	repr := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr)
  2920  	if repr.AST.ExportsKind == js_ast.ExportsCommonJS || repr.AST.ExportsKind == js_ast.ExportsESMWithDynamicFallback {
  2921  		return true
  2922  	}
  2923  
  2924  	// Avoid infinite loops due to cycles in the export star graph
  2925  	if visited[sourceIndex] {
  2926  		return false
  2927  	}
  2928  	visited[sourceIndex] = true
  2929  
  2930  	// Scan over the export star graph
  2931  	for _, importRecordIndex := range repr.AST.ExportStarImportRecords {
  2932  		record := &repr.AST.ImportRecords[importRecordIndex]
  2933  
  2934  		// This file has dynamic exports if the exported imports are from a file
  2935  		// that either has dynamic exports directly or transitively by itself
  2936  		// having an export star from a file with dynamic exports.
  2937  		if (!record.SourceIndex.IsValid() && (!c.graph.Files[sourceIndex].IsEntryPoint() || !c.options.OutputFormat.KeepESMImportExportSyntax())) ||
  2938  			(record.SourceIndex.IsValid() && record.SourceIndex.GetIndex() != sourceIndex && c.hasDynamicExportsDueToExportStar(record.SourceIndex.GetIndex(), visited)) {
  2939  			repr.AST.ExportsKind = js_ast.ExportsESMWithDynamicFallback
  2940  			return true
  2941  		}
  2942  	}
  2943  
  2944  	return false
  2945  }
  2946  
  2947  func (c *linkerContext) addExportsForExportStar(
  2948  	resolvedExports map[string]graph.ExportData,
  2949  	sourceIndex uint32,
  2950  	sourceIndexStack []uint32,
  2951  ) {
  2952  	// Avoid infinite loops due to cycles in the export star graph
  2953  	for _, prevSourceIndex := range sourceIndexStack {
  2954  		if prevSourceIndex == sourceIndex {
  2955  			return
  2956  		}
  2957  	}
  2958  	sourceIndexStack = append(sourceIndexStack, sourceIndex)
  2959  	repr := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr)
  2960  
  2961  	for _, importRecordIndex := range repr.AST.ExportStarImportRecords {
  2962  		record := &repr.AST.ImportRecords[importRecordIndex]
  2963  		if !record.SourceIndex.IsValid() {
  2964  			// This will be resolved at run time instead
  2965  			continue
  2966  		}
  2967  		otherSourceIndex := record.SourceIndex.GetIndex()
  2968  
  2969  		// Export stars from a CommonJS module don't work because they can't be
  2970  		// statically discovered. Just silently ignore them in this case.
  2971  		//
  2972  		// We could attempt to check whether the imported file still has ES6
  2973  		// exports even though it still uses CommonJS features. However, when
  2974  		// doing this we'd also have to rewrite any imports of these export star
  2975  		// re-exports as property accesses off of a generated require() call.
  2976  		otherRepr := c.graph.Files[otherSourceIndex].InputFile.Repr.(*graph.JSRepr)
  2977  		if otherRepr.AST.ExportsKind == js_ast.ExportsCommonJS {
  2978  			// All exports will be resolved at run time instead
  2979  			continue
  2980  		}
  2981  
  2982  		// Accumulate this file's exports
  2983  	nextExport:
  2984  		for alias, name := range otherRepr.AST.NamedExports {
  2985  			// ES6 export star statements ignore exports named "default"
  2986  			if alias == "default" {
  2987  				continue
  2988  			}
  2989  
  2990  			// This export star is shadowed if any file in the stack has a matching real named export
  2991  			for _, prevSourceIndex := range sourceIndexStack {
  2992  				prevRepr := c.graph.Files[prevSourceIndex].InputFile.Repr.(*graph.JSRepr)
  2993  				if _, ok := prevRepr.AST.NamedExports[alias]; ok {
  2994  					continue nextExport
  2995  				}
  2996  			}
  2997  
  2998  			if existing, ok := resolvedExports[alias]; !ok {
  2999  				// Initialize the re-export
  3000  				resolvedExports[alias] = graph.ExportData{
  3001  					Ref:         name.Ref,
  3002  					SourceIndex: otherSourceIndex,
  3003  					NameLoc:     name.AliasLoc,
  3004  				}
  3005  
  3006  				// Make sure the symbol is marked as imported so that code splitting
  3007  				// imports it correctly if it ends up being shared with another chunk
  3008  				repr.Meta.ImportsToBind[name.Ref] = graph.ImportData{
  3009  					Ref:         name.Ref,
  3010  					SourceIndex: otherSourceIndex,
  3011  				}
  3012  			} else if existing.SourceIndex != otherSourceIndex {
  3013  				// Two different re-exports colliding makes it potentially ambiguous
  3014  				existing.PotentiallyAmbiguousExportStarRefs =
  3015  					append(existing.PotentiallyAmbiguousExportStarRefs, graph.ImportData{
  3016  						SourceIndex: otherSourceIndex,
  3017  						Ref:         name.Ref,
  3018  						NameLoc:     name.AliasLoc,
  3019  					})
  3020  				resolvedExports[alias] = existing
  3021  			}
  3022  		}
  3023  
  3024  		// Search further through this file's export stars
  3025  		c.addExportsForExportStar(resolvedExports, otherSourceIndex, sourceIndexStack)
  3026  	}
  3027  }
  3028  
  3029  type importTracker struct {
  3030  	sourceIndex uint32
  3031  	nameLoc     logger.Loc // Optional, goes with sourceIndex, ignore if zero
  3032  	importRef   ast.Ref
  3033  }
  3034  
  3035  type importStatus uint8
  3036  
  3037  const (
  3038  	// The imported file has no matching export
  3039  	importNoMatch importStatus = iota
  3040  
  3041  	// The imported file has a matching export
  3042  	importFound
  3043  
  3044  	// The imported file is CommonJS and has unknown exports
  3045  	importCommonJS
  3046  
  3047  	// The import is missing but there is a dynamic fallback object
  3048  	importDynamicFallback
  3049  
  3050  	// The import was treated as a CommonJS import but the file is known to have no exports
  3051  	importCommonJSWithoutExports
  3052  
  3053  	// The imported file was disabled by mapping it to false in the "browser"
  3054  	// field of package.json
  3055  	importDisabled
  3056  
  3057  	// The imported file is external and has unknown exports
  3058  	importExternal
  3059  
  3060  	// This is a missing re-export in a TypeScript file, so it's probably a type
  3061  	importProbablyTypeScriptType
  3062  )
  3063  
  3064  func (c *linkerContext) advanceImportTracker(tracker importTracker) (importTracker, importStatus, []graph.ImportData) {
  3065  	file := &c.graph.Files[tracker.sourceIndex]
  3066  	repr := file.InputFile.Repr.(*graph.JSRepr)
  3067  	namedImport := repr.AST.NamedImports[tracker.importRef]
  3068  
  3069  	// Is this an external file?
  3070  	record := &repr.AST.ImportRecords[namedImport.ImportRecordIndex]
  3071  	if !record.SourceIndex.IsValid() {
  3072  		return importTracker{}, importExternal, nil
  3073  	}
  3074  
  3075  	// Is this a named import of a file without any exports?
  3076  	otherSourceIndex := record.SourceIndex.GetIndex()
  3077  	otherRepr := c.graph.Files[otherSourceIndex].InputFile.Repr.(*graph.JSRepr)
  3078  	if !namedImport.AliasIsStar && !otherRepr.AST.HasLazyExport &&
  3079  		// CommonJS exports
  3080  		otherRepr.AST.ExportKeyword.Len == 0 && namedImport.Alias != "default" &&
  3081  		// ESM exports
  3082  		!otherRepr.AST.UsesExportsRef && !otherRepr.AST.UsesModuleRef {
  3083  		// Just warn about it and replace the import with "undefined"
  3084  		return importTracker{sourceIndex: otherSourceIndex, importRef: ast.InvalidRef}, importCommonJSWithoutExports, nil
  3085  	}
  3086  
  3087  	// Is this a CommonJS file?
  3088  	if otherRepr.AST.ExportsKind == js_ast.ExportsCommonJS {
  3089  		return importTracker{sourceIndex: otherSourceIndex, importRef: ast.InvalidRef}, importCommonJS, nil
  3090  	}
  3091  
  3092  	// Match this import star with an export star from the imported file
  3093  	if matchingExport := otherRepr.Meta.ResolvedExportStar; namedImport.AliasIsStar && matchingExport != nil {
  3094  		// Check to see if this is a re-export of another import
  3095  		return importTracker{
  3096  			sourceIndex: matchingExport.SourceIndex,
  3097  			importRef:   matchingExport.Ref,
  3098  			nameLoc:     matchingExport.NameLoc,
  3099  		}, importFound, matchingExport.PotentiallyAmbiguousExportStarRefs
  3100  	}
  3101  
  3102  	// Match this import up with an export from the imported file
  3103  	if matchingExport, ok := otherRepr.Meta.ResolvedExports[namedImport.Alias]; ok {
  3104  		// Check to see if this is a re-export of another import
  3105  		return importTracker{
  3106  			sourceIndex: matchingExport.SourceIndex,
  3107  			importRef:   matchingExport.Ref,
  3108  			nameLoc:     matchingExport.NameLoc,
  3109  		}, importFound, matchingExport.PotentiallyAmbiguousExportStarRefs
  3110  	}
  3111  
  3112  	// Is this a file with dynamic exports?
  3113  	if otherRepr.AST.ExportsKind == js_ast.ExportsESMWithDynamicFallback {
  3114  		return importTracker{sourceIndex: otherSourceIndex, importRef: otherRepr.AST.ExportsRef}, importDynamicFallback, nil
  3115  	}
  3116  
  3117  	// Missing re-exports in TypeScript files are indistinguishable from types
  3118  	if file.InputFile.Loader.IsTypeScript() && namedImport.IsExported {
  3119  		return importTracker{}, importProbablyTypeScriptType, nil
  3120  	}
  3121  
  3122  	return importTracker{sourceIndex: otherSourceIndex}, importNoMatch, nil
  3123  }
  3124  
  3125  func (c *linkerContext) treeShakingAndCodeSplitting() {
  3126  	// Tree shaking: Each entry point marks all files reachable from itself
  3127  	c.timer.Begin("Tree shaking")
  3128  	for _, entryPoint := range c.graph.EntryPoints() {
  3129  		c.markFileLiveForTreeShaking(entryPoint.SourceIndex)
  3130  	}
  3131  	c.timer.End("Tree shaking")
  3132  
  3133  	// Code splitting: Determine which entry points can reach which files. This
  3134  	// has to happen after tree shaking because there is an implicit dependency
  3135  	// between live parts within the same file. All liveness has to be computed
  3136  	// first before determining which entry points can reach which files.
  3137  	c.timer.Begin("Code splitting")
  3138  	for i, entryPoint := range c.graph.EntryPoints() {
  3139  		c.markFileReachableForCodeSplitting(entryPoint.SourceIndex, uint(i), 0)
  3140  	}
  3141  	c.timer.End("Code splitting")
  3142  }
  3143  
  3144  func (c *linkerContext) markFileReachableForCodeSplitting(sourceIndex uint32, entryPointBit uint, distanceFromEntryPoint uint32) {
  3145  	file := &c.graph.Files[sourceIndex]
  3146  	if !file.IsLive {
  3147  		return
  3148  	}
  3149  	traverseAgain := false
  3150  
  3151  	// Track the minimum distance to an entry point
  3152  	if distanceFromEntryPoint < file.DistanceFromEntryPoint {
  3153  		file.DistanceFromEntryPoint = distanceFromEntryPoint
  3154  		traverseAgain = true
  3155  	}
  3156  	distanceFromEntryPoint++
  3157  
  3158  	// Don't mark this file more than once
  3159  	if file.EntryBits.HasBit(entryPointBit) && !traverseAgain {
  3160  		return
  3161  	}
  3162  	file.EntryBits.SetBit(entryPointBit)
  3163  
  3164  	switch repr := file.InputFile.Repr.(type) {
  3165  	case *graph.JSRepr:
  3166  		// If the JavaScript stub for a CSS file is included, also include the CSS file
  3167  		if repr.CSSSourceIndex.IsValid() {
  3168  			c.markFileReachableForCodeSplitting(repr.CSSSourceIndex.GetIndex(), entryPointBit, distanceFromEntryPoint)
  3169  		}
  3170  
  3171  		// Traverse into all imported files
  3172  		for _, record := range repr.AST.ImportRecords {
  3173  			if record.SourceIndex.IsValid() && !c.isExternalDynamicImport(&record, sourceIndex) {
  3174  				c.markFileReachableForCodeSplitting(record.SourceIndex.GetIndex(), entryPointBit, distanceFromEntryPoint)
  3175  			}
  3176  		}
  3177  
  3178  		// Traverse into all dependencies of all parts in this file
  3179  		for _, part := range repr.AST.Parts {
  3180  			for _, dependency := range part.Dependencies {
  3181  				if dependency.SourceIndex != sourceIndex {
  3182  					c.markFileReachableForCodeSplitting(dependency.SourceIndex, entryPointBit, distanceFromEntryPoint)
  3183  				}
  3184  			}
  3185  		}
  3186  
  3187  	case *graph.CSSRepr:
  3188  		// Traverse into all dependencies
  3189  		for _, record := range repr.AST.ImportRecords {
  3190  			if record.SourceIndex.IsValid() {
  3191  				c.markFileReachableForCodeSplitting(record.SourceIndex.GetIndex(), entryPointBit, distanceFromEntryPoint)
  3192  			}
  3193  		}
  3194  	}
  3195  }
  3196  
  3197  func (c *linkerContext) markFileLiveForTreeShaking(sourceIndex uint32) {
  3198  	file := &c.graph.Files[sourceIndex]
  3199  
  3200  	// Don't mark this file more than once
  3201  	if file.IsLive {
  3202  		return
  3203  	}
  3204  	file.IsLive = true
  3205  
  3206  	switch repr := file.InputFile.Repr.(type) {
  3207  	case *graph.JSRepr:
  3208  		// If the JavaScript stub for a CSS file is included, also include the CSS file
  3209  		if repr.CSSSourceIndex.IsValid() {
  3210  			c.markFileLiveForTreeShaking(repr.CSSSourceIndex.GetIndex())
  3211  		}
  3212  
  3213  		for partIndex, part := range repr.AST.Parts {
  3214  			canBeRemovedIfUnused := part.CanBeRemovedIfUnused
  3215  
  3216  			// Also include any statement-level imports
  3217  			for _, importRecordIndex := range part.ImportRecordIndices {
  3218  				record := &repr.AST.ImportRecords[importRecordIndex]
  3219  				if record.Kind != ast.ImportStmt {
  3220  					continue
  3221  				}
  3222  
  3223  				if record.SourceIndex.IsValid() {
  3224  					otherSourceIndex := record.SourceIndex.GetIndex()
  3225  
  3226  					// Don't include this module for its side effects if it can be
  3227  					// considered to have no side effects
  3228  					if otherFile := &c.graph.Files[otherSourceIndex]; otherFile.InputFile.SideEffects.Kind != graph.HasSideEffects && !c.options.IgnoreDCEAnnotations {
  3229  						continue
  3230  					}
  3231  
  3232  					// Otherwise, include this module for its side effects
  3233  					c.markFileLiveForTreeShaking(otherSourceIndex)
  3234  				} else if record.Flags.Has(ast.IsExternalWithoutSideEffects) {
  3235  					// This can be removed if it's unused
  3236  					continue
  3237  				}
  3238  
  3239  				// If we get here then the import was included for its side effects, so
  3240  				// we must also keep this part
  3241  				canBeRemovedIfUnused = false
  3242  			}
  3243  
  3244  			// Include all parts in this file with side effects, or just include
  3245  			// everything if tree-shaking is disabled. Note that we still want to
  3246  			// perform tree-shaking on the runtime even if tree-shaking is disabled.
  3247  			if !canBeRemovedIfUnused || (!part.ForceTreeShaking && !c.options.TreeShaking && file.IsEntryPoint()) {
  3248  				c.markPartLiveForTreeShaking(sourceIndex, uint32(partIndex))
  3249  			}
  3250  		}
  3251  
  3252  	case *graph.CSSRepr:
  3253  		// Include all "@import" rules
  3254  		for _, record := range repr.AST.ImportRecords {
  3255  			if record.SourceIndex.IsValid() {
  3256  				c.markFileLiveForTreeShaking(record.SourceIndex.GetIndex())
  3257  			}
  3258  		}
  3259  	}
  3260  }
  3261  
  3262  func (c *linkerContext) isExternalDynamicImport(record *ast.ImportRecord, sourceIndex uint32) bool {
  3263  	return c.options.CodeSplitting &&
  3264  		record.Kind == ast.ImportDynamic &&
  3265  		c.graph.Files[record.SourceIndex.GetIndex()].IsEntryPoint() &&
  3266  		record.SourceIndex.GetIndex() != sourceIndex
  3267  }
  3268  
  3269  func (c *linkerContext) markPartLiveForTreeShaking(sourceIndex uint32, partIndex uint32) {
  3270  	file := &c.graph.Files[sourceIndex]
  3271  	repr := file.InputFile.Repr.(*graph.JSRepr)
  3272  	part := &repr.AST.Parts[partIndex]
  3273  
  3274  	// Don't mark this part more than once
  3275  	if part.IsLive {
  3276  		return
  3277  	}
  3278  	part.IsLive = true
  3279  
  3280  	// Include the file containing this part
  3281  	c.markFileLiveForTreeShaking(sourceIndex)
  3282  
  3283  	// Also include any dependencies
  3284  	for _, dep := range part.Dependencies {
  3285  		c.markPartLiveForTreeShaking(dep.SourceIndex, dep.PartIndex)
  3286  	}
  3287  }
  3288  
  3289  // JavaScript modules are traversed in depth-first postorder. This is the
  3290  // order that JavaScript modules were evaluated in before the top-level await
  3291  // feature was introduced.
  3292  //
  3293  //	  A
  3294  //	 / \
  3295  //	B   C
  3296  //	 \ /
  3297  //	  D
  3298  //
  3299  // If A imports B and then C, B imports D, and C imports D, then the JavaScript
  3300  // traversal order is D B C A.
  3301  //
  3302  // This function may deviate from ESM import order for dynamic imports (both
  3303  // "require()" and "import()"). This is because the import order is impossible
  3304  // to determine since the imports happen at run-time instead of compile-time.
  3305  // In this case we just pick an arbitrary but consistent order.
  3306  func (c *linkerContext) findImportedCSSFilesInJSOrder(entryPoint uint32) (order []uint32) {
  3307  	visited := make(map[uint32]bool)
  3308  	var visit func(uint32)
  3309  
  3310  	// Include this file and all files it imports
  3311  	visit = func(sourceIndex uint32) {
  3312  		if visited[sourceIndex] {
  3313  			return
  3314  		}
  3315  		visited[sourceIndex] = true
  3316  		file := &c.graph.Files[sourceIndex]
  3317  		repr := file.InputFile.Repr.(*graph.JSRepr)
  3318  
  3319  		// Iterate over each part in the file in order
  3320  		for _, part := range repr.AST.Parts {
  3321  			// Traverse any files imported by this part. Note that CommonJS calls
  3322  			// to "require()" count as imports too, sort of as if the part has an
  3323  			// ESM "import" statement in it. This may seem weird because ESM imports
  3324  			// are a compile-time concept while CommonJS imports are a run-time
  3325  			// concept. But we don't want to manipulate <style> tags at run-time so
  3326  			// this is the only way to do it.
  3327  			for _, importRecordIndex := range part.ImportRecordIndices {
  3328  				if record := &repr.AST.ImportRecords[importRecordIndex]; record.SourceIndex.IsValid() {
  3329  					visit(record.SourceIndex.GetIndex())
  3330  				}
  3331  			}
  3332  		}
  3333  
  3334  		// Iterate over the associated CSS imports in postorder
  3335  		if repr.CSSSourceIndex.IsValid() {
  3336  			order = append(order, repr.CSSSourceIndex.GetIndex())
  3337  		}
  3338  	}
  3339  
  3340  	// Include all files reachable from the entry point
  3341  	visit(entryPoint)
  3342  
  3343  	return
  3344  }
  3345  
  3346  type cssImportKind uint8
  3347  
  3348  const (
  3349  	cssImportNone cssImportKind = iota
  3350  	cssImportSourceIndex
  3351  	cssImportExternalPath
  3352  	cssImportLayers
  3353  )
  3354  
  3355  type cssImportOrder struct {
  3356  	conditions             []css_ast.ImportConditions
  3357  	conditionImportRecords []ast.ImportRecord
  3358  
  3359  	layers       [][]string  // kind == cssImportAtLayer
  3360  	externalPath logger.Path // kind == cssImportExternal
  3361  	sourceIndex  uint32      // kind == cssImportSourceIndex
  3362  
  3363  	kind cssImportKind
  3364  }
  3365  
  3366  // CSS files are traversed in depth-first postorder just like JavaScript. But
  3367  // unlike JavaScript import statements, CSS "@import" rules are evaluated every
  3368  // time instead of just the first time.
  3369  //
  3370  //	  A
  3371  //	 / \
  3372  //	B   C
  3373  //	 \ /
  3374  //	  D
  3375  //
  3376  // If A imports B and then C, B imports D, and C imports D, then the CSS
  3377  // traversal order is D B D C A.
  3378  //
  3379  // However, evaluating a CSS file multiple times is sort of equivalent to
  3380  // evaluating it once at the last location. So we basically drop all but the
  3381  // last evaluation in the order.
  3382  //
  3383  // The only exception to this is "@layer". Evaluating a CSS file multiple
  3384  // times is sort of equivalent to evaluating it once at the first location
  3385  // as far as "@layer" is concerned. So we may in some cases keep both the
  3386  // first and last locations and only write out the "@layer" information
  3387  // for the first location.
  3388  func (c *linkerContext) findImportedFilesInCSSOrder(entryPoints []uint32) (order []cssImportOrder) {
  3389  	var visit func(uint32, []uint32, []css_ast.ImportConditions, []ast.ImportRecord)
  3390  	hasExternalImport := false
  3391  
  3392  	// Include this file and all files it imports
  3393  	visit = func(
  3394  		sourceIndex uint32,
  3395  		visited []uint32,
  3396  		wrappingConditions []css_ast.ImportConditions,
  3397  		wrappingImportRecords []ast.ImportRecord,
  3398  	) {
  3399  		// The CSS specification strangely does not describe what to do when there
  3400  		// is a cycle. So we are left with reverse-engineering the behavior from a
  3401  		// real browser. Here's what the WebKit code base has to say about this:
  3402  		//
  3403  		//   "Check for a cycle in our import chain. If we encounter a stylesheet
  3404  		//   in our parent chain with the same URL, then just bail."
  3405  		//
  3406  		// So that's what we do here. See "StyleRuleImport::requestStyleSheet()" in
  3407  		// WebKit for more information.
  3408  		for _, visitedSourceIndex := range visited {
  3409  			if visitedSourceIndex == sourceIndex {
  3410  				return
  3411  			}
  3412  		}
  3413  		visited = append(visited, sourceIndex)
  3414  
  3415  		repr := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.CSSRepr)
  3416  		topLevelRules := repr.AST.Rules
  3417  
  3418  		// Any pre-import layers come first
  3419  		if len(repr.AST.LayersPreImport) > 0 {
  3420  			order = append(order, cssImportOrder{
  3421  				kind:                   cssImportLayers,
  3422  				layers:                 repr.AST.LayersPreImport,
  3423  				conditions:             wrappingConditions,
  3424  				conditionImportRecords: wrappingImportRecords,
  3425  			})
  3426  		}
  3427  
  3428  		// Iterate over the top-level "@import" rules
  3429  		for _, rule := range topLevelRules {
  3430  			if atImport, ok := rule.Data.(*css_ast.RAtImport); ok {
  3431  				record := &repr.AST.ImportRecords[atImport.ImportRecordIndex]
  3432  
  3433  				// Follow internal dependencies
  3434  				if record.SourceIndex.IsValid() {
  3435  					nestedConditions := wrappingConditions
  3436  					nestedImportRecords := wrappingImportRecords
  3437  
  3438  					// If this import has conditions, fork our state so that the entire
  3439  					// imported stylesheet subtree is wrapped in all of the conditions
  3440  					if atImport.ImportConditions != nil {
  3441  						// Fork our state
  3442  						nestedConditions = append([]css_ast.ImportConditions{}, nestedConditions...)
  3443  						nestedImportRecords = append([]ast.ImportRecord{}, nestedImportRecords...)
  3444  
  3445  						// Clone these import conditions and append them to the state
  3446  						var conditions css_ast.ImportConditions
  3447  						conditions, nestedImportRecords = atImport.ImportConditions.CloneWithImportRecords(repr.AST.ImportRecords, nestedImportRecords)
  3448  						nestedConditions = append(nestedConditions, conditions)
  3449  					}
  3450  
  3451  					visit(record.SourceIndex.GetIndex(), visited, nestedConditions, nestedImportRecords)
  3452  					continue
  3453  				}
  3454  
  3455  				// Record external dependencies
  3456  				if (record.Flags & ast.WasLoadedWithEmptyLoader) == 0 {
  3457  					allConditions := wrappingConditions
  3458  					allImportRecords := wrappingImportRecords
  3459  
  3460  					// If this import has conditions, append it to the list of overall
  3461  					// conditions for this external import. Note that an external import
  3462  					// may actually have multiple sets of conditions that can't be
  3463  					// merged. When this happens we need to generate a nested imported
  3464  					// CSS file using a data URL.
  3465  					if atImport.ImportConditions != nil {
  3466  						var conditions css_ast.ImportConditions
  3467  						allConditions = append([]css_ast.ImportConditions{}, allConditions...)
  3468  						allImportRecords = append([]ast.ImportRecord{}, allImportRecords...)
  3469  						conditions, allImportRecords = atImport.ImportConditions.CloneWithImportRecords(repr.AST.ImportRecords, allImportRecords)
  3470  						allConditions = append(allConditions, conditions)
  3471  					}
  3472  
  3473  					order = append(order, cssImportOrder{
  3474  						kind:                   cssImportExternalPath,
  3475  						externalPath:           record.Path,
  3476  						conditions:             allConditions,
  3477  						conditionImportRecords: allImportRecords,
  3478  					})
  3479  					hasExternalImport = true
  3480  				}
  3481  			}
  3482  		}
  3483  
  3484  		// Iterate over the "composes" directives. Note that the order doesn't
  3485  		// matter for these because the output order is explicitly undefined
  3486  		// in the specification.
  3487  		for _, record := range repr.AST.ImportRecords {
  3488  			if record.Kind == ast.ImportComposesFrom && record.SourceIndex.IsValid() {
  3489  				visit(record.SourceIndex.GetIndex(), visited, wrappingConditions, wrappingImportRecords)
  3490  			}
  3491  		}
  3492  
  3493  		// Accumulate imports in depth-first postorder
  3494  		order = append(order, cssImportOrder{
  3495  			kind:                   cssImportSourceIndex,
  3496  			sourceIndex:            sourceIndex,
  3497  			conditions:             wrappingConditions,
  3498  			conditionImportRecords: wrappingImportRecords,
  3499  		})
  3500  	}
  3501  
  3502  	// Include all files reachable from any entry point
  3503  	var visited [16]uint32 // Preallocate some space for the visited set
  3504  	for _, sourceIndex := range entryPoints {
  3505  		visit(sourceIndex, visited[:], nil, nil)
  3506  	}
  3507  
  3508  	// Create a temporary array that we can use for filtering
  3509  	wipOrder := make([]cssImportOrder, 0, len(order))
  3510  
  3511  	// CSS syntax unfortunately only allows "@import" rules at the top of the
  3512  	// file. This means we must hoist all external "@import" rules to the top of
  3513  	// the file when bundling, even though doing so will change the order of CSS
  3514  	// evaluation.
  3515  	if hasExternalImport {
  3516  		// Pass 1: Pull out leading "@layer" and external "@import" rules
  3517  		isAtLayerPrefix := true
  3518  		for _, entry := range order {
  3519  			if (entry.kind == cssImportLayers && isAtLayerPrefix) || entry.kind == cssImportExternalPath {
  3520  				wipOrder = append(wipOrder, entry)
  3521  			}
  3522  			if entry.kind != cssImportLayers {
  3523  				isAtLayerPrefix = false
  3524  			}
  3525  		}
  3526  
  3527  		// Pass 2: Append everything that we didn't pull out in pass 1
  3528  		isAtLayerPrefix = true
  3529  		for _, entry := range order {
  3530  			if (entry.kind != cssImportLayers || !isAtLayerPrefix) && entry.kind != cssImportExternalPath {
  3531  				wipOrder = append(wipOrder, entry)
  3532  			}
  3533  			if entry.kind != cssImportLayers {
  3534  				isAtLayerPrefix = false
  3535  			}
  3536  		}
  3537  
  3538  		order, wipOrder = wipOrder, order[:0]
  3539  	}
  3540  
  3541  	// Next, optimize import order. If there are duplicate copies of an imported
  3542  	// file, replace all but the last copy with just the layers that are in that
  3543  	// file. This works because in CSS, the last instance of a declaration
  3544  	// overrides all previous instances of that declaration.
  3545  	{
  3546  		sourceIndexDuplicates := make(map[uint32][]int)
  3547  		externalPathDuplicates := make(map[logger.Path][]int)
  3548  
  3549  	nextBackward:
  3550  		for i := len(order) - 1; i >= 0; i-- {
  3551  			entry := order[i]
  3552  			switch entry.kind {
  3553  			case cssImportSourceIndex:
  3554  				duplicates := sourceIndexDuplicates[entry.sourceIndex]
  3555  				for _, j := range duplicates {
  3556  					if isConditionalImportRedundant(entry.conditions, order[j].conditions) {
  3557  						order[i].kind = cssImportLayers
  3558  						order[i].layers = c.graph.Files[entry.sourceIndex].InputFile.Repr.(*graph.CSSRepr).AST.LayersPostImport
  3559  						continue nextBackward
  3560  					}
  3561  				}
  3562  				sourceIndexDuplicates[entry.sourceIndex] = append(duplicates, i)
  3563  
  3564  			case cssImportExternalPath:
  3565  				duplicates := externalPathDuplicates[entry.externalPath]
  3566  				for _, j := range duplicates {
  3567  					if isConditionalImportRedundant(entry.conditions, order[j].conditions) {
  3568  						// Don't remove duplicates entirely. The import conditions may
  3569  						// still introduce layers to the layer order. Represent this as a
  3570  						// file with an empty layer list.
  3571  						order[i].kind = cssImportLayers
  3572  						continue nextBackward
  3573  					}
  3574  				}
  3575  				externalPathDuplicates[entry.externalPath] = append(duplicates, i)
  3576  			}
  3577  		}
  3578  	}
  3579  
  3580  	// Then optimize "@layer" rules by removing redundant ones. This loop goes
  3581  	// forward instead of backward because "@layer" takes effect at the first
  3582  	// copy instead of the last copy like other things in CSS.
  3583  	{
  3584  		type duplicateEntry struct {
  3585  			layers  [][]string
  3586  			indices []int
  3587  		}
  3588  		var layerDuplicates []duplicateEntry
  3589  
  3590  	nextForward:
  3591  		for i := range order {
  3592  			entry := order[i]
  3593  
  3594  			// Simplify the conditions since we know they only wrap "@layer"
  3595  			if entry.kind == cssImportLayers {
  3596  				// Truncate the conditions at the first anonymous layer
  3597  				for i, conditions := range entry.conditions {
  3598  					// The layer is anonymous if it's a "layer" token without any
  3599  					// children instead of a "layer(...)" token with children:
  3600  					//
  3601  					//   /* entry.css */
  3602  					//   @import "foo.css" layer;
  3603  					//
  3604  					//   /* foo.css */
  3605  					//   @layer foo;
  3606  					//
  3607  					// We don't need to generate this (as far as I can tell):
  3608  					//
  3609  					//   @layer {
  3610  					//     @layer foo;
  3611  					//   }
  3612  					//
  3613  					if conditions.Layers != nil && len(conditions.Layers) == 1 && conditions.Layers[0].Children == nil {
  3614  						entry.conditions = entry.conditions[:i]
  3615  						entry.layers = nil
  3616  						break
  3617  					}
  3618  				}
  3619  
  3620  				// If there are no layer names for this file, trim all conditions
  3621  				// without layers because we know they have no effect.
  3622  				//
  3623  				//   /* entry.css */
  3624  				//   @import "foo.css" layer(foo) supports(display: flex);
  3625  				//
  3626  				//   /* foo.css */
  3627  				//   @import "empty.css" supports(display: grid);
  3628  				//
  3629  				// That would result in this:
  3630  				//
  3631  				//   @supports (display: flex) {
  3632  				//     @layer foo {
  3633  				//       @supports (display: grid) {}
  3634  				//     }
  3635  				//   }
  3636  				//
  3637  				// Here we can trim "supports(display: grid)" to generate this:
  3638  				//
  3639  				//   @supports (display: flex) {
  3640  				//     @layer foo;
  3641  				//   }
  3642  				//
  3643  				if len(entry.layers) == 0 {
  3644  					for i := len(entry.conditions) - 1; i >= 0; i-- {
  3645  						if len(entry.conditions[i].Layers) > 0 {
  3646  							break
  3647  						}
  3648  						entry.conditions = entry.conditions[:i]
  3649  					}
  3650  				}
  3651  
  3652  				// Remove unnecessary entries entirely
  3653  				if len(entry.conditions) == 0 && len(entry.layers) == 0 {
  3654  					continue
  3655  				}
  3656  			}
  3657  
  3658  			// Omit redundant "@layer" rules with the same set of layer names. Note
  3659  			// that this tests all import order entries (not just layer ones) because
  3660  			// sometimes non-layer ones can make following layer ones redundant.
  3661  			layersKey := entry.layers
  3662  			if entry.kind == cssImportSourceIndex {
  3663  				layersKey = c.graph.Files[entry.sourceIndex].InputFile.Repr.(*graph.CSSRepr).AST.LayersPostImport
  3664  			}
  3665  			index := 0
  3666  			for index < len(layerDuplicates) {
  3667  				if helpers.StringArrayArraysEqual(layersKey, layerDuplicates[index].layers) {
  3668  					break
  3669  				}
  3670  				index++
  3671  			}
  3672  			if index == len(layerDuplicates) {
  3673  				// This is the first time we've seen this combination of layer names.
  3674  				// Allocate a new set of duplicate indices to track this combination.
  3675  				layerDuplicates = append(layerDuplicates, duplicateEntry{layers: layersKey})
  3676  			}
  3677  			duplicates := layerDuplicates[index].indices
  3678  			for j := len(duplicates) - 1; j >= 0; j-- {
  3679  				if index := duplicates[j]; isConditionalImportRedundant(entry.conditions, wipOrder[index].conditions) {
  3680  					if entry.kind != cssImportLayers {
  3681  						// If an empty layer is followed immediately by a full layer and
  3682  						// everything else is identical, then we don't need to emit the
  3683  						// empty layer. For example:
  3684  						//
  3685  						//   @media screen {
  3686  						//     @supports (display: grid) {
  3687  						//       @layer foo;
  3688  						//     }
  3689  						//   }
  3690  						//   @media screen {
  3691  						//     @supports (display: grid) {
  3692  						//       @layer foo {
  3693  						//         div {
  3694  						//           color: red;
  3695  						//         }
  3696  						//       }
  3697  						//     }
  3698  						//   }
  3699  						//
  3700  						// This can be improved by dropping the empty layer. But we can
  3701  						// only do this if there's nothing in between these two rules.
  3702  						if j == len(duplicates)-1 && index == len(wipOrder)-1 {
  3703  							if other := wipOrder[index]; other.kind == cssImportLayers && importConditionsAreEqual(entry.conditions, other.conditions) {
  3704  								// Remove the previous entry and then overwrite it below
  3705  								duplicates = duplicates[:j]
  3706  								wipOrder = wipOrder[:index]
  3707  								break
  3708  							}
  3709  						}
  3710  
  3711  						// Non-layer entries still need to be present because they have
  3712  						// other side effects beside inserting things in the layer order
  3713  						wipOrder = append(wipOrder, entry)
  3714  					}
  3715  
  3716  					// Don't add this to the duplicate list below because it's redundant
  3717  					continue nextForward
  3718  				}
  3719  			}
  3720  			layerDuplicates[index].indices = append(duplicates, len(wipOrder))
  3721  			wipOrder = append(wipOrder, entry)
  3722  		}
  3723  
  3724  		order, wipOrder = wipOrder, order[:0]
  3725  	}
  3726  
  3727  	// Finally, merge adjacent "@layer" rules with identical conditions together.
  3728  	{
  3729  		didClone := -1
  3730  		for _, entry := range order {
  3731  			if entry.kind == cssImportLayers && len(wipOrder) > 0 {
  3732  				prevIndex := len(wipOrder) - 1
  3733  				prev := wipOrder[prevIndex]
  3734  				if prev.kind == cssImportLayers && importConditionsAreEqual(prev.conditions, entry.conditions) {
  3735  					if didClone != prevIndex {
  3736  						didClone = prevIndex
  3737  						prev.layers = append([][]string{}, prev.layers...)
  3738  					}
  3739  					wipOrder[prevIndex].layers = append(prev.layers, entry.layers...)
  3740  					continue
  3741  				}
  3742  			}
  3743  			wipOrder = append(wipOrder, entry)
  3744  		}
  3745  		order = wipOrder
  3746  	}
  3747  
  3748  	return
  3749  }
  3750  
  3751  func importConditionsAreEqual(a []css_ast.ImportConditions, b []css_ast.ImportConditions) bool {
  3752  	if len(a) != len(b) {
  3753  		return false
  3754  	}
  3755  	for i := 0; i < len(a); i++ {
  3756  		ai := a[i]
  3757  		bi := b[i]
  3758  		if !css_ast.TokensEqualIgnoringWhitespace(ai.Layers, bi.Layers) ||
  3759  			!css_ast.TokensEqualIgnoringWhitespace(ai.Supports, bi.Supports) ||
  3760  			!css_ast.TokensEqualIgnoringWhitespace(ai.Media, bi.Media) {
  3761  			return false
  3762  		}
  3763  	}
  3764  	return true
  3765  }
  3766  
  3767  // Given two "@import" rules for the same source index (an earlier one and a
  3768  // later one), the earlier one is masked by the later one if the later one's
  3769  // condition list is a prefix of the earlier one's condition list.
  3770  //
  3771  // For example:
  3772  //
  3773  //	// entry.css
  3774  //	@import "foo.css" supports(display: flex);
  3775  //	@import "bar.css" supports(display: flex);
  3776  //
  3777  //	// foo.css
  3778  //	@import "lib.css" screen;
  3779  //
  3780  //	// bar.css
  3781  //	@import "lib.css";
  3782  //
  3783  // When we bundle this code we'll get an import order as follows:
  3784  //
  3785  //  1. lib.css [supports(display: flex), screen]
  3786  //  2. foo.css [supports(display: flex)]
  3787  //  3. lib.css [supports(display: flex)]
  3788  //  4. bar.css [supports(display: flex)]
  3789  //  5. entry.css []
  3790  //
  3791  // For "lib.css", the entry with the conditions [supports(display: flex)] should
  3792  // make the entry with the conditions [supports(display: flex), screen] redundant.
  3793  //
  3794  // Note that all of this deliberately ignores the existence of "@layer" because
  3795  // that is handled separately. All of this is only for handling unlayered styles.
  3796  func isConditionalImportRedundant(earlier []css_ast.ImportConditions, later []css_ast.ImportConditions) bool {
  3797  	if len(later) > len(earlier) {
  3798  		return false
  3799  	}
  3800  
  3801  	for i := 0; i < len(later); i++ {
  3802  		a := earlier[i]
  3803  		b := later[i]
  3804  
  3805  		// Only compare "@supports" and "@media" if "@layers" is equal
  3806  		if css_ast.TokensEqualIgnoringWhitespace(a.Layers, b.Layers) {
  3807  			sameSupports := css_ast.TokensEqualIgnoringWhitespace(a.Supports, b.Supports)
  3808  			sameMedia := css_ast.TokensEqualIgnoringWhitespace(a.Media, b.Media)
  3809  
  3810  			// If the import conditions are exactly equal, then only keep
  3811  			// the later one. The earlier one is redundant. Example:
  3812  			//
  3813  			//   @import "foo.css" layer(abc) supports(display: flex) screen;
  3814  			//   @import "foo.css" layer(abc) supports(display: flex) screen;
  3815  			//
  3816  			// The later one makes the earlier one redundant.
  3817  			if sameSupports && sameMedia {
  3818  				continue
  3819  			}
  3820  
  3821  			// If the media conditions are exactly equal and the later one
  3822  			// doesn't have any supports conditions, then the later one will
  3823  			// apply in all cases where the earlier one applies. Example:
  3824  			//
  3825  			//   @import "foo.css" layer(abc) supports(display: flex) screen;
  3826  			//   @import "foo.css" layer(abc) screen;
  3827  			//
  3828  			// The later one makes the earlier one redundant.
  3829  			if sameMedia && len(b.Supports) == 0 {
  3830  				continue
  3831  			}
  3832  
  3833  			// If the supports conditions are exactly equal and the later one
  3834  			// doesn't have any media conditions, then the later one will
  3835  			// apply in all cases where the earlier one applies. Example:
  3836  			//
  3837  			//   @import "foo.css" layer(abc) supports(display: flex) screen;
  3838  			//   @import "foo.css" layer(abc) supports(display: flex);
  3839  			//
  3840  			// The later one makes the earlier one redundant.
  3841  			if sameSupports && len(b.Media) == 0 {
  3842  				continue
  3843  			}
  3844  		}
  3845  
  3846  		return false
  3847  	}
  3848  
  3849  	return true
  3850  }
  3851  
  3852  func (c *linkerContext) computeChunks() {
  3853  	c.timer.Begin("Compute chunks")
  3854  	defer c.timer.End("Compute chunks")
  3855  
  3856  	jsChunks := make(map[string]chunkInfo)
  3857  	cssChunks := make(map[string]chunkInfo)
  3858  
  3859  	// Create chunks for entry points
  3860  	for i, entryPoint := range c.graph.EntryPoints() {
  3861  		file := &c.graph.Files[entryPoint.SourceIndex]
  3862  
  3863  		// Create a chunk for the entry point here to ensure that the chunk is
  3864  		// always generated even if the resulting file is empty
  3865  		entryBits := helpers.NewBitSet(uint(len(c.graph.EntryPoints())))
  3866  		entryBits.SetBit(uint(i))
  3867  		key := entryBits.String()
  3868  		chunk := chunkInfo{
  3869  			entryBits:             entryBits,
  3870  			isEntryPoint:          true,
  3871  			sourceIndex:           entryPoint.SourceIndex,
  3872  			entryPointBit:         uint(i),
  3873  			filesWithPartsInChunk: make(map[uint32]bool),
  3874  		}
  3875  
  3876  		switch file.InputFile.Repr.(type) {
  3877  		case *graph.JSRepr:
  3878  			chunkRepr := &chunkReprJS{}
  3879  			chunk.chunkRepr = chunkRepr
  3880  			jsChunks[key] = chunk
  3881  
  3882  			// If this JS entry point has an associated CSS entry point, generate it
  3883  			// now. This is essentially done by generating a virtual CSS file that
  3884  			// only contains "@import" statements in the order that the files were
  3885  			// discovered in JS source order, where JS source order is arbitrary but
  3886  			// consistent for dynamic imports. Then we run the CSS import order
  3887  			// algorithm to determine the final CSS file order for the chunk.
  3888  
  3889  			if cssSourceIndices := c.findImportedCSSFilesInJSOrder(entryPoint.SourceIndex); len(cssSourceIndices) > 0 {
  3890  				order := c.findImportedFilesInCSSOrder(cssSourceIndices)
  3891  				cssFilesWithPartsInChunk := make(map[uint32]bool)
  3892  				for _, entry := range order {
  3893  					if entry.kind == cssImportSourceIndex {
  3894  						cssFilesWithPartsInChunk[uint32(entry.sourceIndex)] = true
  3895  					}
  3896  				}
  3897  				cssChunks[key] = chunkInfo{
  3898  					entryBits:             entryBits,
  3899  					isEntryPoint:          true,
  3900  					sourceIndex:           entryPoint.SourceIndex,
  3901  					entryPointBit:         uint(i),
  3902  					filesWithPartsInChunk: cssFilesWithPartsInChunk,
  3903  					chunkRepr: &chunkReprCSS{
  3904  						importsInChunkInOrder: order,
  3905  					},
  3906  				}
  3907  				chunkRepr.hasCSSChunk = true
  3908  			}
  3909  
  3910  		case *graph.CSSRepr:
  3911  			order := c.findImportedFilesInCSSOrder([]uint32{entryPoint.SourceIndex})
  3912  			for _, entry := range order {
  3913  				if entry.kind == cssImportSourceIndex {
  3914  					chunk.filesWithPartsInChunk[uint32(entry.sourceIndex)] = true
  3915  				}
  3916  			}
  3917  			chunk.chunkRepr = &chunkReprCSS{
  3918  				importsInChunkInOrder: order,
  3919  			}
  3920  			cssChunks[key] = chunk
  3921  		}
  3922  	}
  3923  
  3924  	// Figure out which JS files are in which chunk
  3925  	for _, sourceIndex := range c.graph.ReachableFiles {
  3926  		if file := &c.graph.Files[sourceIndex]; file.IsLive {
  3927  			if _, ok := file.InputFile.Repr.(*graph.JSRepr); ok {
  3928  				key := file.EntryBits.String()
  3929  				chunk, ok := jsChunks[key]
  3930  				if !ok {
  3931  					chunk.entryBits = file.EntryBits
  3932  					chunk.filesWithPartsInChunk = make(map[uint32]bool)
  3933  					chunk.chunkRepr = &chunkReprJS{}
  3934  					jsChunks[key] = chunk
  3935  				}
  3936  				chunk.filesWithPartsInChunk[uint32(sourceIndex)] = true
  3937  			}
  3938  		}
  3939  	}
  3940  
  3941  	// Sort the chunks for determinism. This matters because we use chunk indices
  3942  	// as sorting keys in a few places.
  3943  	sortedChunks := make([]chunkInfo, 0, len(jsChunks)+len(cssChunks))
  3944  	sortedKeys := make([]string, 0, len(jsChunks)+len(cssChunks))
  3945  	for key := range jsChunks {
  3946  		sortedKeys = append(sortedKeys, key)
  3947  	}
  3948  	sort.Strings(sortedKeys)
  3949  	jsChunkIndicesForCSS := make(map[string]uint32)
  3950  	for _, key := range sortedKeys {
  3951  		chunk := jsChunks[key]
  3952  		if chunk.chunkRepr.(*chunkReprJS).hasCSSChunk {
  3953  			jsChunkIndicesForCSS[key] = uint32(len(sortedChunks))
  3954  		}
  3955  		sortedChunks = append(sortedChunks, chunk)
  3956  	}
  3957  	sortedKeys = sortedKeys[:0]
  3958  	for key := range cssChunks {
  3959  		sortedKeys = append(sortedKeys, key)
  3960  	}
  3961  	sort.Strings(sortedKeys)
  3962  	for _, key := range sortedKeys {
  3963  		chunk := cssChunks[key]
  3964  		if jsChunkIndex, ok := jsChunkIndicesForCSS[key]; ok {
  3965  			sortedChunks[jsChunkIndex].chunkRepr.(*chunkReprJS).cssChunkIndex = uint32(len(sortedChunks))
  3966  		}
  3967  		sortedChunks = append(sortedChunks, chunk)
  3968  	}
  3969  
  3970  	// Map from the entry point file to its chunk. We will need this later if
  3971  	// a file contains a dynamic import to this entry point, since we'll need
  3972  	// to look up the path for this chunk to use with the import.
  3973  	for chunkIndex, chunk := range sortedChunks {
  3974  		if chunk.isEntryPoint {
  3975  			file := &c.graph.Files[chunk.sourceIndex]
  3976  
  3977  			// JS entry points that import CSS files generate two chunks, a JS chunk
  3978  			// and a CSS chunk. Don't link the CSS chunk to the JS file since the CSS
  3979  			// chunk is secondary (the JS chunk is primary).
  3980  			if _, ok := chunk.chunkRepr.(*chunkReprCSS); ok {
  3981  				if _, ok := file.InputFile.Repr.(*graph.JSRepr); ok {
  3982  					continue
  3983  				}
  3984  			}
  3985  
  3986  			file.EntryPointChunkIndex = uint32(chunkIndex)
  3987  		}
  3988  	}
  3989  
  3990  	// Determine the order of JS files (and parts) within the chunk ahead of time
  3991  	for _, chunk := range sortedChunks {
  3992  		if chunkRepr, ok := chunk.chunkRepr.(*chunkReprJS); ok {
  3993  			chunkRepr.filesInChunkInOrder, chunkRepr.partsInChunkInOrder = c.findImportedPartsInJSOrder(&chunk)
  3994  		}
  3995  	}
  3996  
  3997  	// Assign general information to each chunk
  3998  	for chunkIndex := range sortedChunks {
  3999  		chunk := &sortedChunks[chunkIndex]
  4000  
  4001  		// Assign a unique key to each chunk. This key encodes the index directly so
  4002  		// we can easily recover it later without needing to look it up in a map. The
  4003  		// last 8 numbers of the key are the chunk index.
  4004  		chunk.uniqueKey = fmt.Sprintf("%sC%08d", c.uniqueKeyPrefix, chunkIndex)
  4005  
  4006  		// Determine the standard file extension
  4007  		var stdExt string
  4008  		switch chunk.chunkRepr.(type) {
  4009  		case *chunkReprJS:
  4010  			stdExt = c.options.OutputExtensionJS
  4011  		case *chunkReprCSS:
  4012  			stdExt = c.options.OutputExtensionCSS
  4013  		}
  4014  
  4015  		// Compute the template substitutions
  4016  		var dir, base, ext string
  4017  		var template []config.PathTemplate
  4018  		if chunk.isEntryPoint {
  4019  			// Only use the entry path template for user-specified entry points
  4020  			file := &c.graph.Files[chunk.sourceIndex]
  4021  			if file.IsUserSpecifiedEntryPoint() {
  4022  				template = c.options.EntryPathTemplate
  4023  			} else {
  4024  				template = c.options.ChunkPathTemplate
  4025  			}
  4026  
  4027  			if c.options.AbsOutputFile != "" {
  4028  				// If the output path was configured explicitly, use it verbatim
  4029  				dir = "/"
  4030  				base = c.fs.Base(c.options.AbsOutputFile)
  4031  				originalExt := c.fs.Ext(base)
  4032  				base = base[:len(base)-len(originalExt)]
  4033  
  4034  				// Use the extension from the explicit output file path. However, don't do
  4035  				// that if this is a CSS chunk but the entry point file is not CSS. In that
  4036  				// case use the standard extension. This happens when importing CSS into JS.
  4037  				if _, ok := file.InputFile.Repr.(*graph.CSSRepr); ok || stdExt != c.options.OutputExtensionCSS {
  4038  					ext = originalExt
  4039  				} else {
  4040  					ext = stdExt
  4041  				}
  4042  			} else {
  4043  				// Otherwise, derive the output path from the input path
  4044  				dir, base = bundler.PathRelativeToOutbase(
  4045  					&c.graph.Files[chunk.sourceIndex].InputFile,
  4046  					c.options,
  4047  					c.fs,
  4048  					!file.IsUserSpecifiedEntryPoint(),
  4049  					c.graph.EntryPoints()[chunk.entryPointBit].OutputPath,
  4050  				)
  4051  				ext = stdExt
  4052  			}
  4053  		} else {
  4054  			dir = "/"
  4055  			base = "chunk"
  4056  			ext = stdExt
  4057  			template = c.options.ChunkPathTemplate
  4058  		}
  4059  
  4060  		// Determine the output path template
  4061  		templateExt := strings.TrimPrefix(ext, ".")
  4062  		template = append(append(make([]config.PathTemplate, 0, len(template)+1), template...), config.PathTemplate{Data: ext})
  4063  		chunk.finalTemplate = config.SubstituteTemplate(template, config.PathPlaceholders{
  4064  			Dir:  &dir,
  4065  			Name: &base,
  4066  			Ext:  &templateExt,
  4067  		})
  4068  	}
  4069  
  4070  	c.chunks = sortedChunks
  4071  }
  4072  
  4073  type chunkOrder struct {
  4074  	sourceIndex uint32
  4075  	distance    uint32
  4076  	tieBreaker  uint32
  4077  }
  4078  
  4079  // This type is just so we can use Go's native sort function
  4080  type chunkOrderArray []chunkOrder
  4081  
  4082  func (a chunkOrderArray) Len() int          { return len(a) }
  4083  func (a chunkOrderArray) Swap(i int, j int) { a[i], a[j] = a[j], a[i] }
  4084  
  4085  func (a chunkOrderArray) Less(i int, j int) bool {
  4086  	ai := a[i]
  4087  	aj := a[j]
  4088  	return ai.distance < aj.distance || (ai.distance == aj.distance && ai.tieBreaker < aj.tieBreaker)
  4089  }
  4090  
  4091  func appendOrExtendPartRange(ranges []partRange, sourceIndex uint32, partIndex uint32) []partRange {
  4092  	if i := len(ranges) - 1; i >= 0 {
  4093  		if r := &ranges[i]; r.sourceIndex == sourceIndex && r.partIndexEnd == partIndex {
  4094  			r.partIndexEnd = partIndex + 1
  4095  			return ranges
  4096  		}
  4097  	}
  4098  
  4099  	return append(ranges, partRange{
  4100  		sourceIndex:    sourceIndex,
  4101  		partIndexBegin: partIndex,
  4102  		partIndexEnd:   partIndex + 1,
  4103  	})
  4104  }
  4105  
  4106  func (c *linkerContext) shouldIncludePart(repr *graph.JSRepr, part js_ast.Part) bool {
  4107  	// As an optimization, ignore parts containing a single import statement to
  4108  	// an internal non-wrapped file. These will be ignored anyway and it's a
  4109  	// performance hit to spin up a goroutine only to discover this later.
  4110  	if len(part.Stmts) == 1 {
  4111  		if s, ok := part.Stmts[0].Data.(*js_ast.SImport); ok {
  4112  			record := &repr.AST.ImportRecords[s.ImportRecordIndex]
  4113  			if record.SourceIndex.IsValid() && c.graph.Files[record.SourceIndex.GetIndex()].InputFile.Repr.(*graph.JSRepr).Meta.Wrap == graph.WrapNone {
  4114  				return false
  4115  			}
  4116  		}
  4117  	}
  4118  	return true
  4119  }
  4120  
  4121  func (c *linkerContext) findImportedPartsInJSOrder(chunk *chunkInfo) (js []uint32, jsParts []partRange) {
  4122  	sorted := make(chunkOrderArray, 0, len(chunk.filesWithPartsInChunk))
  4123  
  4124  	// Attach information to the files for use with sorting
  4125  	for sourceIndex := range chunk.filesWithPartsInChunk {
  4126  		file := &c.graph.Files[sourceIndex]
  4127  		sorted = append(sorted, chunkOrder{
  4128  			sourceIndex: sourceIndex,
  4129  			distance:    file.DistanceFromEntryPoint,
  4130  			tieBreaker:  c.graph.StableSourceIndices[sourceIndex],
  4131  		})
  4132  	}
  4133  
  4134  	// Sort so files closest to an entry point come first. If two files are
  4135  	// equidistant to an entry point, then break the tie by sorting on the
  4136  	// stable source index derived from the DFS over all entry points.
  4137  	sort.Sort(sorted)
  4138  
  4139  	visited := make(map[uint32]bool)
  4140  	jsPartsPrefix := []partRange{}
  4141  
  4142  	// Traverse the graph using this stable order and linearize the files with
  4143  	// dependencies before dependents
  4144  	var visit func(uint32)
  4145  	visit = func(sourceIndex uint32) {
  4146  		if visited[sourceIndex] {
  4147  			return
  4148  		}
  4149  
  4150  		visited[sourceIndex] = true
  4151  		file := &c.graph.Files[sourceIndex]
  4152  
  4153  		if repr, ok := file.InputFile.Repr.(*graph.JSRepr); ok {
  4154  			isFileInThisChunk := chunk.entryBits.Equals(file.EntryBits)
  4155  
  4156  			// Wrapped files can't be split because they are all inside the wrapper
  4157  			canFileBeSplit := repr.Meta.Wrap == graph.WrapNone
  4158  
  4159  			// Make sure the generated call to "__export(exports, ...)" comes first
  4160  			// before anything else in this file
  4161  			if canFileBeSplit && isFileInThisChunk && repr.AST.Parts[js_ast.NSExportPartIndex].IsLive {
  4162  				jsParts = appendOrExtendPartRange(jsParts, sourceIndex, js_ast.NSExportPartIndex)
  4163  			}
  4164  
  4165  			for partIndex, part := range repr.AST.Parts {
  4166  				isPartInThisChunk := isFileInThisChunk && repr.AST.Parts[partIndex].IsLive
  4167  
  4168  				// Also traverse any files imported by this part
  4169  				for _, importRecordIndex := range part.ImportRecordIndices {
  4170  					record := &repr.AST.ImportRecords[importRecordIndex]
  4171  					if record.SourceIndex.IsValid() && (record.Kind == ast.ImportStmt || isPartInThisChunk) {
  4172  						if c.isExternalDynamicImport(record, sourceIndex) {
  4173  							// Don't follow import() dependencies
  4174  							continue
  4175  						}
  4176  						visit(record.SourceIndex.GetIndex())
  4177  					}
  4178  				}
  4179  
  4180  				// Then include this part after the files it imports
  4181  				if isPartInThisChunk {
  4182  					isFileInThisChunk = true
  4183  					if canFileBeSplit && uint32(partIndex) != js_ast.NSExportPartIndex && c.shouldIncludePart(repr, part) {
  4184  						if sourceIndex == runtime.SourceIndex {
  4185  							jsPartsPrefix = appendOrExtendPartRange(jsPartsPrefix, sourceIndex, uint32(partIndex))
  4186  						} else {
  4187  							jsParts = appendOrExtendPartRange(jsParts, sourceIndex, uint32(partIndex))
  4188  						}
  4189  					}
  4190  				}
  4191  			}
  4192  
  4193  			if isFileInThisChunk {
  4194  				js = append(js, sourceIndex)
  4195  
  4196  				// CommonJS files are all-or-nothing so all parts must be contiguous
  4197  				if !canFileBeSplit {
  4198  					jsPartsPrefix = append(jsPartsPrefix, partRange{
  4199  						sourceIndex:    sourceIndex,
  4200  						partIndexBegin: 0,
  4201  						partIndexEnd:   uint32(len(repr.AST.Parts)),
  4202  					})
  4203  				}
  4204  			}
  4205  		}
  4206  	}
  4207  
  4208  	// Always put the runtime code first before anything else
  4209  	visit(runtime.SourceIndex)
  4210  	for _, data := range sorted {
  4211  		visit(data.sourceIndex)
  4212  	}
  4213  	jsParts = append(jsPartsPrefix, jsParts...)
  4214  	return
  4215  }
  4216  
  4217  func (c *linkerContext) shouldRemoveImportExportStmt(
  4218  	sourceIndex uint32,
  4219  	stmtList *stmtList,
  4220  	loc logger.Loc,
  4221  	namespaceRef ast.Ref,
  4222  	importRecordIndex uint32,
  4223  ) bool {
  4224  	repr := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr)
  4225  	record := &repr.AST.ImportRecords[importRecordIndex]
  4226  
  4227  	// Is this an external import?
  4228  	if !record.SourceIndex.IsValid() {
  4229  		// Keep the "import" statement if "import" statements are supported
  4230  		if c.options.OutputFormat.KeepESMImportExportSyntax() {
  4231  			return false
  4232  		}
  4233  
  4234  		// Otherwise, replace this statement with a call to "require()"
  4235  		stmtList.insideWrapperPrefix = append(stmtList.insideWrapperPrefix, js_ast.Stmt{
  4236  			Loc: loc,
  4237  			Data: &js_ast.SLocal{Decls: []js_ast.Decl{{
  4238  				Binding: js_ast.Binding{Loc: loc, Data: &js_ast.BIdentifier{Ref: namespaceRef}},
  4239  				ValueOrNil: js_ast.Expr{Loc: record.Range.Loc, Data: &js_ast.ERequireString{
  4240  					ImportRecordIndex: importRecordIndex,
  4241  				}},
  4242  			}}},
  4243  		})
  4244  		return true
  4245  	}
  4246  
  4247  	// We don't need a call to "require()" if this is a self-import inside a
  4248  	// CommonJS-style module, since we can just reference the exports directly.
  4249  	if repr.AST.ExportsKind == js_ast.ExportsCommonJS && ast.FollowSymbols(c.graph.Symbols, namespaceRef) == repr.AST.ExportsRef {
  4250  		return true
  4251  	}
  4252  
  4253  	otherFile := &c.graph.Files[record.SourceIndex.GetIndex()]
  4254  	otherRepr := otherFile.InputFile.Repr.(*graph.JSRepr)
  4255  	switch otherRepr.Meta.Wrap {
  4256  	case graph.WrapNone:
  4257  		// Remove the statement entirely if this module is not wrapped
  4258  
  4259  	case graph.WrapCJS:
  4260  		// Replace the statement with a call to "require()"
  4261  		stmtList.insideWrapperPrefix = append(stmtList.insideWrapperPrefix, js_ast.Stmt{
  4262  			Loc: loc,
  4263  			Data: &js_ast.SLocal{Decls: []js_ast.Decl{{
  4264  				Binding: js_ast.Binding{Loc: loc, Data: &js_ast.BIdentifier{Ref: namespaceRef}},
  4265  				ValueOrNil: js_ast.Expr{Loc: record.Range.Loc, Data: &js_ast.ERequireString{
  4266  					ImportRecordIndex: importRecordIndex,
  4267  				}},
  4268  			}}},
  4269  		})
  4270  
  4271  	case graph.WrapESM:
  4272  		// Ignore this file if it's not included in the bundle. This can happen for
  4273  		// wrapped ESM files but not for wrapped CommonJS files because we allow
  4274  		// tree shaking inside wrapped ESM files.
  4275  		if !otherFile.IsLive {
  4276  			break
  4277  		}
  4278  
  4279  		// Replace the statement with a call to "init()"
  4280  		value := js_ast.Expr{Loc: loc, Data: &js_ast.ECall{Target: js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: otherRepr.AST.WrapperRef}}}}
  4281  		if otherRepr.Meta.IsAsyncOrHasAsyncDependency {
  4282  			// This currently evaluates sibling dependencies in serial instead of in
  4283  			// parallel, which is incorrect. This should be changed to store a promise
  4284  			// and await all stored promises after all imports but before any code.
  4285  			value.Data = &js_ast.EAwait{Value: value}
  4286  		}
  4287  		stmtList.insideWrapperPrefix = append(stmtList.insideWrapperPrefix, js_ast.Stmt{Loc: loc, Data: &js_ast.SExpr{Value: value}})
  4288  	}
  4289  
  4290  	return true
  4291  }
  4292  
  4293  func (c *linkerContext) convertStmtsForChunk(sourceIndex uint32, stmtList *stmtList, partStmts []js_ast.Stmt) {
  4294  	file := &c.graph.Files[sourceIndex]
  4295  	shouldStripExports := c.options.Mode != config.ModePassThrough || !file.IsEntryPoint()
  4296  	repr := file.InputFile.Repr.(*graph.JSRepr)
  4297  	shouldExtractESMStmtsForWrap := repr.Meta.Wrap != graph.WrapNone
  4298  
  4299  	// If this file is a CommonJS entry point, double-write re-exports to the
  4300  	// external CommonJS "module.exports" object in addition to our internal ESM
  4301  	// export namespace object. The difference between these two objects is that
  4302  	// our internal one must not have the "__esModule" marker while the external
  4303  	// one must have the "__esModule" marker. This is done because an ES module
  4304  	// importing itself should not see the "__esModule" marker but a CommonJS module
  4305  	// importing us should see the "__esModule" marker.
  4306  	var moduleExportsForReExportOrNil js_ast.Expr
  4307  	if c.options.OutputFormat == config.FormatCommonJS && file.IsEntryPoint() {
  4308  		moduleExportsForReExportOrNil = js_ast.Expr{Data: &js_ast.EDot{
  4309  			Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: c.unboundModuleRef}},
  4310  			Name:   "exports",
  4311  		}}
  4312  	}
  4313  
  4314  	for _, stmt := range partStmts {
  4315  		switch s := stmt.Data.(type) {
  4316  		case *js_ast.SImport:
  4317  			// "import * as ns from 'path'"
  4318  			// "import {foo} from 'path'"
  4319  			if c.shouldRemoveImportExportStmt(sourceIndex, stmtList, stmt.Loc, s.NamespaceRef, s.ImportRecordIndex) {
  4320  				continue
  4321  			}
  4322  
  4323  			if c.options.UnsupportedJSFeatures.Has(compat.ArbitraryModuleNamespaceNames) && s.Items != nil {
  4324  				for _, item := range *s.Items {
  4325  					c.maybeForbidArbitraryModuleNamespaceIdentifier("import", sourceIndex, item.AliasLoc, item.Alias)
  4326  				}
  4327  			}
  4328  
  4329  			// Make sure these don't end up in the wrapper closure
  4330  			if shouldExtractESMStmtsForWrap {
  4331  				stmtList.outsideWrapperPrefix = append(stmtList.outsideWrapperPrefix, stmt)
  4332  				continue
  4333  			}
  4334  
  4335  		case *js_ast.SExportStar:
  4336  			// "export * as ns from 'path'"
  4337  			if s.Alias != nil {
  4338  				if c.shouldRemoveImportExportStmt(sourceIndex, stmtList, stmt.Loc, s.NamespaceRef, s.ImportRecordIndex) {
  4339  					continue
  4340  				}
  4341  
  4342  				if c.options.UnsupportedJSFeatures.Has(compat.ArbitraryModuleNamespaceNames) {
  4343  					c.maybeForbidArbitraryModuleNamespaceIdentifier("export", sourceIndex, s.Alias.Loc, s.Alias.OriginalName)
  4344  				}
  4345  
  4346  				if shouldStripExports {
  4347  					// Turn this statement into "import * as ns from 'path'"
  4348  					stmt.Data = &js_ast.SImport{
  4349  						NamespaceRef:      s.NamespaceRef,
  4350  						StarNameLoc:       &s.Alias.Loc,
  4351  						ImportRecordIndex: s.ImportRecordIndex,
  4352  					}
  4353  				}
  4354  
  4355  				// Make sure these don't end up in the wrapper closure
  4356  				if shouldExtractESMStmtsForWrap {
  4357  					stmtList.outsideWrapperPrefix = append(stmtList.outsideWrapperPrefix, stmt)
  4358  					continue
  4359  				}
  4360  				break
  4361  			}
  4362  
  4363  			// "export * from 'path'"
  4364  			if !shouldStripExports {
  4365  				break
  4366  			}
  4367  			record := &repr.AST.ImportRecords[s.ImportRecordIndex]
  4368  
  4369  			// Is this export star evaluated at run time?
  4370  			if !record.SourceIndex.IsValid() && c.options.OutputFormat.KeepESMImportExportSyntax() {
  4371  				if record.Flags.Has(ast.CallsRunTimeReExportFn) {
  4372  					// Turn this statement into "import * as ns from 'path'"
  4373  					stmt.Data = &js_ast.SImport{
  4374  						NamespaceRef:      s.NamespaceRef,
  4375  						StarNameLoc:       &logger.Loc{Start: stmt.Loc.Start},
  4376  						ImportRecordIndex: s.ImportRecordIndex,
  4377  					}
  4378  
  4379  					// Prefix this module with "__reExport(exports, ns, module.exports)"
  4380  					exportStarRef := c.graph.Files[runtime.SourceIndex].InputFile.Repr.(*graph.JSRepr).AST.ModuleScope.Members["__reExport"].Ref
  4381  					args := []js_ast.Expr{
  4382  						{Loc: stmt.Loc, Data: &js_ast.EIdentifier{Ref: repr.AST.ExportsRef}},
  4383  						{Loc: stmt.Loc, Data: &js_ast.EIdentifier{Ref: s.NamespaceRef}},
  4384  					}
  4385  					if moduleExportsForReExportOrNil.Data != nil {
  4386  						args = append(args, moduleExportsForReExportOrNil)
  4387  					}
  4388  					stmtList.insideWrapperPrefix = append(stmtList.insideWrapperPrefix, js_ast.Stmt{
  4389  						Loc: stmt.Loc,
  4390  						Data: &js_ast.SExpr{Value: js_ast.Expr{Loc: stmt.Loc, Data: &js_ast.ECall{
  4391  							Target: js_ast.Expr{Loc: stmt.Loc, Data: &js_ast.EIdentifier{Ref: exportStarRef}},
  4392  							Args:   args,
  4393  						}}},
  4394  					})
  4395  
  4396  					// Make sure these don't end up in the wrapper closure
  4397  					if shouldExtractESMStmtsForWrap {
  4398  						stmtList.outsideWrapperPrefix = append(stmtList.outsideWrapperPrefix, stmt)
  4399  						continue
  4400  					}
  4401  				}
  4402  			} else {
  4403  				if record.SourceIndex.IsValid() {
  4404  					if otherRepr := c.graph.Files[record.SourceIndex.GetIndex()].InputFile.Repr.(*graph.JSRepr); otherRepr.Meta.Wrap == graph.WrapESM {
  4405  						stmtList.insideWrapperPrefix = append(stmtList.insideWrapperPrefix, js_ast.Stmt{Loc: stmt.Loc,
  4406  							Data: &js_ast.SExpr{Value: js_ast.Expr{Loc: stmt.Loc, Data: &js_ast.ECall{
  4407  								Target: js_ast.Expr{Loc: stmt.Loc, Data: &js_ast.EIdentifier{Ref: otherRepr.AST.WrapperRef}}}}}})
  4408  					}
  4409  				}
  4410  
  4411  				if record.Flags.Has(ast.CallsRunTimeReExportFn) {
  4412  					var target js_ast.E
  4413  					if record.SourceIndex.IsValid() {
  4414  						if otherRepr := c.graph.Files[record.SourceIndex.GetIndex()].InputFile.Repr.(*graph.JSRepr); otherRepr.AST.ExportsKind == js_ast.ExportsESMWithDynamicFallback {
  4415  							// Prefix this module with "__reExport(exports, otherExports, module.exports)"
  4416  							target = &js_ast.EIdentifier{Ref: otherRepr.AST.ExportsRef}
  4417  						}
  4418  					}
  4419  					if target == nil {
  4420  						// Prefix this module with "__reExport(exports, require(path), module.exports)"
  4421  						target = &js_ast.ERequireString{
  4422  							ImportRecordIndex: s.ImportRecordIndex,
  4423  						}
  4424  					}
  4425  					exportStarRef := c.graph.Files[runtime.SourceIndex].InputFile.Repr.(*graph.JSRepr).AST.ModuleScope.Members["__reExport"].Ref
  4426  					args := []js_ast.Expr{
  4427  						{Loc: stmt.Loc, Data: &js_ast.EIdentifier{Ref: repr.AST.ExportsRef}},
  4428  						{Loc: record.Range.Loc, Data: target},
  4429  					}
  4430  					if moduleExportsForReExportOrNil.Data != nil {
  4431  						args = append(args, moduleExportsForReExportOrNil)
  4432  					}
  4433  					stmtList.insideWrapperPrefix = append(stmtList.insideWrapperPrefix, js_ast.Stmt{
  4434  						Loc: stmt.Loc,
  4435  						Data: &js_ast.SExpr{Value: js_ast.Expr{Loc: stmt.Loc, Data: &js_ast.ECall{
  4436  							Target: js_ast.Expr{Loc: stmt.Loc, Data: &js_ast.EIdentifier{Ref: exportStarRef}},
  4437  							Args:   args,
  4438  						}}},
  4439  					})
  4440  				}
  4441  
  4442  				// Remove the export star statement
  4443  				continue
  4444  			}
  4445  
  4446  		case *js_ast.SExportFrom:
  4447  			// "export {foo} from 'path'"
  4448  			if c.shouldRemoveImportExportStmt(sourceIndex, stmtList, stmt.Loc, s.NamespaceRef, s.ImportRecordIndex) {
  4449  				continue
  4450  			}
  4451  
  4452  			if c.options.UnsupportedJSFeatures.Has(compat.ArbitraryModuleNamespaceNames) {
  4453  				for _, item := range s.Items {
  4454  					c.maybeForbidArbitraryModuleNamespaceIdentifier("export", sourceIndex, item.AliasLoc, item.Alias)
  4455  					if item.AliasLoc != item.Name.Loc {
  4456  						c.maybeForbidArbitraryModuleNamespaceIdentifier("import", sourceIndex, item.Name.Loc, item.OriginalName)
  4457  					}
  4458  				}
  4459  			}
  4460  
  4461  			if shouldStripExports {
  4462  				// Turn this statement into "import {foo} from 'path'"
  4463  				for i, item := range s.Items {
  4464  					s.Items[i].Alias = item.OriginalName
  4465  				}
  4466  				stmt.Data = &js_ast.SImport{
  4467  					NamespaceRef:      s.NamespaceRef,
  4468  					Items:             &s.Items,
  4469  					ImportRecordIndex: s.ImportRecordIndex,
  4470  					IsSingleLine:      s.IsSingleLine,
  4471  				}
  4472  			}
  4473  
  4474  			// Make sure these don't end up in the wrapper closure
  4475  			if shouldExtractESMStmtsForWrap {
  4476  				stmtList.outsideWrapperPrefix = append(stmtList.outsideWrapperPrefix, stmt)
  4477  				continue
  4478  			}
  4479  
  4480  		case *js_ast.SExportClause:
  4481  			if shouldStripExports {
  4482  				// Remove export statements entirely
  4483  				continue
  4484  			}
  4485  
  4486  			if c.options.UnsupportedJSFeatures.Has(compat.ArbitraryModuleNamespaceNames) {
  4487  				for _, item := range s.Items {
  4488  					c.maybeForbidArbitraryModuleNamespaceIdentifier("export", sourceIndex, item.AliasLoc, item.Alias)
  4489  				}
  4490  			}
  4491  
  4492  			// Make sure these don't end up in the wrapper closure
  4493  			if shouldExtractESMStmtsForWrap {
  4494  				stmtList.outsideWrapperPrefix = append(stmtList.outsideWrapperPrefix, stmt)
  4495  				continue
  4496  			}
  4497  
  4498  		case *js_ast.SFunction:
  4499  			// Strip the "export" keyword while bundling
  4500  			if shouldStripExports && s.IsExport {
  4501  				// Be careful to not modify the original statement
  4502  				clone := *s
  4503  				clone.IsExport = false
  4504  				stmt.Data = &clone
  4505  			}
  4506  
  4507  		case *js_ast.SClass:
  4508  			if shouldStripExports && s.IsExport {
  4509  				// Be careful to not modify the original statement
  4510  				clone := *s
  4511  				clone.IsExport = false
  4512  				stmt.Data = &clone
  4513  			}
  4514  
  4515  		case *js_ast.SLocal:
  4516  			if shouldStripExports && s.IsExport {
  4517  				// Be careful to not modify the original statement
  4518  				clone := *s
  4519  				clone.IsExport = false
  4520  				stmt.Data = &clone
  4521  			}
  4522  
  4523  		case *js_ast.SExportDefault:
  4524  			// If we're bundling, convert "export default" into a normal declaration
  4525  			if shouldStripExports {
  4526  				switch s2 := s.Value.Data.(type) {
  4527  				case *js_ast.SExpr:
  4528  					// "export default foo;" => "var default = foo;"
  4529  					stmt = js_ast.Stmt{Loc: stmt.Loc, Data: &js_ast.SLocal{Decls: []js_ast.Decl{
  4530  						{Binding: js_ast.Binding{Loc: s.DefaultName.Loc, Data: &js_ast.BIdentifier{Ref: s.DefaultName.Ref}}, ValueOrNil: s2.Value},
  4531  					}}}
  4532  
  4533  				case *js_ast.SFunction:
  4534  					// "export default function() {}" => "function default() {}"
  4535  					// "export default function foo() {}" => "function foo() {}"
  4536  
  4537  					// Be careful to not modify the original statement
  4538  					s2 = &js_ast.SFunction{Fn: s2.Fn}
  4539  					s2.Fn.Name = &s.DefaultName
  4540  
  4541  					stmt = js_ast.Stmt{Loc: s.Value.Loc, Data: s2}
  4542  
  4543  				case *js_ast.SClass:
  4544  					// "export default class {}" => "class default {}"
  4545  					// "export default class Foo {}" => "class Foo {}"
  4546  
  4547  					// Be careful to not modify the original statement
  4548  					s2 = &js_ast.SClass{Class: s2.Class}
  4549  					s2.Class.Name = &s.DefaultName
  4550  
  4551  					stmt = js_ast.Stmt{Loc: s.Value.Loc, Data: s2}
  4552  
  4553  				default:
  4554  					panic("Internal error")
  4555  				}
  4556  			}
  4557  		}
  4558  
  4559  		stmtList.insideWrapperSuffix = append(stmtList.insideWrapperSuffix, stmt)
  4560  	}
  4561  }
  4562  
  4563  // "var a = 1; var b = 2;" => "var a = 1, b = 2;"
  4564  func mergeAdjacentLocalStmts(stmts []js_ast.Stmt) []js_ast.Stmt {
  4565  	if len(stmts) == 0 {
  4566  		return stmts
  4567  	}
  4568  
  4569  	didMergeWithPreviousLocal := false
  4570  	end := 1
  4571  
  4572  	for _, stmt := range stmts[1:] {
  4573  		// Try to merge with the previous variable statement
  4574  		if after, ok := stmt.Data.(*js_ast.SLocal); ok {
  4575  			if before, ok := stmts[end-1].Data.(*js_ast.SLocal); ok {
  4576  				// It must be the same kind of variable statement (i.e. let/var/const)
  4577  				if before.Kind == after.Kind && before.IsExport == after.IsExport {
  4578  					if didMergeWithPreviousLocal {
  4579  						// Avoid O(n^2) behavior for repeated variable declarations
  4580  						before.Decls = append(before.Decls, after.Decls...)
  4581  					} else {
  4582  						// Be careful to not modify the original statement
  4583  						didMergeWithPreviousLocal = true
  4584  						clone := *before
  4585  						clone.Decls = make([]js_ast.Decl, 0, len(before.Decls)+len(after.Decls))
  4586  						clone.Decls = append(clone.Decls, before.Decls...)
  4587  						clone.Decls = append(clone.Decls, after.Decls...)
  4588  						stmts[end-1].Data = &clone
  4589  					}
  4590  					continue
  4591  				}
  4592  			}
  4593  		}
  4594  
  4595  		// Otherwise, append a normal statement
  4596  		didMergeWithPreviousLocal = false
  4597  		stmts[end] = stmt
  4598  		end++
  4599  	}
  4600  
  4601  	return stmts[:end]
  4602  }
  4603  
  4604  type stmtList struct {
  4605  	// These statements come first, and can be inside the wrapper
  4606  	insideWrapperPrefix []js_ast.Stmt
  4607  
  4608  	// These statements come last, and can be inside the wrapper
  4609  	insideWrapperSuffix []js_ast.Stmt
  4610  
  4611  	outsideWrapperPrefix []js_ast.Stmt
  4612  }
  4613  
  4614  type compileResultJS struct {
  4615  	js_printer.PrintResult
  4616  
  4617  	sourceIndex uint32
  4618  
  4619  	// This is the line and column offset since the previous JavaScript string
  4620  	// or the start of the file if this is the first JavaScript string.
  4621  	generatedOffset sourcemap.LineColumnOffset
  4622  }
  4623  
  4624  func (c *linkerContext) requireOrImportMetaForSource(sourceIndex uint32) (meta js_printer.RequireOrImportMeta) {
  4625  	repr := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr)
  4626  	meta.WrapperRef = repr.AST.WrapperRef
  4627  	meta.IsWrapperAsync = repr.Meta.IsAsyncOrHasAsyncDependency
  4628  	if repr.Meta.Wrap == graph.WrapESM {
  4629  		meta.ExportsRef = repr.AST.ExportsRef
  4630  	} else {
  4631  		meta.ExportsRef = ast.InvalidRef
  4632  	}
  4633  	return
  4634  }
  4635  
  4636  func (c *linkerContext) generateCodeForFileInChunkJS(
  4637  	r renamer.Renamer,
  4638  	waitGroup *sync.WaitGroup,
  4639  	partRange partRange,
  4640  	toCommonJSRef ast.Ref,
  4641  	toESMRef ast.Ref,
  4642  	runtimeRequireRef ast.Ref,
  4643  	result *compileResultJS,
  4644  	dataForSourceMaps []bundler.DataForSourceMap,
  4645  ) {
  4646  	defer c.recoverInternalError(waitGroup, partRange.sourceIndex)
  4647  
  4648  	file := &c.graph.Files[partRange.sourceIndex]
  4649  	repr := file.InputFile.Repr.(*graph.JSRepr)
  4650  	nsExportPartIndex := js_ast.NSExportPartIndex
  4651  	needsWrapper := false
  4652  	stmtList := stmtList{}
  4653  
  4654  	// The top-level directive must come first (the non-wrapped case is handled
  4655  	// by the chunk generation code, although only for the entry point)
  4656  	if repr.Meta.Wrap != graph.WrapNone && !file.IsEntryPoint() {
  4657  		for _, directive := range repr.AST.Directives {
  4658  			stmtList.insideWrapperPrefix = append(stmtList.insideWrapperPrefix, js_ast.Stmt{
  4659  				Data: &js_ast.SDirective{Value: helpers.StringToUTF16(directive)},
  4660  			})
  4661  		}
  4662  	}
  4663  
  4664  	// Make sure the generated call to "__export(exports, ...)" comes first
  4665  	// before anything else.
  4666  	if nsExportPartIndex >= partRange.partIndexBegin && nsExportPartIndex < partRange.partIndexEnd &&
  4667  		repr.AST.Parts[nsExportPartIndex].IsLive {
  4668  		c.convertStmtsForChunk(partRange.sourceIndex, &stmtList, repr.AST.Parts[nsExportPartIndex].Stmts)
  4669  
  4670  		// Move everything to the prefix list
  4671  		if repr.Meta.Wrap == graph.WrapESM {
  4672  			stmtList.outsideWrapperPrefix = append(stmtList.outsideWrapperPrefix, stmtList.insideWrapperSuffix...)
  4673  		} else {
  4674  			stmtList.insideWrapperPrefix = append(stmtList.insideWrapperPrefix, stmtList.insideWrapperSuffix...)
  4675  		}
  4676  		stmtList.insideWrapperSuffix = nil
  4677  	}
  4678  
  4679  	var partIndexForLazyDefaultExport ast.Index32
  4680  	if repr.AST.HasLazyExport {
  4681  		if defaultExport, ok := repr.Meta.ResolvedExports["default"]; ok {
  4682  			partIndexForLazyDefaultExport = ast.MakeIndex32(repr.TopLevelSymbolToParts(defaultExport.Ref)[0])
  4683  		}
  4684  	}
  4685  
  4686  	// Add all other parts in this chunk
  4687  	for partIndex := partRange.partIndexBegin; partIndex < partRange.partIndexEnd; partIndex++ {
  4688  		part := repr.AST.Parts[partIndex]
  4689  		if !repr.AST.Parts[partIndex].IsLive {
  4690  			// Skip the part if it's not in this chunk
  4691  			continue
  4692  		}
  4693  
  4694  		if uint32(partIndex) == nsExportPartIndex {
  4695  			// Skip the generated call to "__export()" that was extracted above
  4696  			continue
  4697  		}
  4698  
  4699  		// Mark if we hit the dummy part representing the wrapper
  4700  		if uint32(partIndex) == repr.Meta.WrapperPartIndex.GetIndex() {
  4701  			needsWrapper = true
  4702  			continue
  4703  		}
  4704  
  4705  		stmts := part.Stmts
  4706  
  4707  		// If this could be a JSON file that exports a top-level object literal, go
  4708  		// over the non-default top-level properties that ended up being imported
  4709  		// and substitute references to them into the main top-level object literal.
  4710  		// So this JSON file:
  4711  		//
  4712  		//   {
  4713  		//     "foo": [1, 2, 3],
  4714  		//     "bar": [4, 5, 6],
  4715  		//   }
  4716  		//
  4717  		// is initially compiled into this:
  4718  		//
  4719  		//   export var foo = [1, 2, 3];
  4720  		//   export var bar = [4, 5, 6];
  4721  		//   export default {
  4722  		//     foo: [1, 2, 3],
  4723  		//     bar: [4, 5, 6],
  4724  		//   };
  4725  		//
  4726  		// But we turn it into this if both "foo" and "default" are imported:
  4727  		//
  4728  		//   export var foo = [1, 2, 3];
  4729  		//   export default {
  4730  		//     foo,
  4731  		//     bar: [4, 5, 6],
  4732  		//   };
  4733  		//
  4734  		if partIndexForLazyDefaultExport.IsValid() && partIndex == partIndexForLazyDefaultExport.GetIndex() {
  4735  			stmt := stmts[0]
  4736  			defaultExport := stmt.Data.(*js_ast.SExportDefault)
  4737  			defaultExpr := defaultExport.Value.Data.(*js_ast.SExpr)
  4738  
  4739  			// Be careful: the top-level value in a JSON file is not necessarily an object
  4740  			if object, ok := defaultExpr.Value.Data.(*js_ast.EObject); ok {
  4741  				objectClone := *object
  4742  				objectClone.Properties = append([]js_ast.Property{}, objectClone.Properties...)
  4743  
  4744  				// If any top-level properties ended up being imported directly, change
  4745  				// the property to just reference the corresponding variable instead
  4746  				for i, property := range object.Properties {
  4747  					if str, ok := property.Key.Data.(*js_ast.EString); ok {
  4748  						if name := helpers.UTF16ToString(str.Value); name != "default" {
  4749  							if export, ok := repr.Meta.ResolvedExports[name]; ok {
  4750  								if part := repr.AST.Parts[repr.TopLevelSymbolToParts(export.Ref)[0]]; part.IsLive {
  4751  									ref := part.Stmts[0].Data.(*js_ast.SLocal).Decls[0].Binding.Data.(*js_ast.BIdentifier).Ref
  4752  									objectClone.Properties[i].ValueOrNil = js_ast.Expr{Loc: property.Key.Loc, Data: &js_ast.EIdentifier{Ref: ref}}
  4753  								}
  4754  							}
  4755  						}
  4756  					}
  4757  				}
  4758  
  4759  				// Avoid mutating the original AST
  4760  				defaultExprClone := *defaultExpr
  4761  				defaultExprClone.Value.Data = &objectClone
  4762  				defaultExportClone := *defaultExport
  4763  				defaultExportClone.Value.Data = &defaultExprClone
  4764  				stmt.Data = &defaultExportClone
  4765  				stmts = []js_ast.Stmt{stmt}
  4766  			}
  4767  		}
  4768  
  4769  		c.convertStmtsForChunk(partRange.sourceIndex, &stmtList, stmts)
  4770  	}
  4771  
  4772  	// Hoist all import statements before any normal statements. ES6 imports
  4773  	// are different than CommonJS imports. All modules imported via ES6 import
  4774  	// statements are evaluated before the module doing the importing is
  4775  	// evaluated (well, except for cyclic import scenarios). We need to preserve
  4776  	// these semantics even when modules imported via ES6 import statements end
  4777  	// up being CommonJS modules.
  4778  	stmts := stmtList.insideWrapperSuffix
  4779  	if len(stmtList.insideWrapperPrefix) > 0 {
  4780  		stmts = append(stmtList.insideWrapperPrefix, stmts...)
  4781  	}
  4782  	if c.options.MinifySyntax {
  4783  		stmts = mergeAdjacentLocalStmts(stmts)
  4784  	}
  4785  
  4786  	// Optionally wrap all statements in a closure
  4787  	if needsWrapper {
  4788  		switch repr.Meta.Wrap {
  4789  		case graph.WrapCJS:
  4790  			// Only include the arguments that are actually used
  4791  			args := []js_ast.Arg{}
  4792  			if repr.AST.UsesExportsRef || repr.AST.UsesModuleRef {
  4793  				args = append(args, js_ast.Arg{Binding: js_ast.Binding{Data: &js_ast.BIdentifier{Ref: repr.AST.ExportsRef}}})
  4794  				if repr.AST.UsesModuleRef {
  4795  					args = append(args, js_ast.Arg{Binding: js_ast.Binding{Data: &js_ast.BIdentifier{Ref: repr.AST.ModuleRef}}})
  4796  				}
  4797  			}
  4798  
  4799  			var cjsArgs []js_ast.Expr
  4800  			if c.options.ProfilerNames {
  4801  				// "__commonJS({ 'file.js'(exports, module) { ... } })"
  4802  				kind := js_ast.PropertyField
  4803  				if !c.options.UnsupportedJSFeatures.Has(compat.ObjectExtensions) {
  4804  					kind = js_ast.PropertyMethod
  4805  				}
  4806  				cjsArgs = []js_ast.Expr{{Data: &js_ast.EObject{Properties: []js_ast.Property{{
  4807  					Kind:       kind,
  4808  					Key:        js_ast.Expr{Data: &js_ast.EString{Value: helpers.StringToUTF16(file.InputFile.Source.PrettyPath)}},
  4809  					ValueOrNil: js_ast.Expr{Data: &js_ast.EFunction{Fn: js_ast.Fn{Args: args, Body: js_ast.FnBody{Block: js_ast.SBlock{Stmts: stmts}}}}},
  4810  				}}}}}
  4811  			} else if c.options.UnsupportedJSFeatures.Has(compat.Arrow) {
  4812  				// "__commonJS(function (exports, module) { ... })"
  4813  				cjsArgs = []js_ast.Expr{{Data: &js_ast.EFunction{Fn: js_ast.Fn{Args: args, Body: js_ast.FnBody{Block: js_ast.SBlock{Stmts: stmts}}}}}}
  4814  			} else {
  4815  				// "__commonJS((exports, module) => { ... })"
  4816  				cjsArgs = []js_ast.Expr{{Data: &js_ast.EArrow{Args: args, Body: js_ast.FnBody{Block: js_ast.SBlock{Stmts: stmts}}}}}
  4817  			}
  4818  			value := js_ast.Expr{Data: &js_ast.ECall{
  4819  				Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: c.cjsRuntimeRef}},
  4820  				Args:   cjsArgs,
  4821  			}}
  4822  
  4823  			// "var require_foo = __commonJS(...);"
  4824  			stmts = append(stmtList.outsideWrapperPrefix, js_ast.Stmt{Data: &js_ast.SLocal{
  4825  				Decls: []js_ast.Decl{{
  4826  					Binding:    js_ast.Binding{Data: &js_ast.BIdentifier{Ref: repr.AST.WrapperRef}},
  4827  					ValueOrNil: value,
  4828  				}},
  4829  			}})
  4830  
  4831  		case graph.WrapESM:
  4832  			// The wrapper only needs to be "async" if there is a transitive async
  4833  			// dependency. For correctness, we must not use "async" if the module
  4834  			// isn't async because then calling "require()" on that module would
  4835  			// swallow any exceptions thrown during module initialization.
  4836  			isAsync := repr.Meta.IsAsyncOrHasAsyncDependency
  4837  
  4838  			// Hoist all top-level "var" and "function" declarations out of the closure
  4839  			var decls []js_ast.Decl
  4840  			end := 0
  4841  			for _, stmt := range stmts {
  4842  				switch s := stmt.Data.(type) {
  4843  				case *js_ast.SLocal:
  4844  					// Convert the declarations to assignments
  4845  					wrapIdentifier := func(loc logger.Loc, ref ast.Ref) js_ast.Expr {
  4846  						decls = append(decls, js_ast.Decl{Binding: js_ast.Binding{Loc: loc, Data: &js_ast.BIdentifier{Ref: ref}}})
  4847  						return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}}
  4848  					}
  4849  					var value js_ast.Expr
  4850  					for _, decl := range s.Decls {
  4851  						binding := js_ast.ConvertBindingToExpr(decl.Binding, wrapIdentifier)
  4852  						if decl.ValueOrNil.Data != nil {
  4853  							value = js_ast.JoinWithComma(value, js_ast.Assign(binding, decl.ValueOrNil))
  4854  						}
  4855  					}
  4856  					if value.Data == nil {
  4857  						continue
  4858  					}
  4859  					stmt = js_ast.Stmt{Loc: stmt.Loc, Data: &js_ast.SExpr{Value: value}}
  4860  
  4861  				case *js_ast.SFunction:
  4862  					stmtList.outsideWrapperPrefix = append(stmtList.outsideWrapperPrefix, stmt)
  4863  					continue
  4864  				}
  4865  
  4866  				stmts[end] = stmt
  4867  				end++
  4868  			}
  4869  			stmts = stmts[:end]
  4870  
  4871  			var esmArgs []js_ast.Expr
  4872  			if c.options.ProfilerNames {
  4873  				// "__esm({ 'file.js'() { ... } })"
  4874  				kind := js_ast.PropertyField
  4875  				if !c.options.UnsupportedJSFeatures.Has(compat.ObjectExtensions) {
  4876  					kind = js_ast.PropertyMethod
  4877  				}
  4878  				esmArgs = []js_ast.Expr{{Data: &js_ast.EObject{Properties: []js_ast.Property{{
  4879  					Kind:       kind,
  4880  					Key:        js_ast.Expr{Data: &js_ast.EString{Value: helpers.StringToUTF16(file.InputFile.Source.PrettyPath)}},
  4881  					ValueOrNil: js_ast.Expr{Data: &js_ast.EFunction{Fn: js_ast.Fn{Body: js_ast.FnBody{Block: js_ast.SBlock{Stmts: stmts}}, IsAsync: isAsync}}},
  4882  				}}}}}
  4883  			} else if c.options.UnsupportedJSFeatures.Has(compat.Arrow) {
  4884  				// "__esm(function () { ... })"
  4885  				esmArgs = []js_ast.Expr{{Data: &js_ast.EFunction{Fn: js_ast.Fn{Body: js_ast.FnBody{Block: js_ast.SBlock{Stmts: stmts}}, IsAsync: isAsync}}}}
  4886  			} else {
  4887  				// "__esm(() => { ... })"
  4888  				esmArgs = []js_ast.Expr{{Data: &js_ast.EArrow{Body: js_ast.FnBody{Block: js_ast.SBlock{Stmts: stmts}}, IsAsync: isAsync}}}
  4889  			}
  4890  			value := js_ast.Expr{Data: &js_ast.ECall{
  4891  				Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: c.esmRuntimeRef}},
  4892  				Args:   esmArgs,
  4893  			}}
  4894  
  4895  			// "var foo, bar;"
  4896  			if !c.options.MinifySyntax && len(decls) > 0 {
  4897  				stmtList.outsideWrapperPrefix = append(stmtList.outsideWrapperPrefix, js_ast.Stmt{Data: &js_ast.SLocal{
  4898  					Decls: decls,
  4899  				}})
  4900  				decls = nil
  4901  			}
  4902  
  4903  			// "var init_foo = __esm(...);"
  4904  			stmts = append(stmtList.outsideWrapperPrefix, js_ast.Stmt{Data: &js_ast.SLocal{
  4905  				Decls: append(decls, js_ast.Decl{
  4906  					Binding:    js_ast.Binding{Data: &js_ast.BIdentifier{Ref: repr.AST.WrapperRef}},
  4907  					ValueOrNil: value,
  4908  				}),
  4909  			}})
  4910  		}
  4911  	}
  4912  
  4913  	// Only generate a source map if needed
  4914  	var addSourceMappings bool
  4915  	var inputSourceMap *sourcemap.SourceMap
  4916  	var lineOffsetTables []sourcemap.LineOffsetTable
  4917  	if file.InputFile.Loader.CanHaveSourceMap() && c.options.SourceMap != config.SourceMapNone {
  4918  		addSourceMappings = true
  4919  		inputSourceMap = file.InputFile.InputSourceMap
  4920  		lineOffsetTables = dataForSourceMaps[partRange.sourceIndex].LineOffsetTables
  4921  	}
  4922  
  4923  	// Indent the file if everything is wrapped in an IIFE
  4924  	indent := 0
  4925  	if c.options.OutputFormat == config.FormatIIFE {
  4926  		indent++
  4927  	}
  4928  
  4929  	// Convert the AST to JavaScript code
  4930  	printOptions := js_printer.Options{
  4931  		Indent:                       indent,
  4932  		OutputFormat:                 c.options.OutputFormat,
  4933  		MinifyIdentifiers:            c.options.MinifyIdentifiers,
  4934  		MinifyWhitespace:             c.options.MinifyWhitespace,
  4935  		MinifySyntax:                 c.options.MinifySyntax,
  4936  		LineLimit:                    c.options.LineLimit,
  4937  		ASCIIOnly:                    c.options.ASCIIOnly,
  4938  		ToCommonJSRef:                toCommonJSRef,
  4939  		ToESMRef:                     toESMRef,
  4940  		RuntimeRequireRef:            runtimeRequireRef,
  4941  		TSEnums:                      c.graph.TSEnums,
  4942  		ConstValues:                  c.graph.ConstValues,
  4943  		LegalComments:                c.options.LegalComments,
  4944  		UnsupportedFeatures:          c.options.UnsupportedJSFeatures,
  4945  		SourceMap:                    c.options.SourceMap,
  4946  		AddSourceMappings:            addSourceMappings,
  4947  		InputSourceMap:               inputSourceMap,
  4948  		LineOffsetTables:             lineOffsetTables,
  4949  		RequireOrImportMetaForSource: c.requireOrImportMetaForSource,
  4950  		MangledProps:                 c.mangledProps,
  4951  		NeedsMetafile:                c.options.NeedsMetafile,
  4952  	}
  4953  	tree := repr.AST
  4954  	tree.Directives = nil // This is handled elsewhere
  4955  	tree.Parts = []js_ast.Part{{Stmts: stmts}}
  4956  	*result = compileResultJS{
  4957  		PrintResult: js_printer.Print(tree, c.graph.Symbols, r, printOptions),
  4958  		sourceIndex: partRange.sourceIndex,
  4959  	}
  4960  
  4961  	if file.InputFile.Loader == config.LoaderFile {
  4962  		result.JSONMetadataImports = append(result.JSONMetadataImports, fmt.Sprintf("\n        {\n          \"path\": %s,\n          \"kind\": \"file-loader\"\n        }",
  4963  			helpers.QuoteForJSON(file.InputFile.UniqueKeyForAdditionalFile, c.options.ASCIIOnly)))
  4964  	}
  4965  
  4966  	waitGroup.Done()
  4967  }
  4968  
  4969  func (c *linkerContext) generateEntryPointTailJS(
  4970  	r renamer.Renamer,
  4971  	toCommonJSRef ast.Ref,
  4972  	toESMRef ast.Ref,
  4973  	sourceIndex uint32,
  4974  ) (result compileResultJS) {
  4975  	file := &c.graph.Files[sourceIndex]
  4976  	repr := file.InputFile.Repr.(*graph.JSRepr)
  4977  	var stmts []js_ast.Stmt
  4978  
  4979  	switch c.options.OutputFormat {
  4980  	case config.FormatPreserve:
  4981  		if repr.Meta.Wrap != graph.WrapNone {
  4982  			// "require_foo();"
  4983  			// "init_foo();"
  4984  			stmts = append(stmts, js_ast.Stmt{Data: &js_ast.SExpr{Value: js_ast.Expr{Data: &js_ast.ECall{
  4985  				Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: repr.AST.WrapperRef}},
  4986  			}}}})
  4987  		}
  4988  
  4989  	case config.FormatIIFE:
  4990  		if repr.Meta.Wrap == graph.WrapCJS {
  4991  			if len(c.options.GlobalName) > 0 {
  4992  				// "return require_foo();"
  4993  				stmts = append(stmts, js_ast.Stmt{Data: &js_ast.SReturn{ValueOrNil: js_ast.Expr{Data: &js_ast.ECall{
  4994  					Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: repr.AST.WrapperRef}},
  4995  				}}}})
  4996  			} else {
  4997  				// "require_foo();"
  4998  				stmts = append(stmts, js_ast.Stmt{Data: &js_ast.SExpr{Value: js_ast.Expr{Data: &js_ast.ECall{
  4999  					Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: repr.AST.WrapperRef}},
  5000  				}}}})
  5001  			}
  5002  		} else {
  5003  			if repr.Meta.Wrap == graph.WrapESM {
  5004  				// "init_foo();"
  5005  				stmts = append(stmts, js_ast.Stmt{Data: &js_ast.SExpr{Value: js_ast.Expr{Data: &js_ast.ECall{
  5006  					Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: repr.AST.WrapperRef}},
  5007  				}}}})
  5008  			}
  5009  
  5010  			if repr.Meta.ForceIncludeExportsForEntryPoint {
  5011  				// "return __toCommonJS(exports);"
  5012  				stmts = append(stmts, js_ast.Stmt{Data: &js_ast.SReturn{
  5013  					ValueOrNil: js_ast.Expr{Data: &js_ast.ECall{
  5014  						Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: toCommonJSRef}},
  5015  						Args:   []js_ast.Expr{{Data: &js_ast.EIdentifier{Ref: repr.AST.ExportsRef}}},
  5016  					}},
  5017  				}})
  5018  			}
  5019  		}
  5020  
  5021  	case config.FormatCommonJS:
  5022  		if repr.Meta.Wrap == graph.WrapCJS {
  5023  			// "module.exports = require_foo();"
  5024  			stmts = append(stmts, js_ast.AssignStmt(
  5025  				js_ast.Expr{Data: &js_ast.EDot{
  5026  					Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: c.unboundModuleRef}},
  5027  					Name:   "exports",
  5028  				}},
  5029  				js_ast.Expr{Data: &js_ast.ECall{
  5030  					Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: repr.AST.WrapperRef}},
  5031  				}},
  5032  			))
  5033  		} else {
  5034  			if repr.Meta.Wrap == graph.WrapESM {
  5035  				// "init_foo();"
  5036  				stmts = append(stmts, js_ast.Stmt{Data: &js_ast.SExpr{Value: js_ast.Expr{Data: &js_ast.ECall{
  5037  					Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: repr.AST.WrapperRef}},
  5038  				}}}})
  5039  			}
  5040  		}
  5041  
  5042  		// If we are generating CommonJS for node, encode the known export names in
  5043  		// a form that node can understand them. This relies on the specific behavior
  5044  		// of this parser, which the node project uses to detect named exports in
  5045  		// CommonJS files: https://github.com/guybedford/cjs-module-lexer. Think of
  5046  		// this code as an annotation for that parser.
  5047  		if c.options.Platform == config.PlatformNode {
  5048  			// Add a comment since otherwise people will surely wonder what this is.
  5049  			// This annotation means you can do this and have it work:
  5050  			//
  5051  			//   import { name } from './file-from-esbuild.cjs'
  5052  			//
  5053  			// when "file-from-esbuild.cjs" looks like this:
  5054  			//
  5055  			//   __export(exports, { name: () => name });
  5056  			//   0 && (module.exports = {name});
  5057  			//
  5058  			// The maintainer of "cjs-module-lexer" is receptive to adding esbuild-
  5059  			// friendly patterns to this library. However, this library has already
  5060  			// shipped in node and using existing patterns instead of defining new
  5061  			// patterns is maximally compatible.
  5062  			//
  5063  			// An alternative to doing this could be to use "Object.defineProperties"
  5064  			// instead of "__export" but support for that would need to be added to
  5065  			// "cjs-module-lexer" and then we would need to be ok with not supporting
  5066  			// older versions of node that don't have that newly-added support.
  5067  
  5068  			// "{a, b, if: null}"
  5069  			var moduleExports []js_ast.Property
  5070  			for _, export := range repr.Meta.SortedAndFilteredExportAliases {
  5071  				if export == "default" {
  5072  					// In node the default export is always "module.exports" regardless of
  5073  					// what the annotation says. So don't bother generating "default".
  5074  					continue
  5075  				}
  5076  
  5077  				// "{if: null}"
  5078  				var valueOrNil js_ast.Expr
  5079  				if _, ok := js_lexer.Keywords[export]; ok {
  5080  					// Make sure keywords don't cause a syntax error. This has to map to
  5081  					// "null" instead of something shorter like "0" because the library
  5082  					// "cjs-module-lexer" only supports identifiers in this position, and
  5083  					// it thinks "null" is an identifier.
  5084  					valueOrNil = js_ast.Expr{Data: js_ast.ENullShared}
  5085  				}
  5086  
  5087  				moduleExports = append(moduleExports, js_ast.Property{
  5088  					Key:        js_ast.Expr{Data: &js_ast.EString{Value: helpers.StringToUTF16(export)}},
  5089  					ValueOrNil: valueOrNil,
  5090  				})
  5091  			}
  5092  
  5093  			// Add annotations for re-exports: "{...require('./foo')}"
  5094  			for _, importRecordIndex := range repr.AST.ExportStarImportRecords {
  5095  				if record := &repr.AST.ImportRecords[importRecordIndex]; !record.SourceIndex.IsValid() {
  5096  					moduleExports = append(moduleExports, js_ast.Property{
  5097  						Kind:       js_ast.PropertySpread,
  5098  						ValueOrNil: js_ast.Expr{Data: &js_ast.ERequireString{ImportRecordIndex: importRecordIndex}},
  5099  					})
  5100  				}
  5101  			}
  5102  
  5103  			if len(moduleExports) > 0 {
  5104  				// "0 && (module.exports = {a, b, if: null});"
  5105  				expr := js_ast.Expr{Data: &js_ast.EBinary{
  5106  					Op:   js_ast.BinOpLogicalAnd,
  5107  					Left: js_ast.Expr{Data: &js_ast.ENumber{Value: 0}},
  5108  					Right: js_ast.Assign(
  5109  						js_ast.Expr{Data: &js_ast.EDot{
  5110  							Target: js_ast.Expr{Data: &js_ast.EIdentifier{Ref: c.unboundModuleRef}},
  5111  							Name:   "exports",
  5112  						}},
  5113  						js_ast.Expr{Data: &js_ast.EObject{Properties: moduleExports}},
  5114  					),
  5115  				}}
  5116  
  5117  				if !c.options.MinifyWhitespace {
  5118  					stmts = append(stmts,
  5119  						js_ast.Stmt{Data: &js_ast.SComment{Text: `// Annotate the CommonJS export names for ESM import in node:`}},
  5120  					)
  5121  				}
  5122  
  5123  				stmts = append(stmts, js_ast.Stmt{Data: &js_ast.SExpr{Value: expr}})
  5124  			}
  5125  		}
  5126  
  5127  	case config.FormatESModule:
  5128  		if repr.Meta.Wrap == graph.WrapCJS {
  5129  			// "export default require_foo();"
  5130  			stmts = append(stmts, js_ast.Stmt{
  5131  				Data: &js_ast.SExportDefault{Value: js_ast.Stmt{
  5132  					Data: &js_ast.SExpr{Value: js_ast.Expr{
  5133  						Data: &js_ast.ECall{Target: js_ast.Expr{
  5134  							Data: &js_ast.EIdentifier{Ref: repr.AST.WrapperRef}}}}}}}})
  5135  		} else {
  5136  			if repr.Meta.Wrap == graph.WrapESM {
  5137  				if repr.Meta.IsAsyncOrHasAsyncDependency {
  5138  					// "await init_foo();"
  5139  					stmts = append(stmts, js_ast.Stmt{
  5140  						Data: &js_ast.SExpr{Value: js_ast.Expr{
  5141  							Data: &js_ast.EAwait{Value: js_ast.Expr{
  5142  								Data: &js_ast.ECall{Target: js_ast.Expr{
  5143  									Data: &js_ast.EIdentifier{Ref: repr.AST.WrapperRef}}}}}}}})
  5144  				} else {
  5145  					// "init_foo();"
  5146  					stmts = append(stmts, js_ast.Stmt{
  5147  						Data: &js_ast.SExpr{
  5148  							Value: js_ast.Expr{Data: &js_ast.ECall{Target: js_ast.Expr{
  5149  								Data: &js_ast.EIdentifier{Ref: repr.AST.WrapperRef}}}}}})
  5150  				}
  5151  			}
  5152  
  5153  			if len(repr.Meta.SortedAndFilteredExportAliases) > 0 {
  5154  				// If the output format is ES6 modules and we're an entry point, generate an
  5155  				// ES6 export statement containing all exports. Except don't do that if this
  5156  				// entry point is a CommonJS-style module, since that would generate an ES6
  5157  				// export statement that's not top-level. Instead, we will export the CommonJS
  5158  				// exports as a default export later on.
  5159  				var items []js_ast.ClauseItem
  5160  
  5161  				for i, alias := range repr.Meta.SortedAndFilteredExportAliases {
  5162  					export := repr.Meta.ResolvedExports[alias]
  5163  
  5164  					// If this is an export of an import, reference the symbol that the import
  5165  					// was eventually resolved to. We need to do this because imports have
  5166  					// already been resolved by this point, so we can't generate a new import
  5167  					// and have that be resolved later.
  5168  					if importData, ok := c.graph.Files[export.SourceIndex].InputFile.Repr.(*graph.JSRepr).Meta.ImportsToBind[export.Ref]; ok {
  5169  						export.Ref = importData.Ref
  5170  						export.SourceIndex = importData.SourceIndex
  5171  					}
  5172  
  5173  					// Exports of imports need EImportIdentifier in case they need to be re-
  5174  					// written to a property access later on
  5175  					if c.graph.Symbols.Get(export.Ref).NamespaceAlias != nil {
  5176  						// Create both a local variable and an export clause for that variable.
  5177  						// The local variable is initialized with the initial value of the
  5178  						// export. This isn't fully correct because it's a "dead" binding and
  5179  						// doesn't update with the "live" value as it changes. But ES6 modules
  5180  						// don't have any syntax for bare named getter functions so this is the
  5181  						// best we can do.
  5182  						//
  5183  						// These input files:
  5184  						//
  5185  						//   // entry_point.js
  5186  						//   export {foo} from './cjs-format.js'
  5187  						//
  5188  						//   // cjs-format.js
  5189  						//   Object.defineProperty(exports, 'foo', {
  5190  						//     enumerable: true,
  5191  						//     get: () => Math.random(),
  5192  						//   })
  5193  						//
  5194  						// Become this output file:
  5195  						//
  5196  						//   // cjs-format.js
  5197  						//   var require_cjs_format = __commonJS((exports) => {
  5198  						//     Object.defineProperty(exports, "foo", {
  5199  						//       enumerable: true,
  5200  						//       get: () => Math.random()
  5201  						//     });
  5202  						//   });
  5203  						//
  5204  						//   // entry_point.js
  5205  						//   var cjs_format = __toESM(require_cjs_format());
  5206  						//   var export_foo = cjs_format.foo;
  5207  						//   export {
  5208  						//     export_foo as foo
  5209  						//   };
  5210  						//
  5211  						tempRef := repr.Meta.CJSExportCopies[i]
  5212  						stmts = append(stmts, js_ast.Stmt{Data: &js_ast.SLocal{
  5213  							Decls: []js_ast.Decl{{
  5214  								Binding:    js_ast.Binding{Data: &js_ast.BIdentifier{Ref: tempRef}},
  5215  								ValueOrNil: js_ast.Expr{Data: &js_ast.EImportIdentifier{Ref: export.Ref}},
  5216  							}},
  5217  						}})
  5218  						items = append(items, js_ast.ClauseItem{
  5219  							Name:  ast.LocRef{Ref: tempRef},
  5220  							Alias: alias,
  5221  						})
  5222  					} else {
  5223  						// Local identifiers can be exported using an export clause. This is done
  5224  						// this way instead of leaving the "export" keyword on the local declaration
  5225  						// itself both because it lets the local identifier be minified and because
  5226  						// it works transparently for re-exports across files.
  5227  						//
  5228  						// These input files:
  5229  						//
  5230  						//   // entry_point.js
  5231  						//   export * from './esm-format.js'
  5232  						//
  5233  						//   // esm-format.js
  5234  						//   export let foo = 123
  5235  						//
  5236  						// Become this output file:
  5237  						//
  5238  						//   // esm-format.js
  5239  						//   let foo = 123;
  5240  						//
  5241  						//   // entry_point.js
  5242  						//   export {
  5243  						//     foo
  5244  						//   };
  5245  						//
  5246  						items = append(items, js_ast.ClauseItem{
  5247  							Name:  ast.LocRef{Ref: export.Ref},
  5248  							Alias: alias,
  5249  						})
  5250  					}
  5251  				}
  5252  
  5253  				stmts = append(stmts, js_ast.Stmt{Data: &js_ast.SExportClause{Items: items}})
  5254  			}
  5255  		}
  5256  	}
  5257  
  5258  	if len(stmts) == 0 {
  5259  		return
  5260  	}
  5261  
  5262  	tree := repr.AST
  5263  	tree.Directives = nil
  5264  	tree.Parts = []js_ast.Part{{Stmts: stmts}}
  5265  
  5266  	// Indent the file if everything is wrapped in an IIFE
  5267  	indent := 0
  5268  	if c.options.OutputFormat == config.FormatIIFE {
  5269  		indent++
  5270  	}
  5271  
  5272  	// Convert the AST to JavaScript code
  5273  	printOptions := js_printer.Options{
  5274  		Indent:                       indent,
  5275  		OutputFormat:                 c.options.OutputFormat,
  5276  		MinifyIdentifiers:            c.options.MinifyIdentifiers,
  5277  		MinifyWhitespace:             c.options.MinifyWhitespace,
  5278  		MinifySyntax:                 c.options.MinifySyntax,
  5279  		LineLimit:                    c.options.LineLimit,
  5280  		ASCIIOnly:                    c.options.ASCIIOnly,
  5281  		ToCommonJSRef:                toCommonJSRef,
  5282  		ToESMRef:                     toESMRef,
  5283  		LegalComments:                c.options.LegalComments,
  5284  		UnsupportedFeatures:          c.options.UnsupportedJSFeatures,
  5285  		RequireOrImportMetaForSource: c.requireOrImportMetaForSource,
  5286  		MangledProps:                 c.mangledProps,
  5287  	}
  5288  	result.PrintResult = js_printer.Print(tree, c.graph.Symbols, r, printOptions)
  5289  	return
  5290  }
  5291  
  5292  func (c *linkerContext) renameSymbolsInChunk(chunk *chunkInfo, filesInOrder []uint32, timer *helpers.Timer) renamer.Renamer {
  5293  	if c.options.MinifyIdentifiers {
  5294  		timer.Begin("Minify symbols")
  5295  		defer timer.End("Minify symbols")
  5296  	} else {
  5297  		timer.Begin("Rename symbols")
  5298  		defer timer.End("Rename symbols")
  5299  	}
  5300  
  5301  	// Determine the reserved names (e.g. can't generate the name "if")
  5302  	timer.Begin("Compute reserved names")
  5303  	moduleScopes := make([]*js_ast.Scope, len(filesInOrder))
  5304  	for i, sourceIndex := range filesInOrder {
  5305  		moduleScopes[i] = c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr).AST.ModuleScope
  5306  	}
  5307  	reservedNames := renamer.ComputeReservedNames(moduleScopes, c.graph.Symbols)
  5308  
  5309  	// Node contains code that scans CommonJS modules in an attempt to statically
  5310  	// detect the  set of export names that a module will use. However, it doesn't
  5311  	// do any scope analysis so it can be fooled by local variables with the same
  5312  	// name as the CommonJS module-scope variables "exports" and "module". Avoid
  5313  	// using these names in this case even if there is not a risk of a name
  5314  	// collision because there is still a risk of node incorrectly detecting
  5315  	// something in a nested scope as an top-level export. Here's a case where
  5316  	// this happened: https://github.com/evanw/esbuild/issues/3544
  5317  	if c.options.OutputFormat == config.FormatCommonJS && c.options.Platform == config.PlatformNode {
  5318  		reservedNames["exports"] = 1
  5319  		reservedNames["module"] = 1
  5320  	}
  5321  
  5322  	// These are used to implement bundling, and need to be free for use
  5323  	if c.options.Mode != config.ModePassThrough {
  5324  		reservedNames["require"] = 1
  5325  		reservedNames["Promise"] = 1
  5326  	}
  5327  	timer.End("Compute reserved names")
  5328  
  5329  	// Make sure imports get a chance to be renamed too
  5330  	var sortedImportsFromOtherChunks stableRefArray
  5331  	for _, imports := range chunk.chunkRepr.(*chunkReprJS).importsFromOtherChunks {
  5332  		for _, item := range imports {
  5333  			sortedImportsFromOtherChunks = append(sortedImportsFromOtherChunks, stableRef{
  5334  				StableSourceIndex: c.graph.StableSourceIndices[item.ref.SourceIndex],
  5335  				Ref:               item.ref,
  5336  			})
  5337  		}
  5338  	}
  5339  	sort.Sort(sortedImportsFromOtherChunks)
  5340  
  5341  	// Minification uses frequency analysis to give shorter names to more frequent symbols
  5342  	if c.options.MinifyIdentifiers {
  5343  		// Determine the first top-level slot (i.e. not in a nested scope)
  5344  		var firstTopLevelSlots ast.SlotCounts
  5345  		for _, sourceIndex := range filesInOrder {
  5346  			firstTopLevelSlots.UnionMax(c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr).AST.NestedScopeSlotCounts)
  5347  		}
  5348  		r := renamer.NewMinifyRenamer(c.graph.Symbols, firstTopLevelSlots, reservedNames)
  5349  
  5350  		// Accumulate nested symbol usage counts
  5351  		timer.Begin("Accumulate symbol counts")
  5352  		timer.Begin("Parallel phase")
  5353  		allTopLevelSymbols := make([]renamer.StableSymbolCountArray, len(filesInOrder))
  5354  		stableSourceIndices := c.graph.StableSourceIndices
  5355  		freq := ast.CharFreq{}
  5356  		waitGroup := sync.WaitGroup{}
  5357  		waitGroup.Add(len(filesInOrder))
  5358  		for i, sourceIndex := range filesInOrder {
  5359  			repr := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr)
  5360  
  5361  			// Do this outside of the goroutine because it's not atomic
  5362  			if repr.AST.CharFreq != nil {
  5363  				freq.Include(repr.AST.CharFreq)
  5364  			}
  5365  
  5366  			go func(topLevelSymbols *renamer.StableSymbolCountArray, repr *graph.JSRepr) {
  5367  				if repr.AST.UsesExportsRef {
  5368  					r.AccumulateSymbolCount(topLevelSymbols, repr.AST.ExportsRef, 1, stableSourceIndices)
  5369  				}
  5370  				if repr.AST.UsesModuleRef {
  5371  					r.AccumulateSymbolCount(topLevelSymbols, repr.AST.ModuleRef, 1, stableSourceIndices)
  5372  				}
  5373  
  5374  				for partIndex, part := range repr.AST.Parts {
  5375  					if !repr.AST.Parts[partIndex].IsLive {
  5376  						// Skip the part if it's not in this chunk
  5377  						continue
  5378  					}
  5379  
  5380  					// Accumulate symbol use counts
  5381  					r.AccumulateSymbolUseCounts(topLevelSymbols, part.SymbolUses, stableSourceIndices)
  5382  
  5383  					// Make sure to also count the declaration in addition to the uses
  5384  					for _, declared := range part.DeclaredSymbols {
  5385  						r.AccumulateSymbolCount(topLevelSymbols, declared.Ref, 1, stableSourceIndices)
  5386  					}
  5387  				}
  5388  
  5389  				sort.Sort(topLevelSymbols)
  5390  				waitGroup.Done()
  5391  			}(&allTopLevelSymbols[i], repr)
  5392  		}
  5393  		waitGroup.Wait()
  5394  		timer.End("Parallel phase")
  5395  
  5396  		// Accumulate top-level symbol usage counts
  5397  		timer.Begin("Serial phase")
  5398  		capacity := len(sortedImportsFromOtherChunks)
  5399  		for _, array := range allTopLevelSymbols {
  5400  			capacity += len(array)
  5401  		}
  5402  		topLevelSymbols := make(renamer.StableSymbolCountArray, 0, capacity)
  5403  		for _, stable := range sortedImportsFromOtherChunks {
  5404  			r.AccumulateSymbolCount(&topLevelSymbols, stable.Ref, 1, stableSourceIndices)
  5405  		}
  5406  		for _, array := range allTopLevelSymbols {
  5407  			topLevelSymbols = append(topLevelSymbols, array...)
  5408  		}
  5409  		r.AllocateTopLevelSymbolSlots(topLevelSymbols)
  5410  		timer.End("Serial phase")
  5411  		timer.End("Accumulate symbol counts")
  5412  
  5413  		// Add all of the character frequency histograms for all files in this
  5414  		// chunk together, then use it to compute the character sequence used to
  5415  		// generate minified names. This results in slightly better gzip compression
  5416  		// over assigning minified names in order (i.e. "a b c ..."). Even though
  5417  		// it's a very small win, we still do it because it's simple to do and very
  5418  		// cheap to compute.
  5419  		minifier := ast.DefaultNameMinifierJS.ShuffleByCharFreq(freq)
  5420  		timer.Begin("Assign names by frequency")
  5421  		r.AssignNamesByFrequency(&minifier)
  5422  		timer.End("Assign names by frequency")
  5423  		return r
  5424  	}
  5425  
  5426  	// When we're not minifying, just append numbers to symbol names to avoid collisions
  5427  	r := renamer.NewNumberRenamer(c.graph.Symbols, reservedNames)
  5428  	nestedScopes := make(map[uint32][]*js_ast.Scope)
  5429  
  5430  	timer.Begin("Add top-level symbols")
  5431  	for _, stable := range sortedImportsFromOtherChunks {
  5432  		r.AddTopLevelSymbol(stable.Ref)
  5433  	}
  5434  	for _, sourceIndex := range filesInOrder {
  5435  		repr := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr)
  5436  		var scopes []*js_ast.Scope
  5437  
  5438  		// Modules wrapped in a CommonJS closure look like this:
  5439  		//
  5440  		//   // foo.js
  5441  		//   var require_foo = __commonJS((exports, module) => {
  5442  		//     exports.foo = 123;
  5443  		//   });
  5444  		//
  5445  		// The symbol "require_foo" is stored in "file.ast.WrapperRef". We want
  5446  		// to be able to minify everything inside the closure without worrying
  5447  		// about collisions with other CommonJS modules. Set up the scopes such
  5448  		// that it appears as if the file was structured this way all along. It's
  5449  		// not completely accurate (e.g. we don't set the parent of the module
  5450  		// scope to this new top-level scope) but it's good enough for the
  5451  		// renaming code.
  5452  		if repr.Meta.Wrap == graph.WrapCJS {
  5453  			r.AddTopLevelSymbol(repr.AST.WrapperRef)
  5454  
  5455  			// External import statements will be hoisted outside of the CommonJS
  5456  			// wrapper if the output format supports import statements. We need to
  5457  			// add those symbols to the top-level scope to avoid causing name
  5458  			// collisions. This code special-cases only those symbols.
  5459  			if c.options.OutputFormat.KeepESMImportExportSyntax() {
  5460  				for _, part := range repr.AST.Parts {
  5461  					for _, stmt := range part.Stmts {
  5462  						switch s := stmt.Data.(type) {
  5463  						case *js_ast.SImport:
  5464  							if !repr.AST.ImportRecords[s.ImportRecordIndex].SourceIndex.IsValid() {
  5465  								r.AddTopLevelSymbol(s.NamespaceRef)
  5466  								if s.DefaultName != nil {
  5467  									r.AddTopLevelSymbol(s.DefaultName.Ref)
  5468  								}
  5469  								if s.Items != nil {
  5470  									for _, item := range *s.Items {
  5471  										r.AddTopLevelSymbol(item.Name.Ref)
  5472  									}
  5473  								}
  5474  							}
  5475  
  5476  						case *js_ast.SExportStar:
  5477  							if !repr.AST.ImportRecords[s.ImportRecordIndex].SourceIndex.IsValid() {
  5478  								r.AddTopLevelSymbol(s.NamespaceRef)
  5479  							}
  5480  
  5481  						case *js_ast.SExportFrom:
  5482  							if !repr.AST.ImportRecords[s.ImportRecordIndex].SourceIndex.IsValid() {
  5483  								r.AddTopLevelSymbol(s.NamespaceRef)
  5484  								for _, item := range s.Items {
  5485  									r.AddTopLevelSymbol(item.Name.Ref)
  5486  								}
  5487  							}
  5488  						}
  5489  					}
  5490  				}
  5491  			}
  5492  
  5493  			nestedScopes[sourceIndex] = []*js_ast.Scope{repr.AST.ModuleScope}
  5494  			continue
  5495  		}
  5496  
  5497  		// Modules wrapped in an ESM closure look like this:
  5498  		//
  5499  		//   // foo.js
  5500  		//   var foo, foo_exports = {};
  5501  		//   __export(foo_exports, {
  5502  		//     foo: () => foo
  5503  		//   });
  5504  		//   let init_foo = __esm(() => {
  5505  		//     foo = 123;
  5506  		//   });
  5507  		//
  5508  		// The symbol "init_foo" is stored in "file.ast.WrapperRef". We need to
  5509  		// minify everything inside the closure without introducing a new scope
  5510  		// since all top-level variables will be hoisted outside of the closure.
  5511  		if repr.Meta.Wrap == graph.WrapESM {
  5512  			r.AddTopLevelSymbol(repr.AST.WrapperRef)
  5513  		}
  5514  
  5515  		// Rename each top-level symbol declaration in this chunk
  5516  		for partIndex, part := range repr.AST.Parts {
  5517  			if repr.AST.Parts[partIndex].IsLive {
  5518  				for _, declared := range part.DeclaredSymbols {
  5519  					if declared.IsTopLevel {
  5520  						r.AddTopLevelSymbol(declared.Ref)
  5521  					}
  5522  				}
  5523  				scopes = append(scopes, part.Scopes...)
  5524  			}
  5525  		}
  5526  
  5527  		nestedScopes[sourceIndex] = scopes
  5528  	}
  5529  	timer.End("Add top-level symbols")
  5530  
  5531  	// Recursively rename symbols in child scopes now that all top-level
  5532  	// symbols have been renamed. This is done in parallel because the symbols
  5533  	// inside nested scopes are independent and can't conflict.
  5534  	timer.Begin("Assign names by scope")
  5535  	r.AssignNamesByScope(nestedScopes)
  5536  	timer.End("Assign names by scope")
  5537  	return r
  5538  }
  5539  
  5540  func (c *linkerContext) generateChunkJS(chunkIndex int, chunkWaitGroup *sync.WaitGroup) {
  5541  	defer c.recoverInternalError(chunkWaitGroup, runtime.SourceIndex)
  5542  
  5543  	chunk := &c.chunks[chunkIndex]
  5544  
  5545  	timer := c.timer.Fork()
  5546  	if timer != nil {
  5547  		timeName := fmt.Sprintf("Generate chunk %q", path.Clean(config.TemplateToString(chunk.finalTemplate)))
  5548  		timer.Begin(timeName)
  5549  		defer c.timer.Join(timer)
  5550  		defer timer.End(timeName)
  5551  	}
  5552  
  5553  	chunkRepr := chunk.chunkRepr.(*chunkReprJS)
  5554  	compileResults := make([]compileResultJS, 0, len(chunkRepr.partsInChunkInOrder))
  5555  	runtimeMembers := c.graph.Files[runtime.SourceIndex].InputFile.Repr.(*graph.JSRepr).AST.ModuleScope.Members
  5556  	toCommonJSRef := ast.FollowSymbols(c.graph.Symbols, runtimeMembers["__toCommonJS"].Ref)
  5557  	toESMRef := ast.FollowSymbols(c.graph.Symbols, runtimeMembers["__toESM"].Ref)
  5558  	runtimeRequireRef := ast.FollowSymbols(c.graph.Symbols, runtimeMembers["__require"].Ref)
  5559  	r := c.renameSymbolsInChunk(chunk, chunkRepr.filesInChunkInOrder, timer)
  5560  	dataForSourceMaps := c.dataForSourceMaps()
  5561  
  5562  	// Note: This contains placeholders instead of what the placeholders are
  5563  	// substituted with. That should be fine though because this should only
  5564  	// ever be used for figuring out how many "../" to add to a relative path
  5565  	// from a chunk whose final path hasn't been calculated yet to a chunk
  5566  	// whose final path has already been calculated. That and placeholders are
  5567  	// never substituted with something containing a "/" so substitution should
  5568  	// never change the "../" count.
  5569  	chunkAbsDir := c.fs.Dir(c.fs.Join(c.options.AbsOutputDir, config.TemplateToString(chunk.finalTemplate)))
  5570  
  5571  	// Generate JavaScript for each file in parallel
  5572  	timer.Begin("Print JavaScript files")
  5573  	waitGroup := sync.WaitGroup{}
  5574  	for _, partRange := range chunkRepr.partsInChunkInOrder {
  5575  		// Skip the runtime in test output
  5576  		if partRange.sourceIndex == runtime.SourceIndex && c.options.OmitRuntimeForTests {
  5577  			continue
  5578  		}
  5579  
  5580  		// Create a goroutine for this file
  5581  		compileResults = append(compileResults, compileResultJS{})
  5582  		compileResult := &compileResults[len(compileResults)-1]
  5583  		waitGroup.Add(1)
  5584  		go c.generateCodeForFileInChunkJS(
  5585  			r,
  5586  			&waitGroup,
  5587  			partRange,
  5588  			toCommonJSRef,
  5589  			toESMRef,
  5590  			runtimeRequireRef,
  5591  			compileResult,
  5592  			dataForSourceMaps,
  5593  		)
  5594  	}
  5595  
  5596  	// Also generate the cross-chunk binding code
  5597  	var crossChunkPrefix []byte
  5598  	var crossChunkSuffix []byte
  5599  	var jsonMetadataImports []string
  5600  	{
  5601  		// Indent the file if everything is wrapped in an IIFE
  5602  		indent := 0
  5603  		if c.options.OutputFormat == config.FormatIIFE {
  5604  			indent++
  5605  		}
  5606  		printOptions := js_printer.Options{
  5607  			Indent:            indent,
  5608  			OutputFormat:      c.options.OutputFormat,
  5609  			MinifyIdentifiers: c.options.MinifyIdentifiers,
  5610  			MinifyWhitespace:  c.options.MinifyWhitespace,
  5611  			MinifySyntax:      c.options.MinifySyntax,
  5612  			LineLimit:         c.options.LineLimit,
  5613  			NeedsMetafile:     c.options.NeedsMetafile,
  5614  		}
  5615  		crossChunkImportRecords := make([]ast.ImportRecord, len(chunk.crossChunkImports))
  5616  		for i, chunkImport := range chunk.crossChunkImports {
  5617  			crossChunkImportRecords[i] = ast.ImportRecord{
  5618  				Kind:  chunkImport.importKind,
  5619  				Path:  logger.Path{Text: c.chunks[chunkImport.chunkIndex].uniqueKey},
  5620  				Flags: ast.ShouldNotBeExternalInMetafile | ast.ContainsUniqueKey,
  5621  			}
  5622  		}
  5623  		crossChunkResult := js_printer.Print(js_ast.AST{
  5624  			ImportRecords: crossChunkImportRecords,
  5625  			Parts:         []js_ast.Part{{Stmts: chunkRepr.crossChunkPrefixStmts}},
  5626  		}, c.graph.Symbols, r, printOptions)
  5627  		crossChunkPrefix = crossChunkResult.JS
  5628  		jsonMetadataImports = crossChunkResult.JSONMetadataImports
  5629  		crossChunkSuffix = js_printer.Print(js_ast.AST{
  5630  			Parts: []js_ast.Part{{Stmts: chunkRepr.crossChunkSuffixStmts}},
  5631  		}, c.graph.Symbols, r, printOptions).JS
  5632  	}
  5633  
  5634  	// Generate the exports for the entry point, if there are any
  5635  	var entryPointTail compileResultJS
  5636  	if chunk.isEntryPoint {
  5637  		entryPointTail = c.generateEntryPointTailJS(
  5638  			r,
  5639  			toCommonJSRef,
  5640  			toESMRef,
  5641  			chunk.sourceIndex,
  5642  		)
  5643  	}
  5644  
  5645  	waitGroup.Wait()
  5646  	timer.End("Print JavaScript files")
  5647  	timer.Begin("Join JavaScript files")
  5648  
  5649  	j := helpers.Joiner{}
  5650  	prevOffset := sourcemap.LineColumnOffset{}
  5651  
  5652  	// Optionally strip whitespace
  5653  	indent := ""
  5654  	space := " "
  5655  	newline := "\n"
  5656  	if c.options.MinifyWhitespace {
  5657  		space = ""
  5658  		newline = ""
  5659  	}
  5660  	newlineBeforeComment := false
  5661  	isExecutable := false
  5662  
  5663  	// Start with the hashbang if there is one. This must be done before the
  5664  	// banner because it only works if it's literally the first character.
  5665  	if chunk.isEntryPoint {
  5666  		if repr := c.graph.Files[chunk.sourceIndex].InputFile.Repr.(*graph.JSRepr); repr.AST.Hashbang != "" {
  5667  			hashbang := repr.AST.Hashbang + "\n"
  5668  			prevOffset.AdvanceString(hashbang)
  5669  			j.AddString(hashbang)
  5670  			newlineBeforeComment = true
  5671  			isExecutable = true
  5672  		}
  5673  	}
  5674  
  5675  	// Then emit the banner after the hashbang. This must come before the
  5676  	// "use strict" directive below because some people use the banner to
  5677  	// emit a hashbang, which must be the first thing in the file.
  5678  	if len(c.options.JSBanner) > 0 {
  5679  		prevOffset.AdvanceString(c.options.JSBanner)
  5680  		prevOffset.AdvanceString("\n")
  5681  		j.AddString(c.options.JSBanner)
  5682  		j.AddString("\n")
  5683  		newlineBeforeComment = true
  5684  	}
  5685  
  5686  	// Add the top-level directive if present (but omit "use strict" in ES
  5687  	// modules because all ES modules are automatically in strict mode)
  5688  	if chunk.isEntryPoint {
  5689  		repr := c.graph.Files[chunk.sourceIndex].InputFile.Repr.(*graph.JSRepr)
  5690  		for _, directive := range repr.AST.Directives {
  5691  			if directive != "use strict" || c.options.OutputFormat != config.FormatESModule {
  5692  				quoted := string(helpers.QuoteForJSON(directive, c.options.ASCIIOnly)) + ";" + newline
  5693  				prevOffset.AdvanceString(quoted)
  5694  				j.AddString(quoted)
  5695  				newlineBeforeComment = true
  5696  			}
  5697  		}
  5698  	}
  5699  
  5700  	// Optionally wrap with an IIFE
  5701  	if c.options.OutputFormat == config.FormatIIFE {
  5702  		var text string
  5703  		indent = "  "
  5704  		if len(c.options.GlobalName) > 0 {
  5705  			text = c.generateGlobalNamePrefix()
  5706  		}
  5707  		if c.options.UnsupportedJSFeatures.Has(compat.Arrow) {
  5708  			text += "(function()" + space + "{" + newline
  5709  		} else {
  5710  			text += "(()" + space + "=>" + space + "{" + newline
  5711  		}
  5712  		prevOffset.AdvanceString(text)
  5713  		j.AddString(text)
  5714  		newlineBeforeComment = false
  5715  	}
  5716  
  5717  	// Put the cross-chunk prefix inside the IIFE
  5718  	if len(crossChunkPrefix) > 0 {
  5719  		newlineBeforeComment = true
  5720  		prevOffset.AdvanceBytes(crossChunkPrefix)
  5721  		j.AddBytes(crossChunkPrefix)
  5722  	}
  5723  
  5724  	// Start the metadata
  5725  	jMeta := helpers.Joiner{}
  5726  	if c.options.NeedsMetafile {
  5727  		// Print imports
  5728  		isFirstMeta := true
  5729  		jMeta.AddString("{\n      \"imports\": [")
  5730  		for _, json := range jsonMetadataImports {
  5731  			if isFirstMeta {
  5732  				isFirstMeta = false
  5733  			} else {
  5734  				jMeta.AddString(",")
  5735  			}
  5736  			jMeta.AddString(json)
  5737  		}
  5738  		for _, compileResult := range compileResults {
  5739  			for _, json := range compileResult.JSONMetadataImports {
  5740  				if isFirstMeta {
  5741  					isFirstMeta = false
  5742  				} else {
  5743  					jMeta.AddString(",")
  5744  				}
  5745  				jMeta.AddString(json)
  5746  			}
  5747  		}
  5748  		if !isFirstMeta {
  5749  			jMeta.AddString("\n      ")
  5750  		}
  5751  
  5752  		// Print exports
  5753  		jMeta.AddString("],\n      \"exports\": [")
  5754  		var aliases []string
  5755  		if c.options.OutputFormat.KeepESMImportExportSyntax() {
  5756  			if chunk.isEntryPoint {
  5757  				if fileRepr := c.graph.Files[chunk.sourceIndex].InputFile.Repr.(*graph.JSRepr); fileRepr.Meta.Wrap == graph.WrapCJS {
  5758  					aliases = []string{"default"}
  5759  				} else {
  5760  					resolvedExports := fileRepr.Meta.ResolvedExports
  5761  					aliases = make([]string, 0, len(resolvedExports))
  5762  					for alias := range resolvedExports {
  5763  						aliases = append(aliases, alias)
  5764  					}
  5765  				}
  5766  			} else {
  5767  				aliases = make([]string, 0, len(chunkRepr.exportsToOtherChunks))
  5768  				for _, alias := range chunkRepr.exportsToOtherChunks {
  5769  					aliases = append(aliases, alias)
  5770  				}
  5771  			}
  5772  		}
  5773  		isFirstMeta = true
  5774  		sort.Strings(aliases) // Sort for determinism
  5775  		for _, alias := range aliases {
  5776  			if isFirstMeta {
  5777  				isFirstMeta = false
  5778  			} else {
  5779  				jMeta.AddString(",")
  5780  			}
  5781  			jMeta.AddString(fmt.Sprintf("\n        %s",
  5782  				helpers.QuoteForJSON(alias, c.options.ASCIIOnly)))
  5783  		}
  5784  		if !isFirstMeta {
  5785  			jMeta.AddString("\n      ")
  5786  		}
  5787  		jMeta.AddString("],\n")
  5788  		if chunk.isEntryPoint {
  5789  			entryPoint := c.graph.Files[chunk.sourceIndex].InputFile.Source.PrettyPath
  5790  			jMeta.AddString(fmt.Sprintf("      \"entryPoint\": %s,\n", helpers.QuoteForJSON(entryPoint, c.options.ASCIIOnly)))
  5791  		}
  5792  		if chunkRepr.hasCSSChunk {
  5793  			jMeta.AddString(fmt.Sprintf("      \"cssBundle\": %s,\n", helpers.QuoteForJSON(c.chunks[chunkRepr.cssChunkIndex].uniqueKey, c.options.ASCIIOnly)))
  5794  		}
  5795  		jMeta.AddString("      \"inputs\": {")
  5796  	}
  5797  
  5798  	// Concatenate the generated JavaScript chunks together
  5799  	var compileResultsForSourceMap []compileResultForSourceMap
  5800  	var legalCommentList []legalCommentEntry
  5801  	var metaOrder []uint32
  5802  	var metaBytes map[uint32][][]byte
  5803  	prevFileNameComment := uint32(0)
  5804  	if c.options.NeedsMetafile {
  5805  		metaOrder = make([]uint32, 0, len(compileResults))
  5806  		metaBytes = make(map[uint32][][]byte, len(compileResults))
  5807  	}
  5808  	for _, compileResult := range compileResults {
  5809  		if len(compileResult.ExtractedLegalComments) > 0 {
  5810  			legalCommentList = append(legalCommentList, legalCommentEntry{
  5811  				sourceIndex: compileResult.sourceIndex,
  5812  				comments:    compileResult.ExtractedLegalComments,
  5813  			})
  5814  		}
  5815  
  5816  		// Add a comment with the file path before the file contents
  5817  		if c.options.Mode == config.ModeBundle && !c.options.MinifyWhitespace &&
  5818  			prevFileNameComment != compileResult.sourceIndex && len(compileResult.JS) > 0 {
  5819  			if newlineBeforeComment {
  5820  				prevOffset.AdvanceString("\n")
  5821  				j.AddString("\n")
  5822  			}
  5823  
  5824  			path := c.graph.Files[compileResult.sourceIndex].InputFile.Source.PrettyPath
  5825  
  5826  			// Make sure newlines in the path can't cause a syntax error. This does
  5827  			// not minimize allocations because it's expected that this case never
  5828  			// comes up in practice.
  5829  			path = strings.ReplaceAll(path, "\r", "\\r")
  5830  			path = strings.ReplaceAll(path, "\n", "\\n")
  5831  			path = strings.ReplaceAll(path, "\u2028", "\\u2028")
  5832  			path = strings.ReplaceAll(path, "\u2029", "\\u2029")
  5833  
  5834  			text := fmt.Sprintf("%s// %s\n", indent, path)
  5835  			prevOffset.AdvanceString(text)
  5836  			j.AddString(text)
  5837  			prevFileNameComment = compileResult.sourceIndex
  5838  		}
  5839  
  5840  		// Don't include the runtime in source maps
  5841  		if c.graph.Files[compileResult.sourceIndex].InputFile.OmitFromSourceMapsAndMetafile {
  5842  			prevOffset.AdvanceString(string(compileResult.JS))
  5843  			j.AddBytes(compileResult.JS)
  5844  		} else {
  5845  			// Save the offset to the start of the stored JavaScript
  5846  			compileResult.generatedOffset = prevOffset
  5847  			j.AddBytes(compileResult.JS)
  5848  
  5849  			// Ignore empty source map chunks
  5850  			if compileResult.SourceMapChunk.ShouldIgnore {
  5851  				prevOffset.AdvanceBytes(compileResult.JS)
  5852  			} else {
  5853  				prevOffset = sourcemap.LineColumnOffset{}
  5854  
  5855  				// Include this file in the source map
  5856  				if c.options.SourceMap != config.SourceMapNone {
  5857  					compileResultsForSourceMap = append(compileResultsForSourceMap, compileResultForSourceMap{
  5858  						sourceMapChunk:  compileResult.SourceMapChunk,
  5859  						generatedOffset: compileResult.generatedOffset,
  5860  						sourceIndex:     compileResult.sourceIndex,
  5861  					})
  5862  				}
  5863  			}
  5864  
  5865  			// Include this file in the metadata
  5866  			if c.options.NeedsMetafile {
  5867  				// Accumulate file sizes since a given file may be split into multiple parts
  5868  				bytes, ok := metaBytes[compileResult.sourceIndex]
  5869  				if !ok {
  5870  					metaOrder = append(metaOrder, compileResult.sourceIndex)
  5871  				}
  5872  				metaBytes[compileResult.sourceIndex] = append(bytes, compileResult.JS)
  5873  			}
  5874  		}
  5875  
  5876  		// Put a newline before the next file path comment
  5877  		if len(compileResult.JS) > 0 {
  5878  			newlineBeforeComment = true
  5879  		}
  5880  	}
  5881  
  5882  	// Stick the entry point tail at the end of the file. Deliberately don't
  5883  	// include any source mapping information for this because it's automatically
  5884  	// generated and doesn't correspond to a location in the input file.
  5885  	j.AddBytes(entryPointTail.JS)
  5886  
  5887  	// Put the cross-chunk suffix inside the IIFE
  5888  	if len(crossChunkSuffix) > 0 {
  5889  		if newlineBeforeComment {
  5890  			j.AddString(newline)
  5891  		}
  5892  		j.AddBytes(crossChunkSuffix)
  5893  	}
  5894  
  5895  	// Optionally wrap with an IIFE
  5896  	if c.options.OutputFormat == config.FormatIIFE {
  5897  		j.AddString("})();" + newline)
  5898  	}
  5899  
  5900  	// Make sure the file ends with a newline
  5901  	j.EnsureNewlineAtEnd()
  5902  	slashTag := "/script"
  5903  	if c.options.UnsupportedJSFeatures.Has(compat.InlineScript) {
  5904  		slashTag = ""
  5905  	}
  5906  	c.maybeAppendLegalComments(c.options.LegalComments, legalCommentList, chunk, &j, slashTag)
  5907  
  5908  	if len(c.options.JSFooter) > 0 {
  5909  		j.AddString(c.options.JSFooter)
  5910  		j.AddString("\n")
  5911  	}
  5912  
  5913  	// The JavaScript contents are done now that the source map comment is in
  5914  	chunk.intermediateOutput = c.breakJoinerIntoPieces(j)
  5915  	timer.End("Join JavaScript files")
  5916  
  5917  	if c.options.SourceMap != config.SourceMapNone {
  5918  		timer.Begin("Generate source map")
  5919  		canHaveShifts := chunk.intermediateOutput.pieces != nil
  5920  		chunk.outputSourceMap = c.generateSourceMapForChunk(compileResultsForSourceMap, chunkAbsDir, dataForSourceMaps, canHaveShifts)
  5921  		timer.End("Generate source map")
  5922  	}
  5923  
  5924  	// End the metadata lazily. The final output size is not known until the
  5925  	// final import paths are substituted into the output pieces generated below.
  5926  	if c.options.NeedsMetafile {
  5927  		pieces := make([][]intermediateOutput, len(metaOrder))
  5928  		for i, sourceIndex := range metaOrder {
  5929  			slices := metaBytes[sourceIndex]
  5930  			outputs := make([]intermediateOutput, len(slices))
  5931  			for j, slice := range slices {
  5932  				outputs[j] = c.breakOutputIntoPieces(slice)
  5933  			}
  5934  			pieces[i] = outputs
  5935  		}
  5936  		chunk.jsonMetadataChunkCallback = func(finalOutputSize int) helpers.Joiner {
  5937  			finalRelDir := c.fs.Dir(chunk.finalRelPath)
  5938  			for i, sourceIndex := range metaOrder {
  5939  				if i > 0 {
  5940  					jMeta.AddString(",")
  5941  				}
  5942  				count := 0
  5943  				for _, output := range pieces[i] {
  5944  					count += c.accurateFinalByteCount(output, finalRelDir)
  5945  				}
  5946  				jMeta.AddString(fmt.Sprintf("\n        %s: {\n          \"bytesInOutput\": %d\n        %s}",
  5947  					helpers.QuoteForJSON(c.graph.Files[sourceIndex].InputFile.Source.PrettyPath, c.options.ASCIIOnly),
  5948  					count, c.generateExtraDataForFileJS(sourceIndex)))
  5949  			}
  5950  			if len(metaOrder) > 0 {
  5951  				jMeta.AddString("\n      ")
  5952  			}
  5953  			jMeta.AddString(fmt.Sprintf("},\n      \"bytes\": %d\n    }", finalOutputSize))
  5954  			return jMeta
  5955  		}
  5956  	}
  5957  
  5958  	c.generateIsolatedHashInParallel(chunk)
  5959  	chunk.isExecutable = isExecutable
  5960  	chunkWaitGroup.Done()
  5961  }
  5962  
  5963  func (c *linkerContext) generateGlobalNamePrefix() string {
  5964  	var text string
  5965  	globalName := c.options.GlobalName
  5966  	prefix := globalName[0]
  5967  	space := " "
  5968  	join := ";\n"
  5969  
  5970  	if c.options.MinifyWhitespace {
  5971  		space = ""
  5972  		join = ";"
  5973  	}
  5974  
  5975  	// Use "||=" to make the code more compact when it's supported
  5976  	if len(globalName) > 1 && !c.options.UnsupportedJSFeatures.Has(compat.LogicalAssignment) {
  5977  		if js_printer.CanEscapeIdentifier(prefix, c.options.UnsupportedJSFeatures, c.options.ASCIIOnly) {
  5978  			if c.options.ASCIIOnly {
  5979  				prefix = string(js_printer.QuoteIdentifier(nil, prefix, c.options.UnsupportedJSFeatures))
  5980  			}
  5981  			text = fmt.Sprintf("var %s%s", prefix, join)
  5982  		} else {
  5983  			prefix = fmt.Sprintf("this[%s]", helpers.QuoteForJSON(prefix, c.options.ASCIIOnly))
  5984  		}
  5985  		for _, name := range globalName[1:] {
  5986  			var dotOrIndex string
  5987  			if js_printer.CanEscapeIdentifier(name, c.options.UnsupportedJSFeatures, c.options.ASCIIOnly) {
  5988  				if c.options.ASCIIOnly {
  5989  					name = string(js_printer.QuoteIdentifier(nil, name, c.options.UnsupportedJSFeatures))
  5990  				}
  5991  				dotOrIndex = fmt.Sprintf(".%s", name)
  5992  			} else {
  5993  				dotOrIndex = fmt.Sprintf("[%s]", helpers.QuoteForJSON(name, c.options.ASCIIOnly))
  5994  			}
  5995  			prefix = fmt.Sprintf("(%s%s||=%s{})%s", prefix, space, space, dotOrIndex)
  5996  		}
  5997  		return fmt.Sprintf("%s%s%s=%s", text, prefix, space, space)
  5998  	}
  5999  
  6000  	if js_printer.CanEscapeIdentifier(prefix, c.options.UnsupportedJSFeatures, c.options.ASCIIOnly) {
  6001  		if c.options.ASCIIOnly {
  6002  			prefix = string(js_printer.QuoteIdentifier(nil, prefix, c.options.UnsupportedJSFeatures))
  6003  		}
  6004  		text = fmt.Sprintf("var %s%s=%s", prefix, space, space)
  6005  	} else {
  6006  		prefix = fmt.Sprintf("this[%s]", helpers.QuoteForJSON(prefix, c.options.ASCIIOnly))
  6007  		text = fmt.Sprintf("%s%s=%s", prefix, space, space)
  6008  	}
  6009  
  6010  	for _, name := range globalName[1:] {
  6011  		oldPrefix := prefix
  6012  		if js_printer.CanEscapeIdentifier(name, c.options.UnsupportedJSFeatures, c.options.ASCIIOnly) {
  6013  			if c.options.ASCIIOnly {
  6014  				name = string(js_printer.QuoteIdentifier(nil, name, c.options.UnsupportedJSFeatures))
  6015  			}
  6016  			prefix = fmt.Sprintf("%s.%s", prefix, name)
  6017  		} else {
  6018  			prefix = fmt.Sprintf("%s[%s]", prefix, helpers.QuoteForJSON(name, c.options.ASCIIOnly))
  6019  		}
  6020  		text += fmt.Sprintf("%s%s||%s{}%s%s%s=%s", oldPrefix, space, space, join, prefix, space, space)
  6021  	}
  6022  
  6023  	return text
  6024  }
  6025  
  6026  type compileResultCSS struct {
  6027  	css_printer.PrintResult
  6028  
  6029  	// This is the line and column offset since the previous CSS string
  6030  	// or the start of the file if this is the first CSS string.
  6031  	generatedOffset sourcemap.LineColumnOffset
  6032  
  6033  	// The source index can be invalid for short snippets that aren't necessarily
  6034  	// tied to any one file and/or that don't really need source mappings. The
  6035  	// source index is really only valid for the compile result that contains the
  6036  	// main contents of a file, which we try to only ever write out once.
  6037  	sourceIndex ast.Index32
  6038  	hasCharset  bool
  6039  }
  6040  
  6041  func (c *linkerContext) generateChunkCSS(chunkIndex int, chunkWaitGroup *sync.WaitGroup) {
  6042  	defer c.recoverInternalError(chunkWaitGroup, runtime.SourceIndex)
  6043  
  6044  	chunk := &c.chunks[chunkIndex]
  6045  
  6046  	timer := c.timer.Fork()
  6047  	if timer != nil {
  6048  		timeName := fmt.Sprintf("Generate chunk %q", path.Clean(config.TemplateToString(chunk.finalTemplate)))
  6049  		timer.Begin(timeName)
  6050  		defer c.timer.Join(timer)
  6051  		defer timer.End(timeName)
  6052  	}
  6053  
  6054  	chunkRepr := chunk.chunkRepr.(*chunkReprCSS)
  6055  	compileResults := make([]compileResultCSS, len(chunkRepr.importsInChunkInOrder))
  6056  	dataForSourceMaps := c.dataForSourceMaps()
  6057  
  6058  	// Note: This contains placeholders instead of what the placeholders are
  6059  	// substituted with. That should be fine though because this should only
  6060  	// ever be used for figuring out how many "../" to add to a relative path
  6061  	// from a chunk whose final path hasn't been calculated yet to a chunk
  6062  	// whose final path has already been calculated. That and placeholders are
  6063  	// never substituted with something containing a "/" so substitution should
  6064  	// never change the "../" count.
  6065  	chunkAbsDir := c.fs.Dir(c.fs.Join(c.options.AbsOutputDir, config.TemplateToString(chunk.finalTemplate)))
  6066  
  6067  	// Remove duplicate rules across files. This must be done in serial, not
  6068  	// in parallel, and must be done from the last rule to the first rule.
  6069  	timer.Begin("Prepare CSS ASTs")
  6070  	asts := make([]css_ast.AST, len(chunkRepr.importsInChunkInOrder))
  6071  	var remover css_parser.DuplicateRuleRemover
  6072  	if c.options.MinifySyntax {
  6073  		remover = css_parser.MakeDuplicateRuleMangler(c.graph.Symbols)
  6074  	}
  6075  	for i := len(chunkRepr.importsInChunkInOrder) - 1; i >= 0; i-- {
  6076  		entry := chunkRepr.importsInChunkInOrder[i]
  6077  		switch entry.kind {
  6078  		case cssImportLayers:
  6079  			var rules []css_ast.Rule
  6080  			if len(entry.layers) > 0 {
  6081  				rules = append(rules, css_ast.Rule{Data: &css_ast.RAtLayer{Names: entry.layers}})
  6082  			}
  6083  			rules, importRecords := wrapRulesWithConditions(rules, nil, entry.conditions, entry.conditionImportRecords)
  6084  			asts[i] = css_ast.AST{Rules: rules, ImportRecords: importRecords}
  6085  
  6086  		case cssImportExternalPath:
  6087  			var conditions *css_ast.ImportConditions
  6088  			if len(entry.conditions) > 0 {
  6089  				conditions = &entry.conditions[0]
  6090  
  6091  				// Handling a chain of nested conditions is complicated. We can't
  6092  				// necessarily join them together because a) there may be multiple
  6093  				// layer names and b) layer names are only supposed to be inserted
  6094  				// into the layer order if the parent conditions are applied.
  6095  				//
  6096  				// Instead we handle them by preserving the "@import" nesting using
  6097  				// imports of data URL stylesheets. This may seem strange but I think
  6098  				// this is the only way to do this in CSS.
  6099  				for i := len(entry.conditions) - 1; i > 0; i-- {
  6100  					astImport := css_ast.AST{
  6101  						Rules: []css_ast.Rule{{Data: &css_ast.RAtImport{
  6102  							ImportRecordIndex: uint32(len(entry.conditionImportRecords)),
  6103  							ImportConditions:  &entry.conditions[i],
  6104  						}}},
  6105  						ImportRecords: append(entry.conditionImportRecords, ast.ImportRecord{
  6106  							Kind: ast.ImportAt,
  6107  							Path: entry.externalPath,
  6108  						}),
  6109  					}
  6110  					astResult := css_printer.Print(astImport, c.graph.Symbols, css_printer.Options{
  6111  						MinifyWhitespace: c.options.MinifyWhitespace,
  6112  						ASCIIOnly:        c.options.ASCIIOnly,
  6113  					})
  6114  					entry.externalPath = logger.Path{Text: helpers.EncodeStringAsShortestDataURL("text/css", string(bytes.TrimSpace(astResult.CSS)))}
  6115  				}
  6116  			}
  6117  			asts[i] = css_ast.AST{
  6118  				ImportRecords: append(append([]ast.ImportRecord{}, entry.conditionImportRecords...), ast.ImportRecord{
  6119  					Kind: ast.ImportAt,
  6120  					Path: entry.externalPath,
  6121  				}),
  6122  				Rules: []css_ast.Rule{{Data: &css_ast.RAtImport{
  6123  					ImportRecordIndex: uint32(len(entry.conditionImportRecords)),
  6124  					ImportConditions:  conditions,
  6125  				}}},
  6126  			}
  6127  
  6128  		case cssImportSourceIndex:
  6129  			file := &c.graph.Files[entry.sourceIndex]
  6130  			ast := file.InputFile.Repr.(*graph.CSSRepr).AST
  6131  
  6132  			// Filter out "@charset", "@import", and leading "@layer" rules
  6133  			rules := make([]css_ast.Rule, 0, len(ast.Rules))
  6134  			didFindAtImport := false
  6135  			didFindAtLayer := false
  6136  			for _, rule := range ast.Rules {
  6137  				switch rule.Data.(type) {
  6138  				case *css_ast.RAtCharset:
  6139  					compileResults[i].hasCharset = true
  6140  					continue
  6141  				case *css_ast.RAtLayer:
  6142  					didFindAtLayer = true
  6143  				case *css_ast.RAtImport:
  6144  					if !didFindAtImport {
  6145  						didFindAtImport = true
  6146  						if didFindAtLayer {
  6147  							// Filter out the pre-import layers once we see the first
  6148  							// "@import". These layers are special-cased by the linker
  6149  							// and already appear as a separate entry in import order.
  6150  							end := 0
  6151  							for _, rule := range rules {
  6152  								if _, ok := rule.Data.(*css_ast.RAtLayer); !ok {
  6153  									rules[end] = rule
  6154  									end++
  6155  								}
  6156  							}
  6157  							rules = rules[:end]
  6158  						}
  6159  					}
  6160  					continue
  6161  				}
  6162  				rules = append(rules, rule)
  6163  			}
  6164  
  6165  			rules, ast.ImportRecords = wrapRulesWithConditions(rules, ast.ImportRecords, entry.conditions, entry.conditionImportRecords)
  6166  
  6167  			// Remove top-level duplicate rules across files
  6168  			if c.options.MinifySyntax {
  6169  				rules = remover.RemoveDuplicateRulesInPlace(entry.sourceIndex, rules, ast.ImportRecords)
  6170  			}
  6171  
  6172  			ast.Rules = rules
  6173  			asts[i] = ast
  6174  		}
  6175  	}
  6176  	timer.End("Prepare CSS ASTs")
  6177  
  6178  	// Generate CSS for each file in parallel
  6179  	timer.Begin("Print CSS files")
  6180  	waitGroup := sync.WaitGroup{}
  6181  	for i, entry := range chunkRepr.importsInChunkInOrder {
  6182  		// Create a goroutine for this file
  6183  		waitGroup.Add(1)
  6184  		go func(i int, entry cssImportOrder, compileResult *compileResultCSS) {
  6185  			cssOptions := css_printer.Options{
  6186  				MinifyWhitespace:    c.options.MinifyWhitespace,
  6187  				LineLimit:           c.options.LineLimit,
  6188  				ASCIIOnly:           c.options.ASCIIOnly,
  6189  				LegalComments:       c.options.LegalComments,
  6190  				SourceMap:           c.options.SourceMap,
  6191  				UnsupportedFeatures: c.options.UnsupportedCSSFeatures,
  6192  				NeedsMetafile:       c.options.NeedsMetafile,
  6193  				LocalNames:          c.mangledProps,
  6194  			}
  6195  
  6196  			if entry.kind == cssImportSourceIndex {
  6197  				defer c.recoverInternalError(&waitGroup, entry.sourceIndex)
  6198  				file := &c.graph.Files[entry.sourceIndex]
  6199  
  6200  				// Only generate a source map if needed
  6201  				if file.InputFile.Loader.CanHaveSourceMap() && c.options.SourceMap != config.SourceMapNone {
  6202  					cssOptions.AddSourceMappings = true
  6203  					cssOptions.InputSourceMap = file.InputFile.InputSourceMap
  6204  					cssOptions.LineOffsetTables = dataForSourceMaps[entry.sourceIndex].LineOffsetTables
  6205  				}
  6206  
  6207  				cssOptions.InputSourceIndex = entry.sourceIndex
  6208  				compileResult.sourceIndex = ast.MakeIndex32(entry.sourceIndex)
  6209  			}
  6210  
  6211  			compileResult.PrintResult = css_printer.Print(asts[i], c.graph.Symbols, cssOptions)
  6212  			waitGroup.Done()
  6213  		}(i, entry, &compileResults[i])
  6214  	}
  6215  
  6216  	waitGroup.Wait()
  6217  	timer.End("Print CSS files")
  6218  	timer.Begin("Join CSS files")
  6219  	j := helpers.Joiner{}
  6220  	prevOffset := sourcemap.LineColumnOffset{}
  6221  	newlineBeforeComment := false
  6222  
  6223  	if len(c.options.CSSBanner) > 0 {
  6224  		prevOffset.AdvanceString(c.options.CSSBanner)
  6225  		j.AddString(c.options.CSSBanner)
  6226  		prevOffset.AdvanceString("\n")
  6227  		j.AddString("\n")
  6228  	}
  6229  
  6230  	// Generate any prefix rules now
  6231  	var jsonMetadataImports []string
  6232  	{
  6233  		tree := css_ast.AST{}
  6234  
  6235  		// "@charset" is the only thing that comes before "@import"
  6236  		for _, compileResult := range compileResults {
  6237  			if compileResult.hasCharset {
  6238  				tree.Rules = append(tree.Rules, css_ast.Rule{Data: &css_ast.RAtCharset{Encoding: "UTF-8"}})
  6239  				break
  6240  			}
  6241  		}
  6242  
  6243  		if len(tree.Rules) > 0 {
  6244  			result := css_printer.Print(tree, c.graph.Symbols, css_printer.Options{
  6245  				MinifyWhitespace: c.options.MinifyWhitespace,
  6246  				LineLimit:        c.options.LineLimit,
  6247  				ASCIIOnly:        c.options.ASCIIOnly,
  6248  				NeedsMetafile:    c.options.NeedsMetafile,
  6249  			})
  6250  			jsonMetadataImports = result.JSONMetadataImports
  6251  			if len(result.CSS) > 0 {
  6252  				prevOffset.AdvanceBytes(result.CSS)
  6253  				j.AddBytes(result.CSS)
  6254  				newlineBeforeComment = true
  6255  			}
  6256  		}
  6257  	}
  6258  
  6259  	// Start the metadata
  6260  	jMeta := helpers.Joiner{}
  6261  	if c.options.NeedsMetafile {
  6262  		isFirstMeta := true
  6263  		jMeta.AddString("{\n      \"imports\": [")
  6264  		for _, json := range jsonMetadataImports {
  6265  			if isFirstMeta {
  6266  				isFirstMeta = false
  6267  			} else {
  6268  				jMeta.AddString(",")
  6269  			}
  6270  			jMeta.AddString(json)
  6271  		}
  6272  		for _, compileResult := range compileResults {
  6273  			for _, json := range compileResult.JSONMetadataImports {
  6274  				if isFirstMeta {
  6275  					isFirstMeta = false
  6276  				} else {
  6277  					jMeta.AddString(",")
  6278  				}
  6279  				jMeta.AddString(json)
  6280  			}
  6281  		}
  6282  		if !isFirstMeta {
  6283  			jMeta.AddString("\n      ")
  6284  		}
  6285  		if chunk.isEntryPoint {
  6286  			file := &c.graph.Files[chunk.sourceIndex]
  6287  
  6288  			// Do not generate "entryPoint" for CSS files that are the result of
  6289  			// importing CSS into JavaScript. We want this to be a 1:1 relationship
  6290  			// and there is already an output file for the JavaScript entry point.
  6291  			if _, ok := file.InputFile.Repr.(*graph.CSSRepr); ok {
  6292  				jMeta.AddString(fmt.Sprintf("],\n      \"entryPoint\": %s,\n      \"inputs\": {",
  6293  					helpers.QuoteForJSON(file.InputFile.Source.PrettyPath, c.options.ASCIIOnly)))
  6294  			} else {
  6295  				jMeta.AddString("],\n      \"inputs\": {")
  6296  			}
  6297  		} else {
  6298  			jMeta.AddString("],\n      \"inputs\": {")
  6299  		}
  6300  	}
  6301  
  6302  	// Concatenate the generated CSS chunks together
  6303  	var compileResultsForSourceMap []compileResultForSourceMap
  6304  	var legalCommentList []legalCommentEntry
  6305  	for _, compileResult := range compileResults {
  6306  		if len(compileResult.ExtractedLegalComments) > 0 && compileResult.sourceIndex.IsValid() {
  6307  			legalCommentList = append(legalCommentList, legalCommentEntry{
  6308  				sourceIndex: compileResult.sourceIndex.GetIndex(),
  6309  				comments:    compileResult.ExtractedLegalComments,
  6310  			})
  6311  		}
  6312  
  6313  		if c.options.Mode == config.ModeBundle && !c.options.MinifyWhitespace && compileResult.sourceIndex.IsValid() {
  6314  			var newline string
  6315  			if newlineBeforeComment {
  6316  				newline = "\n"
  6317  			}
  6318  			comment := fmt.Sprintf("%s/* %s */\n", newline, c.graph.Files[compileResult.sourceIndex.GetIndex()].InputFile.Source.PrettyPath)
  6319  			prevOffset.AdvanceString(comment)
  6320  			j.AddString(comment)
  6321  		}
  6322  		if len(compileResult.CSS) > 0 {
  6323  			newlineBeforeComment = true
  6324  		}
  6325  
  6326  		// Save the offset to the start of the stored JavaScript
  6327  		compileResult.generatedOffset = prevOffset
  6328  		j.AddBytes(compileResult.CSS)
  6329  
  6330  		// Ignore empty source map chunks
  6331  		if compileResult.SourceMapChunk.ShouldIgnore {
  6332  			prevOffset.AdvanceBytes(compileResult.CSS)
  6333  		} else {
  6334  			prevOffset = sourcemap.LineColumnOffset{}
  6335  
  6336  			// Include this file in the source map
  6337  			if c.options.SourceMap != config.SourceMapNone && compileResult.sourceIndex.IsValid() {
  6338  				compileResultsForSourceMap = append(compileResultsForSourceMap, compileResultForSourceMap{
  6339  					sourceMapChunk:  compileResult.SourceMapChunk,
  6340  					generatedOffset: compileResult.generatedOffset,
  6341  					sourceIndex:     compileResult.sourceIndex.GetIndex(),
  6342  				})
  6343  			}
  6344  		}
  6345  	}
  6346  
  6347  	// Make sure the file ends with a newline
  6348  	j.EnsureNewlineAtEnd()
  6349  	slashTag := "/style"
  6350  	if c.options.UnsupportedCSSFeatures.Has(compat.InlineStyle) {
  6351  		slashTag = ""
  6352  	}
  6353  	c.maybeAppendLegalComments(c.options.LegalComments, legalCommentList, chunk, &j, slashTag)
  6354  
  6355  	if len(c.options.CSSFooter) > 0 {
  6356  		j.AddString(c.options.CSSFooter)
  6357  		j.AddString("\n")
  6358  	}
  6359  
  6360  	// The CSS contents are done now that the source map comment is in
  6361  	chunk.intermediateOutput = c.breakJoinerIntoPieces(j)
  6362  	timer.End("Join CSS files")
  6363  
  6364  	if c.options.SourceMap != config.SourceMapNone {
  6365  		timer.Begin("Generate source map")
  6366  		canHaveShifts := chunk.intermediateOutput.pieces != nil
  6367  		chunk.outputSourceMap = c.generateSourceMapForChunk(compileResultsForSourceMap, chunkAbsDir, dataForSourceMaps, canHaveShifts)
  6368  		timer.End("Generate source map")
  6369  	}
  6370  
  6371  	// End the metadata lazily. The final output size is not known until the
  6372  	// final import paths are substituted into the output pieces generated below.
  6373  	if c.options.NeedsMetafile {
  6374  		pieces := make([]intermediateOutput, len(compileResults))
  6375  		for i, compileResult := range compileResults {
  6376  			pieces[i] = c.breakOutputIntoPieces(compileResult.CSS)
  6377  		}
  6378  		chunk.jsonMetadataChunkCallback = func(finalOutputSize int) helpers.Joiner {
  6379  			finalRelDir := c.fs.Dir(chunk.finalRelPath)
  6380  			isFirst := true
  6381  			for i, compileResult := range compileResults {
  6382  				if !compileResult.sourceIndex.IsValid() {
  6383  					continue
  6384  				}
  6385  				if isFirst {
  6386  					isFirst = false
  6387  				} else {
  6388  					jMeta.AddString(",")
  6389  				}
  6390  				jMeta.AddString(fmt.Sprintf("\n        %s: {\n          \"bytesInOutput\": %d\n        }",
  6391  					helpers.QuoteForJSON(c.graph.Files[compileResult.sourceIndex.GetIndex()].InputFile.Source.PrettyPath, c.options.ASCIIOnly),
  6392  					c.accurateFinalByteCount(pieces[i], finalRelDir)))
  6393  			}
  6394  			if len(compileResults) > 0 {
  6395  				jMeta.AddString("\n      ")
  6396  			}
  6397  			jMeta.AddString(fmt.Sprintf("},\n      \"bytes\": %d\n    }", finalOutputSize))
  6398  			return jMeta
  6399  		}
  6400  	}
  6401  
  6402  	c.generateIsolatedHashInParallel(chunk)
  6403  	chunkWaitGroup.Done()
  6404  }
  6405  
  6406  func wrapRulesWithConditions(
  6407  	rules []css_ast.Rule, importRecords []ast.ImportRecord,
  6408  	conditions []css_ast.ImportConditions, conditionImportRecords []ast.ImportRecord,
  6409  ) ([]css_ast.Rule, []ast.ImportRecord) {
  6410  	for i := len(conditions) - 1; i >= 0; i-- {
  6411  		item := conditions[i]
  6412  
  6413  		// Generate "@layer" wrappers. Note that empty "@layer" rules still have
  6414  		// a side effect (they set the layer order) so they cannot be removed.
  6415  		for _, t := range item.Layers {
  6416  			if len(rules) == 0 {
  6417  				if t.Children == nil {
  6418  					// Omit an empty "@layer {}" entirely
  6419  					continue
  6420  				} else {
  6421  					// Generate "@layer foo;" instead of "@layer foo {}"
  6422  					rules = nil
  6423  				}
  6424  			}
  6425  			var prelude []css_ast.Token
  6426  			if t.Children != nil {
  6427  				prelude = *t.Children
  6428  			}
  6429  			prelude, importRecords = css_ast.CloneTokensWithImportRecords(prelude, conditionImportRecords, nil, importRecords)
  6430  			rules = []css_ast.Rule{{Data: &css_ast.RKnownAt{
  6431  				AtToken: "layer",
  6432  				Prelude: prelude,
  6433  				Rules:   rules,
  6434  			}}}
  6435  		}
  6436  
  6437  		// Generate "@supports" wrappers. This is not done if the rule block is
  6438  		// empty because empty "@supports" rules have no effect.
  6439  		if len(rules) > 0 {
  6440  			for _, t := range item.Supports {
  6441  				t.Kind = css_lexer.TOpenParen
  6442  				t.Text = "("
  6443  				var prelude []css_ast.Token
  6444  				prelude, importRecords = css_ast.CloneTokensWithImportRecords([]css_ast.Token{t}, conditionImportRecords, nil, importRecords)
  6445  				rules = []css_ast.Rule{{Data: &css_ast.RKnownAt{
  6446  					AtToken: "supports",
  6447  					Prelude: prelude,
  6448  					Rules:   rules,
  6449  				}}}
  6450  			}
  6451  		}
  6452  
  6453  		// Generate "@media" wrappers. This is not done if the rule block is
  6454  		// empty because empty "@media" rules have no effect.
  6455  		if len(rules) > 0 && len(item.Media) > 0 {
  6456  			var prelude []css_ast.Token
  6457  			prelude, importRecords = css_ast.CloneTokensWithImportRecords(item.Media, conditionImportRecords, nil, importRecords)
  6458  			rules = []css_ast.Rule{{Data: &css_ast.RKnownAt{
  6459  				AtToken: "media",
  6460  				Prelude: prelude,
  6461  				Rules:   rules,
  6462  			}}}
  6463  		}
  6464  	}
  6465  
  6466  	return rules, importRecords
  6467  }
  6468  
  6469  type legalCommentEntry struct {
  6470  	sourceIndex uint32
  6471  	comments    []string
  6472  }
  6473  
  6474  // Add all unique legal comments to the end of the file. These are
  6475  // deduplicated because some projects have thousands of files with the same
  6476  // comment. The comment must be preserved in the output for legal reasons but
  6477  // at the same time we want to generate a small bundle when minifying.
  6478  func (c *linkerContext) maybeAppendLegalComments(
  6479  	legalComments config.LegalComments,
  6480  	legalCommentList []legalCommentEntry,
  6481  	chunk *chunkInfo,
  6482  	j *helpers.Joiner,
  6483  	slashTag string,
  6484  ) {
  6485  	switch legalComments {
  6486  	case config.LegalCommentsNone, config.LegalCommentsInline:
  6487  		return
  6488  	}
  6489  
  6490  	type thirdPartyEntry struct {
  6491  		packagePath string
  6492  		comments    []string
  6493  	}
  6494  
  6495  	var uniqueFirstPartyComments []string
  6496  	var thirdPartyComments []thirdPartyEntry
  6497  	hasFirstPartyComment := make(map[string]struct{})
  6498  
  6499  	for _, entry := range legalCommentList {
  6500  		source := c.graph.Files[entry.sourceIndex].InputFile.Source
  6501  		packagePath := ""
  6502  
  6503  		// Try to extract a package name from the source path. If we can find a
  6504  		// "node_modules" path component in the path, then assume this is a legal
  6505  		// comment in third-party code and that everything after "node_modules" is
  6506  		// the package name and subpath. If we can't, then assume this is a legal
  6507  		// comment in first-party code.
  6508  		//
  6509  		// The rationale for this behavior: If we just include third-party comments
  6510  		// as-is and the third-party comments don't say what package they're from
  6511  		// (which isn't uncommon), then it'll look like that comment applies to
  6512  		// all code in the file which is very wrong. So we need to somehow say
  6513  		// where the comment comes from. But we don't want to say where every
  6514  		// comment comes from because people probably won't appreciate this for
  6515  		// first-party comments. And we don't want to include the whole path to
  6516  		// each third-part module because a) that could contain information about
  6517  		// the local machine that people don't want in their bundle and b) that
  6518  		// could differ depending on unimportant details like the package manager
  6519  		// used to install the packages (npm vs. pnpm vs. yarn).
  6520  		if source.KeyPath.Namespace != "dataurl" {
  6521  			path := source.KeyPath.Text
  6522  			previous := len(path)
  6523  			for previous > 0 {
  6524  				slash := strings.LastIndexAny(path[:previous], "\\/")
  6525  				component := path[slash+1 : previous]
  6526  				if component == "node_modules" {
  6527  					if previous < len(path) {
  6528  						packagePath = strings.ReplaceAll(path[previous+1:], "\\", "/")
  6529  					}
  6530  					break
  6531  				}
  6532  				previous = slash
  6533  			}
  6534  		}
  6535  
  6536  		if packagePath != "" {
  6537  			thirdPartyComments = append(thirdPartyComments, thirdPartyEntry{
  6538  				packagePath: packagePath,
  6539  				comments:    entry.comments,
  6540  			})
  6541  		} else {
  6542  			for _, comment := range entry.comments {
  6543  				if _, ok := hasFirstPartyComment[comment]; !ok {
  6544  					hasFirstPartyComment[comment] = struct{}{}
  6545  					uniqueFirstPartyComments = append(uniqueFirstPartyComments, comment)
  6546  				}
  6547  			}
  6548  		}
  6549  	}
  6550  
  6551  	switch legalComments {
  6552  	case config.LegalCommentsEndOfFile:
  6553  		for _, comment := range uniqueFirstPartyComments {
  6554  			j.AddString(helpers.EscapeClosingTag(comment, slashTag))
  6555  			j.AddString("\n")
  6556  		}
  6557  
  6558  		if len(thirdPartyComments) > 0 {
  6559  			j.AddString("/*! Bundled license information:\n")
  6560  			for _, entry := range thirdPartyComments {
  6561  				j.AddString(fmt.Sprintf("\n%s:\n", helpers.EscapeClosingTag(entry.packagePath, slashTag)))
  6562  				for _, comment := range entry.comments {
  6563  					comment = helpers.EscapeClosingTag(comment, slashTag)
  6564  					if strings.HasPrefix(comment, "//") {
  6565  						j.AddString(fmt.Sprintf("  (*%s *)\n", comment[2:]))
  6566  					} else if strings.HasPrefix(comment, "/*") && strings.HasSuffix(comment, "*/") {
  6567  						j.AddString(fmt.Sprintf("  (%s)\n", strings.ReplaceAll(comment[1:len(comment)-1], "\n", "\n  ")))
  6568  					}
  6569  				}
  6570  			}
  6571  			j.AddString("*/\n")
  6572  		}
  6573  
  6574  	case config.LegalCommentsLinkedWithComment, config.LegalCommentsExternalWithoutComment:
  6575  		var jComments helpers.Joiner
  6576  
  6577  		for _, comment := range uniqueFirstPartyComments {
  6578  			jComments.AddString(comment)
  6579  			jComments.AddString("\n")
  6580  		}
  6581  
  6582  		if len(thirdPartyComments) > 0 {
  6583  			if len(uniqueFirstPartyComments) > 0 {
  6584  				jComments.AddString("\n")
  6585  			}
  6586  			jComments.AddString("Bundled license information:\n")
  6587  			for _, entry := range thirdPartyComments {
  6588  				jComments.AddString(fmt.Sprintf("\n%s:\n", entry.packagePath))
  6589  				for _, comment := range entry.comments {
  6590  					jComments.AddString(fmt.Sprintf("  %s\n", strings.ReplaceAll(comment, "\n", "\n  ")))
  6591  				}
  6592  			}
  6593  		}
  6594  
  6595  		chunk.externalLegalComments = jComments.Done()
  6596  	}
  6597  }
  6598  
  6599  func (c *linkerContext) appendIsolatedHashesForImportedChunks(
  6600  	hash hash.Hash,
  6601  	chunkIndex uint32,
  6602  	visited []uint32,
  6603  	visitedKey uint32,
  6604  ) {
  6605  	// Only visit each chunk at most once. This is important because there may be
  6606  	// cycles in the chunk import graph. If there's a cycle, we want to include
  6607  	// the hash of every chunk involved in the cycle (along with all of their
  6608  	// dependencies). This depth-first traversal will naturally do that.
  6609  	if visited[chunkIndex] == visitedKey {
  6610  		return
  6611  	}
  6612  	visited[chunkIndex] = visitedKey
  6613  	chunk := &c.chunks[chunkIndex]
  6614  
  6615  	// Visit the other chunks that this chunk imports before visiting this chunk
  6616  	for _, chunkImport := range chunk.crossChunkImports {
  6617  		c.appendIsolatedHashesForImportedChunks(hash, chunkImport.chunkIndex, visited, visitedKey)
  6618  	}
  6619  
  6620  	// Mix in hashes for referenced asset paths (i.e. the "file" loader)
  6621  	for _, piece := range chunk.intermediateOutput.pieces {
  6622  		if piece.kind == outputPieceAssetIndex {
  6623  			file := c.graph.Files[piece.index]
  6624  			if len(file.InputFile.AdditionalFiles) != 1 {
  6625  				panic("Internal error")
  6626  			}
  6627  			relPath, _ := c.fs.Rel(c.options.AbsOutputDir, file.InputFile.AdditionalFiles[0].AbsPath)
  6628  
  6629  			// Make sure to always use forward slashes, even on Windows
  6630  			relPath = strings.ReplaceAll(relPath, "\\", "/")
  6631  
  6632  			// Mix in the hash for the relative path, which ends up as a JS string
  6633  			hashWriteLengthPrefixed(hash, []byte(relPath))
  6634  		}
  6635  	}
  6636  
  6637  	// Mix in the hash for this chunk
  6638  	hash.Write(chunk.waitForIsolatedHash())
  6639  }
  6640  
  6641  func (c *linkerContext) breakJoinerIntoPieces(j helpers.Joiner) intermediateOutput {
  6642  	// Optimization: If there can be no substitutions, just reuse the initial
  6643  	// joiner that was used when generating the intermediate chunk output
  6644  	// instead of creating another one and copying the whole file into it.
  6645  	if !j.Contains(c.uniqueKeyPrefix, c.uniqueKeyPrefixBytes) {
  6646  		return intermediateOutput{joiner: j}
  6647  	}
  6648  	return c.breakOutputIntoPieces(j.Done())
  6649  }
  6650  
  6651  func (c *linkerContext) breakOutputIntoPieces(output []byte) intermediateOutput {
  6652  	var pieces []outputPiece
  6653  	prefix := c.uniqueKeyPrefixBytes
  6654  	for {
  6655  		// Scan for the next piece boundary
  6656  		boundary := bytes.Index(output, prefix)
  6657  
  6658  		// Try to parse the piece boundary
  6659  		var kind outputPieceIndexKind
  6660  		var index uint32
  6661  		if boundary != -1 {
  6662  			if start := boundary + len(prefix); start+9 > len(output) {
  6663  				boundary = -1
  6664  			} else {
  6665  				switch output[start] {
  6666  				case 'A':
  6667  					kind = outputPieceAssetIndex
  6668  				case 'C':
  6669  					kind = outputPieceChunkIndex
  6670  				}
  6671  				for j := 1; j < 9; j++ {
  6672  					c := output[start+j]
  6673  					if c < '0' || c > '9' {
  6674  						boundary = -1
  6675  						break
  6676  					}
  6677  					index = index*10 + uint32(c) - '0'
  6678  				}
  6679  			}
  6680  		}
  6681  
  6682  		// Validate the boundary
  6683  		switch kind {
  6684  		case outputPieceAssetIndex:
  6685  			if index >= uint32(len(c.graph.Files)) {
  6686  				boundary = -1
  6687  			}
  6688  
  6689  		case outputPieceChunkIndex:
  6690  			if index >= uint32(len(c.chunks)) {
  6691  				boundary = -1
  6692  			}
  6693  
  6694  		default:
  6695  			boundary = -1
  6696  		}
  6697  
  6698  		// If we're at the end, generate one final piece
  6699  		if boundary == -1 {
  6700  			pieces = append(pieces, outputPiece{
  6701  				data: output,
  6702  			})
  6703  			break
  6704  		}
  6705  
  6706  		// Otherwise, generate an interior piece and continue
  6707  		pieces = append(pieces, outputPiece{
  6708  			data:  output[:boundary],
  6709  			index: index,
  6710  			kind:  kind,
  6711  		})
  6712  		output = output[boundary+len(prefix)+9:]
  6713  	}
  6714  	return intermediateOutput{pieces: pieces}
  6715  }
  6716  
  6717  func (c *linkerContext) generateIsolatedHashInParallel(chunk *chunkInfo) {
  6718  	// Compute the hash in parallel. This is a speedup when it turns out the hash
  6719  	// isn't needed (well, as long as there are threads to spare).
  6720  	channel := make(chan []byte, 1)
  6721  	chunk.waitForIsolatedHash = func() []byte {
  6722  		data := <-channel
  6723  		channel <- data
  6724  		return data
  6725  	}
  6726  	go c.generateIsolatedHash(chunk, channel)
  6727  }
  6728  
  6729  func (c *linkerContext) generateIsolatedHash(chunk *chunkInfo, channel chan []byte) {
  6730  	hash := xxhash.New()
  6731  
  6732  	// Mix the file names and part ranges of all of the files in this chunk into
  6733  	// the hash. Objects that appear identical but that live in separate files or
  6734  	// that live in separate parts in the same file must not be merged. This only
  6735  	// needs to be done for JavaScript files, not CSS files.
  6736  	if chunkRepr, ok := chunk.chunkRepr.(*chunkReprJS); ok {
  6737  		for _, partRange := range chunkRepr.partsInChunkInOrder {
  6738  			var filePath string
  6739  			file := &c.graph.Files[partRange.sourceIndex]
  6740  			if file.InputFile.Source.KeyPath.Namespace == "file" {
  6741  				// Use the pretty path as the file name since it should be platform-
  6742  				// independent (relative paths and the "/" path separator)
  6743  				filePath = file.InputFile.Source.PrettyPath
  6744  			} else {
  6745  				// If this isn't in the "file" namespace, just use the full path text
  6746  				// verbatim. This could be a source of cross-platform differences if
  6747  				// plugins are storing platform-specific information in here, but then
  6748  				// that problem isn't caused by esbuild itself.
  6749  				filePath = file.InputFile.Source.KeyPath.Text
  6750  			}
  6751  
  6752  			// Include the path namespace in the hash
  6753  			hashWriteLengthPrefixed(hash, []byte(file.InputFile.Source.KeyPath.Namespace))
  6754  
  6755  			// Then include the file path
  6756  			hashWriteLengthPrefixed(hash, []byte(filePath))
  6757  
  6758  			// Also write the part range. These numbers are deterministic and allocated
  6759  			// per-file so this should be a well-behaved base for a hash.
  6760  			hashWriteUint32(hash, partRange.partIndexBegin)
  6761  			hashWriteUint32(hash, partRange.partIndexEnd)
  6762  		}
  6763  	}
  6764  
  6765  	// Hash the output path template as part of the content hash because we want
  6766  	// any import to be considered different if the import's output path has changed.
  6767  	for _, part := range chunk.finalTemplate {
  6768  		hashWriteLengthPrefixed(hash, []byte(part.Data))
  6769  	}
  6770  
  6771  	// Also hash the public path. If provided, this is used whenever files
  6772  	// reference each other such as cross-chunk imports, asset file references,
  6773  	// and source map comments. We always include the hash in all chunks instead
  6774  	// of trying to figure out which chunks will include the public path for
  6775  	// simplicity and for robustness to code changes in the future.
  6776  	if c.options.PublicPath != "" {
  6777  		hashWriteLengthPrefixed(hash, []byte(c.options.PublicPath))
  6778  	}
  6779  
  6780  	// Include the generated output content in the hash. This excludes the
  6781  	// randomly-generated import paths (the unique keys) and only includes the
  6782  	// data in the spans between them.
  6783  	if chunk.intermediateOutput.pieces != nil {
  6784  		for _, piece := range chunk.intermediateOutput.pieces {
  6785  			hashWriteLengthPrefixed(hash, piece.data)
  6786  		}
  6787  	} else {
  6788  		bytes := chunk.intermediateOutput.joiner.Done()
  6789  		hashWriteLengthPrefixed(hash, bytes)
  6790  	}
  6791  
  6792  	// Also include the source map data in the hash. The source map is named the
  6793  	// same name as the chunk name for ease of discovery. So we want the hash to
  6794  	// change if the source map data changes even if the chunk data doesn't change.
  6795  	// Otherwise the output path for the source map wouldn't change and the source
  6796  	// map wouldn't end up being updated.
  6797  	//
  6798  	// Note that this means the contents of all input files are included in the
  6799  	// hash because of "sourcesContent", so changing a comment in an input file
  6800  	// can now change the hash of the output file. This only happens when you
  6801  	// have source maps enabled (and "sourcesContent", which is on by default).
  6802  	//
  6803  	// The generated positions in the mappings here are in the output content
  6804  	// *before* the final paths have been substituted. This may seem weird.
  6805  	// However, I think this shouldn't cause issues because a) the unique key
  6806  	// values are all always the same length so the offsets are deterministic
  6807  	// and b) the final paths will be folded into the final hash later.
  6808  	hashWriteLengthPrefixed(hash, chunk.outputSourceMap.Prefix)
  6809  	hashWriteLengthPrefixed(hash, chunk.outputSourceMap.Mappings)
  6810  	hashWriteLengthPrefixed(hash, chunk.outputSourceMap.Suffix)
  6811  
  6812  	// Store the hash so far. All other chunks that import this chunk will mix
  6813  	// this hash into their final hash to ensure that the import path changes
  6814  	// if this chunk (or any dependencies of this chunk) is changed.
  6815  	channel <- hash.Sum(nil)
  6816  }
  6817  
  6818  func hashWriteUint32(hash hash.Hash, value uint32) {
  6819  	var lengthBytes [4]byte
  6820  	binary.LittleEndian.PutUint32(lengthBytes[:], value)
  6821  	hash.Write(lengthBytes[:])
  6822  }
  6823  
  6824  // Hash the data in length-prefixed form because boundary locations are
  6825  // important. We don't want "a" + "bc" to hash the same as "ab" + "c".
  6826  func hashWriteLengthPrefixed(hash hash.Hash, bytes []byte) {
  6827  	hashWriteUint32(hash, uint32(len(bytes)))
  6828  	hash.Write(bytes)
  6829  }
  6830  
  6831  // Marking a symbol as unbound prevents it from being renamed or minified.
  6832  // This is only used when a module is compiled independently. We use a very
  6833  // different way of handling exports and renaming/minifying when bundling.
  6834  func (c *linkerContext) preventExportsFromBeingRenamed(sourceIndex uint32) {
  6835  	repr, ok := c.graph.Files[sourceIndex].InputFile.Repr.(*graph.JSRepr)
  6836  	if !ok {
  6837  		return
  6838  	}
  6839  	hasImportOrExport := false
  6840  
  6841  	for _, part := range repr.AST.Parts {
  6842  		for _, stmt := range part.Stmts {
  6843  			switch s := stmt.Data.(type) {
  6844  			case *js_ast.SImport:
  6845  				// Ignore imports from internal (i.e. non-external) code. Since this
  6846  				// function is only called when we're not bundling, these imports are
  6847  				// all for files that were generated automatically and aren't part of
  6848  				// the original source code (e.g. the runtime or an injected file).
  6849  				// We shouldn't consider the file a module if the only ESM imports or
  6850  				// exports are automatically generated ones.
  6851  				if repr.AST.ImportRecords[s.ImportRecordIndex].SourceIndex.IsValid() {
  6852  					continue
  6853  				}
  6854  
  6855  				hasImportOrExport = true
  6856  
  6857  			case *js_ast.SLocal:
  6858  				if s.IsExport {
  6859  					js_ast.ForEachIdentifierBindingInDecls(s.Decls, func(loc logger.Loc, b *js_ast.BIdentifier) {
  6860  						c.graph.Symbols.Get(b.Ref).Flags |= ast.MustNotBeRenamed
  6861  					})
  6862  					hasImportOrExport = true
  6863  				}
  6864  
  6865  			case *js_ast.SFunction:
  6866  				if s.IsExport {
  6867  					c.graph.Symbols.Get(s.Fn.Name.Ref).Kind = ast.SymbolUnbound
  6868  					hasImportOrExport = true
  6869  				}
  6870  
  6871  			case *js_ast.SClass:
  6872  				if s.IsExport {
  6873  					c.graph.Symbols.Get(s.Class.Name.Ref).Kind = ast.SymbolUnbound
  6874  					hasImportOrExport = true
  6875  				}
  6876  
  6877  			case *js_ast.SExportClause, *js_ast.SExportDefault, *js_ast.SExportStar:
  6878  				hasImportOrExport = true
  6879  
  6880  			case *js_ast.SExportFrom:
  6881  				hasImportOrExport = true
  6882  			}
  6883  		}
  6884  	}
  6885  
  6886  	// Heuristic: If this module has top-level import or export statements, we
  6887  	// consider this an ES6 module and only preserve the names of the exported
  6888  	// symbols. Everything else is minified since the names are private.
  6889  	//
  6890  	// Otherwise, we consider this potentially a script-type file instead of an
  6891  	// ES6 module. In that case, preserve the names of all top-level symbols
  6892  	// since they are all potentially exported (e.g. if this is used in a
  6893  	// <script> tag). All symbols in nested scopes are still minified.
  6894  	if !hasImportOrExport {
  6895  		for _, member := range repr.AST.ModuleScope.Members {
  6896  			c.graph.Symbols.Get(member.Ref).Flags |= ast.MustNotBeRenamed
  6897  		}
  6898  	}
  6899  }
  6900  
  6901  type compileResultForSourceMap struct {
  6902  	sourceMapChunk  sourcemap.Chunk
  6903  	generatedOffset sourcemap.LineColumnOffset
  6904  	sourceIndex     uint32
  6905  }
  6906  
  6907  func (c *linkerContext) generateSourceMapForChunk(
  6908  	results []compileResultForSourceMap,
  6909  	chunkAbsDir string,
  6910  	dataForSourceMaps []bundler.DataForSourceMap,
  6911  	canHaveShifts bool,
  6912  ) (pieces sourcemap.SourceMapPieces) {
  6913  	j := helpers.Joiner{}
  6914  	j.AddString("{\n  \"version\": 3")
  6915  
  6916  	// Only write out the sources for a given source index once
  6917  	sourceIndexToSourcesIndex := make(map[uint32]int)
  6918  
  6919  	// Generate the "sources" and "sourcesContent" arrays
  6920  	type item struct {
  6921  		path           logger.Path
  6922  		prettyPath     string
  6923  		quotedContents []byte
  6924  	}
  6925  	items := make([]item, 0, len(results))
  6926  	nextSourcesIndex := 0
  6927  	for _, result := range results {
  6928  		if _, ok := sourceIndexToSourcesIndex[result.sourceIndex]; ok {
  6929  			continue
  6930  		}
  6931  		sourceIndexToSourcesIndex[result.sourceIndex] = nextSourcesIndex
  6932  		file := &c.graph.Files[result.sourceIndex]
  6933  
  6934  		// Simple case: no nested source map
  6935  		if file.InputFile.InputSourceMap == nil {
  6936  			var quotedContents []byte
  6937  			if !c.options.ExcludeSourcesContent {
  6938  				quotedContents = dataForSourceMaps[result.sourceIndex].QuotedContents[0]
  6939  			}
  6940  			items = append(items, item{
  6941  				path:           file.InputFile.Source.KeyPath,
  6942  				prettyPath:     file.InputFile.Source.PrettyPath,
  6943  				quotedContents: quotedContents,
  6944  			})
  6945  			nextSourcesIndex++
  6946  			continue
  6947  		}
  6948  
  6949  		// Complex case: nested source map
  6950  		sm := file.InputFile.InputSourceMap
  6951  		for i, source := range sm.Sources {
  6952  			path := logger.Path{
  6953  				Namespace: file.InputFile.Source.KeyPath.Namespace,
  6954  				Text:      source,
  6955  			}
  6956  
  6957  			// If this file is in the "file" namespace, change the relative path in
  6958  			// the source map into an absolute path using the directory of this file
  6959  			if path.Namespace == "file" {
  6960  				path.Text = c.fs.Join(c.fs.Dir(file.InputFile.Source.KeyPath.Text), source)
  6961  			}
  6962  
  6963  			var quotedContents []byte
  6964  			if !c.options.ExcludeSourcesContent {
  6965  				quotedContents = dataForSourceMaps[result.sourceIndex].QuotedContents[i]
  6966  			}
  6967  			items = append(items, item{
  6968  				path:           path,
  6969  				prettyPath:     source,
  6970  				quotedContents: quotedContents,
  6971  			})
  6972  		}
  6973  		nextSourcesIndex += len(sm.Sources)
  6974  	}
  6975  
  6976  	// Write the sources
  6977  	j.AddString(",\n  \"sources\": [")
  6978  	for i, item := range items {
  6979  		if i != 0 {
  6980  			j.AddString(", ")
  6981  		}
  6982  
  6983  		// Modify the absolute path to the original file to be relative to the
  6984  		// directory that will contain the output file for this chunk
  6985  		if item.path.Namespace == "file" {
  6986  			if relPath, ok := c.fs.Rel(chunkAbsDir, item.path.Text); ok {
  6987  				// Make sure to always use forward slashes, even on Windows
  6988  				item.prettyPath = strings.ReplaceAll(relPath, "\\", "/")
  6989  			}
  6990  		}
  6991  
  6992  		j.AddBytes(helpers.QuoteForJSON(item.prettyPath, c.options.ASCIIOnly))
  6993  	}
  6994  	j.AddString("]")
  6995  
  6996  	if c.options.SourceRoot != "" {
  6997  		j.AddString(",\n  \"sourceRoot\": ")
  6998  		j.AddBytes(helpers.QuoteForJSON(c.options.SourceRoot, c.options.ASCIIOnly))
  6999  	}
  7000  
  7001  	// Write the sourcesContent
  7002  	if !c.options.ExcludeSourcesContent {
  7003  		j.AddString(",\n  \"sourcesContent\": [")
  7004  		for i, item := range items {
  7005  			if i != 0 {
  7006  				j.AddString(", ")
  7007  			}
  7008  			j.AddBytes(item.quotedContents)
  7009  		}
  7010  		j.AddString("]")
  7011  	}
  7012  
  7013  	j.AddString(",\n  \"mappings\": \"")
  7014  
  7015  	// Write the mappings
  7016  	mappingsStart := j.Length()
  7017  	prevEndState := sourcemap.SourceMapState{}
  7018  	prevColumnOffset := 0
  7019  	totalQuotedNameLen := 0
  7020  	for _, result := range results {
  7021  		chunk := result.sourceMapChunk
  7022  		offset := result.generatedOffset
  7023  		sourcesIndex := sourceIndexToSourcesIndex[result.sourceIndex]
  7024  
  7025  		// This should have already been checked earlier
  7026  		if chunk.ShouldIgnore {
  7027  			panic("Internal error")
  7028  		}
  7029  
  7030  		// Because each file for the bundle is converted to a source map once,
  7031  		// the source maps are shared between all entry points in the bundle.
  7032  		// The easiest way of getting this to work is to have all source maps
  7033  		// generate as if their source index is 0. We then adjust the source
  7034  		// index per entry point by modifying the first source mapping. This
  7035  		// is done by AppendSourceMapChunk() using the source index passed
  7036  		// here.
  7037  		startState := sourcemap.SourceMapState{
  7038  			SourceIndex:     sourcesIndex,
  7039  			GeneratedLine:   offset.Lines,
  7040  			GeneratedColumn: offset.Columns,
  7041  			OriginalName:    totalQuotedNameLen,
  7042  		}
  7043  		if offset.Lines == 0 {
  7044  			startState.GeneratedColumn += prevColumnOffset
  7045  		}
  7046  
  7047  		// Append the precomputed source map chunk
  7048  		sourcemap.AppendSourceMapChunk(&j, prevEndState, startState, chunk.Buffer)
  7049  
  7050  		// Generate the relative offset to start from next time
  7051  		prevOriginalName := prevEndState.OriginalName
  7052  		prevEndState = chunk.EndState
  7053  		prevEndState.SourceIndex += sourcesIndex
  7054  		if chunk.Buffer.FirstNameOffset.IsValid() {
  7055  			prevEndState.OriginalName += totalQuotedNameLen
  7056  		} else {
  7057  			// It's possible for a chunk to have mappings but for none of those
  7058  			// mappings to have an associated name. The name is optional and is
  7059  			// omitted when the mapping is for a non-name token or if the final
  7060  			// and original names are the same. In that case we need to restore
  7061  			// the previous original name end state since it wasn't modified after
  7062  			// all. If we don't do this, then files after this will adjust their
  7063  			// name offsets assuming that the previous generated mapping has this
  7064  			// file's offset, which is wrong.
  7065  			prevEndState.OriginalName = prevOriginalName
  7066  		}
  7067  		prevColumnOffset = chunk.FinalGeneratedColumn
  7068  		totalQuotedNameLen += len(chunk.QuotedNames)
  7069  
  7070  		// If this was all one line, include the column offset from the start
  7071  		if prevEndState.GeneratedLine == 0 {
  7072  			prevEndState.GeneratedColumn += startState.GeneratedColumn
  7073  			prevColumnOffset += startState.GeneratedColumn
  7074  		}
  7075  	}
  7076  	mappingsEnd := j.Length()
  7077  
  7078  	// Write the names
  7079  	isFirstName := true
  7080  	j.AddString("\",\n  \"names\": [")
  7081  	for _, result := range results {
  7082  		for _, quotedName := range result.sourceMapChunk.QuotedNames {
  7083  			if isFirstName {
  7084  				isFirstName = false
  7085  			} else {
  7086  				j.AddString(", ")
  7087  			}
  7088  			j.AddBytes(quotedName)
  7089  		}
  7090  	}
  7091  	j.AddString("]")
  7092  
  7093  	// Finish the source map
  7094  	j.AddString("\n}\n")
  7095  	bytes := j.Done()
  7096  
  7097  	if !canHaveShifts {
  7098  		// If there cannot be any shifts, then we can avoid doing extra work later
  7099  		// on by preserving the source map as a single memory allocation throughout
  7100  		// the pipeline. That way we won't need to reallocate it.
  7101  		pieces.Prefix = bytes
  7102  	} else {
  7103  		// Otherwise if there can be shifts, then we need to split this into several
  7104  		// slices so that the shifts in the mappings array can be processed. This is
  7105  		// more expensive because everything will need to be recombined into a new
  7106  		// memory allocation at the end.
  7107  		pieces.Prefix = bytes[:mappingsStart]
  7108  		pieces.Mappings = bytes[mappingsStart:mappingsEnd]
  7109  		pieces.Suffix = bytes[mappingsEnd:]
  7110  	}
  7111  	return
  7112  }
  7113  
  7114  // Recover from a panic by logging it as an internal error instead of crashing
  7115  func (c *linkerContext) recoverInternalError(waitGroup *sync.WaitGroup, sourceIndex uint32) {
  7116  	if r := recover(); r != nil {
  7117  		text := fmt.Sprintf("panic: %v", r)
  7118  		if sourceIndex != runtime.SourceIndex {
  7119  			text = fmt.Sprintf("%s (while printing %q)", text, c.graph.Files[sourceIndex].InputFile.Source.PrettyPath)
  7120  		}
  7121  		c.log.AddErrorWithNotes(nil, logger.Range{}, text,
  7122  			[]logger.MsgData{{Text: helpers.PrettyPrintedStack()}})
  7123  		waitGroup.Done()
  7124  	}
  7125  }
  7126  
  7127  func joinWithPublicPath(publicPath string, relPath string) string {
  7128  	if strings.HasPrefix(relPath, "./") {
  7129  		relPath = relPath[2:]
  7130  
  7131  		// Strip any amount of further no-op slashes (i.e. ".///././/x/y" => "x/y")
  7132  		for {
  7133  			if strings.HasPrefix(relPath, "/") {
  7134  				relPath = relPath[1:]
  7135  			} else if strings.HasPrefix(relPath, "./") {
  7136  				relPath = relPath[2:]
  7137  			} else {
  7138  				break
  7139  			}
  7140  		}
  7141  	}
  7142  
  7143  	// Use a relative path if there is no public path
  7144  	if publicPath == "" {
  7145  		publicPath = "."
  7146  	}
  7147  
  7148  	// Join with a slash
  7149  	slash := "/"
  7150  	if strings.HasSuffix(publicPath, "/") {
  7151  		slash = ""
  7152  	}
  7153  	return fmt.Sprintf("%s%s%s", publicPath, slash, relPath)
  7154  }