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

     1  package js_parser
     2  
     3  import (
     4  	"fmt"
     5  	"math"
     6  	"regexp"
     7  	"sort"
     8  	"strings"
     9  	"unicode/utf8"
    10  
    11  	"github.com/evanw/esbuild/internal/ast"
    12  	"github.com/evanw/esbuild/internal/compat"
    13  	"github.com/evanw/esbuild/internal/config"
    14  	"github.com/evanw/esbuild/internal/helpers"
    15  	"github.com/evanw/esbuild/internal/js_ast"
    16  	"github.com/evanw/esbuild/internal/js_lexer"
    17  	"github.com/evanw/esbuild/internal/logger"
    18  	"github.com/evanw/esbuild/internal/renamer"
    19  	"github.com/evanw/esbuild/internal/runtime"
    20  )
    21  
    22  // This parser does two passes:
    23  //
    24  // 1. Parse the source into an AST, create the scope tree, and declare symbols.
    25  //
    26  //  2. Visit each node in the AST, bind identifiers to declared symbols, do
    27  //     constant folding, substitute compile-time variable definitions, and
    28  //     lower certain syntactic constructs as appropriate given the language
    29  //     target.
    30  //
    31  // So many things have been put in so few passes because we want to minimize
    32  // the number of full-tree passes to improve performance. However, we need
    33  // to have at least two separate passes to handle variable hoisting. See the
    34  // comment about scopesInOrder below for more information.
    35  type parser struct {
    36  	options                    Options
    37  	log                        logger.Log
    38  	source                     logger.Source
    39  	tracker                    logger.LineColumnTracker
    40  	fnOrArrowDataParse         fnOrArrowDataParse
    41  	fnOnlyDataVisit            fnOnlyDataVisit
    42  	allocatedNames             []string
    43  	currentScope               *js_ast.Scope
    44  	scopesForCurrentPart       []*js_ast.Scope
    45  	symbols                    []ast.Symbol
    46  	astHelpers                 js_ast.HelperContext
    47  	tsUseCounts                []uint32
    48  	injectedDefineSymbols      []ast.Ref
    49  	injectedSymbolSources      map[ast.Ref]injectedSymbolSource
    50  	injectedDotNames           map[string][]injectedDotName
    51  	dropLabelsMap              map[string]struct{}
    52  	exprComments               map[logger.Loc][]string
    53  	mangledProps               map[string]ast.Ref
    54  	reservedProps              map[string]bool
    55  	symbolUses                 map[ast.Ref]js_ast.SymbolUse
    56  	importSymbolPropertyUses   map[ast.Ref]map[string]js_ast.SymbolUse
    57  	symbolCallUses             map[ast.Ref]js_ast.SymbolCallUse
    58  	declaredSymbols            []js_ast.DeclaredSymbol
    59  	globPatternImports         []globPatternImport
    60  	runtimeImports             map[string]ast.LocRef
    61  	duplicateCaseChecker       duplicateCaseChecker
    62  	unrepresentableIdentifiers map[string]bool
    63  	legacyOctalLiterals        map[js_ast.E]logger.Range
    64  	scopesInOrderForEnum       map[logger.Loc][]scopeOrder
    65  	binaryExprStack            []binaryExprVisitor
    66  
    67  	// For strict mode handling
    68  	hoistedRefForSloppyModeBlockFn map[ast.Ref]ast.Ref
    69  
    70  	// For lowering private methods
    71  	privateGetters map[ast.Ref]ast.Ref
    72  	privateSetters map[ast.Ref]ast.Ref
    73  
    74  	// These are for TypeScript
    75  	//
    76  	// We build up enough information about the TypeScript namespace hierarchy to
    77  	// be able to resolve scope lookups and property accesses for TypeScript enum
    78  	// and namespace features. Each JavaScript scope object inside a namespace
    79  	// has a reference to a map of exported namespace members from sibling scopes.
    80  	//
    81  	// In addition, there is a map from each relevant symbol reference to the data
    82  	// associated with that namespace or namespace member: "refToTSNamespaceMemberData".
    83  	// This gives enough info to be able to resolve queries into the namespace.
    84  	//
    85  	// When visiting expressions, namespace metadata is associated with the most
    86  	// recently visited node. If namespace metadata is present, "tsNamespaceTarget"
    87  	// will be set to the most recently visited node (as a way to mark that this
    88  	// node has metadata) and "tsNamespaceMemberData" will be set to the metadata.
    89  	refToTSNamespaceMemberData map[ast.Ref]js_ast.TSNamespaceMemberData
    90  	tsNamespaceTarget          js_ast.E
    91  	tsNamespaceMemberData      js_ast.TSNamespaceMemberData
    92  	emittedNamespaceVars       map[ast.Ref]bool
    93  	isExportedInsideNamespace  map[ast.Ref]ast.Ref
    94  	localTypeNames             map[string]bool
    95  	tsEnums                    map[ast.Ref]map[string]js_ast.TSEnumValue
    96  	constValues                map[ast.Ref]js_ast.ConstValue
    97  	propDerivedCtorValue       js_ast.E
    98  	propMethodDecoratorScope   *js_ast.Scope
    99  
   100  	// This is the reference to the generated function argument for the namespace,
   101  	// which is different than the reference to the namespace itself:
   102  	//
   103  	//   namespace ns {
   104  	//   }
   105  	//
   106  	// The code above is transformed into something like this:
   107  	//
   108  	//   var ns1;
   109  	//   (function(ns2) {
   110  	//   })(ns1 || (ns1 = {}));
   111  	//
   112  	// This variable is "ns2" not "ns1". It is only used during the second
   113  	// "visit" pass.
   114  	enclosingNamespaceArgRef *ast.Ref
   115  
   116  	// Imports (both ES6 and CommonJS) are tracked at the top level
   117  	importRecords               []ast.ImportRecord
   118  	importRecordsForCurrentPart []uint32
   119  	exportStarImportRecords     []uint32
   120  
   121  	// These are for handling ES6 imports and exports
   122  	importItemsForNamespace map[ast.Ref]namespaceImportItems
   123  	isImportItem            map[ast.Ref]bool
   124  	namedImports            map[ast.Ref]js_ast.NamedImport
   125  	namedExports            map[string]js_ast.NamedExport
   126  	topLevelSymbolToParts   map[ast.Ref][]uint32
   127  	importNamespaceCCMap    map[importNamespaceCall]bool
   128  
   129  	// The parser does two passes and we need to pass the scope tree information
   130  	// from the first pass to the second pass. That's done by tracking the calls
   131  	// to pushScopeForParsePass() and popScope() during the first pass in
   132  	// scopesInOrder.
   133  	//
   134  	// Then, when the second pass calls pushScopeForVisitPass() and popScope(),
   135  	// we consume entries from scopesInOrder and make sure they are in the same
   136  	// order. This way the second pass can efficiently use the same scope tree
   137  	// as the first pass without having to attach the scope tree to the AST.
   138  	//
   139  	// We need to split this into two passes because the pass that declares the
   140  	// symbols must be separate from the pass that binds identifiers to declared
   141  	// symbols to handle declaring a hoisted "var" symbol in a nested scope and
   142  	// binding a name to it in a parent or sibling scope.
   143  	scopesInOrder []scopeOrder
   144  
   145  	// These propagate the name from the parent context into an anonymous child
   146  	// expression. For example:
   147  	//
   148  	//   let foo = function() {}
   149  	//   assert.strictEqual(foo.name, 'foo')
   150  	//
   151  	nameToKeep      string
   152  	nameToKeepIsFor js_ast.E
   153  
   154  	// These properties are for the visit pass, which runs after the parse pass.
   155  	// The visit pass binds identifiers to declared symbols, does constant
   156  	// folding, substitutes compile-time variable definitions, and lowers certain
   157  	// syntactic constructs as appropriate.
   158  	stmtExprValue                        js_ast.E
   159  	callTarget                           js_ast.E
   160  	dotOrIndexTarget                     js_ast.E
   161  	templateTag                          js_ast.E
   162  	deleteTarget                         js_ast.E
   163  	loopBody                             js_ast.S
   164  	suspiciousLogicalOperatorInsideArrow js_ast.E
   165  	moduleScope                          *js_ast.Scope
   166  
   167  	// This is internal-only data used for the implementation of Yarn PnP
   168  	manifestForYarnPnP     js_ast.Expr
   169  	stringLocalsForYarnPnP map[ast.Ref]stringLocalForYarnPnP
   170  
   171  	// This helps recognize the "await import()" pattern. When this is present,
   172  	// warnings about non-string import paths will be omitted inside try blocks.
   173  	awaitTarget js_ast.E
   174  
   175  	// This helps recognize the "import().catch()" pattern. We also try to avoid
   176  	// warning about this just like the "try { await import() }" pattern.
   177  	thenCatchChain thenCatchChain
   178  
   179  	// When bundling, hoisted top-level local variables declared with "var" in
   180  	// nested scopes are moved up to be declared in the top-level scope instead.
   181  	// The old "var" statements are turned into regular assignments instead. This
   182  	// makes it easier to quickly scan the top-level statements for "var" locals
   183  	// with the guarantee that all will be found.
   184  	relocatedTopLevelVars []ast.LocRef
   185  
   186  	// We need to lower private names such as "#foo" if they are used in a brand
   187  	// check such as "#foo in x" even if the private name syntax would otherwise
   188  	// be supported. This is because private names are a newly-added feature.
   189  	//
   190  	// However, this parser operates in only two passes for speed. The first pass
   191  	// parses things and declares variables, and the second pass lowers things and
   192  	// resolves references to declared variables. So the existence of a "#foo in x"
   193  	// expression for a specific "#foo" cannot be used to decide to lower "#foo"
   194  	// because it's too late by that point. There may be another expression such
   195  	// as "x.#foo" before that point and that must be lowered as well even though
   196  	// it has already been visited.
   197  	//
   198  	// Instead what we do is track just the names of fields used in private brand
   199  	// checks during the first pass. This tracks the names themselves, not symbol
   200  	// references. Then, during the second pass when we are about to enter into
   201  	// a class, we conservatively decide to lower all private names in that class
   202  	// which are used in a brand check anywhere in the file.
   203  	lowerAllOfThesePrivateNames map[string]bool
   204  
   205  	// Temporary variables used for lowering
   206  	tempLetsToDeclare         []ast.Ref
   207  	tempRefsToDeclare         []tempRef
   208  	topLevelTempRefsToDeclare []tempRef
   209  
   210  	lexer js_lexer.Lexer
   211  
   212  	// Private field access in a decorator lowers all private fields in that class
   213  	parseExperimentalDecoratorNesting int
   214  
   215  	// Temporary variables used for lowering
   216  	tempRefCount         int
   217  	topLevelTempRefCount int
   218  
   219  	// We need to scan over the source contents to recover the line and column offsets
   220  	jsxSourceLoc    int
   221  	jsxSourceLine   int
   222  	jsxSourceColumn int
   223  
   224  	exportsRef    ast.Ref
   225  	requireRef    ast.Ref
   226  	moduleRef     ast.Ref
   227  	importMetaRef ast.Ref
   228  	promiseRef    ast.Ref
   229  	regExpRef     ast.Ref
   230  	superCtorRef  ast.Ref
   231  
   232  	// Imports from "react/jsx-runtime" and "react", respectively.
   233  	// (Or whatever was specified in the "importSource" option)
   234  	jsxRuntimeImports map[string]ast.LocRef
   235  	jsxLegacyImports  map[string]ast.LocRef
   236  
   237  	// For lowering private methods
   238  	weakMapRef ast.Ref
   239  	weakSetRef ast.Ref
   240  
   241  	esmImportStatementKeyword logger.Range
   242  	esmImportMeta             logger.Range
   243  	esmExportKeyword          logger.Range
   244  	enclosingClassKeyword     logger.Range
   245  	topLevelAwaitKeyword      logger.Range
   246  	liveTopLevelAwaitKeyword  logger.Range
   247  
   248  	latestArrowArgLoc      logger.Loc
   249  	forbidSuffixAfterAsLoc logger.Loc
   250  	firstJSXElementLoc     logger.Loc
   251  
   252  	fnOrArrowDataVisit fnOrArrowDataVisit
   253  
   254  	// ArrowFunction is a special case in the grammar. Although it appears to be
   255  	// a PrimaryExpression, it's actually an AssignmentExpression. This means if
   256  	// a AssignmentExpression ends up producing an ArrowFunction then nothing can
   257  	// come after it other than the comma operator, since the comma operator is
   258  	// the only thing above AssignmentExpression under the Expression rule:
   259  	//
   260  	//   AssignmentExpression:
   261  	//     ArrowFunction
   262  	//     ConditionalExpression
   263  	//     LeftHandSideExpression = AssignmentExpression
   264  	//     LeftHandSideExpression AssignmentOperator AssignmentExpression
   265  	//
   266  	//   Expression:
   267  	//     AssignmentExpression
   268  	//     Expression , AssignmentExpression
   269  	//
   270  	afterArrowBodyLoc logger.Loc
   271  
   272  	// Setting this to true disables warnings about code that is very likely to
   273  	// be a bug. This is used to ignore issues inside "node_modules" directories.
   274  	// This has caught real issues in the past. However, it's not esbuild's job
   275  	// to find bugs in other libraries, and these warnings are problematic for
   276  	// people using these libraries with esbuild. The only fix is to either
   277  	// disable all esbuild warnings and not get warnings about your own code, or
   278  	// to try to get the warning fixed in the affected library. This is
   279  	// especially annoying if the warning is a false positive as was the case in
   280  	// https://github.com/firebase/firebase-js-sdk/issues/3814. So these warnings
   281  	// are now disabled for code inside "node_modules" directories.
   282  	suppressWarningsAboutWeirdCode bool
   283  
   284  	// A file is considered to be an ECMAScript module if it has any of the
   285  	// features of one (e.g. the "export" keyword), otherwise it's considered
   286  	// a CommonJS module.
   287  	//
   288  	// However, we have a single exception: a file where the only ESM feature
   289  	// is the "import" keyword is allowed to have CommonJS exports. This feature
   290  	// is necessary to be able to synchronously import ESM code into CommonJS,
   291  	// which we need to enable in a few important cases. Some examples are:
   292  	// our runtime code, injected files (the "inject" feature is ESM-only),
   293  	// and certain automatically-generated virtual modules from plugins.
   294  	isFileConsideredToHaveESMExports bool // Use only for export-related stuff
   295  	isFileConsideredESM              bool // Use for all other stuff
   296  
   297  	// Inside a TypeScript namespace, an "export declare" statement can be used
   298  	// to cause a namespace to be emitted even though it has no other observable
   299  	// effect. This flag is used to implement this feature.
   300  	//
   301  	// Specifically, namespaces should be generated for all of the following
   302  	// namespaces below except for "f", which should not be generated:
   303  	//
   304  	//   namespace a { export declare const a }
   305  	//   namespace b { export declare let [[b]] }
   306  	//   namespace c { export declare function c() }
   307  	//   namespace d { export declare class d {} }
   308  	//   namespace e { export declare enum e {} }
   309  	//   namespace f { export declare namespace f {} }
   310  	//
   311  	// The TypeScript compiler compiles this into the following code (notice "f"
   312  	// is missing):
   313  	//
   314  	//   var a; (function (a_1) {})(a || (a = {}));
   315  	//   var b; (function (b_1) {})(b || (b = {}));
   316  	//   var c; (function (c_1) {})(c || (c = {}));
   317  	//   var d; (function (d_1) {})(d || (d = {}));
   318  	//   var e; (function (e_1) {})(e || (e = {}));
   319  	//
   320  	// Note that this should not be implemented by declaring symbols for "export
   321  	// declare" statements because the TypeScript compiler doesn't generate any
   322  	// code for these statements, so these statements are actually references to
   323  	// global variables. There is one exception, which is that local variables
   324  	// *should* be declared as symbols because they are replaced with. This seems
   325  	// like very arbitrary behavior but it's what the TypeScript compiler does,
   326  	// so we try to match it.
   327  	//
   328  	// Specifically, in the following code below "a" and "b" should be declared
   329  	// and should be substituted with "ns.a" and "ns.b" but the other symbols
   330  	// shouldn't. References to the other symbols actually refer to global
   331  	// variables instead of to symbols that are exported from the namespace.
   332  	// This is the case as of TypeScript 4.3. I assume this is a TypeScript bug:
   333  	//
   334  	//   namespace ns {
   335  	//     export declare const a
   336  	//     export declare let [[b]]
   337  	//     export declare function c()
   338  	//     export declare class d { }
   339  	//     export declare enum e { }
   340  	//     console.log(a, b, c, d, e)
   341  	//   }
   342  	//
   343  	// The TypeScript compiler compiles this into the following code:
   344  	//
   345  	//   var ns;
   346  	//   (function (ns) {
   347  	//       console.log(ns.a, ns.b, c, d, e);
   348  	//   })(ns || (ns = {}));
   349  	//
   350  	// Relevant issue: https://github.com/evanw/esbuild/issues/1158
   351  	hasNonLocalExportDeclareInsideNamespace bool
   352  
   353  	// When this flag is enabled, we attempt to fold all expressions that
   354  	// TypeScript would consider to be "constant expressions". This flag is
   355  	// enabled inside each enum body block since TypeScript requires numeric
   356  	// constant folding in enum definitions.
   357  	//
   358  	// We also enable this flag in certain cases in JavaScript files such as when
   359  	// parsing "const" declarations at the top of a non-ESM file, but we still
   360  	// reuse TypeScript's notion of "constant expressions" for our own convenience.
   361  	//
   362  	// As of TypeScript 5.0, a "constant expression" is defined as follows:
   363  	//
   364  	//   An expression is considered a constant expression if it is
   365  	//
   366  	//   * a number or string literal,
   367  	//   * a unary +, -, or ~ applied to a numeric constant expression,
   368  	//   * a binary +, -, *, /, %, **, <<, >>, >>>, |, &, ^ applied to two numeric constant expressions,
   369  	//   * a binary + applied to two constant expressions whereof at least one is a string,
   370  	//   * a template expression where each substitution expression is a constant expression,
   371  	//   * a parenthesized constant expression,
   372  	//   * a dotted name (e.g. x.y.z) that references a const variable with a constant expression initializer and no type annotation,
   373  	//   * a dotted name that references an enum member with an enum literal type, or
   374  	//   * a dotted name indexed by a string literal (e.g. x.y["z"]) that references an enum member with an enum literal type.
   375  	//
   376  	// More detail: https://github.com/microsoft/TypeScript/pull/50528. Note that
   377  	// we don't implement certain items in this list. For example, we don't do all
   378  	// number-to-string conversions since ours might differ from how JavaScript
   379  	// would do it, which would be a correctness issue.
   380  	shouldFoldTypeScriptConstantExpressions bool
   381  
   382  	allowIn                     bool
   383  	allowPrivateIdentifiers     bool
   384  	hasTopLevelReturn           bool
   385  	latestReturnHadSemicolon    bool
   386  	messageAboutThisIsUndefined bool
   387  	isControlFlowDead           bool
   388  
   389  	// If this is true, then all top-level statements are wrapped in a try/catch
   390  	willWrapModuleInTryCatchForUsing bool
   391  }
   392  
   393  type globPatternImport struct {
   394  	assertOrWith     *ast.ImportAssertOrWith
   395  	parts            []helpers.GlobPart
   396  	name             string
   397  	approximateRange logger.Range
   398  	ref              ast.Ref
   399  	kind             ast.ImportKind
   400  }
   401  
   402  type namespaceImportItems struct {
   403  	entries           map[string]ast.LocRef
   404  	importRecordIndex uint32
   405  }
   406  
   407  type stringLocalForYarnPnP struct {
   408  	value []uint16
   409  	loc   logger.Loc
   410  }
   411  
   412  type injectedSymbolSource struct {
   413  	source logger.Source
   414  	loc    logger.Loc
   415  }
   416  
   417  type injectedDotName struct {
   418  	parts               []string
   419  	injectedDefineIndex uint32
   420  }
   421  
   422  type importNamespaceCallKind uint8
   423  
   424  const (
   425  	exprKindCall importNamespaceCallKind = iota
   426  	exprKindNew
   427  	exprKindJSXTag
   428  )
   429  
   430  type importNamespaceCall struct {
   431  	ref  ast.Ref
   432  	kind importNamespaceCallKind
   433  }
   434  
   435  type thenCatchChain struct {
   436  	nextTarget      js_ast.E
   437  	catchLoc        logger.Loc
   438  	hasMultipleArgs bool
   439  	hasCatch        bool
   440  }
   441  
   442  // This is used as part of an incremental build cache key. Some of these values
   443  // can potentially change between builds if they are derived from nearby
   444  // "package.json" or "tsconfig.json" files that were changed since the last
   445  // build.
   446  type Options struct {
   447  	injectedFiles  []config.InjectedFile
   448  	jsx            config.JSXOptions
   449  	tsAlwaysStrict *config.TSAlwaysStrict
   450  	mangleProps    *regexp.Regexp
   451  	reserveProps   *regexp.Regexp
   452  	dropLabels     []string
   453  
   454  	// This pointer will always be different for each build but the contents
   455  	// shouldn't ever behave different semantically. We ignore this field for the
   456  	// equality comparison.
   457  	defines *config.ProcessedDefines
   458  
   459  	// This is an embedded struct. Always access these directly instead of off
   460  	// the name "optionsThatSupportStructuralEquality". This is only grouped like
   461  	// this to make the equality comparison easier and safer (and hopefully faster).
   462  	optionsThatSupportStructuralEquality
   463  }
   464  
   465  type optionsThatSupportStructuralEquality struct {
   466  	originalTargetEnv                 string
   467  	moduleTypeData                    js_ast.ModuleTypeData
   468  	unsupportedJSFeatures             compat.JSFeature
   469  	unsupportedJSFeatureOverrides     compat.JSFeature
   470  	unsupportedJSFeatureOverridesMask compat.JSFeature
   471  
   472  	// Byte-sized values go here (gathered together here to keep this object compact)
   473  	ts                     config.TSOptions
   474  	mode                   config.Mode
   475  	platform               config.Platform
   476  	outputFormat           config.Format
   477  	asciiOnly              bool
   478  	keepNames              bool
   479  	minifySyntax           bool
   480  	minifyIdentifiers      bool
   481  	minifyWhitespace       bool
   482  	omitRuntimeForTests    bool
   483  	omitJSXRuntimeForTests bool
   484  	ignoreDCEAnnotations   bool
   485  	treeShaking            bool
   486  	dropDebugger           bool
   487  	mangleQuoted           bool
   488  
   489  	// This is an internal-only option used for the implementation of Yarn PnP
   490  	decodeHydrateRuntimeStateYarnPnP bool
   491  }
   492  
   493  func OptionsForYarnPnP() Options {
   494  	return Options{
   495  		optionsThatSupportStructuralEquality: optionsThatSupportStructuralEquality{
   496  			decodeHydrateRuntimeStateYarnPnP: true,
   497  		},
   498  	}
   499  }
   500  
   501  func OptionsFromConfig(options *config.Options) Options {
   502  	return Options{
   503  		injectedFiles:  options.InjectedFiles,
   504  		jsx:            options.JSX,
   505  		defines:        options.Defines,
   506  		tsAlwaysStrict: options.TSAlwaysStrict,
   507  		mangleProps:    options.MangleProps,
   508  		reserveProps:   options.ReserveProps,
   509  		dropLabels:     options.DropLabels,
   510  
   511  		optionsThatSupportStructuralEquality: optionsThatSupportStructuralEquality{
   512  			unsupportedJSFeatures:             options.UnsupportedJSFeatures,
   513  			unsupportedJSFeatureOverrides:     options.UnsupportedJSFeatureOverrides,
   514  			unsupportedJSFeatureOverridesMask: options.UnsupportedJSFeatureOverridesMask,
   515  			originalTargetEnv:                 options.OriginalTargetEnv,
   516  			ts:                                options.TS,
   517  			mode:                              options.Mode,
   518  			platform:                          options.Platform,
   519  			outputFormat:                      options.OutputFormat,
   520  			moduleTypeData:                    options.ModuleTypeData,
   521  			asciiOnly:                         options.ASCIIOnly,
   522  			keepNames:                         options.KeepNames,
   523  			minifySyntax:                      options.MinifySyntax,
   524  			minifyIdentifiers:                 options.MinifyIdentifiers,
   525  			minifyWhitespace:                  options.MinifyWhitespace,
   526  			omitRuntimeForTests:               options.OmitRuntimeForTests,
   527  			omitJSXRuntimeForTests:            options.OmitJSXRuntimeForTests,
   528  			ignoreDCEAnnotations:              options.IgnoreDCEAnnotations,
   529  			treeShaking:                       options.TreeShaking,
   530  			dropDebugger:                      options.DropDebugger,
   531  			mangleQuoted:                      options.MangleQuoted,
   532  		},
   533  	}
   534  }
   535  
   536  func (a *Options) Equal(b *Options) bool {
   537  	// Compare "optionsThatSupportStructuralEquality"
   538  	if a.optionsThatSupportStructuralEquality != b.optionsThatSupportStructuralEquality {
   539  		return false
   540  	}
   541  
   542  	// Compare "tsAlwaysStrict"
   543  	if (a.tsAlwaysStrict == nil && b.tsAlwaysStrict != nil) || (a.tsAlwaysStrict != nil && b.tsAlwaysStrict == nil) ||
   544  		(a.tsAlwaysStrict != nil && b.tsAlwaysStrict != nil && *a.tsAlwaysStrict != *b.tsAlwaysStrict) {
   545  		return false
   546  	}
   547  
   548  	// Compare "mangleProps" and "reserveProps"
   549  	if !isSameRegexp(a.mangleProps, b.mangleProps) || !isSameRegexp(a.reserveProps, b.reserveProps) {
   550  		return false
   551  	}
   552  
   553  	// Compare "dropLabels"
   554  	if !helpers.StringArraysEqual(a.dropLabels, b.dropLabels) {
   555  		return false
   556  	}
   557  
   558  	// Compare "injectedFiles"
   559  	if len(a.injectedFiles) != len(b.injectedFiles) {
   560  		return false
   561  	}
   562  	for i, x := range a.injectedFiles {
   563  		y := b.injectedFiles[i]
   564  		if x.Source != y.Source || x.DefineName != y.DefineName || len(x.Exports) != len(y.Exports) {
   565  			return false
   566  		}
   567  		for j := range x.Exports {
   568  			if x.Exports[j] != y.Exports[j] {
   569  				return false
   570  			}
   571  		}
   572  	}
   573  
   574  	// Compare "jsx"
   575  	if a.jsx.Parse != b.jsx.Parse || !jsxExprsEqual(a.jsx.Factory, b.jsx.Factory) || !jsxExprsEqual(a.jsx.Fragment, b.jsx.Fragment) {
   576  		return false
   577  	}
   578  
   579  	// Do a cheap assert that the defines object hasn't changed
   580  	if (a.defines != nil || b.defines != nil) && (a.defines == nil || b.defines == nil ||
   581  		len(a.defines.IdentifierDefines) != len(b.defines.IdentifierDefines) ||
   582  		len(a.defines.DotDefines) != len(b.defines.DotDefines)) {
   583  		panic("Internal error")
   584  	}
   585  
   586  	return true
   587  }
   588  
   589  func isSameRegexp(a *regexp.Regexp, b *regexp.Regexp) bool {
   590  	if a == nil {
   591  		return b == nil
   592  	} else {
   593  		return b != nil && a.String() == b.String()
   594  	}
   595  }
   596  
   597  func jsxExprsEqual(a config.DefineExpr, b config.DefineExpr) bool {
   598  	if !helpers.StringArraysEqual(a.Parts, b.Parts) {
   599  		return false
   600  	}
   601  
   602  	if a.Constant != nil {
   603  		if b.Constant == nil || !js_ast.ValuesLookTheSame(a.Constant, b.Constant) {
   604  			return false
   605  		}
   606  	} else if b.Constant != nil {
   607  		return false
   608  	}
   609  
   610  	return true
   611  }
   612  
   613  type tempRef struct {
   614  	valueOrNil js_ast.Expr
   615  	ref        ast.Ref
   616  }
   617  
   618  const (
   619  	locModuleScope = -1
   620  )
   621  
   622  type scopeOrder struct {
   623  	scope *js_ast.Scope
   624  	loc   logger.Loc
   625  }
   626  
   627  type awaitOrYield uint8
   628  
   629  const (
   630  	// The keyword is used as an identifier, not a special expression
   631  	allowIdent awaitOrYield = iota
   632  
   633  	// Declaring the identifier is forbidden, and the keyword is used as a special expression
   634  	allowExpr
   635  
   636  	// Declaring the identifier is forbidden, and using the identifier is also forbidden
   637  	forbidAll
   638  )
   639  
   640  // This is function-specific information used during parsing. It is saved and
   641  // restored on the call stack around code that parses nested functions and
   642  // arrow expressions.
   643  type fnOrArrowDataParse struct {
   644  	arrowArgErrors      *deferredArrowArgErrors
   645  	decoratorScope      *js_ast.Scope
   646  	asyncRange          logger.Range
   647  	needsAsyncLoc       logger.Loc
   648  	await               awaitOrYield
   649  	yield               awaitOrYield
   650  	allowSuperCall      bool
   651  	allowSuperProperty  bool
   652  	isTopLevel          bool
   653  	isConstructor       bool
   654  	isTypeScriptDeclare bool
   655  	isThisDisallowed    bool
   656  	isReturnDisallowed  bool
   657  
   658  	// In TypeScript, forward declarations of functions have no bodies
   659  	allowMissingBodyForTypeScript bool
   660  }
   661  
   662  // This is function-specific information used during visiting. It is saved and
   663  // restored on the call stack around code that parses nested functions and
   664  // arrow expressions.
   665  type fnOrArrowDataVisit struct {
   666  	// This is used to silence unresolvable imports due to "require" calls inside
   667  	// a try/catch statement. The assumption is that the try/catch statement is
   668  	// there to handle the case where the reference to "require" crashes.
   669  	tryBodyCount int32
   670  	tryCatchLoc  logger.Loc
   671  
   672  	isArrow                        bool
   673  	isAsync                        bool
   674  	isGenerator                    bool
   675  	isInsideLoop                   bool
   676  	isInsideSwitch                 bool
   677  	isDerivedClassCtor             bool
   678  	isOutsideFnOrArrow             bool
   679  	shouldLowerSuperPropertyAccess bool
   680  }
   681  
   682  // This is function-specific information used during visiting. It is saved and
   683  // restored on the call stack around code that parses nested functions (but not
   684  // nested arrow functions).
   685  type fnOnlyDataVisit struct {
   686  	// This is a reference to the magic "arguments" variable that exists inside
   687  	// functions in JavaScript. It will be non-nil inside functions and nil
   688  	// otherwise.
   689  	argumentsRef *ast.Ref
   690  
   691  	// Arrow functions don't capture the value of "this" and "arguments". Instead,
   692  	// the values are inherited from the surrounding context. If arrow functions
   693  	// are turned into regular functions due to lowering, we will need to generate
   694  	// local variables to capture these values so they are preserved correctly.
   695  	thisCaptureRef      *ast.Ref
   696  	argumentsCaptureRef *ast.Ref
   697  
   698  	// If true, we're inside a static class context where "this" expressions
   699  	// should be replaced with the class name.
   700  	shouldReplaceThisWithInnerClassNameRef bool
   701  
   702  	// This is true if "this" is equal to the class name. It's true if we're in a
   703  	// static class field initializer, a static class method, or a static class
   704  	// block.
   705  	isInStaticClassContext bool
   706  
   707  	// This is a reference to the enclosing class name if there is one. It's used
   708  	// to implement "this" and "super" references. A name is automatically generated
   709  	// if one is missing so this will always be present inside a class body.
   710  	innerClassNameRef *ast.Ref
   711  
   712  	// If we're inside an async arrow function and async functions are not
   713  	// supported, then we will have to convert that arrow function to a generator
   714  	// function. That means references to "arguments" inside the arrow function
   715  	// will have to reference a captured variable instead of the real variable.
   716  	isInsideAsyncArrowFn bool
   717  
   718  	// If false, disallow "new.target" expressions. We disallow all "new.target"
   719  	// expressions at the top-level of the file (i.e. not inside a function or
   720  	// a class field). Technically since CommonJS files are wrapped in a function
   721  	// you can use "new.target" in node as an alias for "undefined" but we don't
   722  	// support that.
   723  	isNewTargetAllowed bool
   724  
   725  	// If false, the value for "this" is the top-level module scope "this" value.
   726  	// That means it's "undefined" for ECMAScript modules and "exports" for
   727  	// CommonJS modules. We track this information so that we can substitute the
   728  	// correct value for these top-level "this" references at compile time instead
   729  	// of passing the "this" expression through to the output and leaving the
   730  	// interpretation up to the run-time behavior of the generated code.
   731  	//
   732  	// If true, the value for "this" is nested inside something (either a function
   733  	// or a class declaration). That means the top-level module scope "this" value
   734  	// has been shadowed and is now inaccessible.
   735  	isThisNested bool
   736  
   737  	// Do not warn about "this" being undefined for code that the TypeScript
   738  	// compiler generates that looks like this:
   739  	//
   740  	//   var __rest = (this && this.__rest) || function (s, e) {
   741  	//     ...
   742  	//   };
   743  	//
   744  	silenceMessageAboutThisBeingUndefined bool
   745  }
   746  
   747  const bloomFilterSize = 251
   748  
   749  type duplicateCaseValue struct {
   750  	value js_ast.Expr
   751  	hash  uint32
   752  }
   753  
   754  type duplicateCaseChecker struct {
   755  	cases       []duplicateCaseValue
   756  	bloomFilter [(bloomFilterSize + 7) / 8]byte
   757  }
   758  
   759  func (dc *duplicateCaseChecker) reset() {
   760  	// Preserve capacity
   761  	dc.cases = dc.cases[:0]
   762  
   763  	// This should be optimized by the compiler. See this for more information:
   764  	// https://github.com/golang/go/issues/5373
   765  	bytes := dc.bloomFilter
   766  	for i := range bytes {
   767  		bytes[i] = 0
   768  	}
   769  }
   770  
   771  func (dc *duplicateCaseChecker) check(p *parser, expr js_ast.Expr) {
   772  	if hash, ok := duplicateCaseHash(expr); ok {
   773  		bucket := hash % bloomFilterSize
   774  		entry := &dc.bloomFilter[bucket/8]
   775  		mask := byte(1) << (bucket % 8)
   776  
   777  		// Check for collisions
   778  		if (*entry & mask) != 0 {
   779  			for _, c := range dc.cases {
   780  				if c.hash == hash {
   781  					if equals, couldBeIncorrect := duplicateCaseEquals(c.value, expr); equals {
   782  						var laterRange logger.Range
   783  						var earlierRange logger.Range
   784  						if _, ok := expr.Data.(*js_ast.EString); ok {
   785  							laterRange = p.source.RangeOfString(expr.Loc)
   786  						} else {
   787  							laterRange = p.source.RangeOfOperatorBefore(expr.Loc, "case")
   788  						}
   789  						if _, ok := c.value.Data.(*js_ast.EString); ok {
   790  							earlierRange = p.source.RangeOfString(c.value.Loc)
   791  						} else {
   792  							earlierRange = p.source.RangeOfOperatorBefore(c.value.Loc, "case")
   793  						}
   794  						text := "This case clause will never be evaluated because it duplicates an earlier case clause"
   795  						if couldBeIncorrect {
   796  							text = "This case clause may never be evaluated because it likely duplicates an earlier case clause"
   797  						}
   798  						kind := logger.Warning
   799  						if p.suppressWarningsAboutWeirdCode {
   800  							kind = logger.Debug
   801  						}
   802  						p.log.AddIDWithNotes(logger.MsgID_JS_DuplicateCase, kind, &p.tracker, laterRange, text,
   803  							[]logger.MsgData{p.tracker.MsgData(earlierRange, "The earlier case clause is here:")})
   804  					}
   805  					return
   806  				}
   807  			}
   808  		}
   809  
   810  		*entry |= mask
   811  		dc.cases = append(dc.cases, duplicateCaseValue{hash: hash, value: expr})
   812  	}
   813  }
   814  
   815  func duplicateCaseHash(expr js_ast.Expr) (uint32, bool) {
   816  	switch e := expr.Data.(type) {
   817  	case *js_ast.EInlinedEnum:
   818  		return duplicateCaseHash(e.Value)
   819  
   820  	case *js_ast.ENull:
   821  		return 0, true
   822  
   823  	case *js_ast.EUndefined:
   824  		return 1, true
   825  
   826  	case *js_ast.EBoolean:
   827  		if e.Value {
   828  			return helpers.HashCombine(2, 1), true
   829  		}
   830  		return helpers.HashCombine(2, 0), true
   831  
   832  	case *js_ast.ENumber:
   833  		bits := math.Float64bits(e.Value)
   834  		return helpers.HashCombine(helpers.HashCombine(3, uint32(bits)), uint32(bits>>32)), true
   835  
   836  	case *js_ast.EString:
   837  		hash := uint32(4)
   838  		for _, c := range e.Value {
   839  			hash = helpers.HashCombine(hash, uint32(c))
   840  		}
   841  		return hash, true
   842  
   843  	case *js_ast.EBigInt:
   844  		hash := uint32(5)
   845  		for _, c := range e.Value {
   846  			hash = helpers.HashCombine(hash, uint32(c))
   847  		}
   848  		return hash, true
   849  
   850  	case *js_ast.EIdentifier:
   851  		return helpers.HashCombine(6, e.Ref.InnerIndex), true
   852  
   853  	case *js_ast.EDot:
   854  		if target, ok := duplicateCaseHash(e.Target); ok {
   855  			return helpers.HashCombineString(helpers.HashCombine(7, target), e.Name), true
   856  		}
   857  
   858  	case *js_ast.EIndex:
   859  		if target, ok := duplicateCaseHash(e.Target); ok {
   860  			if index, ok := duplicateCaseHash(e.Index); ok {
   861  				return helpers.HashCombine(helpers.HashCombine(8, target), index), true
   862  			}
   863  		}
   864  	}
   865  
   866  	return 0, false
   867  }
   868  
   869  func duplicateCaseEquals(left js_ast.Expr, right js_ast.Expr) (equals bool, couldBeIncorrect bool) {
   870  	if b, ok := right.Data.(*js_ast.EInlinedEnum); ok {
   871  		return duplicateCaseEquals(left, b.Value)
   872  	}
   873  
   874  	switch a := left.Data.(type) {
   875  	case *js_ast.EInlinedEnum:
   876  		return duplicateCaseEquals(a.Value, right)
   877  
   878  	case *js_ast.ENull:
   879  		_, ok := right.Data.(*js_ast.ENull)
   880  		return ok, false
   881  
   882  	case *js_ast.EUndefined:
   883  		_, ok := right.Data.(*js_ast.EUndefined)
   884  		return ok, false
   885  
   886  	case *js_ast.EBoolean:
   887  		b, ok := right.Data.(*js_ast.EBoolean)
   888  		return ok && a.Value == b.Value, false
   889  
   890  	case *js_ast.ENumber:
   891  		b, ok := right.Data.(*js_ast.ENumber)
   892  		return ok && a.Value == b.Value, false
   893  
   894  	case *js_ast.EString:
   895  		b, ok := right.Data.(*js_ast.EString)
   896  		return ok && helpers.UTF16EqualsUTF16(a.Value, b.Value), false
   897  
   898  	case *js_ast.EBigInt:
   899  		if b, ok := right.Data.(*js_ast.EBigInt); ok {
   900  			equal, ok := js_ast.CheckEqualityBigInt(a.Value, b.Value)
   901  			return ok && equal, false
   902  		}
   903  
   904  	case *js_ast.EIdentifier:
   905  		b, ok := right.Data.(*js_ast.EIdentifier)
   906  		return ok && a.Ref == b.Ref, false
   907  
   908  	case *js_ast.EDot:
   909  		if b, ok := right.Data.(*js_ast.EDot); ok && a.OptionalChain == b.OptionalChain && a.Name == b.Name {
   910  			equals, _ := duplicateCaseEquals(a.Target, b.Target)
   911  			return equals, true
   912  		}
   913  
   914  	case *js_ast.EIndex:
   915  		if b, ok := right.Data.(*js_ast.EIndex); ok && a.OptionalChain == b.OptionalChain {
   916  			if equals, _ := duplicateCaseEquals(a.Index, b.Index); equals {
   917  				equals, _ := duplicateCaseEquals(a.Target, b.Target)
   918  				return equals, true
   919  			}
   920  		}
   921  	}
   922  
   923  	return false, false
   924  }
   925  
   926  type duplicatePropertiesIn uint8
   927  
   928  const (
   929  	duplicatePropertiesInObject duplicatePropertiesIn = iota
   930  	duplicatePropertiesInClass
   931  )
   932  
   933  func (p *parser) warnAboutDuplicateProperties(properties []js_ast.Property, in duplicatePropertiesIn) {
   934  	if len(properties) < 2 {
   935  		return
   936  	}
   937  
   938  	type keyKind uint8
   939  	type existingKey struct {
   940  		loc  logger.Loc
   941  		kind keyKind
   942  	}
   943  	const (
   944  		keyMissing keyKind = iota
   945  		keyNormal
   946  		keyGet
   947  		keySet
   948  		keyGetAndSet
   949  	)
   950  	instanceKeys := make(map[string]existingKey)
   951  	staticKeys := make(map[string]existingKey)
   952  
   953  	for _, property := range properties {
   954  		if property.Kind != js_ast.PropertySpread {
   955  			if str, ok := property.Key.Data.(*js_ast.EString); ok {
   956  				var keys map[string]existingKey
   957  				if property.Flags.Has(js_ast.PropertyIsStatic) {
   958  					keys = staticKeys
   959  				} else {
   960  					keys = instanceKeys
   961  				}
   962  				key := helpers.UTF16ToString(str.Value)
   963  				prevKey := keys[key]
   964  				nextKey := existingKey{kind: keyNormal, loc: property.Key.Loc}
   965  
   966  				if property.Kind == js_ast.PropertyGetter {
   967  					nextKey.kind = keyGet
   968  				} else if property.Kind == js_ast.PropertySetter {
   969  					nextKey.kind = keySet
   970  				}
   971  
   972  				if prevKey.kind != keyMissing && (in != duplicatePropertiesInObject || key != "__proto__") && (in != duplicatePropertiesInClass || key != "constructor") {
   973  					if (prevKey.kind == keyGet && nextKey.kind == keySet) || (prevKey.kind == keySet && nextKey.kind == keyGet) {
   974  						nextKey.kind = keyGetAndSet
   975  					} else {
   976  						var id logger.MsgID
   977  						var what string
   978  						var where string
   979  						switch in {
   980  						case duplicatePropertiesInObject:
   981  							id = logger.MsgID_JS_DuplicateObjectKey
   982  							what = "key"
   983  							where = "object literal"
   984  						case duplicatePropertiesInClass:
   985  							id = logger.MsgID_JS_DuplicateClassMember
   986  							what = "member"
   987  							where = "class body"
   988  						}
   989  						r := js_lexer.RangeOfIdentifier(p.source, property.Key.Loc)
   990  						p.log.AddIDWithNotes(id, logger.Warning, &p.tracker, r,
   991  							fmt.Sprintf("Duplicate %s %q in %s", what, key, where),
   992  							[]logger.MsgData{p.tracker.MsgData(js_lexer.RangeOfIdentifier(p.source, prevKey.loc),
   993  								fmt.Sprintf("The original %s %q is here:", what, key))})
   994  					}
   995  				}
   996  
   997  				keys[key] = nextKey
   998  			}
   999  		}
  1000  	}
  1001  }
  1002  
  1003  func isJumpStatement(data js_ast.S) bool {
  1004  	switch data.(type) {
  1005  	case *js_ast.SBreak, *js_ast.SContinue, *js_ast.SReturn, *js_ast.SThrow:
  1006  		return true
  1007  	}
  1008  
  1009  	return false
  1010  }
  1011  
  1012  func jumpStmtsLookTheSame(left js_ast.S, right js_ast.S) bool {
  1013  	switch a := left.(type) {
  1014  	case *js_ast.SBreak:
  1015  		b, ok := right.(*js_ast.SBreak)
  1016  		return ok && (a.Label == nil) == (b.Label == nil) && (a.Label == nil || a.Label.Ref == b.Label.Ref)
  1017  
  1018  	case *js_ast.SContinue:
  1019  		b, ok := right.(*js_ast.SContinue)
  1020  		return ok && (a.Label == nil) == (b.Label == nil) && (a.Label == nil || a.Label.Ref == b.Label.Ref)
  1021  
  1022  	case *js_ast.SReturn:
  1023  		b, ok := right.(*js_ast.SReturn)
  1024  		return ok && (a.ValueOrNil.Data == nil) == (b.ValueOrNil.Data == nil) &&
  1025  			(a.ValueOrNil.Data == nil || js_ast.ValuesLookTheSame(a.ValueOrNil.Data, b.ValueOrNil.Data))
  1026  
  1027  	case *js_ast.SThrow:
  1028  		b, ok := right.(*js_ast.SThrow)
  1029  		return ok && js_ast.ValuesLookTheSame(a.Value.Data, b.Value.Data)
  1030  	}
  1031  
  1032  	return false
  1033  }
  1034  
  1035  func (p *parser) selectLocalKind(kind js_ast.LocalKind) js_ast.LocalKind {
  1036  	// Use "var" instead of "let" and "const" if the variable declaration may
  1037  	// need to be separated from the initializer. This allows us to safely move
  1038  	// this declaration into a nested scope.
  1039  	if p.currentScope.Parent == nil && (kind == js_ast.LocalLet || kind == js_ast.LocalConst) &&
  1040  		(p.options.mode == config.ModeBundle || p.willWrapModuleInTryCatchForUsing) {
  1041  		return js_ast.LocalVar
  1042  	}
  1043  
  1044  	// Optimization: use "let" instead of "const" because it's shorter. This is
  1045  	// only done when bundling because assigning to "const" is only an error when
  1046  	// bundling.
  1047  	if p.options.mode == config.ModeBundle && kind == js_ast.LocalConst && p.options.minifySyntax {
  1048  		return js_ast.LocalLet
  1049  	}
  1050  
  1051  	return kind
  1052  }
  1053  
  1054  func (p *parser) pushScopeForParsePass(kind js_ast.ScopeKind, loc logger.Loc) int {
  1055  	parent := p.currentScope
  1056  	scope := &js_ast.Scope{
  1057  		Kind:    kind,
  1058  		Parent:  parent,
  1059  		Members: make(map[string]js_ast.ScopeMember),
  1060  		Label:   ast.LocRef{Ref: ast.InvalidRef},
  1061  	}
  1062  	if parent != nil {
  1063  		parent.Children = append(parent.Children, scope)
  1064  		scope.StrictMode = parent.StrictMode
  1065  		scope.UseStrictLoc = parent.UseStrictLoc
  1066  	}
  1067  	p.currentScope = scope
  1068  
  1069  	// Enforce that scope locations are strictly increasing to help catch bugs
  1070  	// where the pushed scopes are mismatched between the first and second passes
  1071  	if len(p.scopesInOrder) > 0 {
  1072  		prevStart := p.scopesInOrder[len(p.scopesInOrder)-1].loc.Start
  1073  		if prevStart >= loc.Start {
  1074  			panic(fmt.Sprintf("Scope location %d must be greater than %d", loc.Start, prevStart))
  1075  		}
  1076  	}
  1077  
  1078  	// Copy down function arguments into the function body scope. That way we get
  1079  	// errors if a statement in the function body tries to re-declare any of the
  1080  	// arguments.
  1081  	if kind == js_ast.ScopeFunctionBody {
  1082  		if scope.Parent.Kind != js_ast.ScopeFunctionArgs {
  1083  			panic("Internal error")
  1084  		}
  1085  		for name, member := range scope.Parent.Members {
  1086  			// Don't copy down the optional function expression name. Re-declaring
  1087  			// the name of a function expression is allowed.
  1088  			kind := p.symbols[member.Ref.InnerIndex].Kind
  1089  			if kind != ast.SymbolHoistedFunction {
  1090  				scope.Members[name] = member
  1091  			}
  1092  		}
  1093  	}
  1094  
  1095  	// Remember the length in case we call popAndDiscardScope() later
  1096  	scopeIndex := len(p.scopesInOrder)
  1097  	p.scopesInOrder = append(p.scopesInOrder, scopeOrder{loc: loc, scope: scope})
  1098  	return scopeIndex
  1099  }
  1100  
  1101  func (p *parser) popScope() {
  1102  	// We cannot rename anything inside a scope containing a direct eval() call
  1103  	if p.currentScope.ContainsDirectEval {
  1104  		for _, member := range p.currentScope.Members {
  1105  			// Using direct eval when bundling is not a good idea in general because
  1106  			// esbuild must assume that it can potentially reach anything in any of
  1107  			// the containing scopes. We try to make it work but this isn't possible
  1108  			// in some cases.
  1109  			//
  1110  			// For example, symbols imported using an ESM import are a live binding
  1111  			// to the underlying symbol in another file. This is emulated during
  1112  			// scope hoisting by erasing the ESM import and just referencing the
  1113  			// underlying symbol in the flattened bundle directly. However, that
  1114  			// symbol may have a different name which could break uses of direct
  1115  			// eval:
  1116  			//
  1117  			//   // Before bundling
  1118  			//   import { foo as bar } from './foo.js'
  1119  			//   console.log(eval('bar'))
  1120  			//
  1121  			//   // After bundling
  1122  			//   let foo = 123 // The contents of "foo.js"
  1123  			//   console.log(eval('bar'))
  1124  			//
  1125  			// There really isn't any way to fix this. You can't just rename "foo" to
  1126  			// "bar" in the example above because there may be a third bundled file
  1127  			// that also contains direct eval and imports the same symbol with a
  1128  			// different conflicting import alias. And there is no way to store a
  1129  			// live binding to the underlying symbol in a variable with the import's
  1130  			// name so that direct eval can access it:
  1131  			//
  1132  			//   // After bundling
  1133  			//   let foo = 123 // The contents of "foo.js"
  1134  			//   const bar = /* cannot express a live binding to "foo" here */
  1135  			//   console.log(eval('bar'))
  1136  			//
  1137  			// Technically a "with" statement could potentially make this work (with
  1138  			// a big hit to performance), but they are deprecated and are unavailable
  1139  			// in strict mode. This is a non-starter since all ESM code is strict mode.
  1140  			//
  1141  			// So while we still try to obey the requirement that all symbol names are
  1142  			// pinned when direct eval is present, we make an exception for top-level
  1143  			// symbols in an ESM file when bundling is enabled. We make no guarantee
  1144  			// that "eval" will be able to reach these symbols and we allow them to be
  1145  			// renamed or removed by tree shaking.
  1146  			if p.options.mode == config.ModeBundle && p.currentScope.Parent == nil && p.isFileConsideredESM {
  1147  				continue
  1148  			}
  1149  
  1150  			p.symbols[member.Ref.InnerIndex].Flags |= ast.MustNotBeRenamed
  1151  		}
  1152  	}
  1153  
  1154  	p.currentScope = p.currentScope.Parent
  1155  }
  1156  
  1157  func (p *parser) popAndDiscardScope(scopeIndex int) {
  1158  	// Unwind any newly-added scopes in reverse order
  1159  	for i := len(p.scopesInOrder) - 1; i >= scopeIndex; i-- {
  1160  		scope := p.scopesInOrder[i].scope
  1161  		parent := scope.Parent
  1162  		last := len(parent.Children) - 1
  1163  		if parent.Children[last] != scope {
  1164  			panic("Internal error")
  1165  		}
  1166  		parent.Children = parent.Children[:last]
  1167  	}
  1168  
  1169  	// Move up to the parent scope
  1170  	p.currentScope = p.currentScope.Parent
  1171  
  1172  	// Truncate the scope order where we started to pretend we never saw this scope
  1173  	p.scopesInOrder = p.scopesInOrder[:scopeIndex]
  1174  }
  1175  
  1176  func (p *parser) popAndFlattenScope(scopeIndex int) {
  1177  	// Move up to the parent scope
  1178  	toFlatten := p.currentScope
  1179  	parent := toFlatten.Parent
  1180  	p.currentScope = parent
  1181  
  1182  	// Erase this scope from the order. This will shift over the indices of all
  1183  	// the scopes that were created after us. However, we shouldn't have to
  1184  	// worry about other code with outstanding scope indices for these scopes.
  1185  	// These scopes were all created in between this scope's push and pop
  1186  	// operations, so they should all be child scopes and should all be popped
  1187  	// by the time we get here.
  1188  	copy(p.scopesInOrder[scopeIndex:], p.scopesInOrder[scopeIndex+1:])
  1189  	p.scopesInOrder = p.scopesInOrder[:len(p.scopesInOrder)-1]
  1190  
  1191  	// Remove the last child from the parent scope
  1192  	last := len(parent.Children) - 1
  1193  	if parent.Children[last] != toFlatten {
  1194  		panic("Internal error")
  1195  	}
  1196  	parent.Children = parent.Children[:last]
  1197  
  1198  	// Reparent our child scopes into our parent
  1199  	for _, scope := range toFlatten.Children {
  1200  		scope.Parent = parent
  1201  		parent.Children = append(parent.Children, scope)
  1202  	}
  1203  }
  1204  
  1205  // Undo all scopes pushed and popped after this scope index. This assumes that
  1206  // the scope stack is at the same level now as it was at the given scope index.
  1207  func (p *parser) discardScopesUpTo(scopeIndex int) {
  1208  	// Remove any direct children from their parent
  1209  	children := p.currentScope.Children
  1210  	for _, child := range p.scopesInOrder[scopeIndex:] {
  1211  		if child.scope.Parent == p.currentScope {
  1212  			for i := len(children) - 1; i >= 0; i-- {
  1213  				if children[i] == child.scope {
  1214  					children = append(children[:i], children[i+1:]...)
  1215  					break
  1216  				}
  1217  			}
  1218  		}
  1219  	}
  1220  	p.currentScope.Children = children
  1221  
  1222  	// Truncate the scope order where we started to pretend we never saw this scope
  1223  	p.scopesInOrder = p.scopesInOrder[:scopeIndex]
  1224  }
  1225  
  1226  func (p *parser) newSymbol(kind ast.SymbolKind, name string) ast.Ref {
  1227  	ref := ast.Ref{SourceIndex: p.source.Index, InnerIndex: uint32(len(p.symbols))}
  1228  	p.symbols = append(p.symbols, ast.Symbol{
  1229  		Kind:         kind,
  1230  		OriginalName: name,
  1231  		Link:         ast.InvalidRef,
  1232  	})
  1233  	if p.options.ts.Parse {
  1234  		p.tsUseCounts = append(p.tsUseCounts, 0)
  1235  	}
  1236  	return ref
  1237  }
  1238  
  1239  // This is similar to "ast.MergeSymbols" but it works with this parser's
  1240  // one-level symbol map instead of the linker's two-level symbol map. It also
  1241  // doesn't handle cycles since they shouldn't come up due to the way this
  1242  // function is used.
  1243  func (p *parser) mergeSymbols(old ast.Ref, new ast.Ref) ast.Ref {
  1244  	if old == new {
  1245  		return new
  1246  	}
  1247  
  1248  	oldSymbol := &p.symbols[old.InnerIndex]
  1249  	if oldSymbol.Link != ast.InvalidRef {
  1250  		oldSymbol.Link = p.mergeSymbols(oldSymbol.Link, new)
  1251  		return oldSymbol.Link
  1252  	}
  1253  
  1254  	newSymbol := &p.symbols[new.InnerIndex]
  1255  	if newSymbol.Link != ast.InvalidRef {
  1256  		newSymbol.Link = p.mergeSymbols(old, newSymbol.Link)
  1257  		return newSymbol.Link
  1258  	}
  1259  
  1260  	oldSymbol.Link = new
  1261  	newSymbol.MergeContentsWith(oldSymbol)
  1262  	return new
  1263  }
  1264  
  1265  type mergeResult int
  1266  
  1267  const (
  1268  	mergeForbidden = iota
  1269  	mergeReplaceWithNew
  1270  	mergeOverwriteWithNew
  1271  	mergeKeepExisting
  1272  	mergeBecomePrivateGetSetPair
  1273  	mergeBecomePrivateStaticGetSetPair
  1274  )
  1275  
  1276  func (p *parser) canMergeSymbols(scope *js_ast.Scope, existing ast.SymbolKind, new ast.SymbolKind) mergeResult {
  1277  	if existing == ast.SymbolUnbound {
  1278  		return mergeReplaceWithNew
  1279  	}
  1280  
  1281  	// In TypeScript, imports are allowed to silently collide with symbols within
  1282  	// the module. Presumably this is because the imports may be type-only:
  1283  	//
  1284  	//   import {Foo} from 'bar'
  1285  	//   class Foo {}
  1286  	//
  1287  	if p.options.ts.Parse && existing == ast.SymbolImport {
  1288  		return mergeReplaceWithNew
  1289  	}
  1290  
  1291  	// "enum Foo {} enum Foo {}"
  1292  	if new == ast.SymbolTSEnum && existing == ast.SymbolTSEnum {
  1293  		return mergeKeepExisting
  1294  	}
  1295  
  1296  	// "namespace Foo { ... } enum Foo {}"
  1297  	if new == ast.SymbolTSEnum && existing == ast.SymbolTSNamespace {
  1298  		return mergeReplaceWithNew
  1299  	}
  1300  
  1301  	// "namespace Foo { ... } namespace Foo { ... }"
  1302  	// "function Foo() {} namespace Foo { ... }"
  1303  	// "enum Foo {} namespace Foo { ... }"
  1304  	if new == ast.SymbolTSNamespace {
  1305  		switch existing {
  1306  		case ast.SymbolTSNamespace, ast.SymbolHoistedFunction, ast.SymbolGeneratorOrAsyncFunction, ast.SymbolTSEnum, ast.SymbolClass:
  1307  			return mergeKeepExisting
  1308  		}
  1309  	}
  1310  
  1311  	// "var foo; var foo;"
  1312  	// "var foo; function foo() {}"
  1313  	// "function foo() {} var foo;"
  1314  	// "function *foo() {} function *foo() {}" but not "{ function *foo() {} function *foo() {} }"
  1315  	if new.IsHoistedOrFunction() && existing.IsHoistedOrFunction() &&
  1316  		(scope.Kind == js_ast.ScopeEntry ||
  1317  			scope.Kind == js_ast.ScopeFunctionBody ||
  1318  			scope.Kind == js_ast.ScopeFunctionArgs ||
  1319  			(new == existing && new.IsHoisted())) {
  1320  		return mergeReplaceWithNew
  1321  	}
  1322  
  1323  	// "get #foo() {} set #foo() {}"
  1324  	// "set #foo() {} get #foo() {}"
  1325  	if (existing == ast.SymbolPrivateGet && new == ast.SymbolPrivateSet) ||
  1326  		(existing == ast.SymbolPrivateSet && new == ast.SymbolPrivateGet) {
  1327  		return mergeBecomePrivateGetSetPair
  1328  	}
  1329  	if (existing == ast.SymbolPrivateStaticGet && new == ast.SymbolPrivateStaticSet) ||
  1330  		(existing == ast.SymbolPrivateStaticSet && new == ast.SymbolPrivateStaticGet) {
  1331  		return mergeBecomePrivateStaticGetSetPair
  1332  	}
  1333  
  1334  	// "try {} catch (e) { var e }"
  1335  	if existing == ast.SymbolCatchIdentifier && new == ast.SymbolHoisted {
  1336  		return mergeReplaceWithNew
  1337  	}
  1338  
  1339  	// "function() { var arguments }"
  1340  	if existing == ast.SymbolArguments && new == ast.SymbolHoisted {
  1341  		return mergeKeepExisting
  1342  	}
  1343  
  1344  	// "function() { let arguments }"
  1345  	if existing == ast.SymbolArguments && new != ast.SymbolHoisted {
  1346  		return mergeOverwriteWithNew
  1347  	}
  1348  
  1349  	return mergeForbidden
  1350  }
  1351  
  1352  func (p *parser) addSymbolAlreadyDeclaredError(name string, newLoc logger.Loc, oldLoc logger.Loc) {
  1353  	p.log.AddErrorWithNotes(&p.tracker,
  1354  		js_lexer.RangeOfIdentifier(p.source, newLoc),
  1355  		fmt.Sprintf("The symbol %q has already been declared", name),
  1356  
  1357  		[]logger.MsgData{p.tracker.MsgData(
  1358  			js_lexer.RangeOfIdentifier(p.source, oldLoc),
  1359  			fmt.Sprintf("The symbol %q was originally declared here:", name),
  1360  		)},
  1361  	)
  1362  }
  1363  
  1364  func (p *parser) declareSymbol(kind ast.SymbolKind, loc logger.Loc, name string) ast.Ref {
  1365  	p.checkForUnrepresentableIdentifier(loc, name)
  1366  
  1367  	// Allocate a new symbol
  1368  	ref := p.newSymbol(kind, name)
  1369  
  1370  	// Check for a collision in the declaring scope
  1371  	if existing, ok := p.currentScope.Members[name]; ok {
  1372  		symbol := &p.symbols[existing.Ref.InnerIndex]
  1373  
  1374  		switch p.canMergeSymbols(p.currentScope, symbol.Kind, kind) {
  1375  		case mergeForbidden:
  1376  			p.addSymbolAlreadyDeclaredError(name, loc, existing.Loc)
  1377  			return existing.Ref
  1378  
  1379  		case mergeKeepExisting:
  1380  			ref = existing.Ref
  1381  
  1382  		case mergeReplaceWithNew:
  1383  			symbol.Link = ref
  1384  			p.currentScope.Replaced = append(p.currentScope.Replaced, existing)
  1385  
  1386  			// If these are both functions, remove the overwritten declaration
  1387  			if p.options.minifySyntax && kind.IsFunction() && symbol.Kind.IsFunction() {
  1388  				symbol.Flags |= ast.RemoveOverwrittenFunctionDeclaration
  1389  			}
  1390  
  1391  		case mergeBecomePrivateGetSetPair:
  1392  			ref = existing.Ref
  1393  			symbol.Kind = ast.SymbolPrivateGetSetPair
  1394  
  1395  		case mergeBecomePrivateStaticGetSetPair:
  1396  			ref = existing.Ref
  1397  			symbol.Kind = ast.SymbolPrivateStaticGetSetPair
  1398  
  1399  		case mergeOverwriteWithNew:
  1400  		}
  1401  	}
  1402  
  1403  	// Overwrite this name in the declaring scope
  1404  	p.currentScope.Members[name] = js_ast.ScopeMember{Ref: ref, Loc: loc}
  1405  	return ref
  1406  
  1407  }
  1408  
  1409  // This type is just so we can use Go's native sort function
  1410  type scopeMemberArray []js_ast.ScopeMember
  1411  
  1412  func (a scopeMemberArray) Len() int          { return len(a) }
  1413  func (a scopeMemberArray) Swap(i int, j int) { a[i], a[j] = a[j], a[i] }
  1414  
  1415  func (a scopeMemberArray) Less(i int, j int) bool {
  1416  	ai := a[i].Ref
  1417  	bj := a[j].Ref
  1418  	return ai.InnerIndex < bj.InnerIndex || (ai.InnerIndex == bj.InnerIndex && ai.SourceIndex < bj.SourceIndex)
  1419  }
  1420  
  1421  func (p *parser) hoistSymbols(scope *js_ast.Scope) {
  1422  	// Duplicate function declarations are forbidden in nested blocks in strict
  1423  	// mode. Separately, they are also forbidden at the top-level of modules.
  1424  	// This check needs to be delayed until now instead of being done when the
  1425  	// functions are declared because we potentially need to scan the whole file
  1426  	// to know if the file is considered to be in strict mode (or is considered
  1427  	// to be a module). We might only encounter an "export {}" clause at the end
  1428  	// of the file.
  1429  	if (scope.StrictMode != js_ast.SloppyMode && scope.Kind == js_ast.ScopeBlock) || (scope.Parent == nil && p.isFileConsideredESM) {
  1430  		for _, replaced := range scope.Replaced {
  1431  			symbol := &p.symbols[replaced.Ref.InnerIndex]
  1432  			if symbol.Kind.IsFunction() {
  1433  				if member, ok := scope.Members[symbol.OriginalName]; ok && p.symbols[member.Ref.InnerIndex].Kind.IsFunction() {
  1434  					var notes []logger.MsgData
  1435  					if scope.Parent == nil && p.isFileConsideredESM {
  1436  						_, notes = p.whyESModule()
  1437  						notes[0].Text = fmt.Sprintf("Duplicate top-level function declarations are not allowed in an ECMAScript module. %s", notes[0].Text)
  1438  					} else {
  1439  						var where string
  1440  						where, notes = p.whyStrictMode(scope)
  1441  						notes[0].Text = fmt.Sprintf("Duplicate function declarations are not allowed in nested blocks %s. %s", where, notes[0].Text)
  1442  					}
  1443  
  1444  					p.log.AddErrorWithNotes(&p.tracker,
  1445  						js_lexer.RangeOfIdentifier(p.source, member.Loc),
  1446  						fmt.Sprintf("The symbol %q has already been declared", symbol.OriginalName),
  1447  
  1448  						append([]logger.MsgData{p.tracker.MsgData(
  1449  							js_lexer.RangeOfIdentifier(p.source, replaced.Loc),
  1450  							fmt.Sprintf("The symbol %q was originally declared here:", symbol.OriginalName),
  1451  						)}, notes...),
  1452  					)
  1453  				}
  1454  			}
  1455  		}
  1456  	}
  1457  
  1458  	if !scope.Kind.StopsHoisting() {
  1459  		// We create new symbols in the loop below, so the iteration order of the
  1460  		// loop must be deterministic to avoid generating different minified names
  1461  		sortedMembers := make(scopeMemberArray, 0, len(scope.Members))
  1462  		for _, member := range scope.Members {
  1463  			sortedMembers = append(sortedMembers, member)
  1464  		}
  1465  		sort.Sort(sortedMembers)
  1466  
  1467  	nextMember:
  1468  		for _, member := range sortedMembers {
  1469  			symbol := &p.symbols[member.Ref.InnerIndex]
  1470  
  1471  			// Handle non-hoisted collisions between catch bindings and the catch body.
  1472  			// This implements "B.3.4 VariableStatements in Catch Blocks" from Annex B
  1473  			// of the ECMAScript standard version 6+ (except for the hoisted case, which
  1474  			// is handled later on below):
  1475  			//
  1476  			// * It is a Syntax Error if any element of the BoundNames of CatchParameter
  1477  			//   also occurs in the LexicallyDeclaredNames of Block.
  1478  			//
  1479  			// * It is a Syntax Error if any element of the BoundNames of CatchParameter
  1480  			//   also occurs in the VarDeclaredNames of Block unless CatchParameter is
  1481  			//   CatchParameter : BindingIdentifier .
  1482  			//
  1483  			if scope.Parent.Kind == js_ast.ScopeCatchBinding && symbol.Kind != ast.SymbolHoisted {
  1484  				if existingMember, ok := scope.Parent.Members[symbol.OriginalName]; ok {
  1485  					p.addSymbolAlreadyDeclaredError(symbol.OriginalName, member.Loc, existingMember.Loc)
  1486  					continue
  1487  				}
  1488  			}
  1489  
  1490  			if !symbol.Kind.IsHoisted() {
  1491  				continue
  1492  			}
  1493  
  1494  			// Implement "Block-Level Function Declarations Web Legacy Compatibility
  1495  			// Semantics" from Annex B of the ECMAScript standard version 6+
  1496  			isSloppyModeBlockLevelFnStmt := false
  1497  			originalMemberRef := member.Ref
  1498  			if symbol.Kind == ast.SymbolHoistedFunction {
  1499  				// Block-level function declarations behave like "let" in strict mode
  1500  				if scope.StrictMode != js_ast.SloppyMode {
  1501  					continue
  1502  				}
  1503  
  1504  				// In sloppy mode, block level functions behave like "let" except with
  1505  				// an assignment to "var", sort of. This code:
  1506  				//
  1507  				//   if (x) {
  1508  				//     f();
  1509  				//     function f() {}
  1510  				//   }
  1511  				//   f();
  1512  				//
  1513  				// behaves like this code:
  1514  				//
  1515  				//   if (x) {
  1516  				//     let f2 = function() {}
  1517  				//     var f = f2;
  1518  				//     f2();
  1519  				//   }
  1520  				//   f();
  1521  				//
  1522  				hoistedRef := p.newSymbol(ast.SymbolHoisted, symbol.OriginalName)
  1523  				scope.Generated = append(scope.Generated, hoistedRef)
  1524  				if p.hoistedRefForSloppyModeBlockFn == nil {
  1525  					p.hoistedRefForSloppyModeBlockFn = make(map[ast.Ref]ast.Ref)
  1526  				}
  1527  				p.hoistedRefForSloppyModeBlockFn[member.Ref] = hoistedRef
  1528  				symbol = &p.symbols[hoistedRef.InnerIndex]
  1529  				member.Ref = hoistedRef
  1530  				isSloppyModeBlockLevelFnStmt = true
  1531  			}
  1532  
  1533  			// Check for collisions that would prevent to hoisting "var" symbols up to the enclosing function scope
  1534  			s := scope.Parent
  1535  			for {
  1536  				// Variable declarations hoisted past a "with" statement may actually end
  1537  				// up overwriting a property on the target of the "with" statement instead
  1538  				// of initializing the variable. We must not rename them or we risk
  1539  				// causing a behavior change.
  1540  				//
  1541  				//   var obj = { foo: 1 }
  1542  				//   with (obj) { var foo = 2 }
  1543  				//   assert(foo === undefined)
  1544  				//   assert(obj.foo === 2)
  1545  				//
  1546  				if s.Kind == js_ast.ScopeWith {
  1547  					symbol.Flags |= ast.MustNotBeRenamed
  1548  				}
  1549  
  1550  				if existingMember, ok := s.Members[symbol.OriginalName]; ok {
  1551  					existingSymbol := &p.symbols[existingMember.Ref.InnerIndex]
  1552  
  1553  					// We can hoist the symbol from the child scope into the symbol in
  1554  					// this scope if:
  1555  					//
  1556  					//   - The symbol is unbound (i.e. a global variable access)
  1557  					//   - The symbol is also another hoisted variable
  1558  					//   - The symbol is a function of any kind and we're in a function or module scope
  1559  					//
  1560  					// Is this unbound (i.e. a global access) or also hoisted?
  1561  					if existingSymbol.Kind == ast.SymbolUnbound || existingSymbol.Kind == ast.SymbolHoisted ||
  1562  						(existingSymbol.Kind.IsFunction() && (s.Kind == js_ast.ScopeEntry || s.Kind == js_ast.ScopeFunctionBody)) {
  1563  						// Silently merge this symbol into the existing symbol
  1564  						symbol.Link = existingMember.Ref
  1565  						s.Members[symbol.OriginalName] = existingMember
  1566  						continue nextMember
  1567  					}
  1568  
  1569  					// Otherwise if this isn't a catch identifier or "arguments", it's a collision
  1570  					if existingSymbol.Kind != ast.SymbolCatchIdentifier && existingSymbol.Kind != ast.SymbolArguments {
  1571  						// An identifier binding from a catch statement and a function
  1572  						// declaration can both silently shadow another hoisted symbol
  1573  						if symbol.Kind != ast.SymbolCatchIdentifier && symbol.Kind != ast.SymbolHoistedFunction {
  1574  							if !isSloppyModeBlockLevelFnStmt {
  1575  								p.addSymbolAlreadyDeclaredError(symbol.OriginalName, member.Loc, existingMember.Loc)
  1576  							} else if s == scope.Parent {
  1577  								// Never mind about this, turns out it's not needed after all
  1578  								delete(p.hoistedRefForSloppyModeBlockFn, originalMemberRef)
  1579  							}
  1580  						}
  1581  						continue nextMember
  1582  					}
  1583  
  1584  					// If this is a catch identifier, silently merge the existing symbol
  1585  					// into this symbol but continue hoisting past this catch scope
  1586  					existingSymbol.Link = member.Ref
  1587  					s.Members[symbol.OriginalName] = member
  1588  				}
  1589  
  1590  				if s.Kind.StopsHoisting() {
  1591  					// Declare the member in the scope that stopped the hoisting
  1592  					s.Members[symbol.OriginalName] = member
  1593  					break
  1594  				}
  1595  				s = s.Parent
  1596  			}
  1597  		}
  1598  	}
  1599  
  1600  	for _, child := range scope.Children {
  1601  		p.hoistSymbols(child)
  1602  	}
  1603  }
  1604  
  1605  func (p *parser) declareBinding(kind ast.SymbolKind, binding js_ast.Binding, opts parseStmtOpts) {
  1606  	js_ast.ForEachIdentifierBinding(binding, func(loc logger.Loc, b *js_ast.BIdentifier) {
  1607  		if !opts.isTypeScriptDeclare || (opts.isNamespaceScope && opts.isExport) {
  1608  			b.Ref = p.declareSymbol(kind, binding.Loc, p.loadNameFromRef(b.Ref))
  1609  		}
  1610  	})
  1611  }
  1612  
  1613  func (p *parser) recordUsage(ref ast.Ref) {
  1614  	// The use count stored in the symbol is used for generating symbol names
  1615  	// during minification. These counts shouldn't include references inside dead
  1616  	// code regions since those will be culled.
  1617  	if !p.isControlFlowDead {
  1618  		p.symbols[ref.InnerIndex].UseCountEstimate++
  1619  		use := p.symbolUses[ref]
  1620  		use.CountEstimate++
  1621  		p.symbolUses[ref] = use
  1622  	}
  1623  
  1624  	// The correctness of TypeScript-to-JavaScript conversion relies on accurate
  1625  	// symbol use counts for the whole file, including dead code regions. This is
  1626  	// tracked separately in a parser-only data structure.
  1627  	if p.options.ts.Parse {
  1628  		p.tsUseCounts[ref.InnerIndex]++
  1629  	}
  1630  }
  1631  
  1632  func (p *parser) ignoreUsage(ref ast.Ref) {
  1633  	// Roll back the use count increment in recordUsage()
  1634  	if !p.isControlFlowDead {
  1635  		p.symbols[ref.InnerIndex].UseCountEstimate--
  1636  		use := p.symbolUses[ref]
  1637  		use.CountEstimate--
  1638  		if use.CountEstimate == 0 {
  1639  			delete(p.symbolUses, ref)
  1640  		} else {
  1641  			p.symbolUses[ref] = use
  1642  		}
  1643  	}
  1644  
  1645  	// Don't roll back the "tsUseCounts" increment. This must be counted even if
  1646  	// the value is ignored because that's what the TypeScript compiler does.
  1647  }
  1648  
  1649  func (p *parser) ignoreUsageOfIdentifierInDotChain(expr js_ast.Expr) {
  1650  	for {
  1651  		switch e := expr.Data.(type) {
  1652  		case *js_ast.EIdentifier:
  1653  			p.ignoreUsage(e.Ref)
  1654  
  1655  		case *js_ast.EDot:
  1656  			expr = e.Target
  1657  			continue
  1658  
  1659  		case *js_ast.EIndex:
  1660  			if _, ok := e.Index.Data.(*js_ast.EString); ok {
  1661  				expr = e.Target
  1662  				continue
  1663  			}
  1664  		}
  1665  
  1666  		return
  1667  	}
  1668  }
  1669  
  1670  func (p *parser) importFromRuntime(loc logger.Loc, name string) js_ast.Expr {
  1671  	it, ok := p.runtimeImports[name]
  1672  	if !ok {
  1673  		it.Loc = loc
  1674  		it.Ref = p.newSymbol(ast.SymbolOther, name)
  1675  		p.moduleScope.Generated = append(p.moduleScope.Generated, it.Ref)
  1676  		p.runtimeImports[name] = it
  1677  	}
  1678  	p.recordUsage(it.Ref)
  1679  	return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: it.Ref}}
  1680  }
  1681  
  1682  func (p *parser) callRuntime(loc logger.Loc, name string, args []js_ast.Expr) js_ast.Expr {
  1683  	return js_ast.Expr{Loc: loc, Data: &js_ast.ECall{
  1684  		Target: p.importFromRuntime(loc, name),
  1685  		Args:   args,
  1686  	}}
  1687  }
  1688  
  1689  type JSXImport uint8
  1690  
  1691  const (
  1692  	JSXImportJSX JSXImport = iota
  1693  	JSXImportJSXS
  1694  	JSXImportFragment
  1695  	JSXImportCreateElement
  1696  )
  1697  
  1698  func (p *parser) importJSXSymbol(loc logger.Loc, jsx JSXImport) js_ast.Expr {
  1699  	var symbols map[string]ast.LocRef
  1700  	var name string
  1701  
  1702  	switch jsx {
  1703  	case JSXImportJSX:
  1704  		symbols = p.jsxRuntimeImports
  1705  		if p.options.jsx.Development {
  1706  			name = "jsxDEV"
  1707  		} else {
  1708  			name = "jsx"
  1709  		}
  1710  
  1711  	case JSXImportJSXS:
  1712  		symbols = p.jsxRuntimeImports
  1713  		if p.options.jsx.Development {
  1714  			name = "jsxDEV"
  1715  		} else {
  1716  			name = "jsxs"
  1717  		}
  1718  
  1719  	case JSXImportFragment:
  1720  		symbols = p.jsxRuntimeImports
  1721  		name = "Fragment"
  1722  
  1723  	case JSXImportCreateElement:
  1724  		symbols = p.jsxLegacyImports
  1725  		name = "createElement"
  1726  	}
  1727  
  1728  	it, ok := symbols[name]
  1729  	if !ok {
  1730  		it.Loc = loc
  1731  		it.Ref = p.newSymbol(ast.SymbolOther, name)
  1732  		p.moduleScope.Generated = append(p.moduleScope.Generated, it.Ref)
  1733  		p.isImportItem[it.Ref] = true
  1734  		symbols[name] = it
  1735  	}
  1736  
  1737  	p.recordUsage(it.Ref)
  1738  	return p.handleIdentifier(loc, &js_ast.EIdentifier{Ref: it.Ref}, identifierOpts{
  1739  		wasOriginallyIdentifier: true,
  1740  	})
  1741  }
  1742  
  1743  func (p *parser) valueToSubstituteForRequire(loc logger.Loc) js_ast.Expr {
  1744  	if p.source.Index != runtime.SourceIndex &&
  1745  		config.ShouldCallRuntimeRequire(p.options.mode, p.options.outputFormat) {
  1746  		return p.importFromRuntime(loc, "__require")
  1747  	}
  1748  
  1749  	p.recordUsage(p.requireRef)
  1750  	return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: p.requireRef}}
  1751  }
  1752  
  1753  func (p *parser) makePromiseRef() ast.Ref {
  1754  	if p.promiseRef == ast.InvalidRef {
  1755  		p.promiseRef = p.newSymbol(ast.SymbolUnbound, "Promise")
  1756  	}
  1757  	return p.promiseRef
  1758  }
  1759  
  1760  func (p *parser) makeRegExpRef() ast.Ref {
  1761  	if p.regExpRef == ast.InvalidRef {
  1762  		p.regExpRef = p.newSymbol(ast.SymbolUnbound, "RegExp")
  1763  		p.moduleScope.Generated = append(p.moduleScope.Generated, p.regExpRef)
  1764  	}
  1765  	return p.regExpRef
  1766  }
  1767  
  1768  // The name is temporarily stored in the ref until the scope traversal pass
  1769  // happens, at which point a symbol will be generated and the ref will point
  1770  // to the symbol instead.
  1771  //
  1772  // The scope traversal pass will reconstruct the name using one of two methods.
  1773  // In the common case, the name is a slice of the file itself. In that case we
  1774  // can just store the slice and not need to allocate any extra memory. In the
  1775  // rare case, the name is an externally-allocated string. In that case we store
  1776  // an index to the string and use that index during the scope traversal pass.
  1777  func (p *parser) storeNameInRef(name js_lexer.MaybeSubstring) ast.Ref {
  1778  	// Is the data in "name" a subset of the data in "p.source.Contents"?
  1779  	if name.Start.IsValid() {
  1780  		// The name is a slice of the file contents, so we can just reference it by
  1781  		// length and don't have to allocate anything. This is the common case.
  1782  		//
  1783  		// It's stored as a negative value so we'll crash if we try to use it. That
  1784  		// way we'll catch cases where we've forgotten to call loadNameFromRef().
  1785  		// The length is the negative part because we know it's non-zero.
  1786  		return ast.Ref{SourceIndex: -uint32(len(name.String)), InnerIndex: uint32(name.Start.GetIndex())}
  1787  	} else {
  1788  		// The name is some memory allocated elsewhere. This is either an inline
  1789  		// string constant in the parser or an identifier with escape sequences
  1790  		// in the source code, which is very unusual. Stash it away for later.
  1791  		// This uses allocations but it should hopefully be very uncommon.
  1792  		ref := ast.Ref{SourceIndex: 0x80000000, InnerIndex: uint32(len(p.allocatedNames))}
  1793  		p.allocatedNames = append(p.allocatedNames, name.String)
  1794  		return ref
  1795  	}
  1796  }
  1797  
  1798  // This is the inverse of storeNameInRef() above
  1799  func (p *parser) loadNameFromRef(ref ast.Ref) string {
  1800  	if ref.SourceIndex == 0x80000000 {
  1801  		return p.allocatedNames[ref.InnerIndex]
  1802  	} else {
  1803  		if (ref.SourceIndex & 0x80000000) == 0 {
  1804  			panic("Internal error: invalid symbol reference")
  1805  		}
  1806  		return p.source.Contents[ref.InnerIndex : int32(ref.InnerIndex)-int32(ref.SourceIndex)]
  1807  	}
  1808  }
  1809  
  1810  // Due to ES6 destructuring patterns, there are many cases where it's
  1811  // impossible to distinguish between an array or object literal and a
  1812  // destructuring assignment until we hit the "=" operator later on.
  1813  // This object defers errors about being in one state or the other
  1814  // until we discover which state we're in.
  1815  type deferredErrors struct {
  1816  	// These are errors for expressions
  1817  	invalidExprDefaultValue  logger.Range
  1818  	invalidExprAfterQuestion logger.Range
  1819  	arraySpreadFeature       logger.Range
  1820  
  1821  	// These errors are for arrow functions
  1822  	invalidParens []logger.Range
  1823  }
  1824  
  1825  func (from *deferredErrors) mergeInto(to *deferredErrors) {
  1826  	if from.invalidExprDefaultValue.Len > 0 {
  1827  		to.invalidExprDefaultValue = from.invalidExprDefaultValue
  1828  	}
  1829  	if from.invalidExprAfterQuestion.Len > 0 {
  1830  		to.invalidExprAfterQuestion = from.invalidExprAfterQuestion
  1831  	}
  1832  	if from.arraySpreadFeature.Len > 0 {
  1833  		to.arraySpreadFeature = from.arraySpreadFeature
  1834  	}
  1835  	if len(from.invalidParens) > 0 {
  1836  		if len(to.invalidParens) > 0 {
  1837  			to.invalidParens = append(to.invalidParens, from.invalidParens...)
  1838  		} else {
  1839  			to.invalidParens = from.invalidParens
  1840  		}
  1841  	}
  1842  }
  1843  
  1844  func (p *parser) logExprErrors(errors *deferredErrors) {
  1845  	if errors.invalidExprDefaultValue.Len > 0 {
  1846  		p.log.AddError(&p.tracker, errors.invalidExprDefaultValue, "Unexpected \"=\"")
  1847  	}
  1848  
  1849  	if errors.invalidExprAfterQuestion.Len > 0 {
  1850  		r := errors.invalidExprAfterQuestion
  1851  		p.log.AddError(&p.tracker, r, fmt.Sprintf("Unexpected %q", p.source.Contents[r.Loc.Start:r.Loc.Start+r.Len]))
  1852  	}
  1853  
  1854  	if errors.arraySpreadFeature.Len > 0 {
  1855  		p.markSyntaxFeature(compat.ArraySpread, errors.arraySpreadFeature)
  1856  	}
  1857  }
  1858  
  1859  func (p *parser) logDeferredArrowArgErrors(errors *deferredErrors) {
  1860  	for _, paren := range errors.invalidParens {
  1861  		p.log.AddError(&p.tracker, paren, "Invalid binding pattern")
  1862  	}
  1863  }
  1864  
  1865  func (p *parser) logNullishCoalescingErrorPrecedenceError(op string) {
  1866  	prevOp := "??"
  1867  	if p.lexer.Token == js_lexer.TQuestionQuestion {
  1868  		op, prevOp = prevOp, op
  1869  	}
  1870  	// p.log.AddError(&p.tracker, p.lexer.Range(), fmt.Sprintf("The %q operator requires parentheses"))
  1871  	p.log.AddErrorWithNotes(&p.tracker, p.lexer.Range(), fmt.Sprintf("Cannot use %q with %q without parentheses", op, prevOp),
  1872  		[]logger.MsgData{{Text: fmt.Sprintf("Expressions of the form \"x %s y %s z\" are not allowed in JavaScript. "+
  1873  			"You must disambiguate between \"(x %s y) %s z\" and \"x %s (y %s z)\" by adding parentheses.", prevOp, op, prevOp, op, prevOp, op)}})
  1874  }
  1875  
  1876  func defineValueCanBeUsedInAssignTarget(data js_ast.E) bool {
  1877  	switch data.(type) {
  1878  	case *js_ast.EIdentifier, *js_ast.EDot:
  1879  		return true
  1880  	}
  1881  
  1882  	// Substituting a constant into an assignment target (e.g. "x = 1" becomes
  1883  	// "0 = 1") will cause a syntax error, so we avoid doing this. The caller
  1884  	// will log a warning instead.
  1885  	return false
  1886  }
  1887  
  1888  func (p *parser) logAssignToDefine(r logger.Range, name string, expr js_ast.Expr) {
  1889  	// If this is a compound expression, pretty-print it for the error message.
  1890  	// We don't use a literal slice of the source text in case it contains
  1891  	// problematic things (e.g. spans multiple lines, has embedded comments).
  1892  	if expr.Data != nil {
  1893  		var parts []string
  1894  		for {
  1895  			if id, ok := expr.Data.(*js_ast.EIdentifier); ok {
  1896  				parts = append(parts, p.loadNameFromRef(id.Ref))
  1897  				break
  1898  			} else if dot, ok := expr.Data.(*js_ast.EDot); ok {
  1899  				parts = append(parts, dot.Name)
  1900  				parts = append(parts, ".")
  1901  				expr = dot.Target
  1902  			} else if index, ok := expr.Data.(*js_ast.EIndex); ok {
  1903  				if str, ok := index.Index.Data.(*js_ast.EString); ok {
  1904  					parts = append(parts, "]")
  1905  					parts = append(parts, string(helpers.QuoteSingle(helpers.UTF16ToString(str.Value), false)))
  1906  					parts = append(parts, "[")
  1907  					expr = index.Target
  1908  				} else {
  1909  					return
  1910  				}
  1911  			} else {
  1912  				return
  1913  			}
  1914  		}
  1915  		for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 {
  1916  			parts[i], parts[j] = parts[j], parts[i]
  1917  		}
  1918  		name = strings.Join(parts, "")
  1919  	}
  1920  
  1921  	kind := logger.Warning
  1922  	if p.suppressWarningsAboutWeirdCode {
  1923  		kind = logger.Debug
  1924  	}
  1925  
  1926  	p.log.AddIDWithNotes(logger.MsgID_JS_AssignToDefine, kind, &p.tracker, r,
  1927  		fmt.Sprintf("Suspicious assignment to defined constant %q", name),
  1928  		[]logger.MsgData{{Text: fmt.Sprintf(
  1929  			"The expression %q has been configured to be replaced with a constant using the \"define\" feature. "+
  1930  				"If this expression is supposed to be a compile-time constant, then it doesn't make sense to assign to it here. "+
  1931  				"Or if this expression is supposed to change at run-time, this \"define\" substitution should be removed.", name)}})
  1932  }
  1933  
  1934  // The "await" and "yield" expressions are never allowed in argument lists but
  1935  // may or may not be allowed otherwise depending on the details of the enclosing
  1936  // function or module. This needs to be handled when parsing an arrow function
  1937  // argument list because we don't know if these expressions are not allowed until
  1938  // we reach the "=>" token (or discover the absence of one).
  1939  //
  1940  // Specifically, for await:
  1941  //
  1942  //	// This is ok
  1943  //	async function foo() { (x = await y) }
  1944  //
  1945  //	// This is an error
  1946  //	async function foo() { (x = await y) => {} }
  1947  //
  1948  // And for yield:
  1949  //
  1950  //	// This is ok
  1951  //	function* foo() { (x = yield y) }
  1952  //
  1953  //	// This is an error
  1954  //	function* foo() { (x = yield y) => {} }
  1955  type deferredArrowArgErrors struct {
  1956  	invalidExprAwait logger.Range
  1957  	invalidExprYield logger.Range
  1958  }
  1959  
  1960  func (p *parser) logArrowArgErrors(errors *deferredArrowArgErrors) {
  1961  	if errors.invalidExprAwait.Len > 0 {
  1962  		p.log.AddError(&p.tracker, errors.invalidExprAwait, "Cannot use an \"await\" expression here:")
  1963  	}
  1964  
  1965  	if errors.invalidExprYield.Len > 0 {
  1966  		p.log.AddError(&p.tracker, errors.invalidExprYield, "Cannot use a \"yield\" expression here:")
  1967  	}
  1968  }
  1969  
  1970  func (p *parser) keyNameForError(key js_ast.Expr) string {
  1971  	switch k := key.Data.(type) {
  1972  	case *js_ast.EString:
  1973  		return fmt.Sprintf("%q", helpers.UTF16ToString(k.Value))
  1974  	case *js_ast.EPrivateIdentifier:
  1975  		return fmt.Sprintf("%q", p.loadNameFromRef(k.Ref))
  1976  	}
  1977  	return "property"
  1978  }
  1979  
  1980  func (p *parser) checkForLegacyOctalLiteral(e js_ast.E) {
  1981  	if p.lexer.IsLegacyOctalLiteral {
  1982  		if p.legacyOctalLiterals == nil {
  1983  			p.legacyOctalLiterals = make(map[js_ast.E]logger.Range)
  1984  		}
  1985  		p.legacyOctalLiterals[e] = p.lexer.Range()
  1986  	}
  1987  }
  1988  
  1989  func (p *parser) notesForAssertTypeJSON(record *ast.ImportRecord, alias string) []logger.MsgData {
  1990  	return []logger.MsgData{p.tracker.MsgData(
  1991  		js_lexer.RangeOfImportAssertOrWith(p.source, *ast.FindAssertOrWithEntry(record.AssertOrWith.Entries, "type"), js_lexer.KeyAndValueRange),
  1992  		"The JSON import assertion is here:"),
  1993  		{Text: fmt.Sprintf("You can either keep the import assertion and only use the \"default\" import, "+
  1994  			"or you can remove the import assertion and use the %q import.", alias)}}
  1995  }
  1996  
  1997  // This assumes the caller has already checked for TStringLiteral or TNoSubstitutionTemplateLiteral
  1998  func (p *parser) parseStringLiteral() js_ast.Expr {
  1999  	var legacyOctalLoc logger.Loc
  2000  	loc := p.lexer.Loc()
  2001  	text := p.lexer.StringLiteral()
  2002  
  2003  	// Enable using a "/* @__KEY__ */" comment to turn a string into a key
  2004  	hasPropertyKeyComment := (p.lexer.HasCommentBefore & js_lexer.KeyCommentBefore) != 0
  2005  	if hasPropertyKeyComment {
  2006  		if name := helpers.UTF16ToString(text); p.isMangledProp(name) {
  2007  			value := js_ast.Expr{Loc: loc, Data: &js_ast.ENameOfSymbol{
  2008  				Ref:                   p.storeNameInRef(js_lexer.MaybeSubstring{String: name}),
  2009  				HasPropertyKeyComment: true,
  2010  			}}
  2011  			p.lexer.Next()
  2012  			return value
  2013  		}
  2014  	}
  2015  
  2016  	if p.lexer.LegacyOctalLoc.Start > loc.Start {
  2017  		legacyOctalLoc = p.lexer.LegacyOctalLoc
  2018  	}
  2019  	value := js_ast.Expr{Loc: loc, Data: &js_ast.EString{
  2020  		Value:                 text,
  2021  		LegacyOctalLoc:        legacyOctalLoc,
  2022  		PreferTemplate:        p.lexer.Token == js_lexer.TNoSubstitutionTemplateLiteral,
  2023  		HasPropertyKeyComment: hasPropertyKeyComment,
  2024  	}}
  2025  	p.lexer.Next()
  2026  	return value
  2027  }
  2028  
  2029  type propertyOpts struct {
  2030  	decorators       []js_ast.Decorator
  2031  	decoratorScope   *js_ast.Scope
  2032  	decoratorContext decoratorContextFlags
  2033  
  2034  	asyncRange     logger.Range
  2035  	generatorRange logger.Range
  2036  	tsDeclareRange logger.Range
  2037  	classKeyword   logger.Range
  2038  	isAsync        bool
  2039  	isGenerator    bool
  2040  
  2041  	// Class-related options
  2042  	isStatic        bool
  2043  	isTSAbstract    bool
  2044  	isClass         bool
  2045  	classHasExtends bool
  2046  }
  2047  
  2048  func (p *parser) parseProperty(startLoc logger.Loc, kind js_ast.PropertyKind, opts propertyOpts, errors *deferredErrors) (js_ast.Property, bool) {
  2049  	var flags js_ast.PropertyFlags
  2050  	var key js_ast.Expr
  2051  	var closeBracketLoc logger.Loc
  2052  	keyRange := p.lexer.Range()
  2053  
  2054  	switch p.lexer.Token {
  2055  	case js_lexer.TNumericLiteral:
  2056  		key = js_ast.Expr{Loc: p.lexer.Loc(), Data: &js_ast.ENumber{Value: p.lexer.Number}}
  2057  		p.checkForLegacyOctalLiteral(key.Data)
  2058  		p.lexer.Next()
  2059  
  2060  	case js_lexer.TStringLiteral:
  2061  		key = p.parseStringLiteral()
  2062  		if !p.options.minifySyntax {
  2063  			flags |= js_ast.PropertyPreferQuotedKey
  2064  		}
  2065  
  2066  	case js_lexer.TBigIntegerLiteral:
  2067  		key = js_ast.Expr{Loc: p.lexer.Loc(), Data: &js_ast.EBigInt{Value: p.lexer.Identifier.String}}
  2068  		p.markSyntaxFeature(compat.Bigint, p.lexer.Range())
  2069  		p.lexer.Next()
  2070  
  2071  	case js_lexer.TPrivateIdentifier:
  2072  		if p.options.ts.Parse && p.options.ts.Config.ExperimentalDecorators == config.True && len(opts.decorators) > 0 {
  2073  			p.log.AddError(&p.tracker, p.lexer.Range(), "TypeScript experimental decorators cannot be used on private identifiers")
  2074  		} else if !opts.isClass {
  2075  			p.lexer.Expected(js_lexer.TIdentifier)
  2076  		} else if opts.tsDeclareRange.Len != 0 {
  2077  			p.log.AddError(&p.tracker, opts.tsDeclareRange, "\"declare\" cannot be used with a private identifier")
  2078  		}
  2079  		name := p.lexer.Identifier
  2080  		key = js_ast.Expr{Loc: p.lexer.Loc(), Data: &js_ast.EPrivateIdentifier{Ref: p.storeNameInRef(name)}}
  2081  		p.reportPrivateNameUsage(name.String)
  2082  		p.lexer.Next()
  2083  
  2084  	case js_lexer.TOpenBracket:
  2085  		flags |= js_ast.PropertyIsComputed
  2086  		p.markSyntaxFeature(compat.ObjectExtensions, p.lexer.Range())
  2087  		p.lexer.Next()
  2088  		wasIdentifier := p.lexer.Token == js_lexer.TIdentifier
  2089  		expr := p.parseExpr(js_ast.LComma)
  2090  
  2091  		// Handle index signatures
  2092  		if p.options.ts.Parse && p.lexer.Token == js_lexer.TColon && wasIdentifier && opts.isClass {
  2093  			if _, ok := expr.Data.(*js_ast.EIdentifier); ok {
  2094  				if opts.tsDeclareRange.Len != 0 {
  2095  					p.log.AddError(&p.tracker, opts.tsDeclareRange, "\"declare\" cannot be used with an index signature")
  2096  				}
  2097  
  2098  				// "[key: string]: any;"
  2099  				p.lexer.Next()
  2100  				p.skipTypeScriptType(js_ast.LLowest)
  2101  				p.lexer.Expect(js_lexer.TCloseBracket)
  2102  				p.lexer.Expect(js_lexer.TColon)
  2103  				p.skipTypeScriptType(js_ast.LLowest)
  2104  				p.lexer.ExpectOrInsertSemicolon()
  2105  
  2106  				// Skip this property entirely
  2107  				return js_ast.Property{}, false
  2108  			}
  2109  		}
  2110  
  2111  		closeBracketLoc = p.saveExprCommentsHere()
  2112  		p.lexer.Expect(js_lexer.TCloseBracket)
  2113  		key = expr
  2114  
  2115  	case js_lexer.TAsterisk:
  2116  		if kind != js_ast.PropertyField && (kind != js_ast.PropertyMethod || opts.isGenerator) {
  2117  			p.lexer.Unexpected()
  2118  		}
  2119  		opts.isGenerator = true
  2120  		opts.generatorRange = p.lexer.Range()
  2121  		p.lexer.Next()
  2122  		return p.parseProperty(startLoc, js_ast.PropertyMethod, opts, errors)
  2123  
  2124  	default:
  2125  		name := p.lexer.Identifier
  2126  		raw := p.lexer.Raw()
  2127  		nameRange := p.lexer.Range()
  2128  		if !p.lexer.IsIdentifierOrKeyword() {
  2129  			p.lexer.Expect(js_lexer.TIdentifier)
  2130  		}
  2131  		p.lexer.Next()
  2132  
  2133  		// Support contextual keywords
  2134  		if kind == js_ast.PropertyField {
  2135  			// Does the following token look like a key?
  2136  			couldBeModifierKeyword := p.lexer.IsIdentifierOrKeyword()
  2137  			if !couldBeModifierKeyword {
  2138  				switch p.lexer.Token {
  2139  				case js_lexer.TOpenBracket, js_lexer.TNumericLiteral, js_lexer.TStringLiteral,
  2140  					js_lexer.TAsterisk, js_lexer.TPrivateIdentifier:
  2141  					couldBeModifierKeyword = true
  2142  				}
  2143  			}
  2144  
  2145  			// If so, check for a modifier keyword
  2146  			if couldBeModifierKeyword {
  2147  				switch name.String {
  2148  				case "get":
  2149  					if !opts.isAsync && raw == name.String {
  2150  						p.markSyntaxFeature(compat.ObjectAccessors, nameRange)
  2151  						return p.parseProperty(startLoc, js_ast.PropertyGetter, opts, nil)
  2152  					}
  2153  
  2154  				case "set":
  2155  					if !opts.isAsync && raw == name.String {
  2156  						p.markSyntaxFeature(compat.ObjectAccessors, nameRange)
  2157  						return p.parseProperty(startLoc, js_ast.PropertySetter, opts, nil)
  2158  					}
  2159  
  2160  				case "accessor":
  2161  					if !p.lexer.HasNewlineBefore && !opts.isAsync && opts.isClass && raw == name.String {
  2162  						return p.parseProperty(startLoc, js_ast.PropertyAutoAccessor, opts, nil)
  2163  					}
  2164  
  2165  				case "async":
  2166  					if !p.lexer.HasNewlineBefore && !opts.isAsync && raw == name.String {
  2167  						opts.isAsync = true
  2168  						opts.asyncRange = nameRange
  2169  						return p.parseProperty(startLoc, js_ast.PropertyMethod, opts, nil)
  2170  					}
  2171  
  2172  				case "static":
  2173  					if !opts.isStatic && !opts.isAsync && opts.isClass && raw == name.String {
  2174  						opts.isStatic = true
  2175  						return p.parseProperty(startLoc, kind, opts, nil)
  2176  					}
  2177  
  2178  				case "declare":
  2179  					if !p.lexer.HasNewlineBefore && opts.isClass && p.options.ts.Parse && opts.tsDeclareRange.Len == 0 && raw == name.String {
  2180  						opts.tsDeclareRange = nameRange
  2181  						scopeIndex := len(p.scopesInOrder)
  2182  
  2183  						if prop, ok := p.parseProperty(startLoc, kind, opts, nil); ok &&
  2184  							prop.Kind == js_ast.PropertyField && prop.ValueOrNil.Data == nil &&
  2185  							(p.options.ts.Config.ExperimentalDecorators == config.True && len(opts.decorators) > 0) {
  2186  							// If this is a well-formed class field with the "declare" keyword,
  2187  							// only keep the declaration to preserve its side-effects when
  2188  							// there are TypeScript experimental decorators present:
  2189  							//
  2190  							//   class Foo {
  2191  							//     // Remove this
  2192  							//     declare [(console.log('side effect 1'), 'foo')]
  2193  							//
  2194  							//     // Keep this
  2195  							//     @decorator(console.log('side effect 2')) declare bar
  2196  							//   }
  2197  							//
  2198  							// This behavior is surprisingly somehow valid with TypeScript
  2199  							// experimental decorators, which was possibly by accident.
  2200  							// TypeScript does not allow this with JavaScript decorators.
  2201  							//
  2202  							// References:
  2203  							//
  2204  							//   https://github.com/evanw/esbuild/issues/1675
  2205  							//   https://github.com/microsoft/TypeScript/issues/46345
  2206  							//
  2207  							prop.Kind = js_ast.PropertyDeclareOrAbstract
  2208  							return prop, true
  2209  						}
  2210  
  2211  						p.discardScopesUpTo(scopeIndex)
  2212  						return js_ast.Property{}, false
  2213  					}
  2214  
  2215  				case "abstract":
  2216  					if !p.lexer.HasNewlineBefore && opts.isClass && p.options.ts.Parse && !opts.isTSAbstract && raw == name.String {
  2217  						opts.isTSAbstract = true
  2218  						scopeIndex := len(p.scopesInOrder)
  2219  
  2220  						if prop, ok := p.parseProperty(startLoc, kind, opts, nil); ok &&
  2221  							prop.Kind == js_ast.PropertyField && prop.ValueOrNil.Data == nil &&
  2222  							(p.options.ts.Config.ExperimentalDecorators == config.True && len(opts.decorators) > 0) {
  2223  							// If this is a well-formed class field with the "abstract" keyword,
  2224  							// only keep the declaration to preserve its side-effects when
  2225  							// there are TypeScript experimental decorators present:
  2226  							//
  2227  							//   abstract class Foo {
  2228  							//     // Remove this
  2229  							//     abstract [(console.log('side effect 1'), 'foo')]
  2230  							//
  2231  							//     // Keep this
  2232  							//     @decorator(console.log('side effect 2')) abstract bar
  2233  							//   }
  2234  							//
  2235  							// This behavior is valid with TypeScript experimental decorators.
  2236  							// TypeScript does not allow this with JavaScript decorators.
  2237  							//
  2238  							// References:
  2239  							//
  2240  							//   https://github.com/evanw/esbuild/issues/3684
  2241  							//
  2242  							prop.Kind = js_ast.PropertyDeclareOrAbstract
  2243  							return prop, true
  2244  						}
  2245  
  2246  						p.discardScopesUpTo(scopeIndex)
  2247  						return js_ast.Property{}, false
  2248  					}
  2249  
  2250  				case "private", "protected", "public", "readonly", "override":
  2251  					// Skip over TypeScript keywords
  2252  					if opts.isClass && p.options.ts.Parse && raw == name.String {
  2253  						return p.parseProperty(startLoc, kind, opts, nil)
  2254  					}
  2255  				}
  2256  			} else if p.lexer.Token == js_lexer.TOpenBrace && name.String == "static" && len(opts.decorators) == 0 {
  2257  				loc := p.lexer.Loc()
  2258  				p.lexer.Next()
  2259  
  2260  				oldFnOrArrowDataParse := p.fnOrArrowDataParse
  2261  				p.fnOrArrowDataParse = fnOrArrowDataParse{
  2262  					isReturnDisallowed: true,
  2263  					allowSuperProperty: true,
  2264  					await:              forbidAll,
  2265  				}
  2266  
  2267  				p.pushScopeForParsePass(js_ast.ScopeClassStaticInit, loc)
  2268  				stmts := p.parseStmtsUpTo(js_lexer.TCloseBrace, parseStmtOpts{})
  2269  				p.popScope()
  2270  
  2271  				p.fnOrArrowDataParse = oldFnOrArrowDataParse
  2272  
  2273  				closeBraceLoc := p.lexer.Loc()
  2274  				p.lexer.Expect(js_lexer.TCloseBrace)
  2275  				return js_ast.Property{
  2276  					Kind: js_ast.PropertyClassStaticBlock,
  2277  					Loc:  startLoc,
  2278  					ClassStaticBlock: &js_ast.ClassStaticBlock{
  2279  						Loc:   loc,
  2280  						Block: js_ast.SBlock{Stmts: stmts, CloseBraceLoc: closeBraceLoc},
  2281  					},
  2282  				}, true
  2283  			}
  2284  		}
  2285  
  2286  		if p.isMangledProp(name.String) {
  2287  			key = js_ast.Expr{Loc: nameRange.Loc, Data: &js_ast.ENameOfSymbol{Ref: p.storeNameInRef(name)}}
  2288  		} else {
  2289  			key = js_ast.Expr{Loc: nameRange.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(name.String)}}
  2290  		}
  2291  
  2292  		// Parse a shorthand property
  2293  		if !opts.isClass && kind == js_ast.PropertyField && p.lexer.Token != js_lexer.TColon &&
  2294  			p.lexer.Token != js_lexer.TOpenParen && p.lexer.Token != js_lexer.TLessThan &&
  2295  			js_lexer.Keywords[name.String] == js_lexer.T(0) {
  2296  
  2297  			// Forbid invalid identifiers
  2298  			if (p.fnOrArrowDataParse.await != allowIdent && name.String == "await") ||
  2299  				(p.fnOrArrowDataParse.yield != allowIdent && name.String == "yield") {
  2300  				p.log.AddError(&p.tracker, nameRange, fmt.Sprintf("Cannot use %q as an identifier here:", name.String))
  2301  			}
  2302  
  2303  			ref := p.storeNameInRef(name)
  2304  			value := js_ast.Expr{Loc: key.Loc, Data: &js_ast.EIdentifier{Ref: ref}}
  2305  
  2306  			// Destructuring patterns have an optional default value
  2307  			var initializerOrNil js_ast.Expr
  2308  			if errors != nil && p.lexer.Token == js_lexer.TEquals {
  2309  				errors.invalidExprDefaultValue = p.lexer.Range()
  2310  				p.lexer.Next()
  2311  				initializerOrNil = p.parseExpr(js_ast.LComma)
  2312  			}
  2313  
  2314  			return js_ast.Property{
  2315  				Kind:             kind,
  2316  				Loc:              startLoc,
  2317  				Key:              key,
  2318  				ValueOrNil:       value,
  2319  				InitializerOrNil: initializerOrNil,
  2320  				Flags:            js_ast.PropertyWasShorthand,
  2321  			}, true
  2322  		}
  2323  	}
  2324  
  2325  	hasTypeParameters := false
  2326  	hasDefiniteAssignmentAssertionOperator := false
  2327  
  2328  	if p.options.ts.Parse {
  2329  		if opts.isClass {
  2330  			if p.lexer.Token == js_lexer.TQuestion {
  2331  				// "class X { foo?: number }"
  2332  				// "class X { foo?(): number }"
  2333  				p.lexer.Next()
  2334  			} else if p.lexer.Token == js_lexer.TExclamation && !p.lexer.HasNewlineBefore &&
  2335  				(kind == js_ast.PropertyField || kind == js_ast.PropertyAutoAccessor) {
  2336  				// "class X { foo!: number }"
  2337  				p.lexer.Next()
  2338  				hasDefiniteAssignmentAssertionOperator = true
  2339  			}
  2340  		}
  2341  
  2342  		// "class X { foo?<T>(): T }"
  2343  		// "const x = { foo<T>(): T {} }"
  2344  		if !hasDefiniteAssignmentAssertionOperator && kind != js_ast.PropertyAutoAccessor {
  2345  			hasTypeParameters = p.skipTypeScriptTypeParameters(allowConstModifier) != didNotSkipAnything
  2346  		}
  2347  	}
  2348  
  2349  	// Parse a class field with an optional initial value
  2350  	if kind == js_ast.PropertyAutoAccessor || (opts.isClass && kind == js_ast.PropertyField &&
  2351  		!hasTypeParameters && (p.lexer.Token != js_lexer.TOpenParen || hasDefiniteAssignmentAssertionOperator)) {
  2352  		var initializerOrNil js_ast.Expr
  2353  
  2354  		// Forbid the names "constructor" and "prototype" in some cases
  2355  		if !flags.Has(js_ast.PropertyIsComputed) {
  2356  			if str, ok := key.Data.(*js_ast.EString); ok && (helpers.UTF16EqualsString(str.Value, "constructor") ||
  2357  				(opts.isStatic && helpers.UTF16EqualsString(str.Value, "prototype"))) {
  2358  				p.log.AddError(&p.tracker, keyRange, fmt.Sprintf("Invalid field name %q", helpers.UTF16ToString(str.Value)))
  2359  			}
  2360  		}
  2361  
  2362  		// Skip over types
  2363  		if p.options.ts.Parse && p.lexer.Token == js_lexer.TColon {
  2364  			p.lexer.Next()
  2365  			p.skipTypeScriptType(js_ast.LLowest)
  2366  		}
  2367  
  2368  		if p.lexer.Token == js_lexer.TEquals {
  2369  			p.lexer.Next()
  2370  
  2371  			// "this" and "super" property access is allowed in field initializers
  2372  			oldIsThisDisallowed := p.fnOrArrowDataParse.isThisDisallowed
  2373  			oldAllowSuperProperty := p.fnOrArrowDataParse.allowSuperProperty
  2374  			p.fnOrArrowDataParse.isThisDisallowed = false
  2375  			p.fnOrArrowDataParse.allowSuperProperty = true
  2376  
  2377  			initializerOrNil = p.parseExpr(js_ast.LComma)
  2378  
  2379  			p.fnOrArrowDataParse.isThisDisallowed = oldIsThisDisallowed
  2380  			p.fnOrArrowDataParse.allowSuperProperty = oldAllowSuperProperty
  2381  		}
  2382  
  2383  		// Special-case private identifiers
  2384  		if private, ok := key.Data.(*js_ast.EPrivateIdentifier); ok {
  2385  			name := p.loadNameFromRef(private.Ref)
  2386  			if name == "#constructor" {
  2387  				p.log.AddError(&p.tracker, keyRange, fmt.Sprintf("Invalid field name %q", name))
  2388  			}
  2389  			var declare ast.SymbolKind
  2390  			if kind == js_ast.PropertyAutoAccessor {
  2391  				if opts.isStatic {
  2392  					declare = ast.SymbolPrivateStaticGetSetPair
  2393  				} else {
  2394  					declare = ast.SymbolPrivateGetSetPair
  2395  				}
  2396  				private.Ref = p.declareSymbol(declare, key.Loc, name)
  2397  				p.privateGetters[private.Ref] = p.newSymbol(ast.SymbolOther, name[1:]+"_get")
  2398  				p.privateSetters[private.Ref] = p.newSymbol(ast.SymbolOther, name[1:]+"_set")
  2399  			} else {
  2400  				if opts.isStatic {
  2401  					declare = ast.SymbolPrivateStaticField
  2402  				} else {
  2403  					declare = ast.SymbolPrivateField
  2404  				}
  2405  				private.Ref = p.declareSymbol(declare, key.Loc, name)
  2406  			}
  2407  		}
  2408  
  2409  		p.lexer.ExpectOrInsertSemicolon()
  2410  		if opts.isStatic {
  2411  			flags |= js_ast.PropertyIsStatic
  2412  		}
  2413  		return js_ast.Property{
  2414  			Decorators:       opts.decorators,
  2415  			Loc:              startLoc,
  2416  			Kind:             kind,
  2417  			Flags:            flags,
  2418  			Key:              key,
  2419  			InitializerOrNil: initializerOrNil,
  2420  			CloseBracketLoc:  closeBracketLoc,
  2421  		}, true
  2422  	}
  2423  
  2424  	// Parse a method expression
  2425  	if p.lexer.Token == js_lexer.TOpenParen || kind.IsMethodDefinition() || opts.isClass {
  2426  		hasError := false
  2427  
  2428  		if !hasError && opts.tsDeclareRange.Len != 0 {
  2429  			what := "method"
  2430  			if kind == js_ast.PropertyGetter {
  2431  				what = "getter"
  2432  			} else if kind == js_ast.PropertySetter {
  2433  				what = "setter"
  2434  			}
  2435  			p.log.AddError(&p.tracker, opts.tsDeclareRange, "\"declare\" cannot be used with a "+what)
  2436  			hasError = true
  2437  		}
  2438  
  2439  		if opts.isAsync && p.markAsyncFn(opts.asyncRange, opts.isGenerator) {
  2440  			hasError = true
  2441  		}
  2442  
  2443  		if !hasError && opts.isGenerator && p.markSyntaxFeature(compat.Generator, opts.generatorRange) {
  2444  			hasError = true
  2445  		}
  2446  
  2447  		if !hasError && p.lexer.Token == js_lexer.TOpenParen && kind != js_ast.PropertyGetter && kind != js_ast.PropertySetter && p.markSyntaxFeature(compat.ObjectExtensions, p.lexer.Range()) {
  2448  			hasError = true
  2449  		}
  2450  
  2451  		loc := p.lexer.Loc()
  2452  		scopeIndex := p.pushScopeForParsePass(js_ast.ScopeFunctionArgs, loc)
  2453  		isConstructor := false
  2454  
  2455  		// Forbid the names "constructor" and "prototype" in some cases
  2456  		if opts.isClass && !flags.Has(js_ast.PropertyIsComputed) {
  2457  			if str, ok := key.Data.(*js_ast.EString); ok {
  2458  				if !opts.isStatic && helpers.UTF16EqualsString(str.Value, "constructor") {
  2459  					switch {
  2460  					case kind == js_ast.PropertyGetter:
  2461  						p.log.AddError(&p.tracker, keyRange, "Class constructor cannot be a getter")
  2462  					case kind == js_ast.PropertySetter:
  2463  						p.log.AddError(&p.tracker, keyRange, "Class constructor cannot be a setter")
  2464  					case opts.isAsync:
  2465  						p.log.AddError(&p.tracker, keyRange, "Class constructor cannot be an async function")
  2466  					case opts.isGenerator:
  2467  						p.log.AddError(&p.tracker, keyRange, "Class constructor cannot be a generator")
  2468  					default:
  2469  						isConstructor = true
  2470  					}
  2471  				} else if opts.isStatic && helpers.UTF16EqualsString(str.Value, "prototype") {
  2472  					p.log.AddError(&p.tracker, keyRange, "Invalid static method name \"prototype\"")
  2473  				}
  2474  			}
  2475  		}
  2476  
  2477  		await := allowIdent
  2478  		yield := allowIdent
  2479  		if opts.isAsync {
  2480  			await = allowExpr
  2481  		}
  2482  		if opts.isGenerator {
  2483  			yield = allowExpr
  2484  		}
  2485  
  2486  		fn, hadBody := p.parseFn(nil, opts.classKeyword, opts.decoratorContext, fnOrArrowDataParse{
  2487  			needsAsyncLoc:      key.Loc,
  2488  			asyncRange:         opts.asyncRange,
  2489  			await:              await,
  2490  			yield:              yield,
  2491  			allowSuperCall:     opts.classHasExtends && isConstructor,
  2492  			allowSuperProperty: true,
  2493  			decoratorScope:     opts.decoratorScope,
  2494  			isConstructor:      isConstructor,
  2495  
  2496  			// Only allow omitting the body if we're parsing TypeScript class
  2497  			allowMissingBodyForTypeScript: p.options.ts.Parse && opts.isClass,
  2498  		})
  2499  
  2500  		// "class Foo { foo(): void; foo(): void {} }"
  2501  		if !hadBody {
  2502  			// Skip this property entirely
  2503  			p.popAndDiscardScope(scopeIndex)
  2504  			return js_ast.Property{}, false
  2505  		}
  2506  
  2507  		p.popScope()
  2508  		fn.IsUniqueFormalParameters = true
  2509  		value := js_ast.Expr{Loc: loc, Data: &js_ast.EFunction{Fn: fn}}
  2510  
  2511  		// Enforce argument rules for accessors
  2512  		switch kind {
  2513  		case js_ast.PropertyGetter:
  2514  			if len(fn.Args) > 0 {
  2515  				r := js_lexer.RangeOfIdentifier(p.source, fn.Args[0].Binding.Loc)
  2516  				p.log.AddError(&p.tracker, r, fmt.Sprintf("Getter %s must have zero arguments", p.keyNameForError(key)))
  2517  			}
  2518  
  2519  		case js_ast.PropertySetter:
  2520  			if len(fn.Args) != 1 {
  2521  				r := js_lexer.RangeOfIdentifier(p.source, key.Loc)
  2522  				if len(fn.Args) > 1 {
  2523  					r = js_lexer.RangeOfIdentifier(p.source, fn.Args[1].Binding.Loc)
  2524  				}
  2525  				p.log.AddError(&p.tracker, r, fmt.Sprintf("Setter %s must have exactly one argument", p.keyNameForError(key)))
  2526  			}
  2527  
  2528  		default:
  2529  			kind = js_ast.PropertyMethod
  2530  		}
  2531  
  2532  		// Special-case private identifiers
  2533  		if private, ok := key.Data.(*js_ast.EPrivateIdentifier); ok {
  2534  			var declare ast.SymbolKind
  2535  			var suffix string
  2536  			switch kind {
  2537  			case js_ast.PropertyGetter:
  2538  				if opts.isStatic {
  2539  					declare = ast.SymbolPrivateStaticGet
  2540  				} else {
  2541  					declare = ast.SymbolPrivateGet
  2542  				}
  2543  				suffix = "_get"
  2544  			case js_ast.PropertySetter:
  2545  				if opts.isStatic {
  2546  					declare = ast.SymbolPrivateStaticSet
  2547  				} else {
  2548  					declare = ast.SymbolPrivateSet
  2549  				}
  2550  				suffix = "_set"
  2551  			default:
  2552  				if opts.isStatic {
  2553  					declare = ast.SymbolPrivateStaticMethod
  2554  				} else {
  2555  					declare = ast.SymbolPrivateMethod
  2556  				}
  2557  				suffix = "_fn"
  2558  			}
  2559  			name := p.loadNameFromRef(private.Ref)
  2560  			if name == "#constructor" {
  2561  				p.log.AddError(&p.tracker, keyRange, fmt.Sprintf("Invalid method name %q", name))
  2562  			}
  2563  			private.Ref = p.declareSymbol(declare, key.Loc, name)
  2564  			methodRef := p.newSymbol(ast.SymbolOther, name[1:]+suffix)
  2565  			if kind == js_ast.PropertySetter {
  2566  				p.privateSetters[private.Ref] = methodRef
  2567  			} else {
  2568  				p.privateGetters[private.Ref] = methodRef
  2569  			}
  2570  		}
  2571  
  2572  		if opts.isStatic {
  2573  			flags |= js_ast.PropertyIsStatic
  2574  		}
  2575  		return js_ast.Property{
  2576  			Decorators:      opts.decorators,
  2577  			Loc:             startLoc,
  2578  			Kind:            kind,
  2579  			Flags:           flags,
  2580  			Key:             key,
  2581  			ValueOrNil:      value,
  2582  			CloseBracketLoc: closeBracketLoc,
  2583  		}, true
  2584  	}
  2585  
  2586  	// Parse an object key/value pair
  2587  	p.lexer.Expect(js_lexer.TColon)
  2588  	value := p.parseExprOrBindings(js_ast.LComma, errors)
  2589  	return js_ast.Property{
  2590  		Loc:             startLoc,
  2591  		Kind:            kind,
  2592  		Flags:           flags,
  2593  		Key:             key,
  2594  		ValueOrNil:      value,
  2595  		CloseBracketLoc: closeBracketLoc,
  2596  	}, true
  2597  }
  2598  
  2599  func (p *parser) parsePropertyBinding() js_ast.PropertyBinding {
  2600  	var key js_ast.Expr
  2601  	var closeBracketLoc logger.Loc
  2602  	isComputed := false
  2603  	preferQuotedKey := false
  2604  	loc := p.lexer.Loc()
  2605  
  2606  	switch p.lexer.Token {
  2607  	case js_lexer.TDotDotDot:
  2608  		p.lexer.Next()
  2609  		value := js_ast.Binding{Loc: p.saveExprCommentsHere(), Data: &js_ast.BIdentifier{Ref: p.storeNameInRef(p.lexer.Identifier)}}
  2610  		p.lexer.Expect(js_lexer.TIdentifier)
  2611  		return js_ast.PropertyBinding{
  2612  			Loc:      loc,
  2613  			IsSpread: true,
  2614  			Value:    value,
  2615  		}
  2616  
  2617  	case js_lexer.TNumericLiteral:
  2618  		key = js_ast.Expr{Loc: p.lexer.Loc(), Data: &js_ast.ENumber{Value: p.lexer.Number}}
  2619  		p.checkForLegacyOctalLiteral(key.Data)
  2620  		p.lexer.Next()
  2621  
  2622  	case js_lexer.TStringLiteral:
  2623  		key = p.parseStringLiteral()
  2624  		preferQuotedKey = !p.options.minifySyntax
  2625  
  2626  	case js_lexer.TBigIntegerLiteral:
  2627  		key = js_ast.Expr{Loc: p.lexer.Loc(), Data: &js_ast.EBigInt{Value: p.lexer.Identifier.String}}
  2628  		p.markSyntaxFeature(compat.Bigint, p.lexer.Range())
  2629  		p.lexer.Next()
  2630  
  2631  	case js_lexer.TOpenBracket:
  2632  		isComputed = true
  2633  		p.lexer.Next()
  2634  		key = p.parseExpr(js_ast.LComma)
  2635  		closeBracketLoc = p.saveExprCommentsHere()
  2636  		p.lexer.Expect(js_lexer.TCloseBracket)
  2637  
  2638  	default:
  2639  		name := p.lexer.Identifier
  2640  		nameRange := p.lexer.Range()
  2641  		if !p.lexer.IsIdentifierOrKeyword() {
  2642  			p.lexer.Expect(js_lexer.TIdentifier)
  2643  		}
  2644  		p.lexer.Next()
  2645  		if p.isMangledProp(name.String) {
  2646  			key = js_ast.Expr{Loc: nameRange.Loc, Data: &js_ast.ENameOfSymbol{Ref: p.storeNameInRef(name)}}
  2647  		} else {
  2648  			key = js_ast.Expr{Loc: nameRange.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(name.String)}}
  2649  		}
  2650  
  2651  		if p.lexer.Token != js_lexer.TColon && p.lexer.Token != js_lexer.TOpenParen {
  2652  			// Forbid invalid identifiers
  2653  			if (p.fnOrArrowDataParse.await != allowIdent && name.String == "await") ||
  2654  				(p.fnOrArrowDataParse.yield != allowIdent && name.String == "yield") {
  2655  				p.log.AddError(&p.tracker, nameRange, fmt.Sprintf("Cannot use %q as an identifier here:", name.String))
  2656  			}
  2657  
  2658  			ref := p.storeNameInRef(name)
  2659  			value := js_ast.Binding{Loc: nameRange.Loc, Data: &js_ast.BIdentifier{Ref: ref}}
  2660  
  2661  			var defaultValueOrNil js_ast.Expr
  2662  			if p.lexer.Token == js_lexer.TEquals {
  2663  				p.lexer.Next()
  2664  				defaultValueOrNil = p.parseExpr(js_ast.LComma)
  2665  			}
  2666  
  2667  			return js_ast.PropertyBinding{
  2668  				Loc:               loc,
  2669  				Key:               key,
  2670  				Value:             value,
  2671  				DefaultValueOrNil: defaultValueOrNil,
  2672  			}
  2673  		}
  2674  	}
  2675  
  2676  	p.lexer.Expect(js_lexer.TColon)
  2677  	value := p.parseBinding(parseBindingOpts{})
  2678  
  2679  	var defaultValueOrNil js_ast.Expr
  2680  	if p.lexer.Token == js_lexer.TEquals {
  2681  		p.lexer.Next()
  2682  		defaultValueOrNil = p.parseExpr(js_ast.LComma)
  2683  	}
  2684  
  2685  	return js_ast.PropertyBinding{
  2686  		Loc:               loc,
  2687  		IsComputed:        isComputed,
  2688  		PreferQuotedKey:   preferQuotedKey,
  2689  		Key:               key,
  2690  		Value:             value,
  2691  		DefaultValueOrNil: defaultValueOrNil,
  2692  		CloseBracketLoc:   closeBracketLoc,
  2693  	}
  2694  }
  2695  
  2696  // These properties have special semantics in JavaScript. They must not be
  2697  // mangled or we could potentially fail to parse valid JavaScript syntax or
  2698  // generate invalid JavaScript syntax as output.
  2699  //
  2700  // This list is only intended to contain properties specific to the JavaScript
  2701  // language itself to avoid syntax errors in the generated output. It's not
  2702  // intended to contain properties for JavaScript APIs. Those must be provided
  2703  // by the user.
  2704  var permanentReservedProps = map[string]bool{
  2705  	"__proto__":   true,
  2706  	"constructor": true,
  2707  	"prototype":   true,
  2708  }
  2709  
  2710  func (p *parser) isMangledProp(name string) bool {
  2711  	if p.options.mangleProps == nil {
  2712  		return false
  2713  	}
  2714  	if p.options.mangleProps.MatchString(name) && !permanentReservedProps[name] && (p.options.reserveProps == nil || !p.options.reserveProps.MatchString(name)) {
  2715  		return true
  2716  	}
  2717  	reservedProps := p.reservedProps
  2718  	if reservedProps == nil {
  2719  		reservedProps = make(map[string]bool)
  2720  		p.reservedProps = reservedProps
  2721  	}
  2722  	reservedProps[name] = true
  2723  	return false
  2724  }
  2725  
  2726  func (p *parser) symbolForMangledProp(name string) ast.Ref {
  2727  	mangledProps := p.mangledProps
  2728  	if mangledProps == nil {
  2729  		mangledProps = make(map[string]ast.Ref)
  2730  		p.mangledProps = mangledProps
  2731  	}
  2732  	ref, ok := mangledProps[name]
  2733  	if !ok {
  2734  		ref = p.newSymbol(ast.SymbolMangledProp, name)
  2735  		mangledProps[name] = ref
  2736  	}
  2737  	if !p.isControlFlowDead {
  2738  		p.symbols[ref.InnerIndex].UseCountEstimate++
  2739  	}
  2740  	return ref
  2741  }
  2742  
  2743  type wasOriginallyDotOrIndex uint8
  2744  
  2745  const (
  2746  	wasOriginallyDot wasOriginallyDotOrIndex = iota
  2747  	wasOriginallyIndex
  2748  )
  2749  
  2750  func (p *parser) dotOrMangledPropParse(
  2751  	target js_ast.Expr,
  2752  	name js_lexer.MaybeSubstring,
  2753  	nameLoc logger.Loc,
  2754  	optionalChain js_ast.OptionalChain,
  2755  	original wasOriginallyDotOrIndex,
  2756  ) js_ast.E {
  2757  	if (original != wasOriginallyIndex || p.options.mangleQuoted) && p.isMangledProp(name.String) {
  2758  		return &js_ast.EIndex{
  2759  			Target:        target,
  2760  			Index:         js_ast.Expr{Loc: nameLoc, Data: &js_ast.ENameOfSymbol{Ref: p.storeNameInRef(name)}},
  2761  			OptionalChain: optionalChain,
  2762  		}
  2763  	}
  2764  
  2765  	return &js_ast.EDot{
  2766  		Target:        target,
  2767  		Name:          name.String,
  2768  		NameLoc:       nameLoc,
  2769  		OptionalChain: optionalChain,
  2770  	}
  2771  }
  2772  
  2773  func (p *parser) dotOrMangledPropVisit(target js_ast.Expr, name string, nameLoc logger.Loc) js_ast.E {
  2774  	if p.isMangledProp(name) {
  2775  		return &js_ast.EIndex{
  2776  			Target: target,
  2777  			Index:  js_ast.Expr{Loc: nameLoc, Data: &js_ast.ENameOfSymbol{Ref: p.symbolForMangledProp(name)}},
  2778  		}
  2779  	}
  2780  
  2781  	return &js_ast.EDot{
  2782  		Target:  target,
  2783  		Name:    name,
  2784  		NameLoc: nameLoc,
  2785  	}
  2786  }
  2787  
  2788  func (p *parser) parseArrowBody(args []js_ast.Arg, data fnOrArrowDataParse) *js_ast.EArrow {
  2789  	arrowLoc := p.lexer.Loc()
  2790  
  2791  	// Newlines are not allowed before "=>"
  2792  	if p.lexer.HasNewlineBefore {
  2793  		p.log.AddError(&p.tracker, p.lexer.Range(), "Unexpected newline before \"=>\"")
  2794  		panic(js_lexer.LexerPanic{})
  2795  	}
  2796  
  2797  	p.lexer.Expect(js_lexer.TEqualsGreaterThan)
  2798  
  2799  	for _, arg := range args {
  2800  		p.declareBinding(ast.SymbolHoisted, arg.Binding, parseStmtOpts{})
  2801  	}
  2802  
  2803  	// The ability to use "this" and "super" is inherited by arrow functions
  2804  	data.isThisDisallowed = p.fnOrArrowDataParse.isThisDisallowed
  2805  	data.allowSuperCall = p.fnOrArrowDataParse.allowSuperCall
  2806  	data.allowSuperProperty = p.fnOrArrowDataParse.allowSuperProperty
  2807  
  2808  	if p.lexer.Token == js_lexer.TOpenBrace {
  2809  		body := p.parseFnBody(data)
  2810  		p.afterArrowBodyLoc = p.lexer.Loc()
  2811  		return &js_ast.EArrow{Args: args, Body: body}
  2812  	}
  2813  
  2814  	p.pushScopeForParsePass(js_ast.ScopeFunctionBody, arrowLoc)
  2815  	defer p.popScope()
  2816  
  2817  	oldFnOrArrowData := p.fnOrArrowDataParse
  2818  	p.fnOrArrowDataParse = data
  2819  	expr := p.parseExpr(js_ast.LComma)
  2820  	p.fnOrArrowDataParse = oldFnOrArrowData
  2821  	return &js_ast.EArrow{
  2822  		Args:       args,
  2823  		PreferExpr: true,
  2824  		Body:       js_ast.FnBody{Loc: arrowLoc, Block: js_ast.SBlock{Stmts: []js_ast.Stmt{{Loc: expr.Loc, Data: &js_ast.SReturn{ValueOrNil: expr}}}}},
  2825  	}
  2826  }
  2827  
  2828  func (p *parser) checkForArrowAfterTheCurrentToken() bool {
  2829  	oldLexer := p.lexer
  2830  	p.lexer.IsLogDisabled = true
  2831  
  2832  	// Implement backtracking by restoring the lexer's memory to its original state
  2833  	defer func() {
  2834  		r := recover()
  2835  		if _, isLexerPanic := r.(js_lexer.LexerPanic); isLexerPanic {
  2836  			p.lexer = oldLexer
  2837  		} else if r != nil {
  2838  			panic(r)
  2839  		}
  2840  	}()
  2841  
  2842  	p.lexer.Next()
  2843  	isArrowAfterThisToken := p.lexer.Token == js_lexer.TEqualsGreaterThan
  2844  
  2845  	p.lexer = oldLexer
  2846  	return isArrowAfterThisToken
  2847  }
  2848  
  2849  // This parses an expression. This assumes we've already parsed the "async"
  2850  // keyword and are currently looking at the following token.
  2851  func (p *parser) parseAsyncPrefixExpr(asyncRange logger.Range, level js_ast.L, flags exprFlag) js_ast.Expr {
  2852  	// "async function() {}"
  2853  	if !p.lexer.HasNewlineBefore && p.lexer.Token == js_lexer.TFunction {
  2854  		return p.parseFnExpr(asyncRange.Loc, true /* isAsync */, asyncRange)
  2855  	}
  2856  
  2857  	// Check the precedence level to avoid parsing an arrow function in
  2858  	// "new async () => {}". This also avoids parsing "new async()" as
  2859  	// "new (async())()" instead.
  2860  	if !p.lexer.HasNewlineBefore && level < js_ast.LMember {
  2861  		switch p.lexer.Token {
  2862  		// "async => {}"
  2863  		case js_lexer.TEqualsGreaterThan:
  2864  			if level <= js_ast.LAssign {
  2865  				arg := js_ast.Arg{Binding: js_ast.Binding{Loc: asyncRange.Loc, Data: &js_ast.BIdentifier{
  2866  					Ref: p.storeNameInRef(js_lexer.MaybeSubstring{String: "async"})}}}
  2867  
  2868  				p.pushScopeForParsePass(js_ast.ScopeFunctionArgs, asyncRange.Loc)
  2869  				defer p.popScope()
  2870  
  2871  				return js_ast.Expr{Loc: asyncRange.Loc, Data: p.parseArrowBody([]js_ast.Arg{arg}, fnOrArrowDataParse{
  2872  					needsAsyncLoc: asyncRange.Loc,
  2873  				})}
  2874  			}
  2875  
  2876  		// "async x => {}"
  2877  		case js_lexer.TIdentifier:
  2878  			if level <= js_ast.LAssign {
  2879  				// See https://github.com/tc39/ecma262/issues/2034 for details
  2880  				isArrowFn := true
  2881  				if (flags&exprFlagForLoopInit) != 0 && p.lexer.Identifier.String == "of" {
  2882  					// "for (async of" is only an arrow function if the next token is "=>"
  2883  					isArrowFn = p.checkForArrowAfterTheCurrentToken()
  2884  
  2885  					// Do not allow "for (async of []) ;" but do allow "for await (async of []) ;"
  2886  					if !isArrowFn && (flags&exprFlagForAwaitLoopInit) == 0 && p.lexer.Raw() == "of" {
  2887  						r := logger.Range{Loc: asyncRange.Loc, Len: p.lexer.Range().End() - asyncRange.Loc.Start}
  2888  						p.log.AddError(&p.tracker, r, "For loop initializers cannot start with \"async of\"")
  2889  						panic(js_lexer.LexerPanic{})
  2890  					}
  2891  				}
  2892  
  2893  				if isArrowFn {
  2894  					p.markAsyncFn(asyncRange, false)
  2895  					ref := p.storeNameInRef(p.lexer.Identifier)
  2896  					arg := js_ast.Arg{Binding: js_ast.Binding{Loc: p.lexer.Loc(), Data: &js_ast.BIdentifier{Ref: ref}}}
  2897  					p.lexer.Next()
  2898  
  2899  					p.pushScopeForParsePass(js_ast.ScopeFunctionArgs, asyncRange.Loc)
  2900  					defer p.popScope()
  2901  
  2902  					arrow := p.parseArrowBody([]js_ast.Arg{arg}, fnOrArrowDataParse{
  2903  						needsAsyncLoc: arg.Binding.Loc,
  2904  						await:         allowExpr,
  2905  					})
  2906  					arrow.IsAsync = true
  2907  					return js_ast.Expr{Loc: asyncRange.Loc, Data: arrow}
  2908  				}
  2909  			}
  2910  
  2911  		// "async()"
  2912  		// "async () => {}"
  2913  		case js_lexer.TOpenParen:
  2914  			p.lexer.Next()
  2915  			return p.parseParenExpr(asyncRange.Loc, level, parenExprOpts{asyncRange: asyncRange})
  2916  
  2917  		// "async<T>()"
  2918  		// "async <T>() => {}"
  2919  		case js_lexer.TLessThan:
  2920  			if p.options.ts.Parse && (!p.options.jsx.Parse || p.isTSArrowFnJSX()) {
  2921  				if result := p.trySkipTypeScriptTypeParametersThenOpenParenWithBacktracking(); result != didNotSkipAnything {
  2922  					p.lexer.Next()
  2923  					return p.parseParenExpr(asyncRange.Loc, level, parenExprOpts{
  2924  						asyncRange:   asyncRange,
  2925  						forceArrowFn: result == definitelyTypeParameters,
  2926  					})
  2927  				}
  2928  			}
  2929  		}
  2930  	}
  2931  
  2932  	// "async"
  2933  	// "async + 1"
  2934  	return js_ast.Expr{Loc: asyncRange.Loc, Data: &js_ast.EIdentifier{
  2935  		Ref: p.storeNameInRef(js_lexer.MaybeSubstring{String: "async"})}}
  2936  }
  2937  
  2938  func (p *parser) parseFnExpr(loc logger.Loc, isAsync bool, asyncRange logger.Range) js_ast.Expr {
  2939  	p.lexer.Next()
  2940  	isGenerator := p.lexer.Token == js_lexer.TAsterisk
  2941  	hasError := false
  2942  	if isAsync {
  2943  		hasError = p.markAsyncFn(asyncRange, isGenerator)
  2944  	}
  2945  	if isGenerator {
  2946  		if !hasError {
  2947  			p.markSyntaxFeature(compat.Generator, p.lexer.Range())
  2948  		}
  2949  		p.lexer.Next()
  2950  	}
  2951  	var name *ast.LocRef
  2952  
  2953  	p.pushScopeForParsePass(js_ast.ScopeFunctionArgs, loc)
  2954  	defer p.popScope()
  2955  
  2956  	// The name is optional
  2957  	if p.lexer.Token == js_lexer.TIdentifier {
  2958  		// Don't declare the name "arguments" since it's shadowed and inaccessible
  2959  		name = &ast.LocRef{Loc: p.lexer.Loc()}
  2960  		if text := p.lexer.Identifier.String; text != "arguments" {
  2961  			name.Ref = p.declareSymbol(ast.SymbolHoistedFunction, name.Loc, text)
  2962  		} else {
  2963  			name.Ref = p.newSymbol(ast.SymbolHoistedFunction, text)
  2964  		}
  2965  		p.lexer.Next()
  2966  	}
  2967  
  2968  	// Even anonymous functions can have TypeScript type parameters
  2969  	if p.options.ts.Parse {
  2970  		p.skipTypeScriptTypeParameters(allowConstModifier)
  2971  	}
  2972  
  2973  	await := allowIdent
  2974  	yield := allowIdent
  2975  	if isAsync {
  2976  		await = allowExpr
  2977  	}
  2978  	if isGenerator {
  2979  		yield = allowExpr
  2980  	}
  2981  
  2982  	fn, _ := p.parseFn(name, logger.Range{}, 0, fnOrArrowDataParse{
  2983  		needsAsyncLoc: loc,
  2984  		asyncRange:    asyncRange,
  2985  		await:         await,
  2986  		yield:         yield,
  2987  	})
  2988  	p.validateFunctionName(fn, fnExpr)
  2989  	return js_ast.Expr{Loc: loc, Data: &js_ast.EFunction{Fn: fn}}
  2990  }
  2991  
  2992  type parenExprOpts struct {
  2993  	asyncRange   logger.Range
  2994  	forceArrowFn bool
  2995  }
  2996  
  2997  // This assumes that the open parenthesis has already been parsed by the caller
  2998  func (p *parser) parseParenExpr(loc logger.Loc, level js_ast.L, opts parenExprOpts) js_ast.Expr {
  2999  	items := []js_ast.Expr{}
  3000  	errors := deferredErrors{}
  3001  	arrowArgErrors := deferredArrowArgErrors{}
  3002  	spreadRange := logger.Range{}
  3003  	typeColonRange := logger.Range{}
  3004  	commaAfterSpread := logger.Loc{}
  3005  	isAsync := opts.asyncRange.Len > 0
  3006  
  3007  	// Push a scope assuming this is an arrow function. It may not be, in which
  3008  	// case we'll need to roll this change back. This has to be done ahead of
  3009  	// parsing the arguments instead of later on when we hit the "=>" token and
  3010  	// we know it's an arrow function because the arguments may have default
  3011  	// values that introduce new scopes and declare new symbols. If this is an
  3012  	// arrow function, then those new scopes will need to be parented under the
  3013  	// scope of the arrow function itself.
  3014  	scopeIndex := p.pushScopeForParsePass(js_ast.ScopeFunctionArgs, loc)
  3015  
  3016  	// Allow "in" inside parentheses
  3017  	oldAllowIn := p.allowIn
  3018  	p.allowIn = true
  3019  
  3020  	// Forbid "await" and "yield", but only for arrow functions
  3021  	oldFnOrArrowData := p.fnOrArrowDataParse
  3022  	p.fnOrArrowDataParse.arrowArgErrors = &arrowArgErrors
  3023  
  3024  	// Scan over the comma-separated arguments or expressions
  3025  	for p.lexer.Token != js_lexer.TCloseParen {
  3026  		itemLoc := p.lexer.Loc()
  3027  		isSpread := p.lexer.Token == js_lexer.TDotDotDot
  3028  
  3029  		if isSpread {
  3030  			spreadRange = p.lexer.Range()
  3031  			p.markSyntaxFeature(compat.RestArgument, spreadRange)
  3032  			p.lexer.Next()
  3033  		}
  3034  
  3035  		// We don't know yet whether these are arguments or expressions, so parse
  3036  		// a superset of the expression syntax. Errors about things that are valid
  3037  		// in one but not in the other are deferred.
  3038  		p.latestArrowArgLoc = p.lexer.Loc()
  3039  		item := p.parseExprOrBindings(js_ast.LComma, &errors)
  3040  
  3041  		if isSpread {
  3042  			item = js_ast.Expr{Loc: itemLoc, Data: &js_ast.ESpread{Value: item}}
  3043  		}
  3044  
  3045  		// Skip over types
  3046  		if p.options.ts.Parse && p.lexer.Token == js_lexer.TColon {
  3047  			typeColonRange = p.lexer.Range()
  3048  			p.lexer.Next()
  3049  			p.skipTypeScriptType(js_ast.LLowest)
  3050  		}
  3051  
  3052  		// There may be a "=" after the type (but not after an "as" cast)
  3053  		if p.options.ts.Parse && p.lexer.Token == js_lexer.TEquals && p.lexer.Loc() != p.forbidSuffixAfterAsLoc {
  3054  			p.lexer.Next()
  3055  			item = js_ast.Assign(item, p.parseExpr(js_ast.LComma))
  3056  		}
  3057  
  3058  		items = append(items, item)
  3059  		if p.lexer.Token != js_lexer.TComma {
  3060  			break
  3061  		}
  3062  
  3063  		// Spread arguments must come last. If there's a spread argument followed
  3064  		// by a comma, throw an error if we use these expressions as bindings.
  3065  		if isSpread {
  3066  			commaAfterSpread = p.lexer.Loc()
  3067  		}
  3068  
  3069  		// Eat the comma token
  3070  		p.lexer.Next()
  3071  	}
  3072  
  3073  	// The parenthetical construct must end with a close parenthesis
  3074  	p.lexer.Expect(js_lexer.TCloseParen)
  3075  
  3076  	// Restore "in" operator status before we parse the arrow function body
  3077  	p.allowIn = oldAllowIn
  3078  
  3079  	// Also restore "await" and "yield" expression errors
  3080  	p.fnOrArrowDataParse = oldFnOrArrowData
  3081  
  3082  	// Are these arguments to an arrow function?
  3083  	if p.lexer.Token == js_lexer.TEqualsGreaterThan || opts.forceArrowFn || (p.options.ts.Parse && p.lexer.Token == js_lexer.TColon) {
  3084  		// Arrow functions are not allowed inside certain expressions
  3085  		if level > js_ast.LAssign {
  3086  			p.lexer.Unexpected()
  3087  		}
  3088  
  3089  		var invalidLog invalidLog
  3090  		args := []js_ast.Arg{}
  3091  
  3092  		if isAsync {
  3093  			p.markAsyncFn(opts.asyncRange, false)
  3094  		}
  3095  
  3096  		// First, try converting the expressions to bindings
  3097  		for _, item := range items {
  3098  			isSpread := false
  3099  			if spread, ok := item.Data.(*js_ast.ESpread); ok {
  3100  				item = spread.Value
  3101  				isSpread = true
  3102  			}
  3103  			binding, initializerOrNil, log := p.convertExprToBindingAndInitializer(item, invalidLog, isSpread)
  3104  			invalidLog = log
  3105  			args = append(args, js_ast.Arg{Binding: binding, DefaultOrNil: initializerOrNil})
  3106  		}
  3107  
  3108  		// Avoid parsing TypeScript code like "a ? (1 + 2) : (3 + 4)" as an arrow
  3109  		// function. The ":" after the ")" may be a return type annotation, so we
  3110  		// attempt to convert the expressions to bindings first before deciding
  3111  		// whether this is an arrow function, and only pick an arrow function if
  3112  		// there were no conversion errors.
  3113  		if p.lexer.Token == js_lexer.TEqualsGreaterThan || (len(invalidLog.invalidTokens) == 0 &&
  3114  			p.trySkipTypeScriptArrowReturnTypeWithBacktracking()) || opts.forceArrowFn {
  3115  			if commaAfterSpread.Start != 0 {
  3116  				p.log.AddError(&p.tracker, logger.Range{Loc: commaAfterSpread, Len: 1}, "Unexpected \",\" after rest pattern")
  3117  			}
  3118  			p.logArrowArgErrors(&arrowArgErrors)
  3119  			p.logDeferredArrowArgErrors(&errors)
  3120  
  3121  			// Now that we've decided we're an arrow function, report binding pattern
  3122  			// conversion errors
  3123  			if len(invalidLog.invalidTokens) > 0 {
  3124  				for _, token := range invalidLog.invalidTokens {
  3125  					p.log.AddError(&p.tracker, token, "Invalid binding pattern")
  3126  				}
  3127  				panic(js_lexer.LexerPanic{})
  3128  			}
  3129  
  3130  			// Also report syntax features used in bindings
  3131  			for _, entry := range invalidLog.syntaxFeatures {
  3132  				p.markSyntaxFeature(entry.feature, entry.token)
  3133  			}
  3134  
  3135  			await := allowIdent
  3136  			if isAsync {
  3137  				await = allowExpr
  3138  			}
  3139  
  3140  			arrow := p.parseArrowBody(args, fnOrArrowDataParse{
  3141  				needsAsyncLoc: loc,
  3142  				await:         await,
  3143  			})
  3144  			arrow.IsAsync = isAsync
  3145  			arrow.HasRestArg = spreadRange.Len > 0
  3146  			p.popScope()
  3147  			return js_ast.Expr{Loc: loc, Data: arrow}
  3148  		}
  3149  	}
  3150  
  3151  	// If we get here, it's not an arrow function so undo the pushing of the
  3152  	// scope we did earlier. This needs to flatten any child scopes into the
  3153  	// parent scope as if the scope was never pushed in the first place.
  3154  	p.popAndFlattenScope(scopeIndex)
  3155  
  3156  	// If this isn't an arrow function, then types aren't allowed
  3157  	if typeColonRange.Len > 0 {
  3158  		p.log.AddError(&p.tracker, typeColonRange, "Unexpected \":\"")
  3159  		panic(js_lexer.LexerPanic{})
  3160  	}
  3161  
  3162  	// Are these arguments for a call to a function named "async"?
  3163  	if isAsync {
  3164  		p.logExprErrors(&errors)
  3165  		async := js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{
  3166  			Ref: p.storeNameInRef(js_lexer.MaybeSubstring{String: "async"})}}
  3167  		return js_ast.Expr{Loc: loc, Data: &js_ast.ECall{
  3168  			Target: async,
  3169  			Args:   items,
  3170  		}}
  3171  	}
  3172  
  3173  	// Is this a chain of expressions and comma operators?
  3174  	if len(items) > 0 {
  3175  		p.logExprErrors(&errors)
  3176  		if spreadRange.Len > 0 {
  3177  			p.log.AddError(&p.tracker, spreadRange, "Unexpected \"...\"")
  3178  			panic(js_lexer.LexerPanic{})
  3179  		}
  3180  		value := js_ast.JoinAllWithComma(items)
  3181  		p.markExprAsParenthesized(value, loc, isAsync)
  3182  		return value
  3183  	}
  3184  
  3185  	// Indicate that we expected an arrow function
  3186  	p.lexer.Expected(js_lexer.TEqualsGreaterThan)
  3187  	return js_ast.Expr{}
  3188  }
  3189  
  3190  type invalidLog struct {
  3191  	invalidTokens  []logger.Range
  3192  	syntaxFeatures []syntaxFeature
  3193  }
  3194  
  3195  type syntaxFeature struct {
  3196  	feature compat.JSFeature
  3197  	token   logger.Range
  3198  }
  3199  
  3200  func (p *parser) convertExprToBindingAndInitializer(
  3201  	expr js_ast.Expr, invalidLog invalidLog, isSpread bool,
  3202  ) (js_ast.Binding, js_ast.Expr, invalidLog) {
  3203  	var initializerOrNil js_ast.Expr
  3204  	if assign, ok := expr.Data.(*js_ast.EBinary); ok && assign.Op == js_ast.BinOpAssign {
  3205  		initializerOrNil = assign.Right
  3206  		expr = assign.Left
  3207  	}
  3208  	binding, invalidLog := p.convertExprToBinding(expr, invalidLog)
  3209  	if initializerOrNil.Data != nil {
  3210  		equalsRange := p.source.RangeOfOperatorBefore(initializerOrNil.Loc, "=")
  3211  		if isSpread {
  3212  			p.log.AddError(&p.tracker, equalsRange, "A rest argument cannot have a default initializer")
  3213  		} else {
  3214  			invalidLog.syntaxFeatures = append(invalidLog.syntaxFeatures, syntaxFeature{
  3215  				feature: compat.DefaultArgument,
  3216  				token:   equalsRange,
  3217  			})
  3218  		}
  3219  	}
  3220  	return binding, initializerOrNil, invalidLog
  3221  }
  3222  
  3223  // Note: do not write to "p.log" in this function. Any errors due to conversion
  3224  // from expression to binding should be written to "invalidLog" instead. That
  3225  // way we can potentially keep this as an expression if it turns out it's not
  3226  // needed as a binding after all.
  3227  func (p *parser) convertExprToBinding(expr js_ast.Expr, invalidLog invalidLog) (js_ast.Binding, invalidLog) {
  3228  	switch e := expr.Data.(type) {
  3229  	case *js_ast.EMissing:
  3230  		return js_ast.Binding{Loc: expr.Loc, Data: js_ast.BMissingShared}, invalidLog
  3231  
  3232  	case *js_ast.EIdentifier:
  3233  		return js_ast.Binding{Loc: expr.Loc, Data: &js_ast.BIdentifier{Ref: e.Ref}}, invalidLog
  3234  
  3235  	case *js_ast.EArray:
  3236  		if e.CommaAfterSpread.Start != 0 {
  3237  			invalidLog.invalidTokens = append(invalidLog.invalidTokens, logger.Range{Loc: e.CommaAfterSpread, Len: 1})
  3238  		}
  3239  		invalidLog.syntaxFeatures = append(invalidLog.syntaxFeatures,
  3240  			syntaxFeature{feature: compat.Destructuring, token: p.source.RangeOfOperatorAfter(expr.Loc, "[")})
  3241  		items := []js_ast.ArrayBinding{}
  3242  		isSpread := false
  3243  		for _, item := range e.Items {
  3244  			if i, ok := item.Data.(*js_ast.ESpread); ok {
  3245  				isSpread = true
  3246  				item = i.Value
  3247  				if _, ok := item.Data.(*js_ast.EIdentifier); !ok {
  3248  					p.markSyntaxFeature(compat.NestedRestBinding, p.source.RangeOfOperatorAfter(item.Loc, "["))
  3249  				}
  3250  			}
  3251  			binding, initializerOrNil, log := p.convertExprToBindingAndInitializer(item, invalidLog, isSpread)
  3252  			invalidLog = log
  3253  			items = append(items, js_ast.ArrayBinding{
  3254  				Binding:           binding,
  3255  				DefaultValueOrNil: initializerOrNil,
  3256  				Loc:               item.Loc,
  3257  			})
  3258  		}
  3259  		return js_ast.Binding{Loc: expr.Loc, Data: &js_ast.BArray{
  3260  			Items:           items,
  3261  			HasSpread:       isSpread,
  3262  			IsSingleLine:    e.IsSingleLine,
  3263  			CloseBracketLoc: e.CloseBracketLoc,
  3264  		}}, invalidLog
  3265  
  3266  	case *js_ast.EObject:
  3267  		if e.CommaAfterSpread.Start != 0 {
  3268  			invalidLog.invalidTokens = append(invalidLog.invalidTokens, logger.Range{Loc: e.CommaAfterSpread, Len: 1})
  3269  		}
  3270  		invalidLog.syntaxFeatures = append(invalidLog.syntaxFeatures,
  3271  			syntaxFeature{feature: compat.Destructuring, token: p.source.RangeOfOperatorAfter(expr.Loc, "{")})
  3272  		properties := []js_ast.PropertyBinding{}
  3273  		for _, property := range e.Properties {
  3274  			if property.Kind.IsMethodDefinition() {
  3275  				invalidLog.invalidTokens = append(invalidLog.invalidTokens, js_lexer.RangeOfIdentifier(p.source, property.Key.Loc))
  3276  				continue
  3277  			}
  3278  			binding, initializerOrNil, log := p.convertExprToBindingAndInitializer(property.ValueOrNil, invalidLog, false)
  3279  			invalidLog = log
  3280  			if initializerOrNil.Data == nil {
  3281  				initializerOrNil = property.InitializerOrNil
  3282  			}
  3283  			properties = append(properties, js_ast.PropertyBinding{
  3284  				Loc:               property.Loc,
  3285  				IsSpread:          property.Kind == js_ast.PropertySpread,
  3286  				IsComputed:        property.Flags.Has(js_ast.PropertyIsComputed),
  3287  				Key:               property.Key,
  3288  				Value:             binding,
  3289  				DefaultValueOrNil: initializerOrNil,
  3290  			})
  3291  		}
  3292  		return js_ast.Binding{Loc: expr.Loc, Data: &js_ast.BObject{
  3293  			Properties:    properties,
  3294  			IsSingleLine:  e.IsSingleLine,
  3295  			CloseBraceLoc: e.CloseBraceLoc,
  3296  		}}, invalidLog
  3297  
  3298  	default:
  3299  		invalidLog.invalidTokens = append(invalidLog.invalidTokens, logger.Range{Loc: expr.Loc})
  3300  		return js_ast.Binding{}, invalidLog
  3301  	}
  3302  }
  3303  
  3304  func (p *parser) saveExprCommentsHere() logger.Loc {
  3305  	loc := p.lexer.Loc()
  3306  	if p.exprComments != nil && len(p.lexer.CommentsBeforeToken) > 0 {
  3307  		comments := make([]string, len(p.lexer.CommentsBeforeToken))
  3308  		for i, comment := range p.lexer.CommentsBeforeToken {
  3309  			comments[i] = p.source.CommentTextWithoutIndent(comment)
  3310  		}
  3311  		p.exprComments[loc] = comments
  3312  		p.lexer.CommentsBeforeToken = p.lexer.CommentsBeforeToken[0:]
  3313  	}
  3314  	return loc
  3315  }
  3316  
  3317  type exprFlag uint8
  3318  
  3319  const (
  3320  	exprFlagDecorator exprFlag = 1 << iota
  3321  	exprFlagForLoopInit
  3322  	exprFlagForAwaitLoopInit
  3323  )
  3324  
  3325  func (p *parser) parsePrefix(level js_ast.L, errors *deferredErrors, flags exprFlag) js_ast.Expr {
  3326  	loc := p.saveExprCommentsHere()
  3327  
  3328  	switch p.lexer.Token {
  3329  	case js_lexer.TSuper:
  3330  		superRange := p.lexer.Range()
  3331  		p.lexer.Next()
  3332  
  3333  		switch p.lexer.Token {
  3334  		case js_lexer.TOpenParen:
  3335  			if level < js_ast.LCall && p.fnOrArrowDataParse.allowSuperCall {
  3336  				return js_ast.Expr{Loc: loc, Data: js_ast.ESuperShared}
  3337  			}
  3338  
  3339  		case js_lexer.TDot, js_lexer.TOpenBracket:
  3340  			if p.fnOrArrowDataParse.allowSuperProperty {
  3341  				return js_ast.Expr{Loc: loc, Data: js_ast.ESuperShared}
  3342  			}
  3343  		}
  3344  
  3345  		p.log.AddError(&p.tracker, superRange, "Unexpected \"super\"")
  3346  		return js_ast.Expr{Loc: loc, Data: js_ast.ESuperShared}
  3347  
  3348  	case js_lexer.TOpenParen:
  3349  		if errors != nil {
  3350  			errors.invalidParens = append(errors.invalidParens, p.lexer.Range())
  3351  		}
  3352  
  3353  		p.lexer.Next()
  3354  
  3355  		// Arrow functions aren't allowed in the middle of expressions
  3356  		if level > js_ast.LAssign {
  3357  			// Allow "in" inside parentheses
  3358  			oldAllowIn := p.allowIn
  3359  			p.allowIn = true
  3360  
  3361  			value := p.parseExpr(js_ast.LLowest)
  3362  			p.markExprAsParenthesized(value, loc, false)
  3363  			p.lexer.Expect(js_lexer.TCloseParen)
  3364  
  3365  			p.allowIn = oldAllowIn
  3366  			return value
  3367  		}
  3368  
  3369  		value := p.parseParenExpr(loc, level, parenExprOpts{})
  3370  		return value
  3371  
  3372  	case js_lexer.TFalse:
  3373  		p.lexer.Next()
  3374  		return js_ast.Expr{Loc: loc, Data: &js_ast.EBoolean{Value: false}}
  3375  
  3376  	case js_lexer.TTrue:
  3377  		p.lexer.Next()
  3378  		return js_ast.Expr{Loc: loc, Data: &js_ast.EBoolean{Value: true}}
  3379  
  3380  	case js_lexer.TNull:
  3381  		p.lexer.Next()
  3382  		return js_ast.Expr{Loc: loc, Data: js_ast.ENullShared}
  3383  
  3384  	case js_lexer.TThis:
  3385  		if p.fnOrArrowDataParse.isThisDisallowed {
  3386  			p.log.AddError(&p.tracker, p.lexer.Range(), "Cannot use \"this\" here:")
  3387  		}
  3388  		p.lexer.Next()
  3389  		return js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}
  3390  
  3391  	case js_lexer.TPrivateIdentifier:
  3392  		if !p.allowPrivateIdentifiers || !p.allowIn || level >= js_ast.LCompare {
  3393  			p.lexer.Unexpected()
  3394  		}
  3395  
  3396  		name := p.lexer.Identifier
  3397  		p.lexer.Next()
  3398  
  3399  		// Check for "#foo in bar"
  3400  		if p.lexer.Token != js_lexer.TIn {
  3401  			p.lexer.Expected(js_lexer.TIn)
  3402  		}
  3403  
  3404  		// Make sure to lower all matching private names
  3405  		if p.options.unsupportedJSFeatures.Has(compat.ClassPrivateBrandCheck) {
  3406  			if p.lowerAllOfThesePrivateNames == nil {
  3407  				p.lowerAllOfThesePrivateNames = make(map[string]bool)
  3408  			}
  3409  			p.lowerAllOfThesePrivateNames[name.String] = true
  3410  		}
  3411  
  3412  		return js_ast.Expr{Loc: loc, Data: &js_ast.EPrivateIdentifier{Ref: p.storeNameInRef(name)}}
  3413  
  3414  	case js_lexer.TIdentifier:
  3415  		name := p.lexer.Identifier
  3416  		nameRange := p.lexer.Range()
  3417  		raw := p.lexer.Raw()
  3418  		p.lexer.Next()
  3419  
  3420  		// Handle async and await expressions
  3421  		switch name.String {
  3422  		case "async":
  3423  			if raw == "async" {
  3424  				return p.parseAsyncPrefixExpr(nameRange, level, flags)
  3425  			}
  3426  
  3427  		case "await":
  3428  			switch p.fnOrArrowDataParse.await {
  3429  			case forbidAll:
  3430  				p.log.AddError(&p.tracker, nameRange, "The keyword \"await\" cannot be used here:")
  3431  
  3432  			case allowExpr:
  3433  				if raw != "await" {
  3434  					p.log.AddError(&p.tracker, nameRange, "The keyword \"await\" cannot be escaped")
  3435  				} else {
  3436  					if p.fnOrArrowDataParse.isTopLevel {
  3437  						p.topLevelAwaitKeyword = nameRange
  3438  					}
  3439  					if p.fnOrArrowDataParse.arrowArgErrors != nil {
  3440  						p.fnOrArrowDataParse.arrowArgErrors.invalidExprAwait = nameRange
  3441  					}
  3442  					value := p.parseExpr(js_ast.LPrefix)
  3443  					if p.lexer.Token == js_lexer.TAsteriskAsterisk {
  3444  						p.lexer.Unexpected()
  3445  					}
  3446  					return js_ast.Expr{Loc: loc, Data: &js_ast.EAwait{Value: value}}
  3447  				}
  3448  
  3449  			case allowIdent:
  3450  				p.lexer.PrevTokenWasAwaitKeyword = true
  3451  				p.lexer.AwaitKeywordLoc = loc
  3452  				p.lexer.FnOrArrowStartLoc = p.fnOrArrowDataParse.needsAsyncLoc
  3453  			}
  3454  
  3455  		case "yield":
  3456  			switch p.fnOrArrowDataParse.yield {
  3457  			case forbidAll:
  3458  				p.log.AddError(&p.tracker, nameRange, "The keyword \"yield\" cannot be used here:")
  3459  
  3460  			case allowExpr:
  3461  				if raw != "yield" {
  3462  					p.log.AddError(&p.tracker, nameRange, "The keyword \"yield\" cannot be escaped")
  3463  				} else {
  3464  					if level > js_ast.LAssign {
  3465  						p.log.AddError(&p.tracker, nameRange, "Cannot use a \"yield\" expression here without parentheses:")
  3466  					}
  3467  					if p.fnOrArrowDataParse.arrowArgErrors != nil {
  3468  						p.fnOrArrowDataParse.arrowArgErrors.invalidExprYield = nameRange
  3469  					}
  3470  					return p.parseYieldExpr(loc)
  3471  				}
  3472  
  3473  			case allowIdent:
  3474  				if !p.lexer.HasNewlineBefore {
  3475  					// Try to gracefully recover if "yield" is used in the wrong place
  3476  					switch p.lexer.Token {
  3477  					case js_lexer.TNull, js_lexer.TIdentifier, js_lexer.TFalse, js_lexer.TTrue,
  3478  						js_lexer.TNumericLiteral, js_lexer.TBigIntegerLiteral, js_lexer.TStringLiteral:
  3479  						p.log.AddError(&p.tracker, nameRange, "Cannot use \"yield\" outside a generator function")
  3480  						return p.parseYieldExpr(loc)
  3481  					}
  3482  				}
  3483  			}
  3484  		}
  3485  
  3486  		// Handle the start of an arrow expression
  3487  		if p.lexer.Token == js_lexer.TEqualsGreaterThan && level <= js_ast.LAssign {
  3488  			ref := p.storeNameInRef(name)
  3489  			arg := js_ast.Arg{Binding: js_ast.Binding{Loc: loc, Data: &js_ast.BIdentifier{Ref: ref}}}
  3490  
  3491  			p.pushScopeForParsePass(js_ast.ScopeFunctionArgs, loc)
  3492  			defer p.popScope()
  3493  
  3494  			return js_ast.Expr{Loc: loc, Data: p.parseArrowBody([]js_ast.Arg{arg}, fnOrArrowDataParse{
  3495  				needsAsyncLoc: loc,
  3496  			})}
  3497  		}
  3498  
  3499  		ref := p.storeNameInRef(name)
  3500  		return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}}
  3501  
  3502  	case js_lexer.TStringLiteral, js_lexer.TNoSubstitutionTemplateLiteral:
  3503  		return p.parseStringLiteral()
  3504  
  3505  	case js_lexer.TTemplateHead:
  3506  		var legacyOctalLoc logger.Loc
  3507  		headLoc := p.lexer.Loc()
  3508  		head := p.lexer.StringLiteral()
  3509  		if p.lexer.LegacyOctalLoc.Start > loc.Start {
  3510  			legacyOctalLoc = p.lexer.LegacyOctalLoc
  3511  		}
  3512  		parts, tailLegacyOctalLoc := p.parseTemplateParts(false /* includeRaw */)
  3513  		if tailLegacyOctalLoc.Start > 0 {
  3514  			legacyOctalLoc = tailLegacyOctalLoc
  3515  		}
  3516  		return js_ast.Expr{Loc: loc, Data: &js_ast.ETemplate{
  3517  			HeadLoc:        headLoc,
  3518  			HeadCooked:     head,
  3519  			Parts:          parts,
  3520  			LegacyOctalLoc: legacyOctalLoc,
  3521  		}}
  3522  
  3523  	case js_lexer.TNumericLiteral:
  3524  		value := js_ast.Expr{Loc: loc, Data: &js_ast.ENumber{Value: p.lexer.Number}}
  3525  		p.checkForLegacyOctalLiteral(value.Data)
  3526  		p.lexer.Next()
  3527  		return value
  3528  
  3529  	case js_lexer.TBigIntegerLiteral:
  3530  		value := p.lexer.Identifier
  3531  		p.markSyntaxFeature(compat.Bigint, p.lexer.Range())
  3532  		p.lexer.Next()
  3533  		return js_ast.Expr{Loc: loc, Data: &js_ast.EBigInt{Value: value.String}}
  3534  
  3535  	case js_lexer.TSlash, js_lexer.TSlashEquals:
  3536  		p.lexer.ScanRegExp()
  3537  		value := p.lexer.Raw()
  3538  		p.lexer.Next()
  3539  		return js_ast.Expr{Loc: loc, Data: &js_ast.ERegExp{Value: value}}
  3540  
  3541  	case js_lexer.TVoid:
  3542  		p.lexer.Next()
  3543  		value := p.parseExpr(js_ast.LPrefix)
  3544  		if p.lexer.Token == js_lexer.TAsteriskAsterisk {
  3545  			p.lexer.Unexpected()
  3546  		}
  3547  		return js_ast.Expr{Loc: loc, Data: &js_ast.EUnary{Op: js_ast.UnOpVoid, Value: value}}
  3548  
  3549  	case js_lexer.TTypeof:
  3550  		p.lexer.Next()
  3551  		value := p.parseExpr(js_ast.LPrefix)
  3552  		if p.lexer.Token == js_lexer.TAsteriskAsterisk {
  3553  			p.lexer.Unexpected()
  3554  		}
  3555  		_, valueIsIdentifier := value.Data.(*js_ast.EIdentifier)
  3556  		return js_ast.Expr{Loc: loc, Data: &js_ast.EUnary{
  3557  			Op:                            js_ast.UnOpTypeof,
  3558  			Value:                         value,
  3559  			WasOriginallyTypeofIdentifier: valueIsIdentifier,
  3560  		}}
  3561  
  3562  	case js_lexer.TDelete:
  3563  		p.lexer.Next()
  3564  		value := p.parseExpr(js_ast.LPrefix)
  3565  		if p.lexer.Token == js_lexer.TAsteriskAsterisk {
  3566  			p.lexer.Unexpected()
  3567  		}
  3568  		if index, ok := value.Data.(*js_ast.EIndex); ok {
  3569  			if private, ok := index.Index.Data.(*js_ast.EPrivateIdentifier); ok {
  3570  				name := p.loadNameFromRef(private.Ref)
  3571  				r := logger.Range{Loc: index.Index.Loc, Len: int32(len(name))}
  3572  				p.log.AddError(&p.tracker, r, fmt.Sprintf("Deleting the private name %q is forbidden", name))
  3573  			}
  3574  		}
  3575  		_, valueIsIdentifier := value.Data.(*js_ast.EIdentifier)
  3576  		return js_ast.Expr{Loc: loc, Data: &js_ast.EUnary{
  3577  			Op:    js_ast.UnOpDelete,
  3578  			Value: value,
  3579  			WasOriginallyDeleteOfIdentifierOrPropertyAccess: valueIsIdentifier || js_ast.IsPropertyAccess(value),
  3580  		}}
  3581  
  3582  	case js_lexer.TPlus:
  3583  		p.lexer.Next()
  3584  		value := p.parseExpr(js_ast.LPrefix)
  3585  		if p.lexer.Token == js_lexer.TAsteriskAsterisk {
  3586  			p.lexer.Unexpected()
  3587  		}
  3588  		return js_ast.Expr{Loc: loc, Data: &js_ast.EUnary{Op: js_ast.UnOpPos, Value: value}}
  3589  
  3590  	case js_lexer.TMinus:
  3591  		p.lexer.Next()
  3592  		value := p.parseExpr(js_ast.LPrefix)
  3593  		if p.lexer.Token == js_lexer.TAsteriskAsterisk {
  3594  			p.lexer.Unexpected()
  3595  		}
  3596  		return js_ast.Expr{Loc: loc, Data: &js_ast.EUnary{Op: js_ast.UnOpNeg, Value: value}}
  3597  
  3598  	case js_lexer.TTilde:
  3599  		p.lexer.Next()
  3600  		value := p.parseExpr(js_ast.LPrefix)
  3601  		if p.lexer.Token == js_lexer.TAsteriskAsterisk {
  3602  			p.lexer.Unexpected()
  3603  		}
  3604  		return js_ast.Expr{Loc: loc, Data: &js_ast.EUnary{Op: js_ast.UnOpCpl, Value: value}}
  3605  
  3606  	case js_lexer.TExclamation:
  3607  		p.lexer.Next()
  3608  		value := p.parseExpr(js_ast.LPrefix)
  3609  		if p.lexer.Token == js_lexer.TAsteriskAsterisk {
  3610  			p.lexer.Unexpected()
  3611  		}
  3612  		return js_ast.Expr{Loc: loc, Data: &js_ast.EUnary{Op: js_ast.UnOpNot, Value: value}}
  3613  
  3614  	case js_lexer.TMinusMinus:
  3615  		p.lexer.Next()
  3616  		return js_ast.Expr{Loc: loc, Data: &js_ast.EUnary{Op: js_ast.UnOpPreDec, Value: p.parseExpr(js_ast.LPrefix)}}
  3617  
  3618  	case js_lexer.TPlusPlus:
  3619  		p.lexer.Next()
  3620  		return js_ast.Expr{Loc: loc, Data: &js_ast.EUnary{Op: js_ast.UnOpPreInc, Value: p.parseExpr(js_ast.LPrefix)}}
  3621  
  3622  	case js_lexer.TFunction:
  3623  		return p.parseFnExpr(loc, false /* isAsync */, logger.Range{})
  3624  
  3625  	case js_lexer.TClass:
  3626  		return p.parseClassExpr(nil)
  3627  
  3628  	case js_lexer.TAt:
  3629  		// Parse decorators before class expressions
  3630  		decorators := p.parseDecorators(p.currentScope, logger.Range{}, decoratorBeforeClassExpr)
  3631  		return p.parseClassExpr(decorators)
  3632  
  3633  	case js_lexer.TNew:
  3634  		p.lexer.Next()
  3635  
  3636  		// Special-case the weird "new.target" expression here
  3637  		if p.lexer.Token == js_lexer.TDot {
  3638  			p.lexer.Next()
  3639  			if p.lexer.Token != js_lexer.TIdentifier || p.lexer.Raw() != "target" {
  3640  				p.lexer.Unexpected()
  3641  			}
  3642  			r := logger.Range{Loc: loc, Len: p.lexer.Range().End() - loc.Start}
  3643  			p.markSyntaxFeature(compat.NewTarget, r)
  3644  			p.lexer.Next()
  3645  			return js_ast.Expr{Loc: loc, Data: &js_ast.ENewTarget{Range: r}}
  3646  		}
  3647  
  3648  		target := p.parseExprWithFlags(js_ast.LMember, flags)
  3649  		args := []js_ast.Expr{}
  3650  		var closeParenLoc logger.Loc
  3651  		var isMultiLine bool
  3652  
  3653  		if p.lexer.Token == js_lexer.TOpenParen {
  3654  			args, closeParenLoc, isMultiLine = p.parseCallArgs()
  3655  		}
  3656  
  3657  		return js_ast.Expr{Loc: loc, Data: &js_ast.ENew{
  3658  			Target:        target,
  3659  			Args:          args,
  3660  			CloseParenLoc: closeParenLoc,
  3661  			IsMultiLine:   isMultiLine,
  3662  		}}
  3663  
  3664  	case js_lexer.TOpenBracket:
  3665  		p.lexer.Next()
  3666  		isSingleLine := !p.lexer.HasNewlineBefore
  3667  		items := []js_ast.Expr{}
  3668  		selfErrors := deferredErrors{}
  3669  		commaAfterSpread := logger.Loc{}
  3670  
  3671  		// Allow "in" inside arrays
  3672  		oldAllowIn := p.allowIn
  3673  		p.allowIn = true
  3674  
  3675  		for p.lexer.Token != js_lexer.TCloseBracket {
  3676  			switch p.lexer.Token {
  3677  			case js_lexer.TComma:
  3678  				items = append(items, js_ast.Expr{Loc: p.lexer.Loc(), Data: js_ast.EMissingShared})
  3679  
  3680  			case js_lexer.TDotDotDot:
  3681  				if errors != nil {
  3682  					errors.arraySpreadFeature = p.lexer.Range()
  3683  				} else {
  3684  					p.markSyntaxFeature(compat.ArraySpread, p.lexer.Range())
  3685  				}
  3686  				dotsLoc := p.saveExprCommentsHere()
  3687  				p.lexer.Next()
  3688  				item := p.parseExprOrBindings(js_ast.LComma, &selfErrors)
  3689  				items = append(items, js_ast.Expr{Loc: dotsLoc, Data: &js_ast.ESpread{Value: item}})
  3690  
  3691  				// Commas are not allowed here when destructuring
  3692  				if p.lexer.Token == js_lexer.TComma {
  3693  					commaAfterSpread = p.lexer.Loc()
  3694  				}
  3695  
  3696  			default:
  3697  				item := p.parseExprOrBindings(js_ast.LComma, &selfErrors)
  3698  				items = append(items, item)
  3699  			}
  3700  
  3701  			if p.lexer.Token != js_lexer.TComma {
  3702  				break
  3703  			}
  3704  			if p.lexer.HasNewlineBefore {
  3705  				isSingleLine = false
  3706  			}
  3707  			p.lexer.Next()
  3708  			if p.lexer.HasNewlineBefore {
  3709  				isSingleLine = false
  3710  			}
  3711  		}
  3712  
  3713  		if p.lexer.HasNewlineBefore {
  3714  			isSingleLine = false
  3715  		}
  3716  		closeBracketLoc := p.saveExprCommentsHere()
  3717  		p.lexer.Expect(js_lexer.TCloseBracket)
  3718  		p.allowIn = oldAllowIn
  3719  
  3720  		if p.willNeedBindingPattern() {
  3721  			// Is this a binding pattern?
  3722  		} else if errors == nil {
  3723  			// Is this an expression?
  3724  			p.logExprErrors(&selfErrors)
  3725  		} else {
  3726  			// In this case, we can't distinguish between the two yet
  3727  			selfErrors.mergeInto(errors)
  3728  		}
  3729  
  3730  		return js_ast.Expr{Loc: loc, Data: &js_ast.EArray{
  3731  			Items:            items,
  3732  			CommaAfterSpread: commaAfterSpread,
  3733  			IsSingleLine:     isSingleLine,
  3734  			CloseBracketLoc:  closeBracketLoc,
  3735  		}}
  3736  
  3737  	case js_lexer.TOpenBrace:
  3738  		p.lexer.Next()
  3739  		isSingleLine := !p.lexer.HasNewlineBefore
  3740  		properties := []js_ast.Property{}
  3741  		selfErrors := deferredErrors{}
  3742  		commaAfterSpread := logger.Loc{}
  3743  
  3744  		// Allow "in" inside object literals
  3745  		oldAllowIn := p.allowIn
  3746  		p.allowIn = true
  3747  
  3748  		for p.lexer.Token != js_lexer.TCloseBrace {
  3749  			if p.lexer.Token == js_lexer.TDotDotDot {
  3750  				dotLoc := p.saveExprCommentsHere()
  3751  				p.lexer.Next()
  3752  				value := p.parseExprOrBindings(js_ast.LComma, &selfErrors)
  3753  				properties = append(properties, js_ast.Property{
  3754  					Kind:       js_ast.PropertySpread,
  3755  					Loc:        dotLoc,
  3756  					ValueOrNil: value,
  3757  				})
  3758  
  3759  				// Commas are not allowed here when destructuring
  3760  				if p.lexer.Token == js_lexer.TComma {
  3761  					commaAfterSpread = p.lexer.Loc()
  3762  				}
  3763  			} else {
  3764  				// This property may turn out to be a type in TypeScript, which should be ignored
  3765  				if property, ok := p.parseProperty(p.saveExprCommentsHere(), js_ast.PropertyField, propertyOpts{}, &selfErrors); ok {
  3766  					properties = append(properties, property)
  3767  				}
  3768  			}
  3769  
  3770  			if p.lexer.Token != js_lexer.TComma {
  3771  				break
  3772  			}
  3773  			if p.lexer.HasNewlineBefore {
  3774  				isSingleLine = false
  3775  			}
  3776  			p.lexer.Next()
  3777  			if p.lexer.HasNewlineBefore {
  3778  				isSingleLine = false
  3779  			}
  3780  		}
  3781  
  3782  		if p.lexer.HasNewlineBefore {
  3783  			isSingleLine = false
  3784  		}
  3785  		closeBraceLoc := p.saveExprCommentsHere()
  3786  		p.lexer.Expect(js_lexer.TCloseBrace)
  3787  		p.allowIn = oldAllowIn
  3788  
  3789  		if p.willNeedBindingPattern() {
  3790  			// Is this a binding pattern?
  3791  		} else if errors == nil {
  3792  			// Is this an expression?
  3793  			p.logExprErrors(&selfErrors)
  3794  		} else {
  3795  			// In this case, we can't distinguish between the two yet
  3796  			selfErrors.mergeInto(errors)
  3797  		}
  3798  
  3799  		return js_ast.Expr{Loc: loc, Data: &js_ast.EObject{
  3800  			Properties:       properties,
  3801  			CommaAfterSpread: commaAfterSpread,
  3802  			IsSingleLine:     isSingleLine,
  3803  			CloseBraceLoc:    closeBraceLoc,
  3804  		}}
  3805  
  3806  	case js_lexer.TLessThan:
  3807  		// This is a very complicated and highly ambiguous area of TypeScript
  3808  		// syntax. Many similar-looking things are overloaded.
  3809  		//
  3810  		// TS:
  3811  		//
  3812  		//   A type cast:
  3813  		//     <A>(x)
  3814  		//     <[]>(x)
  3815  		//     <A[]>(x)
  3816  		//     <const>(x)
  3817  		//
  3818  		//   An arrow function with type parameters:
  3819  		//     <A>(x) => {}
  3820  		//     <A, B>(x) => {}
  3821  		//     <A = B>(x) => {}
  3822  		//     <A extends B>(x) => {}
  3823  		//     <const A>(x) => {}
  3824  		//     <const A extends B>(x) => {}
  3825  		//
  3826  		//   A syntax error:
  3827  		//     <>() => {}
  3828  		//
  3829  		// TSX:
  3830  		//
  3831  		//   A JSX element:
  3832  		//     <>() => {}</>
  3833  		//     <A>(x) => {}</A>
  3834  		//     <A extends/>
  3835  		//     <A extends>(x) => {}</A>
  3836  		//     <A extends={false}>(x) => {}</A>
  3837  		//     <const A extends/>
  3838  		//     <const A extends>(x) => {}</const>
  3839  		//
  3840  		//   An arrow function with type parameters:
  3841  		//     <A,>(x) => {}
  3842  		//     <A, B>(x) => {}
  3843  		//     <A = B>(x) => {}
  3844  		//     <A extends B>(x) => {}
  3845  		//     <const>(x)</const>
  3846  		//     <const A extends B>(x) => {}
  3847  		//
  3848  		//   A syntax error:
  3849  		//     <[]>(x)
  3850  		//     <A[]>(x)
  3851  		//     <>() => {}
  3852  		//     <A>(x) => {}
  3853  
  3854  		if p.options.ts.Parse && p.options.jsx.Parse && p.isTSArrowFnJSX() {
  3855  			p.skipTypeScriptTypeParameters(allowConstModifier)
  3856  			p.lexer.Expect(js_lexer.TOpenParen)
  3857  			return p.parseParenExpr(loc, level, parenExprOpts{forceArrowFn: true})
  3858  		}
  3859  
  3860  		// Print a friendly error message when parsing JSX as JavaScript
  3861  		if !p.options.jsx.Parse && !p.options.ts.Parse {
  3862  			var how string
  3863  			switch logger.API {
  3864  			case logger.CLIAPI:
  3865  				how = " You can use \"--loader:.js=jsx\" to do that."
  3866  			case logger.JSAPI:
  3867  				how = " You can use \"loader: { '.js': 'jsx' }\" to do that."
  3868  			case logger.GoAPI:
  3869  				how = " You can use 'Loader: map[string]api.Loader{\".js\": api.LoaderJSX}' to do that."
  3870  			}
  3871  			p.log.AddErrorWithNotes(&p.tracker, p.lexer.Range(), "The JSX syntax extension is not currently enabled", []logger.MsgData{{
  3872  				Text: "The esbuild loader for this file is currently set to \"js\" but it must be set to \"jsx\" to be able to parse JSX syntax." + how}})
  3873  			p.options.jsx.Parse = true
  3874  		}
  3875  
  3876  		if p.options.jsx.Parse {
  3877  			// Use NextInsideJSXElement() instead of Next() so we parse "<<" as "<"
  3878  			p.lexer.NextInsideJSXElement()
  3879  			element := p.parseJSXElement(loc)
  3880  
  3881  			// The call to parseJSXElement() above doesn't consume the last
  3882  			// TGreaterThan because the caller knows what Next() function to call.
  3883  			// Use Next() instead of NextInsideJSXElement() here since the next
  3884  			// token is an expression.
  3885  			p.lexer.Next()
  3886  			return element
  3887  		}
  3888  
  3889  		if p.options.ts.Parse {
  3890  			// This is either an old-style type cast or a generic lambda function
  3891  
  3892  			// TypeScript 4.5 introduced the ".mts" and ".cts" extensions that forbid
  3893  			// the use of an expression starting with "<" that would be ambiguous
  3894  			// when the file is in JSX mode.
  3895  			if p.options.ts.NoAmbiguousLessThan && !p.isTSArrowFnJSX() {
  3896  				p.log.AddError(&p.tracker, p.lexer.Range(),
  3897  					"This syntax is not allowed in files with the \".mts\" or \".cts\" extension")
  3898  			}
  3899  
  3900  			// "<T>(x)"
  3901  			// "<T>(x) => {}"
  3902  			if result := p.trySkipTypeScriptTypeParametersThenOpenParenWithBacktracking(); result != didNotSkipAnything {
  3903  				p.lexer.Expect(js_lexer.TOpenParen)
  3904  				return p.parseParenExpr(loc, level, parenExprOpts{
  3905  					forceArrowFn: result == definitelyTypeParameters,
  3906  				})
  3907  			}
  3908  
  3909  			// "<T>x"
  3910  			p.lexer.Next()
  3911  			p.skipTypeScriptType(js_ast.LLowest)
  3912  			p.lexer.ExpectGreaterThan(false /* isInsideJSXElement */)
  3913  			value := p.parsePrefix(level, errors, flags)
  3914  			return value
  3915  		}
  3916  
  3917  		p.lexer.Unexpected()
  3918  		return js_ast.Expr{}
  3919  
  3920  	case js_lexer.TImport:
  3921  		p.lexer.Next()
  3922  		return p.parseImportExpr(loc, level)
  3923  
  3924  	default:
  3925  		p.lexer.Unexpected()
  3926  		return js_ast.Expr{}
  3927  	}
  3928  }
  3929  
  3930  func (p *parser) parseYieldExpr(loc logger.Loc) js_ast.Expr {
  3931  	// Parse a yield-from expression, which yields from an iterator
  3932  	isStar := p.lexer.Token == js_lexer.TAsterisk
  3933  	if isStar && !p.lexer.HasNewlineBefore {
  3934  		p.lexer.Next()
  3935  	}
  3936  
  3937  	var valueOrNil js_ast.Expr
  3938  
  3939  	// The yield expression only has a value in certain cases
  3940  	if isStar {
  3941  		valueOrNil = p.parseExpr(js_ast.LYield)
  3942  	} else {
  3943  		switch p.lexer.Token {
  3944  		case js_lexer.TCloseBrace, js_lexer.TCloseBracket, js_lexer.TCloseParen,
  3945  			js_lexer.TColon, js_lexer.TComma, js_lexer.TSemicolon:
  3946  
  3947  		default:
  3948  			if !p.lexer.HasNewlineBefore {
  3949  				valueOrNil = p.parseExpr(js_ast.LYield)
  3950  			}
  3951  		}
  3952  	}
  3953  
  3954  	return js_ast.Expr{Loc: loc, Data: &js_ast.EYield{ValueOrNil: valueOrNil, IsStar: isStar}}
  3955  }
  3956  
  3957  func (p *parser) willNeedBindingPattern() bool {
  3958  	switch p.lexer.Token {
  3959  	case js_lexer.TEquals:
  3960  		// "[a] = b;"
  3961  		return true
  3962  
  3963  	case js_lexer.TIn:
  3964  		// "for ([a] in b) {}"
  3965  		return !p.allowIn
  3966  
  3967  	case js_lexer.TIdentifier:
  3968  		// "for ([a] of b) {}"
  3969  		return !p.allowIn && p.lexer.IsContextualKeyword("of")
  3970  
  3971  	default:
  3972  		return false
  3973  	}
  3974  }
  3975  
  3976  // Note: The caller has already parsed the "import" keyword
  3977  func (p *parser) parseImportExpr(loc logger.Loc, level js_ast.L) js_ast.Expr {
  3978  	// Parse an "import.meta" expression
  3979  	if p.lexer.Token == js_lexer.TDot {
  3980  		p.lexer.Next()
  3981  		if !p.lexer.IsContextualKeyword("meta") {
  3982  			p.lexer.ExpectedString("\"meta\"")
  3983  		}
  3984  		p.esmImportMeta = logger.Range{Loc: loc, Len: p.lexer.Range().End() - loc.Start}
  3985  		p.lexer.Next()
  3986  		return js_ast.Expr{Loc: loc, Data: &js_ast.EImportMeta{RangeLen: p.esmImportMeta.Len}}
  3987  	}
  3988  
  3989  	if level > js_ast.LCall {
  3990  		r := js_lexer.RangeOfIdentifier(p.source, loc)
  3991  		p.log.AddError(&p.tracker, r, "Cannot use an \"import\" expression here without parentheses:")
  3992  	}
  3993  
  3994  	// Allow "in" inside call arguments
  3995  	oldAllowIn := p.allowIn
  3996  	p.allowIn = true
  3997  
  3998  	p.lexer.Expect(js_lexer.TOpenParen)
  3999  
  4000  	value := p.parseExpr(js_ast.LComma)
  4001  	var optionsOrNil js_ast.Expr
  4002  
  4003  	if p.lexer.Token == js_lexer.TComma {
  4004  		// "import('./foo.json', )"
  4005  		p.lexer.Next()
  4006  
  4007  		if p.lexer.Token != js_lexer.TCloseParen {
  4008  			// "import('./foo.json', { assert: { type: 'json' } })"
  4009  			optionsOrNil = p.parseExpr(js_ast.LComma)
  4010  
  4011  			if p.lexer.Token == js_lexer.TComma {
  4012  				// "import('./foo.json', { assert: { type: 'json' } }, )"
  4013  				p.lexer.Next()
  4014  			}
  4015  		}
  4016  	}
  4017  
  4018  	closeParenLoc := p.saveExprCommentsHere()
  4019  	p.lexer.Expect(js_lexer.TCloseParen)
  4020  
  4021  	p.allowIn = oldAllowIn
  4022  	return js_ast.Expr{Loc: loc, Data: &js_ast.EImportCall{
  4023  		Expr:          value,
  4024  		OptionsOrNil:  optionsOrNil,
  4025  		CloseParenLoc: closeParenLoc,
  4026  	}}
  4027  }
  4028  
  4029  func (p *parser) parseExprOrBindings(level js_ast.L, errors *deferredErrors) js_ast.Expr {
  4030  	return p.parseExprCommon(level, errors, 0)
  4031  }
  4032  
  4033  func (p *parser) parseExpr(level js_ast.L) js_ast.Expr {
  4034  	return p.parseExprCommon(level, nil, 0)
  4035  }
  4036  
  4037  func (p *parser) parseExprWithFlags(level js_ast.L, flags exprFlag) js_ast.Expr {
  4038  	return p.parseExprCommon(level, nil, flags)
  4039  }
  4040  
  4041  func (p *parser) parseExprCommon(level js_ast.L, errors *deferredErrors, flags exprFlag) js_ast.Expr {
  4042  	lexerCommentFlags := p.lexer.HasCommentBefore
  4043  	expr := p.parsePrefix(level, errors, flags)
  4044  
  4045  	if (lexerCommentFlags&(js_lexer.PureCommentBefore|js_lexer.NoSideEffectsCommentBefore)) != 0 && !p.options.ignoreDCEAnnotations {
  4046  		if (lexerCommentFlags & js_lexer.NoSideEffectsCommentBefore) != 0 {
  4047  			switch e := expr.Data.(type) {
  4048  			case *js_ast.EArrow:
  4049  				e.HasNoSideEffectsComment = true
  4050  			case *js_ast.EFunction:
  4051  				e.Fn.HasNoSideEffectsComment = true
  4052  			}
  4053  		}
  4054  
  4055  		// There is no formal spec for "__PURE__" comments but from reverse-
  4056  		// engineering, it looks like they apply to the next CallExpression or
  4057  		// NewExpression. So in "/* @__PURE__ */ a().b() + c()" the comment applies
  4058  		// to the expression "a().b()".
  4059  		if (lexerCommentFlags&js_lexer.PureCommentBefore) != 0 && level < js_ast.LCall {
  4060  			expr = p.parseSuffix(expr, js_ast.LCall-1, errors, flags)
  4061  			switch e := expr.Data.(type) {
  4062  			case *js_ast.ECall:
  4063  				e.CanBeUnwrappedIfUnused = true
  4064  			case *js_ast.ENew:
  4065  				e.CanBeUnwrappedIfUnused = true
  4066  			}
  4067  		}
  4068  	}
  4069  
  4070  	return p.parseSuffix(expr, level, errors, flags)
  4071  }
  4072  
  4073  func (p *parser) parseSuffix(left js_ast.Expr, level js_ast.L, errors *deferredErrors, flags exprFlag) js_ast.Expr {
  4074  	optionalChain := js_ast.OptionalChainNone
  4075  
  4076  	for {
  4077  		if p.lexer.Loc() == p.afterArrowBodyLoc {
  4078  			for {
  4079  				switch p.lexer.Token {
  4080  				case js_lexer.TComma:
  4081  					if level >= js_ast.LComma {
  4082  						return left
  4083  					}
  4084  					p.lexer.Next()
  4085  					left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpComma, Left: left, Right: p.parseExpr(js_ast.LComma)}}
  4086  
  4087  				default:
  4088  					return left
  4089  				}
  4090  			}
  4091  		}
  4092  
  4093  		// Stop now if this token is forbidden to follow a TypeScript "as" cast
  4094  		if p.lexer.Loc() == p.forbidSuffixAfterAsLoc {
  4095  			return left
  4096  		}
  4097  
  4098  		// Reset the optional chain flag by default. That way we won't accidentally
  4099  		// treat "c.d" as OptionalChainContinue in "a?.b + c.d".
  4100  		oldOptionalChain := optionalChain
  4101  		optionalChain = js_ast.OptionalChainNone
  4102  
  4103  		switch p.lexer.Token {
  4104  		case js_lexer.TDot:
  4105  			p.lexer.Next()
  4106  
  4107  			if p.lexer.Token == js_lexer.TPrivateIdentifier && p.allowPrivateIdentifiers {
  4108  				// "a.#b"
  4109  				// "a?.b.#c"
  4110  				if _, ok := left.Data.(*js_ast.ESuper); ok {
  4111  					p.lexer.Expected(js_lexer.TIdentifier)
  4112  				}
  4113  				name := p.lexer.Identifier
  4114  				nameLoc := p.lexer.Loc()
  4115  				p.reportPrivateNameUsage(name.String)
  4116  				p.lexer.Next()
  4117  				ref := p.storeNameInRef(name)
  4118  				left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EIndex{
  4119  					Target:        left,
  4120  					Index:         js_ast.Expr{Loc: nameLoc, Data: &js_ast.EPrivateIdentifier{Ref: ref}},
  4121  					OptionalChain: oldOptionalChain,
  4122  				}}
  4123  			} else {
  4124  				// "a.b"
  4125  				// "a?.b.c"
  4126  				if !p.lexer.IsIdentifierOrKeyword() {
  4127  					p.lexer.Expect(js_lexer.TIdentifier)
  4128  				}
  4129  				name := p.lexer.Identifier
  4130  				nameLoc := p.lexer.Loc()
  4131  				p.lexer.Next()
  4132  				left = js_ast.Expr{Loc: left.Loc, Data: p.dotOrMangledPropParse(left, name, nameLoc, oldOptionalChain, wasOriginallyDot)}
  4133  			}
  4134  
  4135  			optionalChain = oldOptionalChain
  4136  
  4137  		case js_lexer.TQuestionDot:
  4138  			p.lexer.Next()
  4139  			optionalStart := js_ast.OptionalChainStart
  4140  
  4141  			// Remove unnecessary optional chains
  4142  			if p.options.minifySyntax {
  4143  				if isNullOrUndefined, _, ok := js_ast.ToNullOrUndefinedWithSideEffects(left.Data); ok && !isNullOrUndefined {
  4144  					optionalStart = js_ast.OptionalChainNone
  4145  				}
  4146  			}
  4147  
  4148  			switch p.lexer.Token {
  4149  			case js_lexer.TOpenBracket:
  4150  				// "a?.[b]"
  4151  				p.lexer.Next()
  4152  
  4153  				// Allow "in" inside the brackets
  4154  				oldAllowIn := p.allowIn
  4155  				p.allowIn = true
  4156  
  4157  				index := p.parseExpr(js_ast.LLowest)
  4158  
  4159  				p.allowIn = oldAllowIn
  4160  
  4161  				closeBracketLoc := p.saveExprCommentsHere()
  4162  				p.lexer.Expect(js_lexer.TCloseBracket)
  4163  				left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EIndex{
  4164  					Target:          left,
  4165  					Index:           index,
  4166  					OptionalChain:   optionalStart,
  4167  					CloseBracketLoc: closeBracketLoc,
  4168  				}}
  4169  
  4170  			case js_lexer.TOpenParen:
  4171  				// "a?.()"
  4172  				if level >= js_ast.LCall {
  4173  					return left
  4174  				}
  4175  				kind := js_ast.NormalCall
  4176  				if js_ast.IsPropertyAccess(left) {
  4177  					kind = js_ast.TargetWasOriginallyPropertyAccess
  4178  				}
  4179  				args, closeParenLoc, isMultiLine := p.parseCallArgs()
  4180  				left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.ECall{
  4181  					Target:        left,
  4182  					Args:          args,
  4183  					CloseParenLoc: closeParenLoc,
  4184  					OptionalChain: optionalStart,
  4185  					IsMultiLine:   isMultiLine,
  4186  					Kind:          kind,
  4187  				}}
  4188  
  4189  			case js_lexer.TLessThan, js_lexer.TLessThanLessThan:
  4190  				// "a?.<T>()"
  4191  				// "a?.<<T>() => T>()"
  4192  				if !p.options.ts.Parse {
  4193  					p.lexer.Expected(js_lexer.TIdentifier)
  4194  				}
  4195  				p.skipTypeScriptTypeArguments(skipTypeScriptTypeArgumentsOpts{})
  4196  				if p.lexer.Token != js_lexer.TOpenParen {
  4197  					p.lexer.Expected(js_lexer.TOpenParen)
  4198  				}
  4199  				if level >= js_ast.LCall {
  4200  					return left
  4201  				}
  4202  				kind := js_ast.NormalCall
  4203  				if js_ast.IsPropertyAccess(left) {
  4204  					kind = js_ast.TargetWasOriginallyPropertyAccess
  4205  				}
  4206  				args, closeParenLoc, isMultiLine := p.parseCallArgs()
  4207  				left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.ECall{
  4208  					Target:        left,
  4209  					Args:          args,
  4210  					CloseParenLoc: closeParenLoc,
  4211  					OptionalChain: optionalStart,
  4212  					IsMultiLine:   isMultiLine,
  4213  					Kind:          kind,
  4214  				}}
  4215  
  4216  			default:
  4217  				if p.lexer.Token == js_lexer.TPrivateIdentifier && p.allowPrivateIdentifiers {
  4218  					// "a?.#b"
  4219  					name := p.lexer.Identifier
  4220  					nameLoc := p.lexer.Loc()
  4221  					p.reportPrivateNameUsage(name.String)
  4222  					p.lexer.Next()
  4223  					ref := p.storeNameInRef(name)
  4224  					left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EIndex{
  4225  						Target:        left,
  4226  						Index:         js_ast.Expr{Loc: nameLoc, Data: &js_ast.EPrivateIdentifier{Ref: ref}},
  4227  						OptionalChain: optionalStart,
  4228  					}}
  4229  				} else {
  4230  					// "a?.b"
  4231  					if !p.lexer.IsIdentifierOrKeyword() {
  4232  						p.lexer.Expect(js_lexer.TIdentifier)
  4233  					}
  4234  					name := p.lexer.Identifier
  4235  					nameLoc := p.lexer.Loc()
  4236  					p.lexer.Next()
  4237  					left = js_ast.Expr{Loc: left.Loc, Data: p.dotOrMangledPropParse(left, name, nameLoc, optionalStart, wasOriginallyDot)}
  4238  				}
  4239  			}
  4240  
  4241  			// Only continue if we have started
  4242  			if optionalStart == js_ast.OptionalChainStart {
  4243  				optionalChain = js_ast.OptionalChainContinue
  4244  			}
  4245  
  4246  		case js_lexer.TNoSubstitutionTemplateLiteral:
  4247  			if oldOptionalChain != js_ast.OptionalChainNone {
  4248  				p.log.AddError(&p.tracker, p.lexer.Range(), "Template literals cannot have an optional chain as a tag")
  4249  			}
  4250  			headLoc := p.lexer.Loc()
  4251  			headCooked, headRaw := p.lexer.CookedAndRawTemplateContents()
  4252  			p.lexer.Next()
  4253  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.ETemplate{
  4254  				TagOrNil:                       left,
  4255  				HeadLoc:                        headLoc,
  4256  				HeadCooked:                     headCooked,
  4257  				HeadRaw:                        headRaw,
  4258  				TagWasOriginallyPropertyAccess: js_ast.IsPropertyAccess(left),
  4259  			}}
  4260  
  4261  		case js_lexer.TTemplateHead:
  4262  			if oldOptionalChain != js_ast.OptionalChainNone {
  4263  				p.log.AddError(&p.tracker, p.lexer.Range(), "Template literals cannot have an optional chain as a tag")
  4264  			}
  4265  			headLoc := p.lexer.Loc()
  4266  			headCooked, headRaw := p.lexer.CookedAndRawTemplateContents()
  4267  			parts, _ := p.parseTemplateParts(true /* includeRaw */)
  4268  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.ETemplate{
  4269  				TagOrNil:                       left,
  4270  				HeadLoc:                        headLoc,
  4271  				HeadCooked:                     headCooked,
  4272  				HeadRaw:                        headRaw,
  4273  				Parts:                          parts,
  4274  				TagWasOriginallyPropertyAccess: js_ast.IsPropertyAccess(left),
  4275  			}}
  4276  
  4277  		case js_lexer.TOpenBracket:
  4278  			// When parsing a decorator, ignore EIndex expressions since they may be
  4279  			// part of a computed property:
  4280  			//
  4281  			//   class Foo {
  4282  			//     @foo ['computed']() {}
  4283  			//   }
  4284  			//
  4285  			// This matches the behavior of the TypeScript compiler.
  4286  			if (flags & exprFlagDecorator) != 0 {
  4287  				return left
  4288  			}
  4289  
  4290  			p.lexer.Next()
  4291  
  4292  			// Allow "in" inside the brackets
  4293  			oldAllowIn := p.allowIn
  4294  			p.allowIn = true
  4295  
  4296  			index := p.parseExpr(js_ast.LLowest)
  4297  
  4298  			p.allowIn = oldAllowIn
  4299  
  4300  			closeBracketLoc := p.saveExprCommentsHere()
  4301  			p.lexer.Expect(js_lexer.TCloseBracket)
  4302  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EIndex{
  4303  				Target:          left,
  4304  				Index:           index,
  4305  				OptionalChain:   oldOptionalChain,
  4306  				CloseBracketLoc: closeBracketLoc,
  4307  			}}
  4308  			optionalChain = oldOptionalChain
  4309  
  4310  		case js_lexer.TOpenParen:
  4311  			if level >= js_ast.LCall {
  4312  				return left
  4313  			}
  4314  			kind := js_ast.NormalCall
  4315  			if js_ast.IsPropertyAccess(left) {
  4316  				kind = js_ast.TargetWasOriginallyPropertyAccess
  4317  			}
  4318  			args, closeParenLoc, isMultiLine := p.parseCallArgs()
  4319  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.ECall{
  4320  				Target:        left,
  4321  				Args:          args,
  4322  				CloseParenLoc: closeParenLoc,
  4323  				OptionalChain: oldOptionalChain,
  4324  				IsMultiLine:   isMultiLine,
  4325  				Kind:          kind,
  4326  			}}
  4327  			optionalChain = oldOptionalChain
  4328  
  4329  		case js_lexer.TQuestion:
  4330  			if level >= js_ast.LConditional {
  4331  				return left
  4332  			}
  4333  			p.lexer.Next()
  4334  
  4335  			// Stop now if we're parsing one of these:
  4336  			// "(a?) => {}"
  4337  			// "(a?: b) => {}"
  4338  			// "(a?, b?) => {}"
  4339  			if p.options.ts.Parse && left.Loc == p.latestArrowArgLoc && (p.lexer.Token == js_lexer.TColon ||
  4340  				p.lexer.Token == js_lexer.TCloseParen || p.lexer.Token == js_lexer.TComma) {
  4341  				if errors == nil {
  4342  					p.lexer.Unexpected()
  4343  				}
  4344  				errors.invalidExprAfterQuestion = p.lexer.Range()
  4345  				return left
  4346  			}
  4347  
  4348  			// Allow "in" in between "?" and ":"
  4349  			oldAllowIn := p.allowIn
  4350  			p.allowIn = true
  4351  
  4352  			yes := p.parseExpr(js_ast.LComma)
  4353  
  4354  			p.allowIn = oldAllowIn
  4355  
  4356  			p.lexer.Expect(js_lexer.TColon)
  4357  			no := p.parseExpr(js_ast.LComma)
  4358  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EIf{Test: left, Yes: yes, No: no}}
  4359  
  4360  		case js_lexer.TExclamation:
  4361  			// Skip over TypeScript non-null assertions
  4362  			if p.lexer.HasNewlineBefore {
  4363  				return left
  4364  			}
  4365  			if !p.options.ts.Parse {
  4366  				p.lexer.Unexpected()
  4367  			}
  4368  			p.lexer.Next()
  4369  			optionalChain = oldOptionalChain
  4370  
  4371  		case js_lexer.TMinusMinus:
  4372  			if p.lexer.HasNewlineBefore || level >= js_ast.LPostfix {
  4373  				return left
  4374  			}
  4375  			p.lexer.Next()
  4376  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EUnary{Op: js_ast.UnOpPostDec, Value: left}}
  4377  
  4378  		case js_lexer.TPlusPlus:
  4379  			if p.lexer.HasNewlineBefore || level >= js_ast.LPostfix {
  4380  				return left
  4381  			}
  4382  			p.lexer.Next()
  4383  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EUnary{Op: js_ast.UnOpPostInc, Value: left}}
  4384  
  4385  		case js_lexer.TComma:
  4386  			if level >= js_ast.LComma {
  4387  				return left
  4388  			}
  4389  			p.lexer.Next()
  4390  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpComma, Left: left, Right: p.parseExpr(js_ast.LComma)}}
  4391  
  4392  		case js_lexer.TPlus:
  4393  			if level >= js_ast.LAdd {
  4394  				return left
  4395  			}
  4396  			p.lexer.Next()
  4397  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpAdd, Left: left, Right: p.parseExpr(js_ast.LAdd)}}
  4398  
  4399  		case js_lexer.TPlusEquals:
  4400  			if level >= js_ast.LAssign {
  4401  				return left
  4402  			}
  4403  			p.lexer.Next()
  4404  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpAddAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4405  
  4406  		case js_lexer.TMinus:
  4407  			if level >= js_ast.LAdd {
  4408  				return left
  4409  			}
  4410  			p.lexer.Next()
  4411  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpSub, Left: left, Right: p.parseExpr(js_ast.LAdd)}}
  4412  
  4413  		case js_lexer.TMinusEquals:
  4414  			if level >= js_ast.LAssign {
  4415  				return left
  4416  			}
  4417  			p.lexer.Next()
  4418  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpSubAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4419  
  4420  		case js_lexer.TAsterisk:
  4421  			if level >= js_ast.LMultiply {
  4422  				return left
  4423  			}
  4424  			p.lexer.Next()
  4425  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpMul, Left: left, Right: p.parseExpr(js_ast.LMultiply)}}
  4426  
  4427  		case js_lexer.TAsteriskAsterisk:
  4428  			if level >= js_ast.LExponentiation {
  4429  				return left
  4430  			}
  4431  			p.lexer.Next()
  4432  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpPow, Left: left, Right: p.parseExpr(js_ast.LExponentiation - 1)}}
  4433  
  4434  		case js_lexer.TAsteriskAsteriskEquals:
  4435  			if level >= js_ast.LAssign {
  4436  				return left
  4437  			}
  4438  			p.lexer.Next()
  4439  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpPowAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4440  
  4441  		case js_lexer.TAsteriskEquals:
  4442  			if level >= js_ast.LAssign {
  4443  				return left
  4444  			}
  4445  			p.lexer.Next()
  4446  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpMulAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4447  
  4448  		case js_lexer.TPercent:
  4449  			if level >= js_ast.LMultiply {
  4450  				return left
  4451  			}
  4452  			p.lexer.Next()
  4453  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpRem, Left: left, Right: p.parseExpr(js_ast.LMultiply)}}
  4454  
  4455  		case js_lexer.TPercentEquals:
  4456  			if level >= js_ast.LAssign {
  4457  				return left
  4458  			}
  4459  			p.lexer.Next()
  4460  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpRemAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4461  
  4462  		case js_lexer.TSlash:
  4463  			if level >= js_ast.LMultiply {
  4464  				return left
  4465  			}
  4466  			p.lexer.Next()
  4467  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpDiv, Left: left, Right: p.parseExpr(js_ast.LMultiply)}}
  4468  
  4469  		case js_lexer.TSlashEquals:
  4470  			if level >= js_ast.LAssign {
  4471  				return left
  4472  			}
  4473  			p.lexer.Next()
  4474  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpDivAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4475  
  4476  		case js_lexer.TEqualsEquals:
  4477  			if level >= js_ast.LEquals {
  4478  				return left
  4479  			}
  4480  			p.lexer.Next()
  4481  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpLooseEq, Left: left, Right: p.parseExpr(js_ast.LEquals)}}
  4482  
  4483  		case js_lexer.TExclamationEquals:
  4484  			if level >= js_ast.LEquals {
  4485  				return left
  4486  			}
  4487  			p.lexer.Next()
  4488  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpLooseNe, Left: left, Right: p.parseExpr(js_ast.LEquals)}}
  4489  
  4490  		case js_lexer.TEqualsEqualsEquals:
  4491  			if level >= js_ast.LEquals {
  4492  				return left
  4493  			}
  4494  			p.lexer.Next()
  4495  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpStrictEq, Left: left, Right: p.parseExpr(js_ast.LEquals)}}
  4496  
  4497  		case js_lexer.TExclamationEqualsEquals:
  4498  			if level >= js_ast.LEquals {
  4499  				return left
  4500  			}
  4501  			p.lexer.Next()
  4502  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpStrictNe, Left: left, Right: p.parseExpr(js_ast.LEquals)}}
  4503  
  4504  		case js_lexer.TLessThan:
  4505  			// TypeScript allows type arguments to be specified with angle brackets
  4506  			// inside an expression. Unlike in other languages, this unfortunately
  4507  			// appears to require backtracking to parse.
  4508  			if p.options.ts.Parse && p.trySkipTypeArgumentsInExpressionWithBacktracking() {
  4509  				optionalChain = oldOptionalChain
  4510  				continue
  4511  			}
  4512  
  4513  			if level >= js_ast.LCompare {
  4514  				return left
  4515  			}
  4516  			p.lexer.Next()
  4517  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpLt, Left: left, Right: p.parseExpr(js_ast.LCompare)}}
  4518  
  4519  		case js_lexer.TLessThanEquals:
  4520  			if level >= js_ast.LCompare {
  4521  				return left
  4522  			}
  4523  			p.lexer.Next()
  4524  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpLe, Left: left, Right: p.parseExpr(js_ast.LCompare)}}
  4525  
  4526  		case js_lexer.TGreaterThan:
  4527  			if level >= js_ast.LCompare {
  4528  				return left
  4529  			}
  4530  			p.lexer.Next()
  4531  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpGt, Left: left, Right: p.parseExpr(js_ast.LCompare)}}
  4532  
  4533  		case js_lexer.TGreaterThanEquals:
  4534  			if level >= js_ast.LCompare {
  4535  				return left
  4536  			}
  4537  			p.lexer.Next()
  4538  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpGe, Left: left, Right: p.parseExpr(js_ast.LCompare)}}
  4539  
  4540  		case js_lexer.TLessThanLessThan:
  4541  			// TypeScript allows type arguments to be specified with angle brackets
  4542  			// inside an expression. Unlike in other languages, this unfortunately
  4543  			// appears to require backtracking to parse.
  4544  			if p.options.ts.Parse && p.trySkipTypeArgumentsInExpressionWithBacktracking() {
  4545  				optionalChain = oldOptionalChain
  4546  				continue
  4547  			}
  4548  
  4549  			if level >= js_ast.LShift {
  4550  				return left
  4551  			}
  4552  			p.lexer.Next()
  4553  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpShl, Left: left, Right: p.parseExpr(js_ast.LShift)}}
  4554  
  4555  		case js_lexer.TLessThanLessThanEquals:
  4556  			if level >= js_ast.LAssign {
  4557  				return left
  4558  			}
  4559  			p.lexer.Next()
  4560  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpShlAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4561  
  4562  		case js_lexer.TGreaterThanGreaterThan:
  4563  			if level >= js_ast.LShift {
  4564  				return left
  4565  			}
  4566  			p.lexer.Next()
  4567  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpShr, Left: left, Right: p.parseExpr(js_ast.LShift)}}
  4568  
  4569  		case js_lexer.TGreaterThanGreaterThanEquals:
  4570  			if level >= js_ast.LAssign {
  4571  				return left
  4572  			}
  4573  			p.lexer.Next()
  4574  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpShrAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4575  
  4576  		case js_lexer.TGreaterThanGreaterThanGreaterThan:
  4577  			if level >= js_ast.LShift {
  4578  				return left
  4579  			}
  4580  			p.lexer.Next()
  4581  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpUShr, Left: left, Right: p.parseExpr(js_ast.LShift)}}
  4582  
  4583  		case js_lexer.TGreaterThanGreaterThanGreaterThanEquals:
  4584  			if level >= js_ast.LAssign {
  4585  				return left
  4586  			}
  4587  			p.lexer.Next()
  4588  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpUShrAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4589  
  4590  		case js_lexer.TQuestionQuestion:
  4591  			if level >= js_ast.LNullishCoalescing {
  4592  				return left
  4593  			}
  4594  			p.lexer.Next()
  4595  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpNullishCoalescing, Left: left, Right: p.parseExpr(js_ast.LNullishCoalescing)}}
  4596  
  4597  		case js_lexer.TQuestionQuestionEquals:
  4598  			if level >= js_ast.LAssign {
  4599  				return left
  4600  			}
  4601  			p.lexer.Next()
  4602  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpNullishCoalescingAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4603  
  4604  		case js_lexer.TBarBar:
  4605  			if level >= js_ast.LLogicalOr {
  4606  				return left
  4607  			}
  4608  
  4609  			// Prevent "||" inside "??" from the right
  4610  			if level == js_ast.LNullishCoalescing {
  4611  				p.logNullishCoalescingErrorPrecedenceError("||")
  4612  			}
  4613  
  4614  			p.lexer.Next()
  4615  			right := p.parseExpr(js_ast.LLogicalOr)
  4616  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpLogicalOr, Left: left, Right: right}}
  4617  
  4618  			// Prevent "||" inside "??" from the left
  4619  			if level < js_ast.LNullishCoalescing {
  4620  				left = p.parseSuffix(left, js_ast.LNullishCoalescing+1, nil, flags)
  4621  				if p.lexer.Token == js_lexer.TQuestionQuestion {
  4622  					p.logNullishCoalescingErrorPrecedenceError("||")
  4623  				}
  4624  			}
  4625  
  4626  		case js_lexer.TBarBarEquals:
  4627  			if level >= js_ast.LAssign {
  4628  				return left
  4629  			}
  4630  			p.lexer.Next()
  4631  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpLogicalOrAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4632  
  4633  		case js_lexer.TAmpersandAmpersand:
  4634  			if level >= js_ast.LLogicalAnd {
  4635  				return left
  4636  			}
  4637  
  4638  			// Prevent "&&" inside "??" from the right
  4639  			if level == js_ast.LNullishCoalescing {
  4640  				p.logNullishCoalescingErrorPrecedenceError("&&")
  4641  			}
  4642  
  4643  			p.lexer.Next()
  4644  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpLogicalAnd, Left: left, Right: p.parseExpr(js_ast.LLogicalAnd)}}
  4645  
  4646  			// Prevent "&&" inside "??" from the left
  4647  			if level < js_ast.LNullishCoalescing {
  4648  				left = p.parseSuffix(left, js_ast.LNullishCoalescing+1, nil, flags)
  4649  				if p.lexer.Token == js_lexer.TQuestionQuestion {
  4650  					p.logNullishCoalescingErrorPrecedenceError("&&")
  4651  				}
  4652  			}
  4653  
  4654  		case js_lexer.TAmpersandAmpersandEquals:
  4655  			if level >= js_ast.LAssign {
  4656  				return left
  4657  			}
  4658  			p.lexer.Next()
  4659  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpLogicalAndAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4660  
  4661  		case js_lexer.TBar:
  4662  			if level >= js_ast.LBitwiseOr {
  4663  				return left
  4664  			}
  4665  			p.lexer.Next()
  4666  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpBitwiseOr, Left: left, Right: p.parseExpr(js_ast.LBitwiseOr)}}
  4667  
  4668  		case js_lexer.TBarEquals:
  4669  			if level >= js_ast.LAssign {
  4670  				return left
  4671  			}
  4672  			p.lexer.Next()
  4673  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpBitwiseOrAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4674  
  4675  		case js_lexer.TAmpersand:
  4676  			if level >= js_ast.LBitwiseAnd {
  4677  				return left
  4678  			}
  4679  			p.lexer.Next()
  4680  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpBitwiseAnd, Left: left, Right: p.parseExpr(js_ast.LBitwiseAnd)}}
  4681  
  4682  		case js_lexer.TAmpersandEquals:
  4683  			if level >= js_ast.LAssign {
  4684  				return left
  4685  			}
  4686  			p.lexer.Next()
  4687  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpBitwiseAndAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4688  
  4689  		case js_lexer.TCaret:
  4690  			if level >= js_ast.LBitwiseXor {
  4691  				return left
  4692  			}
  4693  			p.lexer.Next()
  4694  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpBitwiseXor, Left: left, Right: p.parseExpr(js_ast.LBitwiseXor)}}
  4695  
  4696  		case js_lexer.TCaretEquals:
  4697  			if level >= js_ast.LAssign {
  4698  				return left
  4699  			}
  4700  			p.lexer.Next()
  4701  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpBitwiseXorAssign, Left: left, Right: p.parseExpr(js_ast.LAssign - 1)}}
  4702  
  4703  		case js_lexer.TEquals:
  4704  			if level >= js_ast.LAssign {
  4705  				return left
  4706  			}
  4707  			p.lexer.Next()
  4708  			left = js_ast.Assign(left, p.parseExpr(js_ast.LAssign-1))
  4709  
  4710  		case js_lexer.TIn:
  4711  			if level >= js_ast.LCompare || !p.allowIn {
  4712  				return left
  4713  			}
  4714  
  4715  			// Warn about "!a in b" instead of "!(a in b)"
  4716  			kind := logger.Warning
  4717  			if p.suppressWarningsAboutWeirdCode {
  4718  				kind = logger.Debug
  4719  			}
  4720  			if e, ok := left.Data.(*js_ast.EUnary); ok && e.Op == js_ast.UnOpNot {
  4721  				r := logger.Range{Loc: left.Loc, Len: p.source.LocBeforeWhitespace(p.lexer.Loc()).Start - left.Loc.Start}
  4722  				data := p.tracker.MsgData(r, "Suspicious use of the \"!\" operator inside the \"in\" operator")
  4723  				data.Location.Suggestion = fmt.Sprintf("(%s)", p.source.TextForRange(r))
  4724  				p.log.AddMsgID(logger.MsgID_JS_SuspiciousBooleanNot, logger.Msg{
  4725  					Kind: kind,
  4726  					Data: data,
  4727  					Notes: []logger.MsgData{{Text: "The code \"!x in y\" is parsed as \"(!x) in y\". " +
  4728  						"You need to insert parentheses to get \"!(x in y)\" instead."}},
  4729  				})
  4730  			}
  4731  
  4732  			p.lexer.Next()
  4733  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpIn, Left: left, Right: p.parseExpr(js_ast.LCompare)}}
  4734  
  4735  		case js_lexer.TInstanceof:
  4736  			if level >= js_ast.LCompare {
  4737  				return left
  4738  			}
  4739  
  4740  			// Warn about "!a instanceof b" instead of "!(a instanceof b)". Here's an
  4741  			// example of code with this problem: https://github.com/mrdoob/three.js/pull/11182.
  4742  			kind := logger.Warning
  4743  			if p.suppressWarningsAboutWeirdCode {
  4744  				kind = logger.Debug
  4745  			}
  4746  			if e, ok := left.Data.(*js_ast.EUnary); ok && e.Op == js_ast.UnOpNot {
  4747  				r := logger.Range{Loc: left.Loc, Len: p.source.LocBeforeWhitespace(p.lexer.Loc()).Start - left.Loc.Start}
  4748  				data := p.tracker.MsgData(r, "Suspicious use of the \"!\" operator inside the \"instanceof\" operator")
  4749  				data.Location.Suggestion = fmt.Sprintf("(%s)", p.source.TextForRange(r))
  4750  				p.log.AddMsgID(logger.MsgID_JS_SuspiciousBooleanNot, logger.Msg{
  4751  					Kind: kind,
  4752  					Data: data,
  4753  					Notes: []logger.MsgData{{Text: "The code \"!x instanceof y\" is parsed as \"(!x) instanceof y\". " +
  4754  						"You need to insert parentheses to get \"!(x instanceof y)\" instead."}},
  4755  				})
  4756  			}
  4757  
  4758  			p.lexer.Next()
  4759  			left = js_ast.Expr{Loc: left.Loc, Data: &js_ast.EBinary{Op: js_ast.BinOpInstanceof, Left: left, Right: p.parseExpr(js_ast.LCompare)}}
  4760  
  4761  		default:
  4762  			// Handle the TypeScript "as"/"satisfies" operator
  4763  			if p.options.ts.Parse && level < js_ast.LCompare && !p.lexer.HasNewlineBefore && (p.lexer.IsContextualKeyword("as") || p.lexer.IsContextualKeyword("satisfies")) {
  4764  				p.lexer.Next()
  4765  				p.skipTypeScriptType(js_ast.LLowest)
  4766  
  4767  				// These tokens are not allowed to follow a cast expression. This isn't
  4768  				// an outright error because it may be on a new line, in which case it's
  4769  				// the start of a new expression when it's after a cast:
  4770  				//
  4771  				//   x = y as z
  4772  				//   (something);
  4773  				//
  4774  				switch p.lexer.Token {
  4775  				case js_lexer.TPlusPlus, js_lexer.TMinusMinus, js_lexer.TNoSubstitutionTemplateLiteral,
  4776  					js_lexer.TTemplateHead, js_lexer.TOpenParen, js_lexer.TOpenBracket, js_lexer.TQuestionDot:
  4777  					p.forbidSuffixAfterAsLoc = p.lexer.Loc()
  4778  					return left
  4779  				}
  4780  				if p.lexer.Token.IsAssign() {
  4781  					p.forbidSuffixAfterAsLoc = p.lexer.Loc()
  4782  					return left
  4783  				}
  4784  				continue
  4785  			}
  4786  
  4787  			return left
  4788  		}
  4789  	}
  4790  }
  4791  
  4792  func (p *parser) parseExprOrLetOrUsingStmt(opts parseStmtOpts) (js_ast.Expr, js_ast.Stmt, []js_ast.Decl) {
  4793  	couldBeLet := false
  4794  	couldBeUsing := false
  4795  	couldBeAwaitUsing := false
  4796  	tokenRange := p.lexer.Range()
  4797  
  4798  	if p.lexer.Token == js_lexer.TIdentifier {
  4799  		raw := p.lexer.Raw()
  4800  		couldBeLet = raw == "let"
  4801  		couldBeUsing = raw == "using"
  4802  		couldBeAwaitUsing = raw == "await" && p.fnOrArrowDataParse.await == allowExpr
  4803  	}
  4804  
  4805  	if !couldBeLet && !couldBeUsing && !couldBeAwaitUsing {
  4806  		var flags exprFlag
  4807  		if opts.isForLoopInit {
  4808  			flags |= exprFlagForLoopInit
  4809  		}
  4810  		if opts.isForAwaitLoopInit {
  4811  			flags |= exprFlagForAwaitLoopInit
  4812  		}
  4813  		return p.parseExprCommon(js_ast.LLowest, nil, flags), js_ast.Stmt{}, nil
  4814  	}
  4815  
  4816  	name := p.lexer.Identifier
  4817  	p.lexer.Next()
  4818  
  4819  	if couldBeLet {
  4820  		isLet := opts.isExport
  4821  		switch p.lexer.Token {
  4822  		case js_lexer.TIdentifier, js_lexer.TOpenBracket, js_lexer.TOpenBrace:
  4823  			if opts.lexicalDecl == lexicalDeclAllowAll || !p.lexer.HasNewlineBefore || p.lexer.Token == js_lexer.TOpenBracket {
  4824  				isLet = true
  4825  			}
  4826  		}
  4827  		if isLet {
  4828  			// Handle a "let" declaration
  4829  			if opts.lexicalDecl != lexicalDeclAllowAll {
  4830  				p.forbidLexicalDecl(tokenRange.Loc)
  4831  			}
  4832  			p.markSyntaxFeature(compat.ConstAndLet, tokenRange)
  4833  			decls := p.parseAndDeclareDecls(ast.SymbolOther, opts)
  4834  			return js_ast.Expr{}, js_ast.Stmt{Loc: tokenRange.Loc, Data: &js_ast.SLocal{
  4835  				Kind:     js_ast.LocalLet,
  4836  				Decls:    decls,
  4837  				IsExport: opts.isExport,
  4838  			}}, decls
  4839  		}
  4840  	} else if couldBeUsing && p.lexer.Token == js_lexer.TIdentifier && !p.lexer.HasNewlineBefore && (!opts.isForLoopInit || p.lexer.Raw() != "of") {
  4841  		// Handle a "using" declaration
  4842  		if opts.lexicalDecl != lexicalDeclAllowAll {
  4843  			p.forbidLexicalDecl(tokenRange.Loc)
  4844  		}
  4845  		opts.isUsingStmt = true
  4846  		decls := p.parseAndDeclareDecls(ast.SymbolConst, opts)
  4847  		if !opts.isForLoopInit {
  4848  			p.requireInitializers(js_ast.LocalUsing, decls)
  4849  		}
  4850  		return js_ast.Expr{}, js_ast.Stmt{Loc: tokenRange.Loc, Data: &js_ast.SLocal{
  4851  			Kind:     js_ast.LocalUsing,
  4852  			Decls:    decls,
  4853  			IsExport: opts.isExport,
  4854  		}}, decls
  4855  	} else if couldBeAwaitUsing {
  4856  		// Handle an "await using" declaration
  4857  		if p.fnOrArrowDataParse.isTopLevel {
  4858  			p.topLevelAwaitKeyword = tokenRange
  4859  		}
  4860  		var value js_ast.Expr
  4861  		if p.lexer.Token == js_lexer.TIdentifier && p.lexer.Raw() == "using" {
  4862  			usingLoc := p.saveExprCommentsHere()
  4863  			usingRange := p.lexer.Range()
  4864  			p.lexer.Next()
  4865  			if p.lexer.Token == js_lexer.TIdentifier && !p.lexer.HasNewlineBefore {
  4866  				// It's an "await using" declaration if we get here
  4867  				if opts.lexicalDecl != lexicalDeclAllowAll {
  4868  					p.forbidLexicalDecl(usingRange.Loc)
  4869  				}
  4870  				opts.isUsingStmt = true
  4871  				decls := p.parseAndDeclareDecls(ast.SymbolConst, opts)
  4872  				if !opts.isForLoopInit {
  4873  					p.requireInitializers(js_ast.LocalAwaitUsing, decls)
  4874  				}
  4875  				return js_ast.Expr{}, js_ast.Stmt{Loc: tokenRange.Loc, Data: &js_ast.SLocal{
  4876  					Kind:     js_ast.LocalAwaitUsing,
  4877  					Decls:    decls,
  4878  					IsExport: opts.isExport,
  4879  				}}, decls
  4880  			}
  4881  			value = js_ast.Expr{Loc: usingLoc, Data: &js_ast.EIdentifier{Ref: p.storeNameInRef(js_lexer.MaybeSubstring{String: "using"})}}
  4882  		} else {
  4883  			value = p.parseExpr(js_ast.LPrefix)
  4884  		}
  4885  		if p.lexer.Token == js_lexer.TAsteriskAsterisk {
  4886  			p.lexer.Unexpected()
  4887  		}
  4888  		value = p.parseSuffix(value, js_ast.LPrefix, nil, 0)
  4889  		expr := js_ast.Expr{Loc: tokenRange.Loc, Data: &js_ast.EAwait{Value: value}}
  4890  		return p.parseSuffix(expr, js_ast.LLowest, nil, 0), js_ast.Stmt{}, nil
  4891  	}
  4892  
  4893  	// Parse the remainder of this expression that starts with an identifier
  4894  	expr := js_ast.Expr{Loc: tokenRange.Loc, Data: &js_ast.EIdentifier{Ref: p.storeNameInRef(name)}}
  4895  	return p.parseSuffix(expr, js_ast.LLowest, nil, 0), js_ast.Stmt{}, nil
  4896  }
  4897  
  4898  func (p *parser) parseCallArgs() (args []js_ast.Expr, closeParenLoc logger.Loc, isMultiLine bool) {
  4899  	// Allow "in" inside call arguments
  4900  	oldAllowIn := p.allowIn
  4901  	p.allowIn = true
  4902  
  4903  	p.lexer.Expect(js_lexer.TOpenParen)
  4904  
  4905  	for p.lexer.Token != js_lexer.TCloseParen {
  4906  		if p.lexer.HasNewlineBefore {
  4907  			isMultiLine = true
  4908  		}
  4909  		loc := p.lexer.Loc()
  4910  		isSpread := p.lexer.Token == js_lexer.TDotDotDot
  4911  		if isSpread {
  4912  			p.markSyntaxFeature(compat.RestArgument, p.lexer.Range())
  4913  			p.lexer.Next()
  4914  		}
  4915  		arg := p.parseExpr(js_ast.LComma)
  4916  		if isSpread {
  4917  			arg = js_ast.Expr{Loc: loc, Data: &js_ast.ESpread{Value: arg}}
  4918  		}
  4919  		args = append(args, arg)
  4920  		if p.lexer.Token != js_lexer.TComma {
  4921  			break
  4922  		}
  4923  		if p.lexer.HasNewlineBefore {
  4924  			isMultiLine = true
  4925  		}
  4926  		p.lexer.Next()
  4927  	}
  4928  
  4929  	if p.lexer.HasNewlineBefore {
  4930  		isMultiLine = true
  4931  	}
  4932  	closeParenLoc = p.saveExprCommentsHere()
  4933  	p.lexer.Expect(js_lexer.TCloseParen)
  4934  	p.allowIn = oldAllowIn
  4935  	return
  4936  }
  4937  
  4938  func (p *parser) parseJSXNamespacedName() (logger.Range, js_lexer.MaybeSubstring) {
  4939  	nameRange := p.lexer.Range()
  4940  	name := p.lexer.Identifier
  4941  	p.lexer.ExpectInsideJSXElement(js_lexer.TIdentifier)
  4942  
  4943  	// Parse JSX namespaces. These are not supported by React or TypeScript
  4944  	// but someone using JSX syntax in more obscure ways may find a use for
  4945  	// them. A namespaced name is just always turned into a string so you
  4946  	// can't use this feature to reference JavaScript identifiers.
  4947  	if p.lexer.Token == js_lexer.TColon {
  4948  		// Parse the colon
  4949  		nameRange.Len = p.lexer.Range().End() - nameRange.Loc.Start
  4950  		ns := name.String + ":"
  4951  		p.lexer.NextInsideJSXElement()
  4952  
  4953  		// Parse the second identifier
  4954  		if p.lexer.Token == js_lexer.TIdentifier {
  4955  			nameRange.Len = p.lexer.Range().End() - nameRange.Loc.Start
  4956  			ns += p.lexer.Identifier.String
  4957  			p.lexer.NextInsideJSXElement()
  4958  		} else {
  4959  			p.log.AddError(&p.tracker, logger.Range{Loc: logger.Loc{Start: nameRange.End()}},
  4960  				fmt.Sprintf("Expected identifier after %q in namespaced JSX name", ns))
  4961  			panic(js_lexer.LexerPanic{})
  4962  		}
  4963  		return nameRange, js_lexer.MaybeSubstring{String: ns}
  4964  	}
  4965  
  4966  	return nameRange, name
  4967  }
  4968  
  4969  func tagOrFragmentHelpText(tag string) string {
  4970  	if tag == "" {
  4971  		return "fragment tag"
  4972  	}
  4973  	return fmt.Sprintf("%q tag", tag)
  4974  }
  4975  
  4976  func (p *parser) parseJSXTag() (logger.Range, string, js_ast.Expr) {
  4977  	loc := p.lexer.Loc()
  4978  
  4979  	// A missing tag is a fragment
  4980  	if p.lexer.Token == js_lexer.TGreaterThan {
  4981  		return logger.Range{Loc: loc, Len: 0}, "", js_ast.Expr{}
  4982  	}
  4983  
  4984  	// The tag is an identifier
  4985  	tagRange, tagName := p.parseJSXNamespacedName()
  4986  
  4987  	// Certain identifiers are strings
  4988  	if strings.ContainsAny(tagName.String, "-:") || (p.lexer.Token != js_lexer.TDot && tagName.String[0] >= 'a' && tagName.String[0] <= 'z') {
  4989  		return tagRange, tagName.String, js_ast.Expr{Loc: loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(tagName.String)}}
  4990  	}
  4991  
  4992  	// Otherwise, this is an identifier
  4993  	tag := js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: p.storeNameInRef(tagName)}}
  4994  
  4995  	// Parse a member expression chain
  4996  	chain := tagName.String
  4997  	for p.lexer.Token == js_lexer.TDot {
  4998  		p.lexer.NextInsideJSXElement()
  4999  		memberRange := p.lexer.Range()
  5000  		member := p.lexer.Identifier
  5001  		p.lexer.ExpectInsideJSXElement(js_lexer.TIdentifier)
  5002  
  5003  		// Dashes are not allowed in member expression chains
  5004  		index := strings.IndexByte(member.String, '-')
  5005  		if index >= 0 {
  5006  			p.log.AddError(&p.tracker, logger.Range{Loc: logger.Loc{Start: memberRange.Loc.Start + int32(index)}},
  5007  				"Unexpected \"-\"")
  5008  			panic(js_lexer.LexerPanic{})
  5009  		}
  5010  
  5011  		chain += "." + member.String
  5012  		tag = js_ast.Expr{Loc: loc, Data: p.dotOrMangledPropParse(tag, member, memberRange.Loc, js_ast.OptionalChainNone, wasOriginallyDot)}
  5013  		tagRange.Len = memberRange.Loc.Start + memberRange.Len - tagRange.Loc.Start
  5014  	}
  5015  
  5016  	return tagRange, chain, tag
  5017  }
  5018  
  5019  func (p *parser) parseJSXElement(loc logger.Loc) js_ast.Expr {
  5020  	// Keep track of the location of the first JSX element for error messages
  5021  	if p.firstJSXElementLoc.Start == -1 {
  5022  		p.firstJSXElementLoc = loc
  5023  	}
  5024  
  5025  	// Parse the tag
  5026  	startRange, startText, startTagOrNil := p.parseJSXTag()
  5027  
  5028  	// The tag may have TypeScript type arguments: "<Foo<T>/>"
  5029  	if p.options.ts.Parse {
  5030  		// Pass a flag to the type argument skipper because we need to call
  5031  		// js_lexer.NextInsideJSXElement() after we hit the closing ">". The next
  5032  		// token after the ">" might be an attribute name with a dash in it
  5033  		// like this: "<Foo<T> data-disabled/>"
  5034  		p.skipTypeScriptTypeArguments(skipTypeScriptTypeArgumentsOpts{isInsideJSXElement: true})
  5035  	}
  5036  
  5037  	// Parse attributes
  5038  	var previousStringWithBackslashLoc logger.Loc
  5039  	properties := []js_ast.Property{}
  5040  	isSingleLine := true
  5041  	if startTagOrNil.Data != nil {
  5042  	parseAttributes:
  5043  		for {
  5044  			if p.lexer.HasNewlineBefore {
  5045  				isSingleLine = false
  5046  			}
  5047  
  5048  			switch p.lexer.Token {
  5049  			case js_lexer.TIdentifier:
  5050  				// Parse the key
  5051  				keyRange, keyName := p.parseJSXNamespacedName()
  5052  				var key js_ast.Expr
  5053  				if p.isMangledProp(keyName.String) && !strings.ContainsRune(keyName.String, ':') {
  5054  					key = js_ast.Expr{Loc: keyRange.Loc, Data: &js_ast.ENameOfSymbol{Ref: p.storeNameInRef(keyName)}}
  5055  				} else {
  5056  					key = js_ast.Expr{Loc: keyRange.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(keyName.String)}}
  5057  				}
  5058  
  5059  				// Parse the value
  5060  				var value js_ast.Expr
  5061  				var flags js_ast.PropertyFlags
  5062  				if p.lexer.Token != js_lexer.TEquals {
  5063  					// Implicitly true value
  5064  					flags |= js_ast.PropertyWasShorthand
  5065  					value = js_ast.Expr{Loc: logger.Loc{Start: keyRange.Loc.Start + keyRange.Len}, Data: &js_ast.EBoolean{Value: true}}
  5066  				} else {
  5067  					// Use NextInsideJSXElement() not Next() so we can parse a JSX-style string literal
  5068  					p.lexer.NextInsideJSXElement()
  5069  					if p.lexer.Token == js_lexer.TStringLiteral {
  5070  						stringLoc := p.lexer.Loc()
  5071  						if p.lexer.PreviousBackslashQuoteInJSX.Loc.Start > stringLoc.Start {
  5072  							previousStringWithBackslashLoc = stringLoc
  5073  						}
  5074  						if p.options.jsx.Preserve {
  5075  							value = js_ast.Expr{Loc: stringLoc, Data: &js_ast.EJSXText{Raw: p.lexer.Raw()}}
  5076  						} else {
  5077  							value = js_ast.Expr{Loc: stringLoc, Data: &js_ast.EString{Value: p.lexer.StringLiteral()}}
  5078  						}
  5079  						p.lexer.NextInsideJSXElement()
  5080  					} else if p.lexer.Token == js_lexer.TLessThan {
  5081  						// This may be removed in the future: https://github.com/facebook/jsx/issues/53
  5082  						loc := p.lexer.Loc()
  5083  						p.lexer.NextInsideJSXElement()
  5084  						flags |= js_ast.PropertyWasShorthand
  5085  						value = p.parseJSXElement(loc)
  5086  
  5087  						// The call to parseJSXElement() above doesn't consume the last
  5088  						// TGreaterThan because the caller knows what Next() function to call.
  5089  						// Use NextJSXElementChild() here since the next token is inside a JSX
  5090  						// element.
  5091  						p.lexer.NextInsideJSXElement()
  5092  					} else {
  5093  						// Use Expect() not ExpectInsideJSXElement() so we can parse expression tokens
  5094  						p.lexer.Expect(js_lexer.TOpenBrace)
  5095  						value = p.parseExpr(js_ast.LLowest)
  5096  						p.lexer.ExpectInsideJSXElement(js_lexer.TCloseBrace)
  5097  					}
  5098  				}
  5099  
  5100  				// Add a property
  5101  				properties = append(properties, js_ast.Property{
  5102  					Loc:        keyRange.Loc,
  5103  					Key:        key,
  5104  					ValueOrNil: value,
  5105  					Flags:      flags,
  5106  				})
  5107  
  5108  			case js_lexer.TOpenBrace:
  5109  				// Use Next() not ExpectInsideJSXElement() so we can parse "..."
  5110  				p.lexer.Next()
  5111  				dotLoc := p.saveExprCommentsHere()
  5112  				p.lexer.Expect(js_lexer.TDotDotDot)
  5113  				value := p.parseExpr(js_ast.LComma)
  5114  				properties = append(properties, js_ast.Property{
  5115  					Kind:       js_ast.PropertySpread,
  5116  					Loc:        dotLoc,
  5117  					ValueOrNil: value,
  5118  				})
  5119  
  5120  				// Use NextInsideJSXElement() not Next() so we can parse ">>" as ">"
  5121  				p.lexer.NextInsideJSXElement()
  5122  
  5123  			default:
  5124  				break parseAttributes
  5125  			}
  5126  		}
  5127  
  5128  		// Check for and warn about duplicate attributes
  5129  		if len(properties) > 1 && !p.suppressWarningsAboutWeirdCode {
  5130  			keys := make(map[string]logger.Loc)
  5131  			for _, property := range properties {
  5132  				if property.Kind != js_ast.PropertySpread {
  5133  					if str, ok := property.Key.Data.(*js_ast.EString); ok {
  5134  						key := helpers.UTF16ToString(str.Value)
  5135  						if prevLoc, ok := keys[key]; ok {
  5136  							r := js_lexer.RangeOfIdentifier(p.source, property.Key.Loc)
  5137  							p.log.AddIDWithNotes(logger.MsgID_JS_DuplicateObjectKey, logger.Warning, &p.tracker, r,
  5138  								fmt.Sprintf("Duplicate %q attribute in JSX element", key),
  5139  								[]logger.MsgData{p.tracker.MsgData(js_lexer.RangeOfIdentifier(p.source, prevLoc),
  5140  									fmt.Sprintf("The original %q attribute is here:", key))})
  5141  						}
  5142  						keys[key] = property.Key.Loc
  5143  					}
  5144  				}
  5145  			}
  5146  		}
  5147  	}
  5148  
  5149  	// People sometimes try to use the output of "JSON.stringify()" as a JSX
  5150  	// attribute when automatically-generating JSX code. Doing so is incorrect
  5151  	// because JSX strings work like XML instead of like JS (since JSX is XML-in-
  5152  	// JS). Specifically, using a backslash before a quote does not cause it to
  5153  	// be escaped:
  5154  	//
  5155  	//   JSX ends the "content" attribute here and sets "content" to 'some so-called \\'
  5156  	//                                          v
  5157  	//         <Button content="some so-called \"button text\"" />
  5158  	//                                                      ^
  5159  	//       There is no "=" after the JSX attribute "text", so we expect a ">"
  5160  	//
  5161  	// This code special-cases this error to provide a less obscure error message.
  5162  	if p.lexer.Token == js_lexer.TSyntaxError && p.lexer.Raw() == "\\" && previousStringWithBackslashLoc.Start > 0 {
  5163  		msg := logger.Msg{Kind: logger.Error, Data: p.tracker.MsgData(p.lexer.Range(),
  5164  			"Unexpected backslash in JSX element")}
  5165  
  5166  		// Option 1: Suggest using an XML escape
  5167  		jsEscape := p.source.TextForRange(p.lexer.PreviousBackslashQuoteInJSX)
  5168  		xmlEscape := ""
  5169  		if jsEscape == "\\\"" {
  5170  			xmlEscape = "&quot;"
  5171  		} else if jsEscape == "\\'" {
  5172  			xmlEscape = "&apos;"
  5173  		}
  5174  		if xmlEscape != "" {
  5175  			data := p.tracker.MsgData(p.lexer.PreviousBackslashQuoteInJSX,
  5176  				"Quoted JSX attributes use XML-style escapes instead of JavaScript-style escapes:")
  5177  			data.Location.Suggestion = xmlEscape
  5178  			msg.Notes = append(msg.Notes, data)
  5179  		}
  5180  
  5181  		// Option 2: Suggest using a JavaScript string
  5182  		if stringRange := p.source.RangeOfString(previousStringWithBackslashLoc); stringRange.Len > 0 {
  5183  			data := p.tracker.MsgData(stringRange,
  5184  				"Consider using a JavaScript string inside {...} instead of a quoted JSX attribute:")
  5185  			data.Location.Suggestion = fmt.Sprintf("{%s}", p.source.TextForRange(stringRange))
  5186  			msg.Notes = append(msg.Notes, data)
  5187  		}
  5188  
  5189  		p.log.AddMsg(msg)
  5190  		panic(js_lexer.LexerPanic{})
  5191  	}
  5192  
  5193  	// A slash here is a self-closing element
  5194  	if p.lexer.Token == js_lexer.TSlash {
  5195  		// Use NextInsideJSXElement() not Next() so we can parse ">>" as ">"
  5196  		closeLoc := p.lexer.Loc()
  5197  		p.lexer.NextInsideJSXElement()
  5198  		if p.lexer.Token != js_lexer.TGreaterThan {
  5199  			p.lexer.Expected(js_lexer.TGreaterThan)
  5200  		}
  5201  		return js_ast.Expr{Loc: loc, Data: &js_ast.EJSXElement{
  5202  			TagOrNil:        startTagOrNil,
  5203  			Properties:      properties,
  5204  			CloseLoc:        closeLoc,
  5205  			IsTagSingleLine: isSingleLine,
  5206  		}}
  5207  	}
  5208  
  5209  	// Attempt to provide a better error message for people incorrectly trying to
  5210  	// use arrow functions in TSX (which doesn't work because they are JSX elements)
  5211  	if p.options.ts.Parse && len(properties) == 0 && startText != "" && p.lexer.Token == js_lexer.TGreaterThan &&
  5212  		strings.HasPrefix(p.source.Contents[p.lexer.Loc().Start:], ">(") {
  5213  		badArrowInTSXRange := p.lexer.BadArrowInTSXRange
  5214  		badArrowInTSXSuggestion := p.lexer.BadArrowInTSXSuggestion
  5215  
  5216  		p.lexer.CouldBeBadArrowInTSX++
  5217  		p.lexer.BadArrowInTSXRange = logger.Range{Loc: loc, Len: p.lexer.Range().End() - loc.Start}
  5218  		p.lexer.BadArrowInTSXSuggestion = fmt.Sprintf("<%s,>", startText)
  5219  
  5220  		defer func() {
  5221  			p.lexer.CouldBeBadArrowInTSX--
  5222  			p.lexer.BadArrowInTSXRange = badArrowInTSXRange
  5223  			p.lexer.BadArrowInTSXSuggestion = badArrowInTSXSuggestion
  5224  		}()
  5225  	}
  5226  
  5227  	// Use ExpectJSXElementChild() so we parse child strings
  5228  	p.lexer.ExpectJSXElementChild(js_lexer.TGreaterThan)
  5229  
  5230  	// Parse the children of this element
  5231  	nullableChildren := []js_ast.Expr{}
  5232  	for {
  5233  		switch p.lexer.Token {
  5234  		case js_lexer.TStringLiteral:
  5235  			if p.options.jsx.Preserve {
  5236  				nullableChildren = append(nullableChildren, js_ast.Expr{Loc: p.lexer.Loc(), Data: &js_ast.EJSXText{Raw: p.lexer.Raw()}})
  5237  			} else {
  5238  				nullableChildren = append(nullableChildren, js_ast.Expr{Loc: p.lexer.Loc(), Data: &js_ast.EString{Value: p.lexer.StringLiteral()}})
  5239  			}
  5240  			p.lexer.NextJSXElementChild()
  5241  
  5242  		case js_lexer.TOpenBrace:
  5243  			// Use Next() instead of NextJSXElementChild() here since the next token is an expression
  5244  			p.lexer.Next()
  5245  
  5246  			// The expression is optional, and may be absent
  5247  			if p.lexer.Token == js_lexer.TCloseBrace {
  5248  				// Save comments even for absent expressions
  5249  				nullableChildren = append(nullableChildren, js_ast.Expr{Loc: p.saveExprCommentsHere(), Data: nil})
  5250  			} else {
  5251  				if p.lexer.Token == js_lexer.TDotDotDot {
  5252  					// TypeScript preserves "..." before JSX child expressions here.
  5253  					// Babel gives the error "Spread children are not supported in React"
  5254  					// instead, so it should be safe to support this TypeScript-specific
  5255  					// behavior. Note that TypeScript's behavior changed in TypeScript 4.5.
  5256  					// Before that, the "..." was omitted instead of being preserved.
  5257  					itemLoc := p.lexer.Loc()
  5258  					p.markSyntaxFeature(compat.RestArgument, p.lexer.Range())
  5259  					p.lexer.Next()
  5260  					nullableChildren = append(nullableChildren, js_ast.Expr{Loc: itemLoc, Data: &js_ast.ESpread{Value: p.parseExpr(js_ast.LLowest)}})
  5261  				} else {
  5262  					nullableChildren = append(nullableChildren, p.parseExpr(js_ast.LLowest))
  5263  				}
  5264  			}
  5265  
  5266  			// Use ExpectJSXElementChild() so we parse child strings
  5267  			p.lexer.ExpectJSXElementChild(js_lexer.TCloseBrace)
  5268  
  5269  		case js_lexer.TLessThan:
  5270  			lessThanLoc := p.lexer.Loc()
  5271  			p.lexer.NextInsideJSXElement()
  5272  
  5273  			if p.lexer.Token != js_lexer.TSlash {
  5274  				// This is a child element
  5275  				nullableChildren = append(nullableChildren, p.parseJSXElement(lessThanLoc))
  5276  
  5277  				// The call to parseJSXElement() above doesn't consume the last
  5278  				// TGreaterThan because the caller knows what Next() function to call.
  5279  				// Use NextJSXElementChild() here since the next token is an element
  5280  				// child.
  5281  				p.lexer.NextJSXElementChild()
  5282  				continue
  5283  			}
  5284  
  5285  			// This is the closing element
  5286  			p.lexer.NextInsideJSXElement()
  5287  			endRange, endText, _ := p.parseJSXTag()
  5288  			if startText != endText {
  5289  				startTag := tagOrFragmentHelpText(startText)
  5290  				endTag := tagOrFragmentHelpText(endText)
  5291  				msg := logger.Msg{
  5292  					Kind:  logger.Error,
  5293  					Data:  p.tracker.MsgData(endRange, fmt.Sprintf("Unexpected closing %s does not match opening %s", endTag, startTag)),
  5294  					Notes: []logger.MsgData{p.tracker.MsgData(startRange, fmt.Sprintf("The opening %s is here:", startTag))},
  5295  				}
  5296  				msg.Data.Location.Suggestion = startText
  5297  				p.log.AddMsg(msg)
  5298  			}
  5299  			if p.lexer.Token != js_lexer.TGreaterThan {
  5300  				p.lexer.Expected(js_lexer.TGreaterThan)
  5301  			}
  5302  
  5303  			return js_ast.Expr{Loc: loc, Data: &js_ast.EJSXElement{
  5304  				TagOrNil:         startTagOrNil,
  5305  				Properties:       properties,
  5306  				NullableChildren: nullableChildren,
  5307  				CloseLoc:         lessThanLoc,
  5308  				IsTagSingleLine:  isSingleLine,
  5309  			}}
  5310  
  5311  		case js_lexer.TEndOfFile:
  5312  			startTag := tagOrFragmentHelpText(startText)
  5313  			msg := logger.Msg{
  5314  				Kind:  logger.Error,
  5315  				Data:  p.tracker.MsgData(p.lexer.Range(), fmt.Sprintf("Unexpected end of file before a closing %s", startTag)),
  5316  				Notes: []logger.MsgData{p.tracker.MsgData(startRange, fmt.Sprintf("The opening %s is here:", startTag))},
  5317  			}
  5318  			msg.Data.Location.Suggestion = fmt.Sprintf("</%s>", startText)
  5319  			p.log.AddMsg(msg)
  5320  			panic(js_lexer.LexerPanic{})
  5321  
  5322  		default:
  5323  			p.lexer.Unexpected()
  5324  		}
  5325  	}
  5326  }
  5327  
  5328  func (p *parser) parseTemplateParts(includeRaw bool) (parts []js_ast.TemplatePart, legacyOctalLoc logger.Loc) {
  5329  	// Allow "in" inside template literals
  5330  	oldAllowIn := p.allowIn
  5331  	p.allowIn = true
  5332  
  5333  	for {
  5334  		p.lexer.Next()
  5335  		value := p.parseExpr(js_ast.LLowest)
  5336  		tailLoc := p.lexer.Loc()
  5337  		p.lexer.RescanCloseBraceAsTemplateToken()
  5338  		if includeRaw {
  5339  			tailCooked, tailRaw := p.lexer.CookedAndRawTemplateContents()
  5340  			parts = append(parts, js_ast.TemplatePart{
  5341  				Value:      value,
  5342  				TailLoc:    tailLoc,
  5343  				TailCooked: tailCooked,
  5344  				TailRaw:    tailRaw,
  5345  			})
  5346  		} else {
  5347  			parts = append(parts, js_ast.TemplatePart{
  5348  				Value:      value,
  5349  				TailLoc:    tailLoc,
  5350  				TailCooked: p.lexer.StringLiteral(),
  5351  			})
  5352  			if p.lexer.LegacyOctalLoc.Start > tailLoc.Start {
  5353  				legacyOctalLoc = p.lexer.LegacyOctalLoc
  5354  			}
  5355  		}
  5356  		if p.lexer.Token == js_lexer.TTemplateTail {
  5357  			p.lexer.Next()
  5358  			break
  5359  		}
  5360  	}
  5361  
  5362  	p.allowIn = oldAllowIn
  5363  
  5364  	return parts, legacyOctalLoc
  5365  }
  5366  
  5367  func (p *parser) parseAndDeclareDecls(kind ast.SymbolKind, opts parseStmtOpts) []js_ast.Decl {
  5368  	decls := []js_ast.Decl{}
  5369  
  5370  	for {
  5371  		// Forbid "let let" and "const let" but not "var let"
  5372  		if (kind == ast.SymbolOther || kind == ast.SymbolConst) && p.lexer.IsContextualKeyword("let") {
  5373  			p.log.AddError(&p.tracker, p.lexer.Range(), "Cannot use \"let\" as an identifier here:")
  5374  		}
  5375  
  5376  		var valueOrNil js_ast.Expr
  5377  		local := p.parseBinding(parseBindingOpts{isUsingStmt: opts.isUsingStmt})
  5378  		p.declareBinding(kind, local, opts)
  5379  
  5380  		// Skip over types
  5381  		if p.options.ts.Parse {
  5382  			// "let foo!"
  5383  			isDefiniteAssignmentAssertion := p.lexer.Token == js_lexer.TExclamation && !p.lexer.HasNewlineBefore
  5384  			if isDefiniteAssignmentAssertion {
  5385  				p.lexer.Next()
  5386  			}
  5387  
  5388  			// "let foo: number"
  5389  			if isDefiniteAssignmentAssertion || p.lexer.Token == js_lexer.TColon {
  5390  				p.lexer.Expect(js_lexer.TColon)
  5391  				p.skipTypeScriptType(js_ast.LLowest)
  5392  			}
  5393  		}
  5394  
  5395  		if p.lexer.Token == js_lexer.TEquals {
  5396  			p.lexer.Next()
  5397  			valueOrNil = p.parseExpr(js_ast.LComma)
  5398  
  5399  			// Rollup (the tool that invented the "@__NO_SIDE_EFFECTS__" comment) only
  5400  			// applies this to the first declaration, and only when it's a "const".
  5401  			// For more info see: https://github.com/rollup/rollup/pull/5024/files
  5402  			if !p.options.ignoreDCEAnnotations && kind == ast.SymbolConst {
  5403  				switch e := valueOrNil.Data.(type) {
  5404  				case *js_ast.EArrow:
  5405  					if opts.hasNoSideEffectsComment {
  5406  						e.HasNoSideEffectsComment = true
  5407  					}
  5408  					if e.HasNoSideEffectsComment && !opts.isTypeScriptDeclare {
  5409  						if b, ok := local.Data.(*js_ast.BIdentifier); ok {
  5410  							p.symbols[b.Ref.InnerIndex].Flags |= ast.CallCanBeUnwrappedIfUnused
  5411  						}
  5412  					}
  5413  
  5414  				case *js_ast.EFunction:
  5415  					if opts.hasNoSideEffectsComment {
  5416  						e.Fn.HasNoSideEffectsComment = true
  5417  					}
  5418  					if e.Fn.HasNoSideEffectsComment && !opts.isTypeScriptDeclare {
  5419  						if b, ok := local.Data.(*js_ast.BIdentifier); ok {
  5420  							p.symbols[b.Ref.InnerIndex].Flags |= ast.CallCanBeUnwrappedIfUnused
  5421  						}
  5422  					}
  5423  				}
  5424  
  5425  				// Only apply this to the first declaration
  5426  				opts.hasNoSideEffectsComment = false
  5427  			}
  5428  		}
  5429  
  5430  		decls = append(decls, js_ast.Decl{Binding: local, ValueOrNil: valueOrNil})
  5431  
  5432  		if p.lexer.Token != js_lexer.TComma {
  5433  			break
  5434  		}
  5435  		p.lexer.Next()
  5436  	}
  5437  
  5438  	return decls
  5439  }
  5440  
  5441  func (p *parser) requireInitializers(kind js_ast.LocalKind, decls []js_ast.Decl) {
  5442  	for _, d := range decls {
  5443  		if d.ValueOrNil.Data == nil {
  5444  			what := "constant"
  5445  			if kind == js_ast.LocalUsing {
  5446  				what = "declaration"
  5447  			}
  5448  			if id, ok := d.Binding.Data.(*js_ast.BIdentifier); ok {
  5449  				r := js_lexer.RangeOfIdentifier(p.source, d.Binding.Loc)
  5450  				p.log.AddError(&p.tracker, r,
  5451  					fmt.Sprintf("The %s %q must be initialized", what, p.symbols[id.Ref.InnerIndex].OriginalName))
  5452  			} else {
  5453  				p.log.AddError(&p.tracker, logger.Range{Loc: d.Binding.Loc},
  5454  					fmt.Sprintf("This %s must be initialized", what))
  5455  			}
  5456  		}
  5457  	}
  5458  }
  5459  
  5460  func (p *parser) forbidInitializers(decls []js_ast.Decl, loopType string, isVar bool) {
  5461  	if len(decls) > 1 {
  5462  		p.log.AddError(&p.tracker, logger.Range{Loc: decls[0].Binding.Loc},
  5463  			fmt.Sprintf("for-%s loops must have a single declaration", loopType))
  5464  	} else if len(decls) == 1 && decls[0].ValueOrNil.Data != nil {
  5465  		if isVar {
  5466  			if _, ok := decls[0].Binding.Data.(*js_ast.BIdentifier); ok {
  5467  				// This is a weird special case. Initializers are allowed in "var"
  5468  				// statements with identifier bindings.
  5469  				return
  5470  			}
  5471  		}
  5472  		p.log.AddError(&p.tracker, logger.Range{Loc: decls[0].ValueOrNil.Loc},
  5473  			fmt.Sprintf("for-%s loop variables cannot have an initializer", loopType))
  5474  	}
  5475  }
  5476  
  5477  func (p *parser) parseClauseAlias(kind string) js_lexer.MaybeSubstring {
  5478  	loc := p.lexer.Loc()
  5479  
  5480  	// The alias may now be a string (see https://github.com/tc39/ecma262/pull/2154)
  5481  	if p.lexer.Token == js_lexer.TStringLiteral {
  5482  		r := p.source.RangeOfString(loc)
  5483  		alias, problem, ok := helpers.UTF16ToStringWithValidation(p.lexer.StringLiteral())
  5484  		if !ok {
  5485  			p.log.AddError(&p.tracker, r,
  5486  				fmt.Sprintf("This %s alias is invalid because it contains the unpaired Unicode surrogate U+%X", kind, problem))
  5487  		}
  5488  		return js_lexer.MaybeSubstring{String: alias}
  5489  	}
  5490  
  5491  	// The alias may be a keyword
  5492  	if !p.lexer.IsIdentifierOrKeyword() {
  5493  		p.lexer.Expect(js_lexer.TIdentifier)
  5494  	}
  5495  
  5496  	alias := p.lexer.Identifier
  5497  	p.checkForUnrepresentableIdentifier(loc, alias.String)
  5498  	return alias
  5499  }
  5500  
  5501  func (p *parser) parseImportClause() ([]js_ast.ClauseItem, bool) {
  5502  	items := []js_ast.ClauseItem{}
  5503  	p.lexer.Expect(js_lexer.TOpenBrace)
  5504  	isSingleLine := !p.lexer.HasNewlineBefore
  5505  
  5506  	for p.lexer.Token != js_lexer.TCloseBrace {
  5507  		isIdentifier := p.lexer.Token == js_lexer.TIdentifier
  5508  		aliasLoc := p.lexer.Loc()
  5509  		alias := p.parseClauseAlias("import")
  5510  		name := ast.LocRef{Loc: aliasLoc, Ref: p.storeNameInRef(alias)}
  5511  		originalName := alias
  5512  		p.lexer.Next()
  5513  
  5514  		// "import { type xx } from 'mod'"
  5515  		// "import { type xx as yy } from 'mod'"
  5516  		// "import { type 'xx' as yy } from 'mod'"
  5517  		// "import { type as } from 'mod'"
  5518  		// "import { type as as } from 'mod'"
  5519  		// "import { type as as as } from 'mod'"
  5520  		if p.options.ts.Parse && alias.String == "type" && p.lexer.Token != js_lexer.TComma && p.lexer.Token != js_lexer.TCloseBrace {
  5521  			if p.lexer.IsContextualKeyword("as") {
  5522  				p.lexer.Next()
  5523  				if p.lexer.IsContextualKeyword("as") {
  5524  					originalName = p.lexer.Identifier
  5525  					name = ast.LocRef{Loc: p.lexer.Loc(), Ref: p.storeNameInRef(originalName)}
  5526  					p.lexer.Next()
  5527  
  5528  					if p.lexer.Token == js_lexer.TIdentifier {
  5529  						// "import { type as as as } from 'mod'"
  5530  						// "import { type as as foo } from 'mod'"
  5531  						p.lexer.Next()
  5532  					} else {
  5533  						// "import { type as as } from 'mod'"
  5534  						items = append(items, js_ast.ClauseItem{
  5535  							Alias:        alias.String,
  5536  							AliasLoc:     aliasLoc,
  5537  							Name:         name,
  5538  							OriginalName: originalName.String,
  5539  						})
  5540  					}
  5541  				} else if p.lexer.Token == js_lexer.TIdentifier {
  5542  					// "import { type as xxx } from 'mod'"
  5543  					originalName = p.lexer.Identifier
  5544  					name = ast.LocRef{Loc: p.lexer.Loc(), Ref: p.storeNameInRef(originalName)}
  5545  					p.lexer.Expect(js_lexer.TIdentifier)
  5546  
  5547  					// Reject forbidden names
  5548  					if isEvalOrArguments(originalName.String) {
  5549  						r := js_lexer.RangeOfIdentifier(p.source, name.Loc)
  5550  						p.log.AddError(&p.tracker, r, fmt.Sprintf("Cannot use %q as an identifier here:", originalName.String))
  5551  					}
  5552  
  5553  					items = append(items, js_ast.ClauseItem{
  5554  						Alias:        alias.String,
  5555  						AliasLoc:     aliasLoc,
  5556  						Name:         name,
  5557  						OriginalName: originalName.String,
  5558  					})
  5559  				}
  5560  			} else {
  5561  				isIdentifier := p.lexer.Token == js_lexer.TIdentifier
  5562  
  5563  				// "import { type xx } from 'mod'"
  5564  				// "import { type xx as yy } from 'mod'"
  5565  				// "import { type if as yy } from 'mod'"
  5566  				// "import { type 'xx' as yy } from 'mod'"
  5567  				p.parseClauseAlias("import")
  5568  				p.lexer.Next()
  5569  
  5570  				if p.lexer.IsContextualKeyword("as") {
  5571  					p.lexer.Next()
  5572  					p.lexer.Expect(js_lexer.TIdentifier)
  5573  				} else if !isIdentifier {
  5574  					// An import where the name is a keyword must have an alias
  5575  					p.lexer.ExpectedString("\"as\"")
  5576  				}
  5577  			}
  5578  		} else {
  5579  			if p.lexer.IsContextualKeyword("as") {
  5580  				p.lexer.Next()
  5581  				originalName = p.lexer.Identifier
  5582  				name = ast.LocRef{Loc: p.lexer.Loc(), Ref: p.storeNameInRef(originalName)}
  5583  				p.lexer.Expect(js_lexer.TIdentifier)
  5584  			} else if !isIdentifier {
  5585  				// An import where the name is a keyword must have an alias
  5586  				p.lexer.ExpectedString("\"as\"")
  5587  			}
  5588  
  5589  			// Reject forbidden names
  5590  			if isEvalOrArguments(originalName.String) {
  5591  				r := js_lexer.RangeOfIdentifier(p.source, name.Loc)
  5592  				p.log.AddError(&p.tracker, r, fmt.Sprintf("Cannot use %q as an identifier here:", originalName.String))
  5593  			}
  5594  
  5595  			items = append(items, js_ast.ClauseItem{
  5596  				Alias:        alias.String,
  5597  				AliasLoc:     aliasLoc,
  5598  				Name:         name,
  5599  				OriginalName: originalName.String,
  5600  			})
  5601  		}
  5602  
  5603  		if p.lexer.Token != js_lexer.TComma {
  5604  			break
  5605  		}
  5606  		if p.lexer.HasNewlineBefore {
  5607  			isSingleLine = false
  5608  		}
  5609  		p.lexer.Next()
  5610  		if p.lexer.HasNewlineBefore {
  5611  			isSingleLine = false
  5612  		}
  5613  	}
  5614  
  5615  	if p.lexer.HasNewlineBefore {
  5616  		isSingleLine = false
  5617  	}
  5618  	p.lexer.Expect(js_lexer.TCloseBrace)
  5619  	return items, isSingleLine
  5620  }
  5621  
  5622  func (p *parser) parseExportClause() ([]js_ast.ClauseItem, bool) {
  5623  	items := []js_ast.ClauseItem{}
  5624  	firstNonIdentifierLoc := logger.Loc{}
  5625  	p.lexer.Expect(js_lexer.TOpenBrace)
  5626  	isSingleLine := !p.lexer.HasNewlineBefore
  5627  
  5628  	for p.lexer.Token != js_lexer.TCloseBrace {
  5629  		alias := p.parseClauseAlias("export")
  5630  		aliasLoc := p.lexer.Loc()
  5631  		name := ast.LocRef{Loc: aliasLoc, Ref: p.storeNameInRef(alias)}
  5632  		originalName := alias
  5633  
  5634  		// The name can actually be a keyword if we're really an "export from"
  5635  		// statement. However, we won't know until later. Allow keywords as
  5636  		// identifiers for now and throw an error later if there's no "from".
  5637  		//
  5638  		//   // This is fine
  5639  		//   export { default } from 'path'
  5640  		//
  5641  		//   // This is a syntax error
  5642  		//   export { default }
  5643  		//
  5644  		if p.lexer.Token != js_lexer.TIdentifier && firstNonIdentifierLoc.Start == 0 {
  5645  			firstNonIdentifierLoc = p.lexer.Loc()
  5646  		}
  5647  		p.lexer.Next()
  5648  
  5649  		if p.options.ts.Parse && alias.String == "type" && p.lexer.Token != js_lexer.TComma && p.lexer.Token != js_lexer.TCloseBrace {
  5650  			if p.lexer.IsContextualKeyword("as") {
  5651  				p.lexer.Next()
  5652  				if p.lexer.IsContextualKeyword("as") {
  5653  					alias = p.parseClauseAlias("export")
  5654  					aliasLoc = p.lexer.Loc()
  5655  					p.lexer.Next()
  5656  
  5657  					if p.lexer.Token != js_lexer.TComma && p.lexer.Token != js_lexer.TCloseBrace {
  5658  						// "export { type as as as }"
  5659  						// "export { type as as foo }"
  5660  						// "export { type as as 'foo' }"
  5661  						p.parseClauseAlias("export")
  5662  						p.lexer.Next()
  5663  					} else {
  5664  						// "export { type as as }"
  5665  						items = append(items, js_ast.ClauseItem{
  5666  							Alias:        alias.String,
  5667  							AliasLoc:     aliasLoc,
  5668  							Name:         name,
  5669  							OriginalName: originalName.String,
  5670  						})
  5671  					}
  5672  				} else if p.lexer.Token != js_lexer.TComma && p.lexer.Token != js_lexer.TCloseBrace {
  5673  					// "export { type as xxx }"
  5674  					// "export { type as 'xxx' }"
  5675  					alias = p.parseClauseAlias("export")
  5676  					aliasLoc = p.lexer.Loc()
  5677  					p.lexer.Next()
  5678  
  5679  					items = append(items, js_ast.ClauseItem{
  5680  						Alias:        alias.String,
  5681  						AliasLoc:     aliasLoc,
  5682  						Name:         name,
  5683  						OriginalName: originalName.String,
  5684  					})
  5685  				}
  5686  			} else {
  5687  				// The name can actually be a keyword if we're really an "export from"
  5688  				// statement. However, we won't know until later. Allow keywords as
  5689  				// identifiers for now and throw an error later if there's no "from".
  5690  				//
  5691  				//   // This is fine
  5692  				//   export { type default } from 'path'
  5693  				//
  5694  				//   // This is a syntax error
  5695  				//   export { type default }
  5696  				//
  5697  				if p.lexer.Token != js_lexer.TIdentifier && firstNonIdentifierLoc.Start == 0 {
  5698  					firstNonIdentifierLoc = p.lexer.Loc()
  5699  				}
  5700  
  5701  				// "export { type xx }"
  5702  				// "export { type xx as yy }"
  5703  				// "export { type xx as if }"
  5704  				// "export { type default } from 'path'"
  5705  				// "export { type default as if } from 'path'"
  5706  				// "export { type xx as 'yy' }"
  5707  				// "export { type 'xx' } from 'mod'"
  5708  				p.parseClauseAlias("export")
  5709  				p.lexer.Next()
  5710  
  5711  				if p.lexer.IsContextualKeyword("as") {
  5712  					p.lexer.Next()
  5713  					p.parseClauseAlias("export")
  5714  					p.lexer.Next()
  5715  				}
  5716  			}
  5717  		} else {
  5718  			if p.lexer.IsContextualKeyword("as") {
  5719  				p.lexer.Next()
  5720  				alias = p.parseClauseAlias("export")
  5721  				aliasLoc = p.lexer.Loc()
  5722  				p.lexer.Next()
  5723  			}
  5724  
  5725  			items = append(items, js_ast.ClauseItem{
  5726  				Alias:        alias.String,
  5727  				AliasLoc:     aliasLoc,
  5728  				Name:         name,
  5729  				OriginalName: originalName.String,
  5730  			})
  5731  		}
  5732  
  5733  		if p.lexer.Token != js_lexer.TComma {
  5734  			break
  5735  		}
  5736  		if p.lexer.HasNewlineBefore {
  5737  			isSingleLine = false
  5738  		}
  5739  		p.lexer.Next()
  5740  		if p.lexer.HasNewlineBefore {
  5741  			isSingleLine = false
  5742  		}
  5743  	}
  5744  
  5745  	if p.lexer.HasNewlineBefore {
  5746  		isSingleLine = false
  5747  	}
  5748  	p.lexer.Expect(js_lexer.TCloseBrace)
  5749  
  5750  	// Throw an error here if we found a keyword earlier and this isn't an
  5751  	// "export from" statement after all
  5752  	if firstNonIdentifierLoc.Start != 0 && !p.lexer.IsContextualKeyword("from") {
  5753  		r := js_lexer.RangeOfIdentifier(p.source, firstNonIdentifierLoc)
  5754  		p.log.AddError(&p.tracker, r, fmt.Sprintf("Expected identifier but found %q", p.source.TextForRange(r)))
  5755  		panic(js_lexer.LexerPanic{})
  5756  	}
  5757  
  5758  	return items, isSingleLine
  5759  }
  5760  
  5761  type parseBindingOpts struct {
  5762  	isUsingStmt bool
  5763  }
  5764  
  5765  func (p *parser) parseBinding(opts parseBindingOpts) js_ast.Binding {
  5766  	loc := p.lexer.Loc()
  5767  
  5768  	switch p.lexer.Token {
  5769  	case js_lexer.TIdentifier:
  5770  		name := p.lexer.Identifier
  5771  
  5772  		// Forbid invalid identifiers
  5773  		if (p.fnOrArrowDataParse.await != allowIdent && name.String == "await") ||
  5774  			(p.fnOrArrowDataParse.yield != allowIdent && name.String == "yield") {
  5775  			p.log.AddError(&p.tracker, p.lexer.Range(), fmt.Sprintf("Cannot use %q as an identifier here:", name.String))
  5776  		}
  5777  
  5778  		ref := p.storeNameInRef(name)
  5779  		p.lexer.Next()
  5780  		return js_ast.Binding{Loc: loc, Data: &js_ast.BIdentifier{Ref: ref}}
  5781  
  5782  	case js_lexer.TOpenBracket:
  5783  		if opts.isUsingStmt {
  5784  			break
  5785  		}
  5786  		p.markSyntaxFeature(compat.Destructuring, p.lexer.Range())
  5787  		p.lexer.Next()
  5788  		isSingleLine := !p.lexer.HasNewlineBefore
  5789  		items := []js_ast.ArrayBinding{}
  5790  		hasSpread := false
  5791  
  5792  		// "in" expressions are allowed
  5793  		oldAllowIn := p.allowIn
  5794  		p.allowIn = true
  5795  
  5796  		for p.lexer.Token != js_lexer.TCloseBracket {
  5797  			itemLoc := p.saveExprCommentsHere()
  5798  
  5799  			if p.lexer.Token == js_lexer.TComma {
  5800  				binding := js_ast.Binding{Loc: itemLoc, Data: js_ast.BMissingShared}
  5801  				items = append(items, js_ast.ArrayBinding{
  5802  					Binding: binding,
  5803  					Loc:     itemLoc,
  5804  				})
  5805  			} else {
  5806  				if p.lexer.Token == js_lexer.TDotDotDot {
  5807  					p.lexer.Next()
  5808  					hasSpread = true
  5809  
  5810  					// This was a bug in the ES2015 spec that was fixed in ES2016
  5811  					if p.lexer.Token != js_lexer.TIdentifier {
  5812  						p.markSyntaxFeature(compat.NestedRestBinding, p.lexer.Range())
  5813  					}
  5814  				}
  5815  
  5816  				p.saveExprCommentsHere()
  5817  				binding := p.parseBinding(parseBindingOpts{})
  5818  
  5819  				var defaultValueOrNil js_ast.Expr
  5820  				if !hasSpread && p.lexer.Token == js_lexer.TEquals {
  5821  					p.lexer.Next()
  5822  					defaultValueOrNil = p.parseExpr(js_ast.LComma)
  5823  				}
  5824  
  5825  				items = append(items, js_ast.ArrayBinding{
  5826  					Binding:           binding,
  5827  					DefaultValueOrNil: defaultValueOrNil,
  5828  					Loc:               itemLoc,
  5829  				})
  5830  
  5831  				// Commas after spread elements are not allowed
  5832  				if hasSpread && p.lexer.Token == js_lexer.TComma {
  5833  					p.log.AddError(&p.tracker, p.lexer.Range(), "Unexpected \",\" after rest pattern")
  5834  					panic(js_lexer.LexerPanic{})
  5835  				}
  5836  			}
  5837  
  5838  			if p.lexer.Token != js_lexer.TComma {
  5839  				break
  5840  			}
  5841  			if p.lexer.HasNewlineBefore {
  5842  				isSingleLine = false
  5843  			}
  5844  			p.lexer.Next()
  5845  			if p.lexer.HasNewlineBefore {
  5846  				isSingleLine = false
  5847  			}
  5848  		}
  5849  
  5850  		p.allowIn = oldAllowIn
  5851  
  5852  		if p.lexer.HasNewlineBefore {
  5853  			isSingleLine = false
  5854  		}
  5855  		closeBracketLoc := p.saveExprCommentsHere()
  5856  		p.lexer.Expect(js_lexer.TCloseBracket)
  5857  		return js_ast.Binding{Loc: loc, Data: &js_ast.BArray{
  5858  			Items:           items,
  5859  			HasSpread:       hasSpread,
  5860  			IsSingleLine:    isSingleLine,
  5861  			CloseBracketLoc: closeBracketLoc,
  5862  		}}
  5863  
  5864  	case js_lexer.TOpenBrace:
  5865  		if opts.isUsingStmt {
  5866  			break
  5867  		}
  5868  		p.markSyntaxFeature(compat.Destructuring, p.lexer.Range())
  5869  		p.lexer.Next()
  5870  		isSingleLine := !p.lexer.HasNewlineBefore
  5871  		properties := []js_ast.PropertyBinding{}
  5872  
  5873  		// "in" expressions are allowed
  5874  		oldAllowIn := p.allowIn
  5875  		p.allowIn = true
  5876  
  5877  		for p.lexer.Token != js_lexer.TCloseBrace {
  5878  			p.saveExprCommentsHere()
  5879  			property := p.parsePropertyBinding()
  5880  			properties = append(properties, property)
  5881  
  5882  			// Commas after spread elements are not allowed
  5883  			if property.IsSpread && p.lexer.Token == js_lexer.TComma {
  5884  				p.log.AddError(&p.tracker, p.lexer.Range(), "Unexpected \",\" after rest pattern")
  5885  				panic(js_lexer.LexerPanic{})
  5886  			}
  5887  
  5888  			if p.lexer.Token != js_lexer.TComma {
  5889  				break
  5890  			}
  5891  			if p.lexer.HasNewlineBefore {
  5892  				isSingleLine = false
  5893  			}
  5894  			p.lexer.Next()
  5895  			if p.lexer.HasNewlineBefore {
  5896  				isSingleLine = false
  5897  			}
  5898  		}
  5899  
  5900  		p.allowIn = oldAllowIn
  5901  
  5902  		if p.lexer.HasNewlineBefore {
  5903  			isSingleLine = false
  5904  		}
  5905  		closeBraceLoc := p.saveExprCommentsHere()
  5906  		p.lexer.Expect(js_lexer.TCloseBrace)
  5907  		return js_ast.Binding{Loc: loc, Data: &js_ast.BObject{
  5908  			Properties:    properties,
  5909  			IsSingleLine:  isSingleLine,
  5910  			CloseBraceLoc: closeBraceLoc,
  5911  		}}
  5912  	}
  5913  
  5914  	p.lexer.Expect(js_lexer.TIdentifier)
  5915  	return js_ast.Binding{}
  5916  }
  5917  
  5918  func (p *parser) parseFn(
  5919  	name *ast.LocRef,
  5920  	classKeyword logger.Range,
  5921  	decoratorContext decoratorContextFlags,
  5922  	data fnOrArrowDataParse,
  5923  ) (fn js_ast.Fn, hadBody bool) {
  5924  	fn.Name = name
  5925  	fn.HasRestArg = false
  5926  	fn.IsAsync = data.await == allowExpr
  5927  	fn.IsGenerator = data.yield == allowExpr
  5928  	fn.ArgumentsRef = ast.InvalidRef
  5929  	fn.OpenParenLoc = p.lexer.Loc()
  5930  	p.lexer.Expect(js_lexer.TOpenParen)
  5931  
  5932  	// Await and yield are not allowed in function arguments
  5933  	oldFnOrArrowData := p.fnOrArrowDataParse
  5934  	if data.await == allowExpr {
  5935  		p.fnOrArrowDataParse.await = forbidAll
  5936  	} else {
  5937  		p.fnOrArrowDataParse.await = allowIdent
  5938  	}
  5939  	if data.yield == allowExpr {
  5940  		p.fnOrArrowDataParse.yield = forbidAll
  5941  	} else {
  5942  		p.fnOrArrowDataParse.yield = allowIdent
  5943  	}
  5944  
  5945  	// Don't suggest inserting "async" before anything if "await" is found
  5946  	p.fnOrArrowDataParse.needsAsyncLoc.Start = -1
  5947  
  5948  	// If "super" is allowed in the body, it's allowed in the arguments
  5949  	p.fnOrArrowDataParse.allowSuperCall = data.allowSuperCall
  5950  	p.fnOrArrowDataParse.allowSuperProperty = data.allowSuperProperty
  5951  
  5952  	for p.lexer.Token != js_lexer.TCloseParen {
  5953  		// Skip over "this" type annotations
  5954  		if p.options.ts.Parse && p.lexer.Token == js_lexer.TThis {
  5955  			p.lexer.Next()
  5956  			if p.lexer.Token == js_lexer.TColon {
  5957  				p.lexer.Next()
  5958  				p.skipTypeScriptType(js_ast.LLowest)
  5959  			}
  5960  			if p.lexer.Token != js_lexer.TComma {
  5961  				break
  5962  			}
  5963  			p.lexer.Next()
  5964  			continue
  5965  		}
  5966  
  5967  		var decorators []js_ast.Decorator
  5968  		if data.decoratorScope != nil {
  5969  			oldAwait := p.fnOrArrowDataParse.await
  5970  			oldNeedsAsyncLoc := p.fnOrArrowDataParse.needsAsyncLoc
  5971  
  5972  			// While TypeScript parameter decorators are expressions, they are not
  5973  			// evaluated where they exist in the code. They are moved to after the
  5974  			// class declaration and evaluated there instead. Specifically this
  5975  			// TypeScript code:
  5976  			//
  5977  			//   class Foo {
  5978  			//     foo(@bar() baz) {}
  5979  			//   }
  5980  			//
  5981  			// becomes this JavaScript code:
  5982  			//
  5983  			//   class Foo {
  5984  			//     foo(baz) {}
  5985  			//   }
  5986  			//   __decorate([
  5987  			//     __param(0, bar())
  5988  			//   ], Foo.prototype, "foo", null);
  5989  			//
  5990  			// One consequence of this is that whether "await" is allowed or not
  5991  			// depends on whether the class declaration itself is inside an "async"
  5992  			// function or not. The TypeScript compiler allows code that does this:
  5993  			//
  5994  			//   async function fn(foo) {
  5995  			//     class Foo {
  5996  			//       foo(@bar(await foo) baz) {}
  5997  			//     }
  5998  			//     return Foo
  5999  			//   }
  6000  			//
  6001  			// because that becomes the following valid JavaScript:
  6002  			//
  6003  			//   async function fn(foo) {
  6004  			//     class Foo {
  6005  			//       foo(baz) {}
  6006  			//     }
  6007  			//     __decorate([
  6008  			//       __param(0, bar(await foo))
  6009  			//     ], Foo.prototype, "foo", null);
  6010  			//     return Foo;
  6011  			//   }
  6012  			//
  6013  			if oldFnOrArrowData.await == allowExpr {
  6014  				p.fnOrArrowDataParse.await = allowExpr
  6015  			} else {
  6016  				p.fnOrArrowDataParse.needsAsyncLoc = oldFnOrArrowData.needsAsyncLoc
  6017  			}
  6018  
  6019  			decorators = p.parseDecorators(data.decoratorScope, classKeyword, decoratorContext|decoratorInFnArgs)
  6020  
  6021  			p.fnOrArrowDataParse.await = oldAwait
  6022  			p.fnOrArrowDataParse.needsAsyncLoc = oldNeedsAsyncLoc
  6023  		}
  6024  
  6025  		if !fn.HasRestArg && p.lexer.Token == js_lexer.TDotDotDot {
  6026  			p.markSyntaxFeature(compat.RestArgument, p.lexer.Range())
  6027  			p.lexer.Next()
  6028  			fn.HasRestArg = true
  6029  		}
  6030  
  6031  		isTypeScriptCtorField := false
  6032  		isIdentifier := p.lexer.Token == js_lexer.TIdentifier
  6033  		text := p.lexer.Identifier.String
  6034  		arg := p.parseBinding(parseBindingOpts{})
  6035  
  6036  		if p.options.ts.Parse {
  6037  			// Skip over TypeScript accessibility modifiers, which turn this argument
  6038  			// into a class field when used inside a class constructor. This is known
  6039  			// as a "parameter property" in TypeScript.
  6040  			if isIdentifier && data.isConstructor {
  6041  				for p.lexer.Token == js_lexer.TIdentifier || p.lexer.Token == js_lexer.TOpenBrace || p.lexer.Token == js_lexer.TOpenBracket {
  6042  					if text != "public" && text != "private" && text != "protected" && text != "readonly" && text != "override" {
  6043  						break
  6044  					}
  6045  					isTypeScriptCtorField = true
  6046  
  6047  					// TypeScript requires an identifier binding
  6048  					if p.lexer.Token != js_lexer.TIdentifier {
  6049  						p.lexer.Expect(js_lexer.TIdentifier)
  6050  					}
  6051  					text = p.lexer.Identifier.String
  6052  
  6053  					// Re-parse the binding (the current binding is the TypeScript keyword)
  6054  					arg = p.parseBinding(parseBindingOpts{})
  6055  				}
  6056  			}
  6057  
  6058  			// "function foo(a?) {}"
  6059  			if p.lexer.Token == js_lexer.TQuestion {
  6060  				p.lexer.Next()
  6061  			}
  6062  
  6063  			// "function foo(a: any) {}"
  6064  			if p.lexer.Token == js_lexer.TColon {
  6065  				p.lexer.Next()
  6066  				p.skipTypeScriptType(js_ast.LLowest)
  6067  			}
  6068  		}
  6069  
  6070  		p.declareBinding(ast.SymbolHoisted, arg, parseStmtOpts{})
  6071  
  6072  		var defaultValueOrNil js_ast.Expr
  6073  		if !fn.HasRestArg && p.lexer.Token == js_lexer.TEquals {
  6074  			p.markSyntaxFeature(compat.DefaultArgument, p.lexer.Range())
  6075  			p.lexer.Next()
  6076  			defaultValueOrNil = p.parseExpr(js_ast.LComma)
  6077  		}
  6078  
  6079  		fn.Args = append(fn.Args, js_ast.Arg{
  6080  			Decorators:   decorators,
  6081  			Binding:      arg,
  6082  			DefaultOrNil: defaultValueOrNil,
  6083  
  6084  			// We need to track this because it affects code generation
  6085  			IsTypeScriptCtorField: isTypeScriptCtorField,
  6086  		})
  6087  
  6088  		if p.lexer.Token != js_lexer.TComma {
  6089  			break
  6090  		}
  6091  		if fn.HasRestArg {
  6092  			// JavaScript does not allow a comma after a rest argument
  6093  			if data.isTypeScriptDeclare {
  6094  				// TypeScript does allow a comma after a rest argument in a "declare" context
  6095  				p.lexer.Next()
  6096  			} else {
  6097  				p.lexer.Expect(js_lexer.TCloseParen)
  6098  			}
  6099  			break
  6100  		}
  6101  		p.lexer.Next()
  6102  	}
  6103  
  6104  	// Reserve the special name "arguments" in this scope. This ensures that it
  6105  	// shadows any variable called "arguments" in any parent scopes. But only do
  6106  	// this if it wasn't already declared above because arguments are allowed to
  6107  	// be called "arguments", in which case the real "arguments" is inaccessible.
  6108  	if _, ok := p.currentScope.Members["arguments"]; !ok {
  6109  		fn.ArgumentsRef = p.declareSymbol(ast.SymbolArguments, fn.OpenParenLoc, "arguments")
  6110  		p.symbols[fn.ArgumentsRef.InnerIndex].Flags |= ast.MustNotBeRenamed
  6111  	}
  6112  
  6113  	p.lexer.Expect(js_lexer.TCloseParen)
  6114  	p.fnOrArrowDataParse = oldFnOrArrowData
  6115  
  6116  	// "function foo(): any {}"
  6117  	if p.options.ts.Parse && p.lexer.Token == js_lexer.TColon {
  6118  		p.lexer.Next()
  6119  		p.skipTypeScriptReturnType()
  6120  	}
  6121  
  6122  	// "function foo(): any;"
  6123  	if data.allowMissingBodyForTypeScript && p.lexer.Token != js_lexer.TOpenBrace {
  6124  		p.lexer.ExpectOrInsertSemicolon()
  6125  		return
  6126  	}
  6127  
  6128  	fn.Body = p.parseFnBody(data)
  6129  	hadBody = true
  6130  	return
  6131  }
  6132  
  6133  type fnKind uint8
  6134  
  6135  const (
  6136  	fnStmt fnKind = iota
  6137  	fnExpr
  6138  )
  6139  
  6140  func (p *parser) validateFunctionName(fn js_ast.Fn, kind fnKind) {
  6141  	// Prevent the function name from being the same as a function-specific keyword
  6142  	if fn.Name != nil {
  6143  		if fn.IsAsync && p.symbols[fn.Name.Ref.InnerIndex].OriginalName == "await" {
  6144  			p.log.AddError(&p.tracker, js_lexer.RangeOfIdentifier(p.source, fn.Name.Loc),
  6145  				"An async function cannot be named \"await\"")
  6146  		} else if fn.IsGenerator && p.symbols[fn.Name.Ref.InnerIndex].OriginalName == "yield" && kind == fnExpr {
  6147  			p.log.AddError(&p.tracker, js_lexer.RangeOfIdentifier(p.source, fn.Name.Loc),
  6148  				"A generator function expression cannot be named \"yield\"")
  6149  		}
  6150  	}
  6151  }
  6152  
  6153  func (p *parser) validateDeclaredSymbolName(loc logger.Loc, name string) {
  6154  	if js_lexer.StrictModeReservedWords[name] {
  6155  		p.markStrictModeFeature(reservedWord, js_lexer.RangeOfIdentifier(p.source, loc), name)
  6156  	} else if isEvalOrArguments(name) {
  6157  		p.markStrictModeFeature(evalOrArguments, js_lexer.RangeOfIdentifier(p.source, loc), name)
  6158  	}
  6159  }
  6160  
  6161  func (p *parser) parseClassStmt(loc logger.Loc, opts parseStmtOpts) js_ast.Stmt {
  6162  	var name *ast.LocRef
  6163  	classKeyword := p.lexer.Range()
  6164  	if p.lexer.Token == js_lexer.TClass {
  6165  		p.markSyntaxFeature(compat.Class, classKeyword)
  6166  		p.lexer.Next()
  6167  	} else {
  6168  		p.lexer.Expected(js_lexer.TClass)
  6169  	}
  6170  
  6171  	if !opts.isNameOptional || (p.lexer.Token == js_lexer.TIdentifier && (!p.options.ts.Parse || p.lexer.Identifier.String != "implements")) {
  6172  		nameLoc := p.lexer.Loc()
  6173  		nameText := p.lexer.Identifier.String
  6174  		p.lexer.Expect(js_lexer.TIdentifier)
  6175  		if p.fnOrArrowDataParse.await != allowIdent && nameText == "await" {
  6176  			p.log.AddError(&p.tracker, js_lexer.RangeOfIdentifier(p.source, nameLoc), "Cannot use \"await\" as an identifier here:")
  6177  		}
  6178  		name = &ast.LocRef{Loc: nameLoc, Ref: ast.InvalidRef}
  6179  		if !opts.isTypeScriptDeclare {
  6180  			name.Ref = p.declareSymbol(ast.SymbolClass, nameLoc, nameText)
  6181  		}
  6182  	}
  6183  
  6184  	// Even anonymous classes can have TypeScript type parameters
  6185  	if p.options.ts.Parse {
  6186  		p.skipTypeScriptTypeParameters(allowInOutVarianceAnnotations | allowConstModifier)
  6187  	}
  6188  
  6189  	classOpts := parseClassOpts{
  6190  		isTypeScriptDeclare: opts.isTypeScriptDeclare,
  6191  	}
  6192  	if opts.deferredDecorators != nil {
  6193  		classOpts.decorators = opts.deferredDecorators.decorators
  6194  	}
  6195  	scopeIndex := p.pushScopeForParsePass(js_ast.ScopeClassName, loc)
  6196  	class := p.parseClass(classKeyword, name, classOpts)
  6197  
  6198  	if opts.isTypeScriptDeclare {
  6199  		p.popAndDiscardScope(scopeIndex)
  6200  
  6201  		if opts.isNamespaceScope && opts.isExport {
  6202  			p.hasNonLocalExportDeclareInsideNamespace = true
  6203  		}
  6204  
  6205  		// Remember that this was a "declare class" so we can allow decorators on it
  6206  		return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptSharedWasDeclareClass}
  6207  	}
  6208  
  6209  	p.popScope()
  6210  	return js_ast.Stmt{Loc: loc, Data: &js_ast.SClass{Class: class, IsExport: opts.isExport}}
  6211  }
  6212  
  6213  func (p *parser) parseClassExpr(decorators []js_ast.Decorator) js_ast.Expr {
  6214  	classKeyword := p.lexer.Range()
  6215  	p.markSyntaxFeature(compat.Class, classKeyword)
  6216  	p.lexer.Expect(js_lexer.TClass)
  6217  	var name *ast.LocRef
  6218  
  6219  	opts := parseClassOpts{
  6220  		decorators:       decorators,
  6221  		decoratorContext: decoratorInClassExpr,
  6222  	}
  6223  	p.pushScopeForParsePass(js_ast.ScopeClassName, classKeyword.Loc)
  6224  
  6225  	// Parse an optional class name
  6226  	if p.lexer.Token == js_lexer.TIdentifier {
  6227  		if nameText := p.lexer.Identifier.String; !p.options.ts.Parse || nameText != "implements" {
  6228  			if p.fnOrArrowDataParse.await != allowIdent && nameText == "await" {
  6229  				p.log.AddError(&p.tracker, p.lexer.Range(), "Cannot use \"await\" as an identifier here:")
  6230  			}
  6231  			name = &ast.LocRef{Loc: p.lexer.Loc(), Ref: p.newSymbol(ast.SymbolOther, nameText)}
  6232  			p.lexer.Next()
  6233  		}
  6234  	}
  6235  
  6236  	// Even anonymous classes can have TypeScript type parameters
  6237  	if p.options.ts.Parse {
  6238  		p.skipTypeScriptTypeParameters(allowInOutVarianceAnnotations | allowConstModifier)
  6239  	}
  6240  
  6241  	class := p.parseClass(classKeyword, name, opts)
  6242  
  6243  	p.popScope()
  6244  	return js_ast.Expr{Loc: classKeyword.Loc, Data: &js_ast.EClass{Class: class}}
  6245  }
  6246  
  6247  type parseClassOpts struct {
  6248  	decorators          []js_ast.Decorator
  6249  	decoratorContext    decoratorContextFlags
  6250  	isTypeScriptDeclare bool
  6251  }
  6252  
  6253  // By the time we call this, the identifier and type parameters have already
  6254  // been parsed. We need to start parsing from the "extends" clause.
  6255  func (p *parser) parseClass(classKeyword logger.Range, name *ast.LocRef, classOpts parseClassOpts) js_ast.Class {
  6256  	var extendsOrNil js_ast.Expr
  6257  
  6258  	if p.lexer.Token == js_lexer.TExtends {
  6259  		p.lexer.Next()
  6260  		extendsOrNil = p.parseExpr(js_ast.LNew)
  6261  
  6262  		// TypeScript's type argument parser inside expressions backtracks if the
  6263  		// first token after the end of the type parameter list is "{", so the
  6264  		// parsed expression above will have backtracked if there are any type
  6265  		// arguments. This means we have to re-parse for any type arguments here.
  6266  		// This seems kind of wasteful to me but it's what the official compiler
  6267  		// does and it probably doesn't have that high of a performance overhead
  6268  		// because "extends" clauses aren't that frequent, so it should be ok.
  6269  		if p.options.ts.Parse {
  6270  			p.skipTypeScriptTypeArguments(skipTypeScriptTypeArgumentsOpts{})
  6271  		}
  6272  	}
  6273  
  6274  	if p.options.ts.Parse && p.lexer.IsContextualKeyword("implements") {
  6275  		p.lexer.Next()
  6276  		for {
  6277  			p.skipTypeScriptType(js_ast.LLowest)
  6278  			if p.lexer.Token != js_lexer.TComma {
  6279  				break
  6280  			}
  6281  			p.lexer.Next()
  6282  		}
  6283  	}
  6284  
  6285  	bodyLoc := p.lexer.Loc()
  6286  	p.lexer.Expect(js_lexer.TOpenBrace)
  6287  	properties := []js_ast.Property{}
  6288  
  6289  	// Allow "in" and private fields inside class bodies
  6290  	oldAllowIn := p.allowIn
  6291  	oldAllowPrivateIdentifiers := p.allowPrivateIdentifiers
  6292  	p.allowIn = true
  6293  	p.allowPrivateIdentifiers = true
  6294  
  6295  	// A scope is needed for private identifiers
  6296  	scopeIndex := p.pushScopeForParsePass(js_ast.ScopeClassBody, bodyLoc)
  6297  
  6298  	opts := propertyOpts{
  6299  		isClass:          true,
  6300  		decoratorScope:   p.currentScope,
  6301  		decoratorContext: classOpts.decoratorContext,
  6302  		classHasExtends:  extendsOrNil.Data != nil,
  6303  		classKeyword:     classKeyword,
  6304  	}
  6305  	hasConstructor := false
  6306  
  6307  	for p.lexer.Token != js_lexer.TCloseBrace {
  6308  		if p.lexer.Token == js_lexer.TSemicolon {
  6309  			p.lexer.Next()
  6310  			continue
  6311  		}
  6312  
  6313  		// Parse decorators for this property
  6314  		firstDecoratorLoc := p.lexer.Loc()
  6315  		scopeIndex := len(p.scopesInOrder)
  6316  		opts.decorators = p.parseDecorators(p.currentScope, classKeyword, opts.decoratorContext)
  6317  
  6318  		// This property may turn out to be a type in TypeScript, which should be ignored
  6319  		if property, ok := p.parseProperty(p.saveExprCommentsHere(), js_ast.PropertyField, opts, nil); ok {
  6320  			properties = append(properties, property)
  6321  
  6322  			// Forbid decorators on class constructors
  6323  			if key, ok := property.Key.Data.(*js_ast.EString); ok && helpers.UTF16EqualsString(key.Value, "constructor") {
  6324  				if len(opts.decorators) > 0 {
  6325  					p.log.AddError(&p.tracker, logger.Range{Loc: firstDecoratorLoc},
  6326  						"Decorators are not allowed on class constructors")
  6327  				}
  6328  				if property.Kind.IsMethodDefinition() && !property.Flags.Has(js_ast.PropertyIsStatic) && !property.Flags.Has(js_ast.PropertyIsComputed) {
  6329  					if hasConstructor {
  6330  						p.log.AddError(&p.tracker, js_lexer.RangeOfIdentifier(p.source, property.Key.Loc),
  6331  							"Classes cannot contain more than one constructor")
  6332  					}
  6333  					hasConstructor = true
  6334  				}
  6335  			}
  6336  		} else if !classOpts.isTypeScriptDeclare && len(opts.decorators) > 0 {
  6337  			p.log.AddError(&p.tracker, logger.Range{Loc: firstDecoratorLoc, Len: 1}, "Decorators are not valid here")
  6338  			p.discardScopesUpTo(scopeIndex)
  6339  		}
  6340  	}
  6341  
  6342  	// Discard the private identifier scope inside a TypeScript "declare class"
  6343  	if classOpts.isTypeScriptDeclare {
  6344  		p.popAndDiscardScope(scopeIndex)
  6345  	} else {
  6346  		p.popScope()
  6347  	}
  6348  
  6349  	p.allowIn = oldAllowIn
  6350  	p.allowPrivateIdentifiers = oldAllowPrivateIdentifiers
  6351  
  6352  	closeBraceLoc := p.saveExprCommentsHere()
  6353  	p.lexer.Expect(js_lexer.TCloseBrace)
  6354  	return js_ast.Class{
  6355  		ClassKeyword:  classKeyword,
  6356  		Decorators:    classOpts.decorators,
  6357  		Name:          name,
  6358  		ExtendsOrNil:  extendsOrNil,
  6359  		BodyLoc:       bodyLoc,
  6360  		Properties:    properties,
  6361  		CloseBraceLoc: closeBraceLoc,
  6362  
  6363  		// TypeScript has legacy behavior that uses assignment semantics instead of
  6364  		// define semantics for class fields when "useDefineForClassFields" is enabled
  6365  		// (in which case TypeScript behaves differently than JavaScript, which is
  6366  		// arguably "wrong").
  6367  		//
  6368  		// This legacy behavior exists because TypeScript added class fields to
  6369  		// TypeScript before they were added to JavaScript. They decided to go with
  6370  		// assignment semantics for whatever reason. Later on TC39 decided to go with
  6371  		// define semantics for class fields instead. This behaves differently if the
  6372  		// base class has a setter with the same name.
  6373  		//
  6374  		// The value of "useDefineForClassFields" defaults to false when it's not
  6375  		// specified and the target is earlier than "ES2022" since the class field
  6376  		// language feature was added in ES2022. However, TypeScript's "target"
  6377  		// setting currently defaults to "ES3" which unfortunately means that the
  6378  		// "useDefineForClassFields" setting defaults to false (i.e. to "wrong").
  6379  		//
  6380  		// We default "useDefineForClassFields" to true (i.e. to "correct") instead.
  6381  		// This is partially because our target defaults to "esnext", and partially
  6382  		// because this is a legacy behavior that no one should be using anymore.
  6383  		// Users that want the wrong behavior can either set "useDefineForClassFields"
  6384  		// to false in "tsconfig.json" explicitly, or set TypeScript's "target" to
  6385  		// "ES2021" or earlier in their in "tsconfig.json" file.
  6386  		UseDefineForClassFields: !p.options.ts.Parse || p.options.ts.Config.UseDefineForClassFields == config.True ||
  6387  			(p.options.ts.Config.UseDefineForClassFields == config.Unspecified && p.options.ts.Config.Target != config.TSTargetBelowES2022),
  6388  	}
  6389  }
  6390  
  6391  func (p *parser) parseLabelName() *ast.LocRef {
  6392  	if p.lexer.Token != js_lexer.TIdentifier || p.lexer.HasNewlineBefore {
  6393  		return nil
  6394  	}
  6395  
  6396  	name := ast.LocRef{Loc: p.lexer.Loc(), Ref: p.storeNameInRef(p.lexer.Identifier)}
  6397  	p.lexer.Next()
  6398  	return &name
  6399  }
  6400  
  6401  func (p *parser) parsePath() (logger.Range, string, *ast.ImportAssertOrWith, ast.ImportRecordFlags) {
  6402  	var flags ast.ImportRecordFlags
  6403  	pathRange := p.lexer.Range()
  6404  	pathText := helpers.UTF16ToString(p.lexer.StringLiteral())
  6405  	if p.lexer.Token == js_lexer.TNoSubstitutionTemplateLiteral {
  6406  		p.lexer.Next()
  6407  	} else {
  6408  		p.lexer.Expect(js_lexer.TStringLiteral)
  6409  	}
  6410  
  6411  	// See https://github.com/tc39/proposal-import-attributes for more info
  6412  	var assertOrWith *ast.ImportAssertOrWith
  6413  	if p.lexer.Token == js_lexer.TWith || (!p.lexer.HasNewlineBefore && p.lexer.IsContextualKeyword("assert")) {
  6414  		// "import './foo.json' assert { type: 'json' }"
  6415  		// "import './foo.json' with { type: 'json' }"
  6416  		var entries []ast.AssertOrWithEntry
  6417  		duplicates := make(map[string]logger.Range)
  6418  		keyword := ast.WithKeyword
  6419  		if p.lexer.Token != js_lexer.TWith {
  6420  			keyword = ast.AssertKeyword
  6421  		}
  6422  		keywordLoc := p.saveExprCommentsHere()
  6423  		p.lexer.Next()
  6424  		openBraceLoc := p.saveExprCommentsHere()
  6425  		p.lexer.Expect(js_lexer.TOpenBrace)
  6426  
  6427  		for p.lexer.Token != js_lexer.TCloseBrace {
  6428  			// Parse the key
  6429  			keyLoc := p.saveExprCommentsHere()
  6430  			preferQuotedKey := false
  6431  			var key []uint16
  6432  			var keyText string
  6433  			if p.lexer.IsIdentifierOrKeyword() {
  6434  				keyText = p.lexer.Identifier.String
  6435  				key = helpers.StringToUTF16(keyText)
  6436  			} else if p.lexer.Token == js_lexer.TStringLiteral {
  6437  				key = p.lexer.StringLiteral()
  6438  				keyText = helpers.UTF16ToString(key)
  6439  				preferQuotedKey = !p.options.minifySyntax
  6440  			} else {
  6441  				p.lexer.Expect(js_lexer.TIdentifier)
  6442  			}
  6443  			if prevRange, ok := duplicates[keyText]; ok {
  6444  				what := "attribute"
  6445  				if keyword == ast.AssertKeyword {
  6446  					what = "assertion"
  6447  				}
  6448  				p.log.AddErrorWithNotes(&p.tracker, p.lexer.Range(), fmt.Sprintf("Duplicate import %s %q", what, keyText),
  6449  					[]logger.MsgData{p.tracker.MsgData(prevRange, fmt.Sprintf("The first %q was here:", keyText))})
  6450  			}
  6451  			duplicates[keyText] = p.lexer.Range()
  6452  			p.lexer.Next()
  6453  			p.lexer.Expect(js_lexer.TColon)
  6454  
  6455  			// Parse the value
  6456  			valueLoc := p.saveExprCommentsHere()
  6457  			value := p.lexer.StringLiteral()
  6458  			p.lexer.Expect(js_lexer.TStringLiteral)
  6459  
  6460  			entries = append(entries, ast.AssertOrWithEntry{
  6461  				Key:             key,
  6462  				KeyLoc:          keyLoc,
  6463  				Value:           value,
  6464  				ValueLoc:        valueLoc,
  6465  				PreferQuotedKey: preferQuotedKey,
  6466  			})
  6467  
  6468  			// Using "assert: { type: 'json' }" triggers special behavior
  6469  			if keyword == ast.AssertKeyword && helpers.UTF16EqualsString(key, "type") && helpers.UTF16EqualsString(value, "json") {
  6470  				flags |= ast.AssertTypeJSON
  6471  			}
  6472  
  6473  			if p.lexer.Token != js_lexer.TComma {
  6474  				break
  6475  			}
  6476  			p.lexer.Next()
  6477  		}
  6478  
  6479  		closeBraceLoc := p.saveExprCommentsHere()
  6480  		p.lexer.Expect(js_lexer.TCloseBrace)
  6481  		if keyword == ast.AssertKeyword {
  6482  			p.maybeWarnAboutAssertKeyword(keywordLoc)
  6483  		}
  6484  		assertOrWith = &ast.ImportAssertOrWith{
  6485  			Entries:            entries,
  6486  			Keyword:            keyword,
  6487  			KeywordLoc:         keywordLoc,
  6488  			InnerOpenBraceLoc:  openBraceLoc,
  6489  			InnerCloseBraceLoc: closeBraceLoc,
  6490  		}
  6491  	}
  6492  
  6493  	return pathRange, pathText, assertOrWith, flags
  6494  }
  6495  
  6496  // Let people know if they probably should be using "with" instead of "assert"
  6497  func (p *parser) maybeWarnAboutAssertKeyword(loc logger.Loc) {
  6498  	if p.options.unsupportedJSFeatures.Has(compat.ImportAssertions) && !p.options.unsupportedJSFeatures.Has(compat.ImportAttributes) {
  6499  		where := config.PrettyPrintTargetEnvironment(p.options.originalTargetEnv, p.options.unsupportedJSFeatureOverridesMask)
  6500  		msg := logger.Msg{
  6501  			Kind:  logger.Warning,
  6502  			Data:  p.tracker.MsgData(js_lexer.RangeOfIdentifier(p.source, loc), "The \"assert\" keyword is not supported in "+where),
  6503  			Notes: []logger.MsgData{{Text: "Did you mean to use \"with\" instead of \"assert\"?"}},
  6504  		}
  6505  		msg.Data.Location.Suggestion = "with"
  6506  		p.log.AddMsgID(logger.MsgID_JS_AssertToWith, msg)
  6507  	}
  6508  }
  6509  
  6510  // This assumes the "function" token has already been parsed
  6511  func (p *parser) parseFnStmt(loc logger.Loc, opts parseStmtOpts, isAsync bool, asyncRange logger.Range) js_ast.Stmt {
  6512  	isGenerator := p.lexer.Token == js_lexer.TAsterisk
  6513  	hasError := false
  6514  	if isAsync {
  6515  		hasError = p.markAsyncFn(asyncRange, isGenerator)
  6516  	}
  6517  	if isGenerator {
  6518  		if !hasError {
  6519  			p.markSyntaxFeature(compat.Generator, p.lexer.Range())
  6520  		}
  6521  		p.lexer.Next()
  6522  	}
  6523  
  6524  	switch opts.lexicalDecl {
  6525  	case lexicalDeclForbid:
  6526  		p.forbidLexicalDecl(loc)
  6527  
  6528  	// Allow certain function statements in certain single-statement contexts
  6529  	case lexicalDeclAllowFnInsideIf, lexicalDeclAllowFnInsideLabel:
  6530  		if opts.isTypeScriptDeclare || isGenerator || isAsync {
  6531  			p.forbidLexicalDecl(loc)
  6532  		}
  6533  	}
  6534  
  6535  	var name *ast.LocRef
  6536  	var nameText string
  6537  
  6538  	// The name is optional for "export default function() {}" pseudo-statements
  6539  	if !opts.isNameOptional || p.lexer.Token == js_lexer.TIdentifier {
  6540  		nameLoc := p.lexer.Loc()
  6541  		nameText = p.lexer.Identifier.String
  6542  		if !isAsync && p.fnOrArrowDataParse.await != allowIdent && nameText == "await" {
  6543  			p.log.AddError(&p.tracker, js_lexer.RangeOfIdentifier(p.source, nameLoc), "Cannot use \"await\" as an identifier here:")
  6544  		}
  6545  		p.lexer.Expect(js_lexer.TIdentifier)
  6546  		name = &ast.LocRef{Loc: nameLoc, Ref: ast.InvalidRef}
  6547  	}
  6548  
  6549  	// Even anonymous functions can have TypeScript type parameters
  6550  	if p.options.ts.Parse {
  6551  		p.skipTypeScriptTypeParameters(allowConstModifier)
  6552  	}
  6553  
  6554  	// Introduce a fake block scope for function declarations inside if statements
  6555  	var ifStmtScopeIndex int
  6556  	hasIfScope := opts.lexicalDecl == lexicalDeclAllowFnInsideIf
  6557  	if hasIfScope {
  6558  		ifStmtScopeIndex = p.pushScopeForParsePass(js_ast.ScopeBlock, loc)
  6559  	}
  6560  
  6561  	scopeIndex := p.pushScopeForParsePass(js_ast.ScopeFunctionArgs, p.lexer.Loc())
  6562  
  6563  	await := allowIdent
  6564  	yield := allowIdent
  6565  	if isAsync {
  6566  		await = allowExpr
  6567  	}
  6568  	if isGenerator {
  6569  		yield = allowExpr
  6570  	}
  6571  
  6572  	fn, hadBody := p.parseFn(name, logger.Range{}, 0, fnOrArrowDataParse{
  6573  		needsAsyncLoc:       loc,
  6574  		asyncRange:          asyncRange,
  6575  		await:               await,
  6576  		yield:               yield,
  6577  		isTypeScriptDeclare: opts.isTypeScriptDeclare,
  6578  
  6579  		// Only allow omitting the body if we're parsing TypeScript
  6580  		allowMissingBodyForTypeScript: p.options.ts.Parse,
  6581  	})
  6582  
  6583  	// Don't output anything if it's just a forward declaration of a function
  6584  	if opts.isTypeScriptDeclare || !hadBody {
  6585  		p.popAndDiscardScope(scopeIndex)
  6586  
  6587  		// Balance the fake block scope introduced above
  6588  		if hasIfScope {
  6589  			p.popAndDiscardScope(ifStmtScopeIndex)
  6590  		}
  6591  
  6592  		if opts.isTypeScriptDeclare && opts.isNamespaceScope && opts.isExport {
  6593  			p.hasNonLocalExportDeclareInsideNamespace = true
  6594  		}
  6595  
  6596  		return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
  6597  	}
  6598  
  6599  	p.popScope()
  6600  
  6601  	// Only declare the function after we know if it had a body or not. Otherwise
  6602  	// TypeScript code such as this will double-declare the symbol:
  6603  	//
  6604  	//     function foo(): void;
  6605  	//     function foo(): void {}
  6606  	//
  6607  	if name != nil {
  6608  		kind := ast.SymbolHoistedFunction
  6609  		if isGenerator || isAsync {
  6610  			kind = ast.SymbolGeneratorOrAsyncFunction
  6611  		}
  6612  		name.Ref = p.declareSymbol(kind, name.Loc, nameText)
  6613  	}
  6614  
  6615  	// Balance the fake block scope introduced above
  6616  	if hasIfScope {
  6617  		p.popScope()
  6618  	}
  6619  
  6620  	fn.HasIfScope = hasIfScope
  6621  	p.validateFunctionName(fn, fnStmt)
  6622  	if opts.hasNoSideEffectsComment && !p.options.ignoreDCEAnnotations {
  6623  		fn.HasNoSideEffectsComment = true
  6624  		if name != nil && !opts.isTypeScriptDeclare {
  6625  			p.symbols[name.Ref.InnerIndex].Flags |= ast.CallCanBeUnwrappedIfUnused
  6626  		}
  6627  	}
  6628  	return js_ast.Stmt{Loc: loc, Data: &js_ast.SFunction{Fn: fn, IsExport: opts.isExport}}
  6629  }
  6630  
  6631  type deferredDecorators struct {
  6632  	decorators []js_ast.Decorator
  6633  }
  6634  
  6635  type decoratorContextFlags uint8
  6636  
  6637  const (
  6638  	decoratorBeforeClassExpr = 1 << iota
  6639  	decoratorInClassExpr
  6640  	decoratorInFnArgs
  6641  )
  6642  
  6643  func (p *parser) parseDecorators(decoratorScope *js_ast.Scope, classKeyword logger.Range, context decoratorContextFlags) (decorators []js_ast.Decorator) {
  6644  	if p.lexer.Token == js_lexer.TAt {
  6645  		if p.options.ts.Parse {
  6646  			if p.options.ts.Config.ExperimentalDecorators == config.True {
  6647  				if (context & decoratorInClassExpr) != 0 {
  6648  					p.lexer.AddRangeErrorWithNotes(p.lexer.Range(), "TypeScript experimental decorators can only be used with class declarations",
  6649  						[]logger.MsgData{p.tracker.MsgData(classKeyword, "This is a class expression, not a class declaration:")})
  6650  				} else if (context & decoratorBeforeClassExpr) != 0 {
  6651  					p.log.AddError(&p.tracker, p.lexer.Range(), "TypeScript experimental decorators cannot be used in expression position")
  6652  				}
  6653  			} else {
  6654  				if (context&decoratorInFnArgs) != 0 && p.options.ts.Config.ExperimentalDecorators != config.True {
  6655  					p.log.AddErrorWithNotes(&p.tracker, p.lexer.Range(), "Parameter decorators only work when experimental decorators are enabled", []logger.MsgData{{
  6656  						Text: "You can enable experimental decorators by adding \"experimentalDecorators\": true to your \"tsconfig.json\" file.",
  6657  					}})
  6658  				}
  6659  			}
  6660  		} else {
  6661  			if (context & decoratorInFnArgs) != 0 {
  6662  				p.log.AddError(&p.tracker, p.lexer.Range(), "Parameter decorators are not allowed in JavaScript")
  6663  			}
  6664  		}
  6665  	}
  6666  
  6667  	// TypeScript decorators cause us to temporarily revert to the scope that
  6668  	// encloses the class declaration, since that's where the generated code
  6669  	// for TypeScript decorators will be inserted.
  6670  	oldScope := p.currentScope
  6671  	p.currentScope = decoratorScope
  6672  
  6673  	for p.lexer.Token == js_lexer.TAt {
  6674  		atLoc := p.lexer.Loc()
  6675  		p.lexer.Next()
  6676  
  6677  		var value js_ast.Expr
  6678  		if p.options.ts.Parse && p.options.ts.Config.ExperimentalDecorators == config.True {
  6679  			// TypeScript's experimental decorator syntax is more permissive than
  6680  			// JavaScript. Parse a new/call expression with "exprFlagDecorator" so
  6681  			// we ignore EIndex expressions, since they may be part of a computed
  6682  			// property:
  6683  			//
  6684  			//   class Foo {
  6685  			//     @foo ['computed']() {}
  6686  			//   }
  6687  			//
  6688  			// This matches the behavior of the TypeScript compiler.
  6689  			p.parseExperimentalDecoratorNesting++
  6690  			value = p.parseExprWithFlags(js_ast.LNew, exprFlagDecorator)
  6691  			p.parseExperimentalDecoratorNesting--
  6692  		} else {
  6693  			// JavaScript's decorator syntax is more restrictive. Parse it using a
  6694  			// special parser that doesn't allow normal expressions (e.g. "?.").
  6695  			value = p.parseDecorator()
  6696  		}
  6697  		decorators = append(decorators, js_ast.Decorator{
  6698  			Value:            value,
  6699  			AtLoc:            atLoc,
  6700  			OmitNewlineAfter: !p.lexer.HasNewlineBefore,
  6701  		})
  6702  	}
  6703  
  6704  	// Avoid "popScope" because this decorator scope is not hierarchical
  6705  	p.currentScope = oldScope
  6706  	return decorators
  6707  }
  6708  
  6709  func (p *parser) parseDecorator() js_ast.Expr {
  6710  	if p.lexer.Token == js_lexer.TOpenParen {
  6711  		p.lexer.Next()
  6712  		value := p.parseExpr(js_ast.LLowest)
  6713  		p.lexer.Expect(js_lexer.TCloseParen)
  6714  		return value
  6715  	}
  6716  
  6717  	name := p.lexer.Identifier
  6718  	nameRange := p.lexer.Range()
  6719  	p.lexer.Expect(js_lexer.TIdentifier)
  6720  
  6721  	// Forbid invalid identifiers
  6722  	if (p.fnOrArrowDataParse.await != allowIdent && name.String == "await") ||
  6723  		(p.fnOrArrowDataParse.yield != allowIdent && name.String == "yield") {
  6724  		p.log.AddError(&p.tracker, nameRange, fmt.Sprintf("Cannot use %q as an identifier here:", name.String))
  6725  	}
  6726  
  6727  	memberExpr := js_ast.Expr{Loc: nameRange.Loc, Data: &js_ast.EIdentifier{Ref: p.storeNameInRef(name)}}
  6728  
  6729  	// Custom error reporting for error recovery
  6730  	var syntaxError logger.MsgData
  6731  	wrapRange := nameRange
  6732  
  6733  loop:
  6734  	for {
  6735  		switch p.lexer.Token {
  6736  		case js_lexer.TExclamation:
  6737  			// Skip over TypeScript non-null assertions
  6738  			if p.lexer.HasNewlineBefore {
  6739  				break loop
  6740  			}
  6741  			if !p.options.ts.Parse {
  6742  				p.lexer.Unexpected()
  6743  			}
  6744  			wrapRange.Len = p.lexer.Range().End() - wrapRange.Loc.Start
  6745  			p.lexer.Next()
  6746  
  6747  		case js_lexer.TDot, js_lexer.TQuestionDot:
  6748  			// The grammar for "DecoratorMemberExpression" currently forbids "?."
  6749  			if p.lexer.Token == js_lexer.TQuestionDot && syntaxError.Location == nil {
  6750  				syntaxError = p.tracker.MsgData(p.lexer.Range(), "JavaScript decorator syntax does not allow \"?.\" here")
  6751  			}
  6752  
  6753  			p.lexer.Next()
  6754  			wrapRange.Len = p.lexer.Range().End() - wrapRange.Loc.Start
  6755  
  6756  			if p.lexer.Token == js_lexer.TPrivateIdentifier {
  6757  				name := p.lexer.Identifier
  6758  				memberExpr.Data = &js_ast.EIndex{
  6759  					Target: memberExpr,
  6760  					Index:  js_ast.Expr{Loc: p.lexer.Loc(), Data: &js_ast.EPrivateIdentifier{Ref: p.storeNameInRef(name)}},
  6761  				}
  6762  				p.reportPrivateNameUsage(name.String)
  6763  				p.lexer.Next()
  6764  			} else {
  6765  				memberExpr.Data = &js_ast.EDot{
  6766  					Target:  memberExpr,
  6767  					Name:    p.lexer.Identifier.String,
  6768  					NameLoc: p.lexer.Loc(),
  6769  				}
  6770  				p.lexer.Expect(js_lexer.TIdentifier)
  6771  			}
  6772  
  6773  		case js_lexer.TOpenParen:
  6774  			args, closeParenLoc, isMultiLine := p.parseCallArgs()
  6775  			memberExpr.Data = &js_ast.ECall{
  6776  				Target:        memberExpr,
  6777  				Args:          args,
  6778  				CloseParenLoc: closeParenLoc,
  6779  				IsMultiLine:   isMultiLine,
  6780  				Kind:          js_ast.TargetWasOriginallyPropertyAccess,
  6781  			}
  6782  			wrapRange.Len = closeParenLoc.Start + 1 - wrapRange.Loc.Start
  6783  
  6784  			// The grammar for "DecoratorCallExpression" currently forbids anything after it
  6785  			if p.lexer.Token == js_lexer.TDot {
  6786  				if syntaxError.Location == nil {
  6787  					syntaxError = p.tracker.MsgData(p.lexer.Range(), "JavaScript decorator syntax does not allow \".\" after a call expression")
  6788  				}
  6789  				continue
  6790  			}
  6791  			break loop
  6792  
  6793  		default:
  6794  			// "@x<y>"
  6795  			// "@x.y<z>"
  6796  			if !p.skipTypeScriptTypeArguments(skipTypeScriptTypeArgumentsOpts{}) {
  6797  				break loop
  6798  			}
  6799  		}
  6800  	}
  6801  
  6802  	// Suggest that non-decorator expressions be wrapped in parentheses
  6803  	if syntaxError.Location != nil {
  6804  		var notes []logger.MsgData
  6805  		if text := p.source.TextForRange(wrapRange); !strings.ContainsRune(text, '\n') {
  6806  			note := p.tracker.MsgData(wrapRange, "Wrap this decorator in parentheses to allow arbitrary expressions:")
  6807  			note.Location.Suggestion = fmt.Sprintf("(%s)", text)
  6808  			notes = []logger.MsgData{note}
  6809  		}
  6810  		p.log.AddMsg(logger.Msg{
  6811  			Kind:  logger.Error,
  6812  			Data:  syntaxError,
  6813  			Notes: notes,
  6814  		})
  6815  	}
  6816  
  6817  	return memberExpr
  6818  }
  6819  
  6820  type lexicalDecl uint8
  6821  
  6822  const (
  6823  	lexicalDeclForbid lexicalDecl = iota
  6824  	lexicalDeclAllowAll
  6825  	lexicalDeclAllowFnInsideIf
  6826  	lexicalDeclAllowFnInsideLabel
  6827  )
  6828  
  6829  type parseStmtOpts struct {
  6830  	deferredDecorators      *deferredDecorators
  6831  	lexicalDecl             lexicalDecl
  6832  	isModuleScope           bool
  6833  	isNamespaceScope        bool
  6834  	isExport                bool
  6835  	isExportDefault         bool
  6836  	isNameOptional          bool // For "export default" pseudo-statements
  6837  	isTypeScriptDeclare     bool
  6838  	isForLoopInit           bool
  6839  	isForAwaitLoopInit      bool
  6840  	allowDirectivePrologue  bool
  6841  	hasNoSideEffectsComment bool
  6842  	isUsingStmt             bool
  6843  }
  6844  
  6845  func (p *parser) parseStmt(opts parseStmtOpts) js_ast.Stmt {
  6846  	loc := p.lexer.Loc()
  6847  
  6848  	if (p.lexer.HasCommentBefore & js_lexer.NoSideEffectsCommentBefore) != 0 {
  6849  		opts.hasNoSideEffectsComment = true
  6850  	}
  6851  
  6852  	// Do not attach any leading comments to the next expression
  6853  	p.lexer.CommentsBeforeToken = p.lexer.CommentsBeforeToken[:0]
  6854  
  6855  	switch p.lexer.Token {
  6856  	case js_lexer.TSemicolon:
  6857  		p.lexer.Next()
  6858  		return js_ast.Stmt{Loc: loc, Data: js_ast.SEmptyShared}
  6859  
  6860  	case js_lexer.TExport:
  6861  		previousExportKeyword := p.esmExportKeyword
  6862  		if opts.isModuleScope {
  6863  			p.esmExportKeyword = p.lexer.Range()
  6864  		} else if !opts.isNamespaceScope {
  6865  			p.lexer.Unexpected()
  6866  		}
  6867  		p.lexer.Next()
  6868  
  6869  		switch p.lexer.Token {
  6870  		case js_lexer.TClass, js_lexer.TConst, js_lexer.TFunction, js_lexer.TVar, js_lexer.TAt:
  6871  			opts.isExport = true
  6872  			return p.parseStmt(opts)
  6873  
  6874  		case js_lexer.TImport:
  6875  			// "export import foo = bar"
  6876  			if p.options.ts.Parse && (opts.isModuleScope || opts.isNamespaceScope) {
  6877  				opts.isExport = true
  6878  				return p.parseStmt(opts)
  6879  			}
  6880  
  6881  			p.lexer.Unexpected()
  6882  			return js_ast.Stmt{}
  6883  
  6884  		case js_lexer.TEnum:
  6885  			if !p.options.ts.Parse {
  6886  				p.lexer.Unexpected()
  6887  			}
  6888  			opts.isExport = true
  6889  			return p.parseStmt(opts)
  6890  
  6891  		case js_lexer.TIdentifier:
  6892  			if p.lexer.IsContextualKeyword("let") {
  6893  				opts.isExport = true
  6894  				return p.parseStmt(opts)
  6895  			}
  6896  
  6897  			if p.lexer.IsContextualKeyword("as") {
  6898  				// "export as namespace ns;"
  6899  				p.lexer.Next()
  6900  				p.lexer.ExpectContextualKeyword("namespace")
  6901  				p.lexer.Expect(js_lexer.TIdentifier)
  6902  				p.lexer.ExpectOrInsertSemicolon()
  6903  				return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
  6904  			}
  6905  
  6906  			if p.lexer.IsContextualKeyword("async") {
  6907  				// "export async function foo() {}"
  6908  				asyncRange := p.lexer.Range()
  6909  				p.lexer.Next()
  6910  				if p.lexer.HasNewlineBefore {
  6911  					p.log.AddError(&p.tracker, logger.Range{Loc: logger.Loc{Start: asyncRange.End()}},
  6912  						"Unexpected newline after \"async\"")
  6913  					panic(js_lexer.LexerPanic{})
  6914  				}
  6915  				p.lexer.Expect(js_lexer.TFunction)
  6916  				opts.isExport = true
  6917  				return p.parseFnStmt(loc, opts, true /* isAsync */, asyncRange)
  6918  			}
  6919  
  6920  			if p.options.ts.Parse {
  6921  				switch p.lexer.Identifier.String {
  6922  				case "type":
  6923  					// "export type foo = ..."
  6924  					typeRange := p.lexer.Range()
  6925  					p.lexer.Next()
  6926  					if p.lexer.HasNewlineBefore && p.lexer.Token != js_lexer.TOpenBrace && p.lexer.Token != js_lexer.TAsterisk {
  6927  						p.log.AddError(&p.tracker, logger.Range{Loc: logger.Loc{Start: typeRange.End()}},
  6928  							"Unexpected newline after \"type\"")
  6929  						panic(js_lexer.LexerPanic{})
  6930  					}
  6931  					p.skipTypeScriptTypeStmt(parseStmtOpts{isModuleScope: opts.isModuleScope, isExport: true})
  6932  					return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
  6933  
  6934  				case "namespace", "abstract", "module", "interface":
  6935  					// "export namespace Foo {}"
  6936  					// "export abstract class Foo {}"
  6937  					// "export module Foo {}"
  6938  					// "export interface Foo {}"
  6939  					opts.isExport = true
  6940  					return p.parseStmt(opts)
  6941  
  6942  				case "declare":
  6943  					// "export declare class Foo {}"
  6944  					opts.isExport = true
  6945  					opts.lexicalDecl = lexicalDeclAllowAll
  6946  					opts.isTypeScriptDeclare = true
  6947  					return p.parseStmt(opts)
  6948  				}
  6949  			}
  6950  
  6951  			p.lexer.Unexpected()
  6952  			return js_ast.Stmt{}
  6953  
  6954  		case js_lexer.TDefault:
  6955  			if !opts.isModuleScope && (!opts.isNamespaceScope || !opts.isTypeScriptDeclare) {
  6956  				p.lexer.Unexpected()
  6957  			}
  6958  
  6959  			defaultLoc := p.lexer.Loc()
  6960  			p.lexer.Next()
  6961  
  6962  			// Also pick up comments after the "default" keyword
  6963  			if (p.lexer.HasCommentBefore & js_lexer.NoSideEffectsCommentBefore) != 0 {
  6964  				opts.hasNoSideEffectsComment = true
  6965  			}
  6966  
  6967  			// The default name is lazily generated only if no other name is present
  6968  			createDefaultName := func() ast.LocRef {
  6969  				// This must be named "default" for when "--keep-names" is active
  6970  				defaultName := ast.LocRef{Loc: defaultLoc, Ref: p.newSymbol(ast.SymbolOther, "default")}
  6971  				p.currentScope.Generated = append(p.currentScope.Generated, defaultName.Ref)
  6972  				return defaultName
  6973  			}
  6974  
  6975  			// "export default async function() {}"
  6976  			// "export default async function foo() {}"
  6977  			if p.lexer.IsContextualKeyword("async") {
  6978  				asyncRange := p.lexer.Range()
  6979  				p.lexer.Next()
  6980  
  6981  				if p.lexer.Token == js_lexer.TFunction && !p.lexer.HasNewlineBefore {
  6982  					p.lexer.Next()
  6983  					stmt := p.parseFnStmt(loc, parseStmtOpts{
  6984  						isNameOptional:          true,
  6985  						lexicalDecl:             lexicalDeclAllowAll,
  6986  						hasNoSideEffectsComment: opts.hasNoSideEffectsComment,
  6987  					}, true /* isAsync */, asyncRange)
  6988  					if _, ok := stmt.Data.(*js_ast.STypeScript); ok {
  6989  						return stmt // This was just a type annotation
  6990  					}
  6991  
  6992  					// Use the statement name if present, since it's a better name
  6993  					var defaultName ast.LocRef
  6994  					if s, ok := stmt.Data.(*js_ast.SFunction); ok && s.Fn.Name != nil {
  6995  						defaultName = ast.LocRef{Loc: defaultLoc, Ref: s.Fn.Name.Ref}
  6996  					} else {
  6997  						defaultName = createDefaultName()
  6998  					}
  6999  
  7000  					return js_ast.Stmt{Loc: loc, Data: &js_ast.SExportDefault{DefaultName: defaultName, Value: stmt}}
  7001  				}
  7002  
  7003  				defaultName := createDefaultName()
  7004  				expr := p.parseSuffix(p.parseAsyncPrefixExpr(asyncRange, js_ast.LComma, 0), js_ast.LComma, nil, 0)
  7005  				p.lexer.ExpectOrInsertSemicolon()
  7006  				return js_ast.Stmt{Loc: loc, Data: &js_ast.SExportDefault{
  7007  					DefaultName: defaultName, Value: js_ast.Stmt{Loc: loc, Data: &js_ast.SExpr{Value: expr}}}}
  7008  			}
  7009  
  7010  			// "export default class {}"
  7011  			// "export default class Foo {}"
  7012  			// "export default @x class {}"
  7013  			// "export default @x class Foo {}"
  7014  			// "export default function() {}"
  7015  			// "export default function foo() {}"
  7016  			// "export default interface Foo {}"
  7017  			// "export default interface + 1"
  7018  			if p.lexer.Token == js_lexer.TFunction || p.lexer.Token == js_lexer.TClass || p.lexer.Token == js_lexer.TAt ||
  7019  				(p.options.ts.Parse && p.lexer.IsContextualKeyword("interface")) {
  7020  				stmt := p.parseStmt(parseStmtOpts{
  7021  					deferredDecorators:      opts.deferredDecorators,
  7022  					isNameOptional:          true,
  7023  					isExportDefault:         true,
  7024  					lexicalDecl:             lexicalDeclAllowAll,
  7025  					hasNoSideEffectsComment: opts.hasNoSideEffectsComment,
  7026  				})
  7027  
  7028  				// Use the statement name if present, since it's a better name
  7029  				var defaultName ast.LocRef
  7030  				switch s := stmt.Data.(type) {
  7031  				case *js_ast.STypeScript, *js_ast.SExpr:
  7032  					return stmt // Handle the "interface" case above
  7033  				case *js_ast.SFunction:
  7034  					if s.Fn.Name != nil {
  7035  						defaultName = ast.LocRef{Loc: defaultLoc, Ref: s.Fn.Name.Ref}
  7036  					} else {
  7037  						defaultName = createDefaultName()
  7038  					}
  7039  				case *js_ast.SClass:
  7040  					if s.Class.Name != nil {
  7041  						defaultName = ast.LocRef{Loc: defaultLoc, Ref: s.Class.Name.Ref}
  7042  					} else {
  7043  						defaultName = createDefaultName()
  7044  					}
  7045  				default:
  7046  					panic("Internal error")
  7047  				}
  7048  				return js_ast.Stmt{Loc: loc, Data: &js_ast.SExportDefault{DefaultName: defaultName, Value: stmt}}
  7049  			}
  7050  
  7051  			isIdentifier := p.lexer.Token == js_lexer.TIdentifier
  7052  			name := p.lexer.Identifier.String
  7053  			expr := p.parseExpr(js_ast.LComma)
  7054  
  7055  			// "export default abstract class {}"
  7056  			// "export default abstract class Foo {}"
  7057  			if p.options.ts.Parse && isIdentifier && name == "abstract" && !p.lexer.HasNewlineBefore {
  7058  				if _, ok := expr.Data.(*js_ast.EIdentifier); ok && p.lexer.Token == js_lexer.TClass {
  7059  					stmt := p.parseClassStmt(loc, parseStmtOpts{
  7060  						deferredDecorators: opts.deferredDecorators,
  7061  						isNameOptional:     true,
  7062  					})
  7063  
  7064  					// Use the statement name if present, since it's a better name
  7065  					var defaultName ast.LocRef
  7066  					if s, ok := stmt.Data.(*js_ast.SClass); ok && s.Class.Name != nil {
  7067  						defaultName = ast.LocRef{Loc: defaultLoc, Ref: s.Class.Name.Ref}
  7068  					} else {
  7069  						defaultName = createDefaultName()
  7070  					}
  7071  
  7072  					return js_ast.Stmt{Loc: loc, Data: &js_ast.SExportDefault{DefaultName: defaultName, Value: stmt}}
  7073  				}
  7074  			}
  7075  
  7076  			p.lexer.ExpectOrInsertSemicolon()
  7077  			defaultName := createDefaultName()
  7078  			return js_ast.Stmt{Loc: loc, Data: &js_ast.SExportDefault{
  7079  				DefaultName: defaultName, Value: js_ast.Stmt{Loc: loc, Data: &js_ast.SExpr{Value: expr}}}}
  7080  
  7081  		case js_lexer.TAsterisk:
  7082  			if !opts.isModuleScope && (!opts.isNamespaceScope || !opts.isTypeScriptDeclare) {
  7083  				p.lexer.Unexpected()
  7084  			}
  7085  
  7086  			p.lexer.Next()
  7087  			var namespaceRef ast.Ref
  7088  			var alias *js_ast.ExportStarAlias
  7089  			var pathRange logger.Range
  7090  			var pathText string
  7091  			var assertOrWith *ast.ImportAssertOrWith
  7092  			var flags ast.ImportRecordFlags
  7093  
  7094  			if p.lexer.IsContextualKeyword("as") {
  7095  				// "export * as ns from 'path'"
  7096  				p.lexer.Next()
  7097  				name := p.parseClauseAlias("export")
  7098  				namespaceRef = p.storeNameInRef(name)
  7099  				alias = &js_ast.ExportStarAlias{Loc: p.lexer.Loc(), OriginalName: name.String}
  7100  				p.lexer.Next()
  7101  				p.lexer.ExpectContextualKeyword("from")
  7102  				pathRange, pathText, assertOrWith, flags = p.parsePath()
  7103  			} else {
  7104  				// "export * from 'path'"
  7105  				p.lexer.ExpectContextualKeyword("from")
  7106  				pathRange, pathText, assertOrWith, flags = p.parsePath()
  7107  				name := js_ast.GenerateNonUniqueNameFromPath(pathText) + "_star"
  7108  				namespaceRef = p.storeNameInRef(js_lexer.MaybeSubstring{String: name})
  7109  			}
  7110  			importRecordIndex := p.addImportRecord(ast.ImportStmt, pathRange, pathText, assertOrWith, flags)
  7111  
  7112  			// Export-star statements anywhere in the file disable top-level const
  7113  			// local prefix because import cycles can be used to trigger TDZ
  7114  			p.currentScope.IsAfterConstLocalPrefix = true
  7115  
  7116  			p.lexer.ExpectOrInsertSemicolon()
  7117  			return js_ast.Stmt{Loc: loc, Data: &js_ast.SExportStar{
  7118  				NamespaceRef:      namespaceRef,
  7119  				Alias:             alias,
  7120  				ImportRecordIndex: importRecordIndex,
  7121  			}}
  7122  
  7123  		case js_lexer.TOpenBrace:
  7124  			if !opts.isModuleScope && (!opts.isNamespaceScope || !opts.isTypeScriptDeclare) {
  7125  				p.lexer.Unexpected()
  7126  			}
  7127  
  7128  			items, isSingleLine := p.parseExportClause()
  7129  			if p.lexer.IsContextualKeyword("from") {
  7130  				// "export {} from 'path'"
  7131  				p.lexer.Next()
  7132  				pathLoc, pathText, assertOrWith, flags := p.parsePath()
  7133  				importRecordIndex := p.addImportRecord(ast.ImportStmt, pathLoc, pathText, assertOrWith, flags)
  7134  				name := "import_" + js_ast.GenerateNonUniqueNameFromPath(pathText)
  7135  				namespaceRef := p.storeNameInRef(js_lexer.MaybeSubstring{String: name})
  7136  
  7137  				// Export clause statements anywhere in the file disable top-level const
  7138  				// local prefix because import cycles can be used to trigger TDZ
  7139  				p.currentScope.IsAfterConstLocalPrefix = true
  7140  
  7141  				p.lexer.ExpectOrInsertSemicolon()
  7142  				return js_ast.Stmt{Loc: loc, Data: &js_ast.SExportFrom{
  7143  					Items:             items,
  7144  					NamespaceRef:      namespaceRef,
  7145  					ImportRecordIndex: importRecordIndex,
  7146  					IsSingleLine:      isSingleLine,
  7147  				}}
  7148  			}
  7149  
  7150  			p.lexer.ExpectOrInsertSemicolon()
  7151  			return js_ast.Stmt{Loc: loc, Data: &js_ast.SExportClause{Items: items, IsSingleLine: isSingleLine}}
  7152  
  7153  		case js_lexer.TEquals:
  7154  			// "export = value;"
  7155  			p.esmExportKeyword = previousExportKeyword // This wasn't an ESM export statement after all
  7156  			if p.options.ts.Parse {
  7157  				p.lexer.Next()
  7158  				value := p.parseExpr(js_ast.LLowest)
  7159  				p.lexer.ExpectOrInsertSemicolon()
  7160  				return js_ast.Stmt{Loc: loc, Data: &js_ast.SExportEquals{Value: value}}
  7161  			}
  7162  			p.lexer.Unexpected()
  7163  			return js_ast.Stmt{}
  7164  
  7165  		default:
  7166  			p.lexer.Unexpected()
  7167  			return js_ast.Stmt{}
  7168  		}
  7169  
  7170  	case js_lexer.TFunction:
  7171  		p.lexer.Next()
  7172  		return p.parseFnStmt(loc, opts, false /* isAsync */, logger.Range{})
  7173  
  7174  	case js_lexer.TEnum:
  7175  		if !p.options.ts.Parse {
  7176  			p.lexer.Unexpected()
  7177  		}
  7178  		return p.parseTypeScriptEnumStmt(loc, opts)
  7179  
  7180  	case js_lexer.TAt:
  7181  		// Parse decorators before class statements, which are potentially exported
  7182  		scopeIndex := len(p.scopesInOrder)
  7183  		decorators := p.parseDecorators(p.currentScope, logger.Range{}, 0)
  7184  
  7185  		// "@x export @y class Foo {}"
  7186  		if opts.deferredDecorators != nil {
  7187  			p.log.AddError(&p.tracker, logger.Range{Loc: loc, Len: 1}, "Decorators are not valid here")
  7188  			p.discardScopesUpTo(scopeIndex)
  7189  			return p.parseStmt(opts)
  7190  		}
  7191  
  7192  		// If this turns out to be a "declare class" statement, we need to undo the
  7193  		// scopes that were potentially pushed while parsing the decorator arguments.
  7194  		// That can look like any one of the following:
  7195  		//
  7196  		//   "@decorator declare class Foo {}"
  7197  		//   "@decorator declare abstract class Foo {}"
  7198  		//   "@decorator export declare class Foo {}"
  7199  		//   "@decorator export declare abstract class Foo {}"
  7200  		//
  7201  		opts.deferredDecorators = &deferredDecorators{
  7202  			decorators: decorators,
  7203  		}
  7204  
  7205  		stmt := p.parseStmt(opts)
  7206  
  7207  		// Check for valid decorator targets
  7208  		switch s := stmt.Data.(type) {
  7209  		case *js_ast.SClass:
  7210  			return stmt
  7211  
  7212  		case *js_ast.SExportDefault:
  7213  			switch s.Value.Data.(type) {
  7214  			case *js_ast.SClass:
  7215  				return stmt
  7216  			}
  7217  
  7218  		case *js_ast.STypeScript:
  7219  			if s.WasDeclareClass {
  7220  				// If this is a type declaration, discard any scopes that were pushed
  7221  				// while parsing decorators. Unlike with the class statements above,
  7222  				// these scopes won't end up being visited during the upcoming visit
  7223  				// pass because type declarations aren't visited at all.
  7224  				p.discardScopesUpTo(scopeIndex)
  7225  				return stmt
  7226  			}
  7227  		}
  7228  
  7229  		// Forbid decorators on anything other than a class statement
  7230  		p.log.AddError(&p.tracker, logger.Range{Loc: loc, Len: 1}, "Decorators are not valid here")
  7231  		stmt.Data = js_ast.STypeScriptShared
  7232  		p.discardScopesUpTo(scopeIndex)
  7233  		return stmt
  7234  
  7235  	case js_lexer.TClass:
  7236  		if opts.lexicalDecl != lexicalDeclAllowAll {
  7237  			p.forbidLexicalDecl(loc)
  7238  		}
  7239  		return p.parseClassStmt(loc, opts)
  7240  
  7241  	case js_lexer.TVar:
  7242  		p.lexer.Next()
  7243  		decls := p.parseAndDeclareDecls(ast.SymbolHoisted, opts)
  7244  		p.lexer.ExpectOrInsertSemicolon()
  7245  		return js_ast.Stmt{Loc: loc, Data: &js_ast.SLocal{
  7246  			Kind:     js_ast.LocalVar,
  7247  			Decls:    decls,
  7248  			IsExport: opts.isExport,
  7249  		}}
  7250  
  7251  	case js_lexer.TConst:
  7252  		if opts.lexicalDecl != lexicalDeclAllowAll {
  7253  			p.forbidLexicalDecl(loc)
  7254  		}
  7255  		p.markSyntaxFeature(compat.ConstAndLet, p.lexer.Range())
  7256  		p.lexer.Next()
  7257  
  7258  		if p.options.ts.Parse && p.lexer.Token == js_lexer.TEnum {
  7259  			return p.parseTypeScriptEnumStmt(loc, opts)
  7260  		}
  7261  
  7262  		decls := p.parseAndDeclareDecls(ast.SymbolConst, opts)
  7263  		p.lexer.ExpectOrInsertSemicolon()
  7264  		if !opts.isTypeScriptDeclare {
  7265  			p.requireInitializers(js_ast.LocalConst, decls)
  7266  		}
  7267  		return js_ast.Stmt{Loc: loc, Data: &js_ast.SLocal{
  7268  			Kind:     js_ast.LocalConst,
  7269  			Decls:    decls,
  7270  			IsExport: opts.isExport,
  7271  		}}
  7272  
  7273  	case js_lexer.TIf:
  7274  		p.lexer.Next()
  7275  		p.lexer.Expect(js_lexer.TOpenParen)
  7276  		test := p.parseExpr(js_ast.LLowest)
  7277  		p.lexer.Expect(js_lexer.TCloseParen)
  7278  		isSingleLineYes := !p.lexer.HasNewlineBefore && p.lexer.Token != js_lexer.TOpenBrace
  7279  		yes := p.parseStmt(parseStmtOpts{lexicalDecl: lexicalDeclAllowFnInsideIf})
  7280  		var noOrNil js_ast.Stmt
  7281  		var isSingleLineNo bool
  7282  		if p.lexer.Token == js_lexer.TElse {
  7283  			p.lexer.Next()
  7284  			isSingleLineNo = !p.lexer.HasNewlineBefore && p.lexer.Token != js_lexer.TOpenBrace
  7285  			noOrNil = p.parseStmt(parseStmtOpts{lexicalDecl: lexicalDeclAllowFnInsideIf})
  7286  		}
  7287  		return js_ast.Stmt{Loc: loc, Data: &js_ast.SIf{Test: test, Yes: yes, NoOrNil: noOrNil, IsSingleLineYes: isSingleLineYes, IsSingleLineNo: isSingleLineNo}}
  7288  
  7289  	case js_lexer.TDo:
  7290  		p.lexer.Next()
  7291  		body := p.parseStmt(parseStmtOpts{})
  7292  		p.lexer.Expect(js_lexer.TWhile)
  7293  		p.lexer.Expect(js_lexer.TOpenParen)
  7294  		test := p.parseExpr(js_ast.LLowest)
  7295  		p.lexer.Expect(js_lexer.TCloseParen)
  7296  
  7297  		// This is a weird corner case where automatic semicolon insertion applies
  7298  		// even without a newline present
  7299  		if p.lexer.Token == js_lexer.TSemicolon {
  7300  			p.lexer.Next()
  7301  		}
  7302  		return js_ast.Stmt{Loc: loc, Data: &js_ast.SDoWhile{Body: body, Test: test}}
  7303  
  7304  	case js_lexer.TWhile:
  7305  		p.lexer.Next()
  7306  		p.lexer.Expect(js_lexer.TOpenParen)
  7307  		test := p.parseExpr(js_ast.LLowest)
  7308  		p.lexer.Expect(js_lexer.TCloseParen)
  7309  		isSingleLineBody := !p.lexer.HasNewlineBefore && p.lexer.Token != js_lexer.TOpenBrace
  7310  		body := p.parseStmt(parseStmtOpts{})
  7311  		return js_ast.Stmt{Loc: loc, Data: &js_ast.SWhile{Test: test, Body: body, IsSingleLineBody: isSingleLineBody}}
  7312  
  7313  	case js_lexer.TWith:
  7314  		p.lexer.Next()
  7315  		p.lexer.Expect(js_lexer.TOpenParen)
  7316  		test := p.parseExpr(js_ast.LLowest)
  7317  		bodyLoc := p.lexer.Loc()
  7318  		p.lexer.Expect(js_lexer.TCloseParen)
  7319  
  7320  		// Push a scope so we make sure to prevent any bare identifiers referenced
  7321  		// within the body from being renamed. Renaming them might change the
  7322  		// semantics of the code.
  7323  		p.pushScopeForParsePass(js_ast.ScopeWith, bodyLoc)
  7324  		isSingleLineBody := !p.lexer.HasNewlineBefore && p.lexer.Token != js_lexer.TOpenBrace
  7325  		body := p.parseStmt(parseStmtOpts{})
  7326  		p.popScope()
  7327  
  7328  		return js_ast.Stmt{Loc: loc, Data: &js_ast.SWith{Value: test, BodyLoc: bodyLoc, Body: body, IsSingleLineBody: isSingleLineBody}}
  7329  
  7330  	case js_lexer.TSwitch:
  7331  		p.lexer.Next()
  7332  		p.lexer.Expect(js_lexer.TOpenParen)
  7333  		test := p.parseExpr(js_ast.LLowest)
  7334  		p.lexer.Expect(js_lexer.TCloseParen)
  7335  
  7336  		bodyLoc := p.lexer.Loc()
  7337  		p.pushScopeForParsePass(js_ast.ScopeBlock, bodyLoc)
  7338  		defer p.popScope()
  7339  
  7340  		p.lexer.Expect(js_lexer.TOpenBrace)
  7341  		cases := []js_ast.Case{}
  7342  		foundDefault := false
  7343  
  7344  		for p.lexer.Token != js_lexer.TCloseBrace {
  7345  			var value js_ast.Expr
  7346  			body := []js_ast.Stmt{}
  7347  			caseLoc := p.lexer.Loc()
  7348  
  7349  			if p.lexer.Token == js_lexer.TDefault {
  7350  				if foundDefault {
  7351  					p.log.AddError(&p.tracker, p.lexer.Range(), "Multiple default clauses are not allowed")
  7352  					panic(js_lexer.LexerPanic{})
  7353  				}
  7354  				foundDefault = true
  7355  				p.lexer.Next()
  7356  				p.lexer.Expect(js_lexer.TColon)
  7357  			} else {
  7358  				p.lexer.Expect(js_lexer.TCase)
  7359  				value = p.parseExpr(js_ast.LLowest)
  7360  				p.lexer.Expect(js_lexer.TColon)
  7361  			}
  7362  
  7363  		caseBody:
  7364  			for {
  7365  				switch p.lexer.Token {
  7366  				case js_lexer.TCloseBrace, js_lexer.TCase, js_lexer.TDefault:
  7367  					break caseBody
  7368  
  7369  				default:
  7370  					body = append(body, p.parseStmt(parseStmtOpts{lexicalDecl: lexicalDeclAllowAll}))
  7371  				}
  7372  			}
  7373  
  7374  			cases = append(cases, js_ast.Case{ValueOrNil: value, Body: body, Loc: caseLoc})
  7375  		}
  7376  
  7377  		closeBraceLoc := p.lexer.Loc()
  7378  		p.lexer.Expect(js_lexer.TCloseBrace)
  7379  		return js_ast.Stmt{Loc: loc, Data: &js_ast.SSwitch{
  7380  			Test:          test,
  7381  			Cases:         cases,
  7382  			BodyLoc:       bodyLoc,
  7383  			CloseBraceLoc: closeBraceLoc,
  7384  		}}
  7385  
  7386  	case js_lexer.TTry:
  7387  		p.lexer.Next()
  7388  		blockLoc := p.lexer.Loc()
  7389  		p.lexer.Expect(js_lexer.TOpenBrace)
  7390  		p.pushScopeForParsePass(js_ast.ScopeBlock, loc)
  7391  		body := p.parseStmtsUpTo(js_lexer.TCloseBrace, parseStmtOpts{})
  7392  		p.popScope()
  7393  		closeBraceLoc := p.lexer.Loc()
  7394  		p.lexer.Next()
  7395  
  7396  		var catch *js_ast.Catch = nil
  7397  		var finally *js_ast.Finally = nil
  7398  
  7399  		if p.lexer.Token == js_lexer.TCatch {
  7400  			catchLoc := p.lexer.Loc()
  7401  			p.pushScopeForParsePass(js_ast.ScopeCatchBinding, catchLoc)
  7402  			p.lexer.Next()
  7403  			var bindingOrNil js_ast.Binding
  7404  
  7405  			// The catch binding is optional, and can be omitted
  7406  			if p.lexer.Token == js_lexer.TOpenBrace {
  7407  				if p.options.unsupportedJSFeatures.Has(compat.OptionalCatchBinding) {
  7408  					// Generate a new symbol for the catch binding for older browsers
  7409  					ref := p.newSymbol(ast.SymbolOther, "e")
  7410  					p.currentScope.Generated = append(p.currentScope.Generated, ref)
  7411  					bindingOrNil = js_ast.Binding{Loc: p.lexer.Loc(), Data: &js_ast.BIdentifier{Ref: ref}}
  7412  				}
  7413  			} else {
  7414  				p.lexer.Expect(js_lexer.TOpenParen)
  7415  				bindingOrNil = p.parseBinding(parseBindingOpts{})
  7416  
  7417  				// Skip over types
  7418  				if p.options.ts.Parse && p.lexer.Token == js_lexer.TColon {
  7419  					p.lexer.Expect(js_lexer.TColon)
  7420  					p.skipTypeScriptType(js_ast.LLowest)
  7421  				}
  7422  
  7423  				p.lexer.Expect(js_lexer.TCloseParen)
  7424  
  7425  				// Bare identifiers are a special case
  7426  				kind := ast.SymbolOther
  7427  				if _, ok := bindingOrNil.Data.(*js_ast.BIdentifier); ok {
  7428  					kind = ast.SymbolCatchIdentifier
  7429  				}
  7430  				p.declareBinding(kind, bindingOrNil, parseStmtOpts{})
  7431  			}
  7432  
  7433  			blockLoc := p.lexer.Loc()
  7434  			p.lexer.Expect(js_lexer.TOpenBrace)
  7435  
  7436  			p.pushScopeForParsePass(js_ast.ScopeBlock, blockLoc)
  7437  			stmts := p.parseStmtsUpTo(js_lexer.TCloseBrace, parseStmtOpts{})
  7438  			p.popScope()
  7439  
  7440  			closeBraceLoc := p.lexer.Loc()
  7441  			p.lexer.Next()
  7442  			catch = &js_ast.Catch{Loc: catchLoc, BindingOrNil: bindingOrNil, BlockLoc: blockLoc, Block: js_ast.SBlock{Stmts: stmts, CloseBraceLoc: closeBraceLoc}}
  7443  			p.popScope()
  7444  		}
  7445  
  7446  		if p.lexer.Token == js_lexer.TFinally || catch == nil {
  7447  			finallyLoc := p.lexer.Loc()
  7448  			p.pushScopeForParsePass(js_ast.ScopeBlock, finallyLoc)
  7449  			p.lexer.Expect(js_lexer.TFinally)
  7450  			p.lexer.Expect(js_lexer.TOpenBrace)
  7451  			stmts := p.parseStmtsUpTo(js_lexer.TCloseBrace, parseStmtOpts{})
  7452  			closeBraceLoc := p.lexer.Loc()
  7453  			p.lexer.Next()
  7454  			finally = &js_ast.Finally{Loc: finallyLoc, Block: js_ast.SBlock{Stmts: stmts, CloseBraceLoc: closeBraceLoc}}
  7455  			p.popScope()
  7456  		}
  7457  
  7458  		return js_ast.Stmt{Loc: loc, Data: &js_ast.STry{
  7459  			BlockLoc: blockLoc,
  7460  			Block:    js_ast.SBlock{Stmts: body, CloseBraceLoc: closeBraceLoc},
  7461  			Catch:    catch,
  7462  			Finally:  finally,
  7463  		}}
  7464  
  7465  	case js_lexer.TFor:
  7466  		p.pushScopeForParsePass(js_ast.ScopeBlock, loc)
  7467  		defer p.popScope()
  7468  
  7469  		p.lexer.Next()
  7470  
  7471  		// "for await (let x of y) {}"
  7472  		var awaitRange logger.Range
  7473  		if p.lexer.IsContextualKeyword("await") {
  7474  			awaitRange = p.lexer.Range()
  7475  			if p.fnOrArrowDataParse.await != allowExpr {
  7476  				p.log.AddError(&p.tracker, awaitRange, "Cannot use \"await\" outside an async function")
  7477  				awaitRange = logger.Range{}
  7478  			} else {
  7479  				didGenerateError := false
  7480  				if p.fnOrArrowDataParse.isTopLevel {
  7481  					p.topLevelAwaitKeyword = awaitRange
  7482  				}
  7483  				if !didGenerateError && p.options.unsupportedJSFeatures.Has(compat.AsyncAwait) && p.options.unsupportedJSFeatures.Has(compat.Generator) {
  7484  					// If for-await loops aren't supported, then we only support lowering
  7485  					// if either async/await or generators is supported. Otherwise we
  7486  					// cannot lower for-await loops.
  7487  					p.markSyntaxFeature(compat.ForAwait, awaitRange)
  7488  				}
  7489  			}
  7490  			p.lexer.Next()
  7491  		}
  7492  
  7493  		p.lexer.Expect(js_lexer.TOpenParen)
  7494  
  7495  		var initOrNil js_ast.Stmt
  7496  		var testOrNil js_ast.Expr
  7497  		var updateOrNil js_ast.Expr
  7498  
  7499  		// "in" expressions aren't allowed here
  7500  		p.allowIn = false
  7501  
  7502  		var badLetRange logger.Range
  7503  		if p.lexer.IsContextualKeyword("let") {
  7504  			badLetRange = p.lexer.Range()
  7505  		}
  7506  		decls := []js_ast.Decl{}
  7507  		initLoc := p.lexer.Loc()
  7508  		isVar := false
  7509  		switch p.lexer.Token {
  7510  		case js_lexer.TVar:
  7511  			isVar = true
  7512  			p.lexer.Next()
  7513  			decls = p.parseAndDeclareDecls(ast.SymbolHoisted, parseStmtOpts{})
  7514  			initOrNil = js_ast.Stmt{Loc: initLoc, Data: &js_ast.SLocal{Kind: js_ast.LocalVar, Decls: decls}}
  7515  
  7516  		case js_lexer.TConst:
  7517  			p.markSyntaxFeature(compat.ConstAndLet, p.lexer.Range())
  7518  			p.lexer.Next()
  7519  			decls = p.parseAndDeclareDecls(ast.SymbolConst, parseStmtOpts{})
  7520  			initOrNil = js_ast.Stmt{Loc: initLoc, Data: &js_ast.SLocal{Kind: js_ast.LocalConst, Decls: decls}}
  7521  
  7522  		case js_lexer.TSemicolon:
  7523  
  7524  		default:
  7525  			var expr js_ast.Expr
  7526  			var stmt js_ast.Stmt
  7527  			expr, stmt, decls = p.parseExprOrLetOrUsingStmt(parseStmtOpts{
  7528  				lexicalDecl:        lexicalDeclAllowAll,
  7529  				isForLoopInit:      true,
  7530  				isForAwaitLoopInit: awaitRange.Len > 0,
  7531  			})
  7532  			if stmt.Data != nil {
  7533  				badLetRange = logger.Range{}
  7534  				initOrNil = stmt
  7535  			} else {
  7536  				initOrNil = js_ast.Stmt{Loc: expr.Loc, Data: &js_ast.SExpr{Value: expr}}
  7537  			}
  7538  		}
  7539  
  7540  		// "in" expressions are allowed again
  7541  		p.allowIn = true
  7542  
  7543  		// Detect for-of loops
  7544  		if p.lexer.IsContextualKeyword("of") || awaitRange.Len > 0 {
  7545  			if badLetRange.Len > 0 {
  7546  				p.log.AddError(&p.tracker, badLetRange, "\"let\" must be wrapped in parentheses to be used as an expression here:")
  7547  			}
  7548  			if awaitRange.Len > 0 && !p.lexer.IsContextualKeyword("of") {
  7549  				if initOrNil.Data != nil {
  7550  					p.lexer.ExpectedString("\"of\"")
  7551  				} else {
  7552  					p.lexer.Unexpected()
  7553  				}
  7554  			}
  7555  			p.forbidInitializers(decls, "of", false)
  7556  			p.markSyntaxFeature(compat.ForOf, p.lexer.Range())
  7557  			p.lexer.Next()
  7558  			value := p.parseExpr(js_ast.LComma)
  7559  			p.lexer.Expect(js_lexer.TCloseParen)
  7560  			isSingleLineBody := !p.lexer.HasNewlineBefore && p.lexer.Token != js_lexer.TOpenBrace
  7561  			body := p.parseStmt(parseStmtOpts{})
  7562  			return js_ast.Stmt{Loc: loc, Data: &js_ast.SForOf{Await: awaitRange, Init: initOrNil, Value: value, Body: body, IsSingleLineBody: isSingleLineBody}}
  7563  		}
  7564  
  7565  		// Detect for-in loops
  7566  		if p.lexer.Token == js_lexer.TIn {
  7567  			p.forbidInitializers(decls, "in", isVar)
  7568  			if len(decls) == 1 {
  7569  				if local, ok := initOrNil.Data.(*js_ast.SLocal); ok {
  7570  					if local.Kind == js_ast.LocalUsing {
  7571  						p.log.AddError(&p.tracker, js_lexer.RangeOfIdentifier(p.source, initOrNil.Loc), "\"using\" declarations are not allowed here")
  7572  					} else if local.Kind == js_ast.LocalAwaitUsing {
  7573  						p.log.AddError(&p.tracker, js_lexer.RangeOfIdentifier(p.source, initOrNil.Loc), "\"await using\" declarations are not allowed here")
  7574  					}
  7575  				}
  7576  			}
  7577  			p.lexer.Next()
  7578  			value := p.parseExpr(js_ast.LLowest)
  7579  			p.lexer.Expect(js_lexer.TCloseParen)
  7580  			isSingleLineBody := !p.lexer.HasNewlineBefore && p.lexer.Token != js_lexer.TOpenBrace
  7581  			body := p.parseStmt(parseStmtOpts{})
  7582  			return js_ast.Stmt{Loc: loc, Data: &js_ast.SForIn{Init: initOrNil, Value: value, Body: body, IsSingleLineBody: isSingleLineBody}}
  7583  		}
  7584  
  7585  		p.lexer.Expect(js_lexer.TSemicolon)
  7586  
  7587  		// "await using" declarations are only allowed in for-of loops
  7588  		if local, ok := initOrNil.Data.(*js_ast.SLocal); ok && local.Kind == js_ast.LocalAwaitUsing {
  7589  			p.log.AddError(&p.tracker, js_lexer.RangeOfIdentifier(p.source, initOrNil.Loc), "\"await using\" declarations are not allowed here")
  7590  		}
  7591  
  7592  		// Only require "const" statement initializers when we know we're a normal for loop
  7593  		if local, ok := initOrNil.Data.(*js_ast.SLocal); ok && (local.Kind == js_ast.LocalConst || local.Kind == js_ast.LocalUsing) {
  7594  			p.requireInitializers(local.Kind, decls)
  7595  		}
  7596  
  7597  		if p.lexer.Token != js_lexer.TSemicolon {
  7598  			testOrNil = p.parseExpr(js_ast.LLowest)
  7599  		}
  7600  
  7601  		p.lexer.Expect(js_lexer.TSemicolon)
  7602  
  7603  		if p.lexer.Token != js_lexer.TCloseParen {
  7604  			updateOrNil = p.parseExpr(js_ast.LLowest)
  7605  		}
  7606  
  7607  		p.lexer.Expect(js_lexer.TCloseParen)
  7608  		isSingleLineBody := !p.lexer.HasNewlineBefore && p.lexer.Token != js_lexer.TOpenBrace
  7609  		body := p.parseStmt(parseStmtOpts{})
  7610  		return js_ast.Stmt{Loc: loc, Data: &js_ast.SFor{
  7611  			InitOrNil:        initOrNil,
  7612  			TestOrNil:        testOrNil,
  7613  			UpdateOrNil:      updateOrNil,
  7614  			Body:             body,
  7615  			IsSingleLineBody: isSingleLineBody,
  7616  		}}
  7617  
  7618  	case js_lexer.TImport:
  7619  		previousImportStatementKeyword := p.esmImportStatementKeyword
  7620  		p.esmImportStatementKeyword = p.lexer.Range()
  7621  		p.lexer.Next()
  7622  		stmt := js_ast.SImport{}
  7623  		wasOriginallyBareImport := false
  7624  
  7625  		// "export import foo = bar"
  7626  		// "import foo = bar" in a namespace
  7627  		if (opts.isExport || (opts.isNamespaceScope && !opts.isTypeScriptDeclare)) && p.lexer.Token != js_lexer.TIdentifier {
  7628  			p.lexer.Expected(js_lexer.TIdentifier)
  7629  		}
  7630  
  7631  	syntaxBeforePath:
  7632  		switch p.lexer.Token {
  7633  		case js_lexer.TOpenParen, js_lexer.TDot:
  7634  			// "import('path')"
  7635  			// "import.meta"
  7636  			p.esmImportStatementKeyword = previousImportStatementKeyword // This wasn't an ESM import statement after all
  7637  			expr := p.parseSuffix(p.parseImportExpr(loc, js_ast.LLowest), js_ast.LLowest, nil, 0)
  7638  			p.lexer.ExpectOrInsertSemicolon()
  7639  			return js_ast.Stmt{Loc: loc, Data: &js_ast.SExpr{Value: expr}}
  7640  
  7641  		case js_lexer.TStringLiteral, js_lexer.TNoSubstitutionTemplateLiteral:
  7642  			// "import 'path'"
  7643  			if !opts.isModuleScope && (!opts.isNamespaceScope || !opts.isTypeScriptDeclare) {
  7644  				p.lexer.Unexpected()
  7645  				return js_ast.Stmt{}
  7646  			}
  7647  
  7648  			wasOriginallyBareImport = true
  7649  
  7650  		case js_lexer.TAsterisk:
  7651  			// "import * as ns from 'path'"
  7652  			if !opts.isModuleScope && (!opts.isNamespaceScope || !opts.isTypeScriptDeclare) {
  7653  				p.lexer.Unexpected()
  7654  				return js_ast.Stmt{}
  7655  			}
  7656  
  7657  			p.lexer.Next()
  7658  			p.lexer.ExpectContextualKeyword("as")
  7659  			stmt.NamespaceRef = p.storeNameInRef(p.lexer.Identifier)
  7660  			starLoc := p.lexer.Loc()
  7661  			stmt.StarNameLoc = &starLoc
  7662  			p.lexer.Expect(js_lexer.TIdentifier)
  7663  			p.lexer.ExpectContextualKeyword("from")
  7664  
  7665  		case js_lexer.TOpenBrace:
  7666  			// "import {item1, item2} from 'path'"
  7667  			if !opts.isModuleScope && (!opts.isNamespaceScope || !opts.isTypeScriptDeclare) {
  7668  				p.lexer.Unexpected()
  7669  				return js_ast.Stmt{}
  7670  			}
  7671  
  7672  			items, isSingleLine := p.parseImportClause()
  7673  			stmt.Items = &items
  7674  			stmt.IsSingleLine = isSingleLine
  7675  			p.lexer.ExpectContextualKeyword("from")
  7676  
  7677  		case js_lexer.TIdentifier:
  7678  			// "import defaultItem from 'path'"
  7679  			// "import foo = bar"
  7680  			if !opts.isModuleScope && !opts.isNamespaceScope {
  7681  				p.lexer.Unexpected()
  7682  				return js_ast.Stmt{}
  7683  			}
  7684  
  7685  			defaultName := p.lexer.Identifier
  7686  			stmt.DefaultName = &ast.LocRef{Loc: p.lexer.Loc(), Ref: p.storeNameInRef(defaultName)}
  7687  			p.lexer.Next()
  7688  
  7689  			if p.options.ts.Parse {
  7690  				// Skip over type-only imports
  7691  				if defaultName.String == "type" {
  7692  					switch p.lexer.Token {
  7693  					case js_lexer.TIdentifier:
  7694  						nameSubstring := p.lexer.Identifier
  7695  						nameLoc := p.lexer.Loc()
  7696  						p.lexer.Next()
  7697  						if p.lexer.Token == js_lexer.TEquals {
  7698  							// "import type foo = require('bar');"
  7699  							// "import type foo = bar.baz;"
  7700  							opts.isTypeScriptDeclare = true
  7701  							return p.parseTypeScriptImportEqualsStmt(loc, opts, nameLoc, nameSubstring.String)
  7702  						} else if p.lexer.Token == js_lexer.TStringLiteral && nameSubstring.String == "from" {
  7703  							// "import type from 'bar';"
  7704  							break syntaxBeforePath
  7705  						} else {
  7706  							// "import type foo from 'bar';"
  7707  							p.lexer.ExpectContextualKeyword("from")
  7708  							p.parsePath()
  7709  							p.lexer.ExpectOrInsertSemicolon()
  7710  							return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
  7711  						}
  7712  
  7713  					case js_lexer.TAsterisk:
  7714  						// "import type * as foo from 'bar';"
  7715  						p.lexer.Next()
  7716  						p.lexer.ExpectContextualKeyword("as")
  7717  						p.lexer.Expect(js_lexer.TIdentifier)
  7718  						p.lexer.ExpectContextualKeyword("from")
  7719  						p.parsePath()
  7720  						p.lexer.ExpectOrInsertSemicolon()
  7721  						return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
  7722  
  7723  					case js_lexer.TOpenBrace:
  7724  						// "import type {foo} from 'bar';"
  7725  						p.parseImportClause()
  7726  						p.lexer.ExpectContextualKeyword("from")
  7727  						p.parsePath()
  7728  						p.lexer.ExpectOrInsertSemicolon()
  7729  						return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
  7730  					}
  7731  				}
  7732  
  7733  				// Parse TypeScript import assignment statements
  7734  				if p.lexer.Token == js_lexer.TEquals || opts.isExport || (opts.isNamespaceScope && !opts.isTypeScriptDeclare) {
  7735  					p.esmImportStatementKeyword = previousImportStatementKeyword // This wasn't an ESM import statement after all
  7736  					return p.parseTypeScriptImportEqualsStmt(loc, opts, stmt.DefaultName.Loc, defaultName.String)
  7737  				}
  7738  			}
  7739  
  7740  			if p.lexer.Token == js_lexer.TComma {
  7741  				p.lexer.Next()
  7742  				switch p.lexer.Token {
  7743  				case js_lexer.TAsterisk:
  7744  					// "import defaultItem, * as ns from 'path'"
  7745  					p.lexer.Next()
  7746  					p.lexer.ExpectContextualKeyword("as")
  7747  					stmt.NamespaceRef = p.storeNameInRef(p.lexer.Identifier)
  7748  					starLoc := p.lexer.Loc()
  7749  					stmt.StarNameLoc = &starLoc
  7750  					p.lexer.Expect(js_lexer.TIdentifier)
  7751  
  7752  				case js_lexer.TOpenBrace:
  7753  					// "import defaultItem, {item1, item2} from 'path'"
  7754  					items, isSingleLine := p.parseImportClause()
  7755  					stmt.Items = &items
  7756  					stmt.IsSingleLine = isSingleLine
  7757  
  7758  				default:
  7759  					p.lexer.Unexpected()
  7760  				}
  7761  			}
  7762  
  7763  			p.lexer.ExpectContextualKeyword("from")
  7764  
  7765  		default:
  7766  			p.lexer.Unexpected()
  7767  			return js_ast.Stmt{}
  7768  		}
  7769  
  7770  		pathLoc, pathText, assertOrWith, flags := p.parsePath()
  7771  		p.lexer.ExpectOrInsertSemicolon()
  7772  
  7773  		// If TypeScript's "preserveValueImports": true setting is active, TypeScript's
  7774  		// "importsNotUsedAsValues": "preserve" setting is NOT active, and the import
  7775  		// clause is present and empty (or is non-empty but filled with type-only
  7776  		// items), then the import statement should still be removed entirely to match
  7777  		// the behavior of the TypeScript compiler:
  7778  		//
  7779  		//   // Keep these
  7780  		//   import 'x'
  7781  		//   import { y } from 'x'
  7782  		//   import { y, type z } from 'x'
  7783  		//
  7784  		//   // Remove these
  7785  		//   import {} from 'x'
  7786  		//   import { type y } from 'x'
  7787  		//
  7788  		//   // Remove the items from these
  7789  		//   import d, {} from 'x'
  7790  		//   import d, { type y } from 'x'
  7791  		//
  7792  		if p.options.ts.Parse && p.options.ts.Config.UnusedImportFlags() == config.TSUnusedImport_KeepValues && stmt.Items != nil && len(*stmt.Items) == 0 {
  7793  			if stmt.DefaultName == nil {
  7794  				return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
  7795  			}
  7796  			stmt.Items = nil
  7797  		}
  7798  
  7799  		if wasOriginallyBareImport {
  7800  			flags |= ast.WasOriginallyBareImport
  7801  		}
  7802  		stmt.ImportRecordIndex = p.addImportRecord(ast.ImportStmt, pathLoc, pathText, assertOrWith, flags)
  7803  
  7804  		if stmt.StarNameLoc != nil {
  7805  			name := p.loadNameFromRef(stmt.NamespaceRef)
  7806  			stmt.NamespaceRef = p.declareSymbol(ast.SymbolImport, *stmt.StarNameLoc, name)
  7807  		} else {
  7808  			// Generate a symbol for the namespace
  7809  			name := "import_" + js_ast.GenerateNonUniqueNameFromPath(pathText)
  7810  			stmt.NamespaceRef = p.newSymbol(ast.SymbolOther, name)
  7811  			p.currentScope.Generated = append(p.currentScope.Generated, stmt.NamespaceRef)
  7812  		}
  7813  		itemRefs := make(map[string]ast.LocRef)
  7814  
  7815  		// Link the default item to the namespace
  7816  		if stmt.DefaultName != nil {
  7817  			name := p.loadNameFromRef(stmt.DefaultName.Ref)
  7818  			ref := p.declareSymbol(ast.SymbolImport, stmt.DefaultName.Loc, name)
  7819  			p.isImportItem[ref] = true
  7820  			stmt.DefaultName.Ref = ref
  7821  		}
  7822  
  7823  		// Link each import item to the namespace
  7824  		if stmt.Items != nil {
  7825  			for i, item := range *stmt.Items {
  7826  				name := p.loadNameFromRef(item.Name.Ref)
  7827  				ref := p.declareSymbol(ast.SymbolImport, item.Name.Loc, name)
  7828  				p.checkForUnrepresentableIdentifier(item.AliasLoc, item.Alias)
  7829  				p.isImportItem[ref] = true
  7830  				(*stmt.Items)[i].Name.Ref = ref
  7831  				itemRefs[item.Alias] = ast.LocRef{Loc: item.Name.Loc, Ref: ref}
  7832  			}
  7833  		}
  7834  
  7835  		// Track the items for this namespace
  7836  		p.importItemsForNamespace[stmt.NamespaceRef] = namespaceImportItems{
  7837  			entries:           itemRefs,
  7838  			importRecordIndex: stmt.ImportRecordIndex,
  7839  		}
  7840  
  7841  		// Import statements anywhere in the file disable top-level const
  7842  		// local prefix because import cycles can be used to trigger TDZ
  7843  		p.currentScope.IsAfterConstLocalPrefix = true
  7844  		return js_ast.Stmt{Loc: loc, Data: &stmt}
  7845  
  7846  	case js_lexer.TBreak:
  7847  		p.lexer.Next()
  7848  		name := p.parseLabelName()
  7849  		p.lexer.ExpectOrInsertSemicolon()
  7850  		return js_ast.Stmt{Loc: loc, Data: &js_ast.SBreak{Label: name}}
  7851  
  7852  	case js_lexer.TContinue:
  7853  		p.lexer.Next()
  7854  		name := p.parseLabelName()
  7855  		p.lexer.ExpectOrInsertSemicolon()
  7856  		return js_ast.Stmt{Loc: loc, Data: &js_ast.SContinue{Label: name}}
  7857  
  7858  	case js_lexer.TReturn:
  7859  		if p.fnOrArrowDataParse.isReturnDisallowed {
  7860  			p.log.AddError(&p.tracker, p.lexer.Range(), "A return statement cannot be used here:")
  7861  		}
  7862  		p.lexer.Next()
  7863  		var value js_ast.Expr
  7864  		if p.lexer.Token != js_lexer.TSemicolon &&
  7865  			!p.lexer.HasNewlineBefore &&
  7866  			p.lexer.Token != js_lexer.TCloseBrace &&
  7867  			p.lexer.Token != js_lexer.TEndOfFile {
  7868  			value = p.parseExpr(js_ast.LLowest)
  7869  		}
  7870  		p.latestReturnHadSemicolon = p.lexer.Token == js_lexer.TSemicolon
  7871  		p.lexer.ExpectOrInsertSemicolon()
  7872  		return js_ast.Stmt{Loc: loc, Data: &js_ast.SReturn{ValueOrNil: value}}
  7873  
  7874  	case js_lexer.TThrow:
  7875  		p.lexer.Next()
  7876  		if p.lexer.HasNewlineBefore {
  7877  			endLoc := logger.Loc{Start: loc.Start + 5}
  7878  			p.log.AddError(&p.tracker, logger.Range{Loc: endLoc},
  7879  				"Unexpected newline after \"throw\"")
  7880  			return js_ast.Stmt{Loc: loc, Data: &js_ast.SThrow{Value: js_ast.Expr{Loc: endLoc, Data: js_ast.ENullShared}}}
  7881  		}
  7882  		expr := p.parseExpr(js_ast.LLowest)
  7883  		p.lexer.ExpectOrInsertSemicolon()
  7884  		return js_ast.Stmt{Loc: loc, Data: &js_ast.SThrow{Value: expr}}
  7885  
  7886  	case js_lexer.TDebugger:
  7887  		p.lexer.Next()
  7888  		p.lexer.ExpectOrInsertSemicolon()
  7889  		return js_ast.Stmt{Loc: loc, Data: js_ast.SDebuggerShared}
  7890  
  7891  	case js_lexer.TOpenBrace:
  7892  		p.pushScopeForParsePass(js_ast.ScopeBlock, loc)
  7893  		defer p.popScope()
  7894  
  7895  		p.lexer.Next()
  7896  		stmts := p.parseStmtsUpTo(js_lexer.TCloseBrace, parseStmtOpts{})
  7897  		closeBraceLoc := p.lexer.Loc()
  7898  		p.lexer.Next()
  7899  		return js_ast.Stmt{Loc: loc, Data: &js_ast.SBlock{Stmts: stmts, CloseBraceLoc: closeBraceLoc}}
  7900  
  7901  	default:
  7902  		isIdentifier := p.lexer.Token == js_lexer.TIdentifier
  7903  		nameRange := p.lexer.Range()
  7904  		name := p.lexer.Identifier.String
  7905  
  7906  		// Parse either an async function, an async expression, or a normal expression
  7907  		var expr js_ast.Expr
  7908  		if isIdentifier && p.lexer.Raw() == "async" {
  7909  			p.lexer.Next()
  7910  			if p.lexer.Token == js_lexer.TFunction && !p.lexer.HasNewlineBefore {
  7911  				p.lexer.Next()
  7912  				return p.parseFnStmt(nameRange.Loc, opts, true /* isAsync */, nameRange)
  7913  			}
  7914  			expr = p.parseSuffix(p.parseAsyncPrefixExpr(nameRange, js_ast.LLowest, 0), js_ast.LLowest, nil, 0)
  7915  		} else {
  7916  			var stmt js_ast.Stmt
  7917  			expr, stmt, _ = p.parseExprOrLetOrUsingStmt(opts)
  7918  			if stmt.Data != nil {
  7919  				p.lexer.ExpectOrInsertSemicolon()
  7920  				return stmt
  7921  			}
  7922  		}
  7923  
  7924  		if isIdentifier {
  7925  			if ident, ok := expr.Data.(*js_ast.EIdentifier); ok {
  7926  				if p.lexer.Token == js_lexer.TColon && opts.deferredDecorators == nil {
  7927  					p.pushScopeForParsePass(js_ast.ScopeLabel, loc)
  7928  					defer p.popScope()
  7929  
  7930  					// Parse a labeled statement
  7931  					p.lexer.Next()
  7932  					name := ast.LocRef{Loc: expr.Loc, Ref: ident.Ref}
  7933  					nestedOpts := parseStmtOpts{}
  7934  					if opts.lexicalDecl == lexicalDeclAllowAll || opts.lexicalDecl == lexicalDeclAllowFnInsideLabel {
  7935  						nestedOpts.lexicalDecl = lexicalDeclAllowFnInsideLabel
  7936  					}
  7937  					isSingleLineStmt := !p.lexer.HasNewlineBefore && p.lexer.Token != js_lexer.TOpenBrace
  7938  					stmt := p.parseStmt(nestedOpts)
  7939  					return js_ast.Stmt{Loc: loc, Data: &js_ast.SLabel{Name: name, Stmt: stmt, IsSingleLineStmt: isSingleLineStmt}}
  7940  				}
  7941  
  7942  				if p.options.ts.Parse {
  7943  					switch name {
  7944  					case "type":
  7945  						if !p.lexer.HasNewlineBefore && p.lexer.Token == js_lexer.TIdentifier {
  7946  							// "type Foo = any"
  7947  							p.skipTypeScriptTypeStmt(parseStmtOpts{isModuleScope: opts.isModuleScope})
  7948  							return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
  7949  						}
  7950  
  7951  					case "namespace", "module":
  7952  						// "namespace Foo {}"
  7953  						// "module Foo {}"
  7954  						// "declare module 'fs' {}"
  7955  						// "declare module 'fs';"
  7956  						if !p.lexer.HasNewlineBefore && (opts.isModuleScope || opts.isNamespaceScope) && (p.lexer.Token == js_lexer.TIdentifier ||
  7957  							(p.lexer.Token == js_lexer.TStringLiteral && opts.isTypeScriptDeclare)) {
  7958  							return p.parseTypeScriptNamespaceStmt(loc, opts)
  7959  						}
  7960  
  7961  					case "interface":
  7962  						// "interface Foo {}"
  7963  						// "export default interface Foo {}"
  7964  						// "export default interface \n Foo {}"
  7965  						if !p.lexer.HasNewlineBefore || opts.isExportDefault {
  7966  							p.skipTypeScriptInterfaceStmt(parseStmtOpts{isModuleScope: opts.isModuleScope})
  7967  							return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
  7968  						}
  7969  
  7970  						// "interface \n Foo {}"
  7971  						// "export interface \n Foo {}"
  7972  						if opts.isExport {
  7973  							p.log.AddError(&p.tracker, nameRange, "Unexpected \"interface\"")
  7974  							panic(js_lexer.LexerPanic{})
  7975  						}
  7976  
  7977  					case "abstract":
  7978  						if !p.lexer.HasNewlineBefore && p.lexer.Token == js_lexer.TClass {
  7979  							return p.parseClassStmt(loc, opts)
  7980  						}
  7981  
  7982  					case "global":
  7983  						// "declare module 'fs' { global { namespace NodeJS {} } }"
  7984  						if opts.isNamespaceScope && opts.isTypeScriptDeclare && p.lexer.Token == js_lexer.TOpenBrace {
  7985  							p.lexer.Next()
  7986  							p.parseStmtsUpTo(js_lexer.TCloseBrace, opts)
  7987  							p.lexer.Next()
  7988  							return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
  7989  						}
  7990  
  7991  					case "declare":
  7992  						if !p.lexer.HasNewlineBefore {
  7993  							opts.lexicalDecl = lexicalDeclAllowAll
  7994  							opts.isTypeScriptDeclare = true
  7995  
  7996  							// "declare global { ... }"
  7997  							if p.lexer.IsContextualKeyword("global") {
  7998  								p.lexer.Next()
  7999  								p.lexer.Expect(js_lexer.TOpenBrace)
  8000  								p.parseStmtsUpTo(js_lexer.TCloseBrace, opts)
  8001  								p.lexer.Next()
  8002  								return js_ast.Stmt{Loc: loc, Data: js_ast.STypeScriptShared}
  8003  							}
  8004  
  8005  							// "declare const x: any"
  8006  							scopeIndex := len(p.scopesInOrder)
  8007  							oldLexer := p.lexer
  8008  							stmt := p.parseStmt(opts)
  8009  							typeDeclarationData := js_ast.STypeScriptShared
  8010  							switch s := stmt.Data.(type) {
  8011  							case *js_ast.SEmpty:
  8012  								return js_ast.Stmt{Loc: loc, Data: &js_ast.SExpr{Value: expr}}
  8013  
  8014  							case *js_ast.STypeScript:
  8015  								// Type declarations are expected. Propagate the "declare class"
  8016  								// status in case our caller is a decorator that needs to know
  8017  								// this was a "declare class" statement.
  8018  								typeDeclarationData = s
  8019  
  8020  							case *js_ast.SLocal:
  8021  								// This is also a type declaration (but doesn't use "STypeScript"
  8022  								// because we need to be able to handle namespace exports below)
  8023  
  8024  							default:
  8025  								// Anything that we don't expect is a syntax error. For example,
  8026  								// we consider this a syntax error:
  8027  								//
  8028  								//   declare let declare: any, foo: any
  8029  								//   declare foo
  8030  								//
  8031  								// Strangely TypeScript allows this code starting with version
  8032  								// 4.4, but I assume this is a bug. This bug was reported here:
  8033  								// https://github.com/microsoft/TypeScript/issues/54602
  8034  								p.lexer = oldLexer
  8035  								p.lexer.Unexpected()
  8036  							}
  8037  							p.discardScopesUpTo(scopeIndex)
  8038  
  8039  							// Unlike almost all uses of "declare", statements that use
  8040  							// "export declare" with "var/let/const" inside a namespace affect
  8041  							// code generation. They cause any declared bindings to be
  8042  							// considered exports of the namespace. Identifier references to
  8043  							// those names must be converted into property accesses off the
  8044  							// namespace object:
  8045  							//
  8046  							//   namespace ns {
  8047  							//     export declare const x
  8048  							//     export function y() { return x }
  8049  							//   }
  8050  							//
  8051  							//   (ns as any).x = 1
  8052  							//   console.log(ns.y())
  8053  							//
  8054  							// In this example, "return x" must be replaced with "return ns.x".
  8055  							// This is handled by replacing each "export declare" statement
  8056  							// inside a namespace with an "export var" statement containing all
  8057  							// of the declared bindings. That "export var" statement will later
  8058  							// cause identifiers to be transformed into property accesses.
  8059  							if opts.isNamespaceScope && opts.isExport {
  8060  								var decls []js_ast.Decl
  8061  								if s, ok := stmt.Data.(*js_ast.SLocal); ok {
  8062  									js_ast.ForEachIdentifierBindingInDecls(s.Decls, func(loc logger.Loc, b *js_ast.BIdentifier) {
  8063  										decls = append(decls, js_ast.Decl{Binding: js_ast.Binding{Loc: loc, Data: b}})
  8064  									})
  8065  								}
  8066  								if len(decls) > 0 {
  8067  									return js_ast.Stmt{Loc: loc, Data: &js_ast.SLocal{
  8068  										Kind:     js_ast.LocalVar,
  8069  										IsExport: true,
  8070  										Decls:    decls,
  8071  									}}
  8072  								}
  8073  							}
  8074  
  8075  							return js_ast.Stmt{Loc: loc, Data: typeDeclarationData}
  8076  						}
  8077  					}
  8078  				}
  8079  			}
  8080  		}
  8081  
  8082  		p.lexer.ExpectOrInsertSemicolon()
  8083  		return js_ast.Stmt{Loc: loc, Data: &js_ast.SExpr{Value: expr}}
  8084  	}
  8085  }
  8086  
  8087  func (p *parser) addImportRecord(kind ast.ImportKind, pathRange logger.Range, text string, assertOrWith *ast.ImportAssertOrWith, flags ast.ImportRecordFlags) uint32 {
  8088  	index := uint32(len(p.importRecords))
  8089  	p.importRecords = append(p.importRecords, ast.ImportRecord{
  8090  		Kind:         kind,
  8091  		Range:        pathRange,
  8092  		Path:         logger.Path{Text: text},
  8093  		AssertOrWith: assertOrWith,
  8094  		Flags:        flags,
  8095  	})
  8096  	return index
  8097  }
  8098  
  8099  func (p *parser) parseFnBody(data fnOrArrowDataParse) js_ast.FnBody {
  8100  	oldFnOrArrowData := p.fnOrArrowDataParse
  8101  	oldAllowIn := p.allowIn
  8102  	p.fnOrArrowDataParse = data
  8103  	p.allowIn = true
  8104  
  8105  	loc := p.lexer.Loc()
  8106  	p.pushScopeForParsePass(js_ast.ScopeFunctionBody, loc)
  8107  	defer p.popScope()
  8108  
  8109  	p.lexer.Expect(js_lexer.TOpenBrace)
  8110  	stmts := p.parseStmtsUpTo(js_lexer.TCloseBrace, parseStmtOpts{
  8111  		allowDirectivePrologue: true,
  8112  	})
  8113  	closeBraceLoc := p.lexer.Loc()
  8114  	p.lexer.Next()
  8115  
  8116  	p.allowIn = oldAllowIn
  8117  	p.fnOrArrowDataParse = oldFnOrArrowData
  8118  	return js_ast.FnBody{Loc: loc, Block: js_ast.SBlock{Stmts: stmts, CloseBraceLoc: closeBraceLoc}}
  8119  }
  8120  
  8121  func (p *parser) forbidLexicalDecl(loc logger.Loc) {
  8122  	r := js_lexer.RangeOfIdentifier(p.source, loc)
  8123  	p.log.AddError(&p.tracker, r, "Cannot use a declaration in a single-statement context")
  8124  }
  8125  
  8126  func (p *parser) parseStmtsUpTo(end js_lexer.T, opts parseStmtOpts) []js_ast.Stmt {
  8127  	stmts := []js_ast.Stmt{}
  8128  	returnWithoutSemicolonStart := int32(-1)
  8129  	opts.lexicalDecl = lexicalDeclAllowAll
  8130  	isDirectivePrologue := opts.allowDirectivePrologue
  8131  
  8132  	for {
  8133  		// Preserve some statement-level comments
  8134  		comments := p.lexer.LegalCommentsBeforeToken
  8135  		if len(comments) > 0 {
  8136  			for _, comment := range comments {
  8137  				stmts = append(stmts, js_ast.Stmt{
  8138  					Loc: comment.Loc,
  8139  					Data: &js_ast.SComment{
  8140  						Text:           p.source.CommentTextWithoutIndent(comment),
  8141  						IsLegalComment: true,
  8142  					},
  8143  				})
  8144  			}
  8145  		}
  8146  
  8147  		if p.lexer.Token == end {
  8148  			break
  8149  		}
  8150  
  8151  		stmt := p.parseStmt(opts)
  8152  
  8153  		// Skip TypeScript types entirely
  8154  		if p.options.ts.Parse {
  8155  			if _, ok := stmt.Data.(*js_ast.STypeScript); ok {
  8156  				continue
  8157  			}
  8158  		}
  8159  
  8160  		// Parse one or more directives at the beginning
  8161  		if isDirectivePrologue {
  8162  			isDirectivePrologue = false
  8163  			if expr, ok := stmt.Data.(*js_ast.SExpr); ok {
  8164  				if str, ok := expr.Value.Data.(*js_ast.EString); ok && !str.PreferTemplate {
  8165  					stmt.Data = &js_ast.SDirective{Value: str.Value, LegacyOctalLoc: str.LegacyOctalLoc}
  8166  					isDirectivePrologue = true
  8167  
  8168  					if helpers.UTF16EqualsString(str.Value, "use strict") {
  8169  						// Track "use strict" directives
  8170  						p.currentScope.StrictMode = js_ast.ExplicitStrictMode
  8171  						p.currentScope.UseStrictLoc = expr.Value.Loc
  8172  
  8173  						// Inside a function, strict mode actually propagates from the child
  8174  						// scope to the parent scope:
  8175  						//
  8176  						//   // This is a syntax error
  8177  						//   function fn(arguments) {
  8178  						//     "use strict";
  8179  						//   }
  8180  						//
  8181  						if p.currentScope.Kind == js_ast.ScopeFunctionBody &&
  8182  							p.currentScope.Parent.Kind == js_ast.ScopeFunctionArgs &&
  8183  							p.currentScope.Parent.StrictMode == js_ast.SloppyMode {
  8184  							p.currentScope.Parent.StrictMode = js_ast.ExplicitStrictMode
  8185  							p.currentScope.Parent.UseStrictLoc = expr.Value.Loc
  8186  						}
  8187  					} else if helpers.UTF16EqualsString(str.Value, "use asm") {
  8188  						// Deliberately remove "use asm" directives. The asm.js subset of
  8189  						// JavaScript has complicated validation rules that are triggered
  8190  						// by this directive. This parser is not designed with asm.js in
  8191  						// mind and round-tripping asm.js code through esbuild will very
  8192  						// likely cause it to no longer validate as asm.js. When this
  8193  						// happens, V8 prints a warning and people don't like seeing the
  8194  						// warning.
  8195  						//
  8196  						// We deliberately do not attempt to preserve the validity of
  8197  						// asm.js code because it's a complicated legacy format and it's
  8198  						// obsolete now that WebAssembly exists. By removing this directive
  8199  						// it will just become normal JavaScript, which will work fine and
  8200  						// won't generate a warning (but will run slower). We don't generate
  8201  						// a warning ourselves in this case because there isn't necessarily
  8202  						// anything easy and actionable that the user can do to fix this.
  8203  						stmt.Data = &js_ast.SEmpty{}
  8204  					}
  8205  				}
  8206  			}
  8207  		}
  8208  
  8209  		stmts = append(stmts, stmt)
  8210  
  8211  		// Warn about ASI and return statements. Here's an example of code with
  8212  		// this problem: https://github.com/rollup/rollup/issues/3729
  8213  		if !p.suppressWarningsAboutWeirdCode {
  8214  			if s, ok := stmt.Data.(*js_ast.SReturn); ok && s.ValueOrNil.Data == nil && !p.latestReturnHadSemicolon {
  8215  				returnWithoutSemicolonStart = stmt.Loc.Start
  8216  			} else {
  8217  				if returnWithoutSemicolonStart != -1 {
  8218  					if _, ok := stmt.Data.(*js_ast.SExpr); ok {
  8219  						p.log.AddID(logger.MsgID_JS_SemicolonAfterReturn, logger.Warning, &p.tracker, logger.Range{Loc: logger.Loc{Start: returnWithoutSemicolonStart + 6}},
  8220  							"The following expression is not returned because of an automatically-inserted semicolon")
  8221  					}
  8222  				}
  8223  				returnWithoutSemicolonStart = -1
  8224  			}
  8225  		}
  8226  	}
  8227  
  8228  	return stmts
  8229  }
  8230  
  8231  type generateTempRefArg uint8
  8232  
  8233  const (
  8234  	tempRefNeedsDeclare generateTempRefArg = iota
  8235  	tempRefNoDeclare
  8236  
  8237  	// This is used when the generated temporary may a) be used inside of a loop
  8238  	// body and b) may be used inside of a closure. In that case we can't use
  8239  	// "var" for the temporary and we can't declare the temporary at the top of
  8240  	// the enclosing function. Instead, we need to use "let" and we need to
  8241  	// declare the temporary in the enclosing block (so it's inside of the loop
  8242  	// body).
  8243  	tempRefNeedsDeclareMayBeCapturedInsideLoop
  8244  )
  8245  
  8246  func (p *parser) generateTempRef(declare generateTempRefArg, optionalName string) ast.Ref {
  8247  	scope := p.currentScope
  8248  
  8249  	if declare != tempRefNeedsDeclareMayBeCapturedInsideLoop {
  8250  		for !scope.Kind.StopsHoisting() {
  8251  			scope = scope.Parent
  8252  		}
  8253  	}
  8254  
  8255  	if optionalName == "" {
  8256  		optionalName = "_" + ast.DefaultNameMinifierJS.NumberToMinifiedName(p.tempRefCount)
  8257  		p.tempRefCount++
  8258  	}
  8259  	ref := p.newSymbol(ast.SymbolOther, optionalName)
  8260  
  8261  	if declare == tempRefNeedsDeclareMayBeCapturedInsideLoop && !scope.Kind.StopsHoisting() {
  8262  		p.tempLetsToDeclare = append(p.tempLetsToDeclare, ref)
  8263  	} else if declare != tempRefNoDeclare {
  8264  		p.tempRefsToDeclare = append(p.tempRefsToDeclare, tempRef{ref: ref})
  8265  	}
  8266  
  8267  	scope.Generated = append(scope.Generated, ref)
  8268  	return ref
  8269  }
  8270  
  8271  func (p *parser) generateTopLevelTempRef() ast.Ref {
  8272  	ref := p.newSymbol(ast.SymbolOther, "_"+ast.DefaultNameMinifierJS.NumberToMinifiedName(p.topLevelTempRefCount))
  8273  	p.topLevelTempRefsToDeclare = append(p.topLevelTempRefsToDeclare, tempRef{ref: ref})
  8274  	p.moduleScope.Generated = append(p.moduleScope.Generated, ref)
  8275  	p.topLevelTempRefCount++
  8276  	return ref
  8277  }
  8278  
  8279  func (p *parser) pushScopeForVisitPass(kind js_ast.ScopeKind, loc logger.Loc) {
  8280  	order := p.scopesInOrder[0]
  8281  
  8282  	// Sanity-check that the scopes generated by the first and second passes match
  8283  	if order.loc != loc || order.scope.Kind != kind {
  8284  		panic(fmt.Sprintf("Expected scope (%d, %d) in %s, found scope (%d, %d)",
  8285  			kind, loc.Start,
  8286  			p.source.PrettyPath,
  8287  			order.scope.Kind, order.loc.Start))
  8288  	}
  8289  
  8290  	p.scopesInOrder = p.scopesInOrder[1:]
  8291  	p.currentScope = order.scope
  8292  	p.scopesForCurrentPart = append(p.scopesForCurrentPart, order.scope)
  8293  }
  8294  
  8295  type findSymbolResult struct {
  8296  	ref               ast.Ref
  8297  	declareLoc        logger.Loc
  8298  	isInsideWithScope bool
  8299  }
  8300  
  8301  func (p *parser) findSymbol(loc logger.Loc, name string) findSymbolResult {
  8302  	var ref ast.Ref
  8303  	var declareLoc logger.Loc
  8304  	isInsideWithScope := false
  8305  	didForbidArguments := false
  8306  	s := p.currentScope
  8307  
  8308  	for {
  8309  		// Track if we're inside a "with" statement body
  8310  		if s.Kind == js_ast.ScopeWith {
  8311  			isInsideWithScope = true
  8312  		}
  8313  
  8314  		// Forbid referencing "arguments" inside class bodies
  8315  		if s.ForbidArguments && name == "arguments" && !didForbidArguments {
  8316  			r := js_lexer.RangeOfIdentifier(p.source, loc)
  8317  			p.log.AddError(&p.tracker, r, fmt.Sprintf("Cannot access %q here:", name))
  8318  			didForbidArguments = true
  8319  		}
  8320  
  8321  		// Is the symbol a member of this scope?
  8322  		if member, ok := s.Members[name]; ok {
  8323  			ref = member.Ref
  8324  			declareLoc = member.Loc
  8325  			break
  8326  		}
  8327  
  8328  		// Is the symbol a member of this scope's TypeScript namespace?
  8329  		if tsNamespace := s.TSNamespace; tsNamespace != nil {
  8330  			if member, ok := tsNamespace.ExportedMembers[name]; ok && tsNamespace.IsEnumScope == member.IsEnumValue {
  8331  				// If this is an identifier from a sibling TypeScript namespace, then we're
  8332  				// going to have to generate a property access instead of a simple reference.
  8333  				// Lazily-generate an identifier that represents this property access.
  8334  				cache := tsNamespace.LazilyGeneratedProperyAccesses
  8335  				if cache == nil {
  8336  					cache = make(map[string]ast.Ref)
  8337  					tsNamespace.LazilyGeneratedProperyAccesses = cache
  8338  				}
  8339  				ref, ok = cache[name]
  8340  				if !ok {
  8341  					ref = p.newSymbol(ast.SymbolOther, name)
  8342  					p.symbols[ref.InnerIndex].NamespaceAlias = &ast.NamespaceAlias{
  8343  						NamespaceRef: tsNamespace.ArgRef,
  8344  						Alias:        name,
  8345  					}
  8346  					cache[name] = ref
  8347  				}
  8348  				declareLoc = member.Loc
  8349  				break
  8350  			}
  8351  		}
  8352  
  8353  		s = s.Parent
  8354  		if s == nil {
  8355  			// Allocate an "unbound" symbol
  8356  			p.checkForUnrepresentableIdentifier(loc, name)
  8357  			ref = p.newSymbol(ast.SymbolUnbound, name)
  8358  			declareLoc = loc
  8359  			p.moduleScope.Members[name] = js_ast.ScopeMember{Ref: ref, Loc: logger.Loc{Start: -1}}
  8360  			break
  8361  		}
  8362  	}
  8363  
  8364  	// If we had to pass through a "with" statement body to get to the symbol
  8365  	// declaration, then this reference could potentially also refer to a
  8366  	// property on the target object of the "with" statement. We must not rename
  8367  	// it or we risk changing the behavior of the code.
  8368  	if isInsideWithScope {
  8369  		p.symbols[ref.InnerIndex].Flags |= ast.MustNotBeRenamed
  8370  	}
  8371  
  8372  	// Track how many times we've referenced this symbol
  8373  	p.recordUsage(ref)
  8374  	return findSymbolResult{ref, declareLoc, isInsideWithScope}
  8375  }
  8376  
  8377  func (p *parser) findLabelSymbol(loc logger.Loc, name string) (ref ast.Ref, isLoop bool, ok bool) {
  8378  	for s := p.currentScope; s != nil && !s.Kind.StopsHoisting(); s = s.Parent {
  8379  		if s.Kind == js_ast.ScopeLabel && name == p.symbols[s.Label.Ref.InnerIndex].OriginalName {
  8380  			// Track how many times we've referenced this symbol
  8381  			p.recordUsage(s.Label.Ref)
  8382  			ref = s.Label.Ref
  8383  			isLoop = s.LabelStmtIsLoop
  8384  			ok = true
  8385  			return
  8386  		}
  8387  	}
  8388  
  8389  	r := js_lexer.RangeOfIdentifier(p.source, loc)
  8390  	p.log.AddError(&p.tracker, r, fmt.Sprintf("There is no containing label named %q", name))
  8391  
  8392  	// Allocate an "unbound" symbol
  8393  	ref = p.newSymbol(ast.SymbolUnbound, name)
  8394  
  8395  	// Track how many times we've referenced this symbol
  8396  	p.recordUsage(ref)
  8397  	return
  8398  }
  8399  
  8400  func findIdentifiers(binding js_ast.Binding, identifiers []js_ast.Decl) []js_ast.Decl {
  8401  	switch b := binding.Data.(type) {
  8402  	case *js_ast.BIdentifier:
  8403  		identifiers = append(identifiers, js_ast.Decl{Binding: binding})
  8404  
  8405  	case *js_ast.BArray:
  8406  		for _, item := range b.Items {
  8407  			identifiers = findIdentifiers(item.Binding, identifiers)
  8408  		}
  8409  
  8410  	case *js_ast.BObject:
  8411  		for _, property := range b.Properties {
  8412  			identifiers = findIdentifiers(property.Value, identifiers)
  8413  		}
  8414  	}
  8415  
  8416  	return identifiers
  8417  }
  8418  
  8419  // If this is in a dead branch, then we want to trim as much dead code as we
  8420  // can. Everything can be trimmed except for hoisted declarations ("var" and
  8421  // "function"), which affect the parent scope. For example:
  8422  //
  8423  //	function foo() {
  8424  //	  if (false) { var x; }
  8425  //	  x = 1;
  8426  //	}
  8427  //
  8428  // We can't trim the entire branch as dead or calling foo() will incorrectly
  8429  // assign to a global variable instead.
  8430  func shouldKeepStmtInDeadControlFlow(stmt js_ast.Stmt) bool {
  8431  	switch s := stmt.Data.(type) {
  8432  	case *js_ast.SEmpty, *js_ast.SExpr, *js_ast.SThrow, *js_ast.SReturn,
  8433  		*js_ast.SBreak, *js_ast.SContinue, *js_ast.SClass, *js_ast.SDebugger:
  8434  		// Omit these statements entirely
  8435  		return false
  8436  
  8437  	case *js_ast.SLocal:
  8438  		if s.Kind != js_ast.LocalVar {
  8439  			// Omit these statements entirely
  8440  			return false
  8441  		}
  8442  
  8443  		// Omit everything except the identifiers
  8444  		identifiers := []js_ast.Decl{}
  8445  		for _, decl := range s.Decls {
  8446  			identifiers = findIdentifiers(decl.Binding, identifiers)
  8447  		}
  8448  		if len(identifiers) == 0 {
  8449  			return false
  8450  		}
  8451  		s.Decls = identifiers
  8452  		return true
  8453  
  8454  	case *js_ast.SBlock:
  8455  		for _, child := range s.Stmts {
  8456  			if shouldKeepStmtInDeadControlFlow(child) {
  8457  				return true
  8458  			}
  8459  		}
  8460  		return false
  8461  
  8462  	case *js_ast.SIf:
  8463  		return shouldKeepStmtInDeadControlFlow(s.Yes) || (s.NoOrNil.Data != nil && shouldKeepStmtInDeadControlFlow(s.NoOrNil))
  8464  
  8465  	case *js_ast.SWhile:
  8466  		return shouldKeepStmtInDeadControlFlow(s.Body)
  8467  
  8468  	case *js_ast.SDoWhile:
  8469  		return shouldKeepStmtInDeadControlFlow(s.Body)
  8470  
  8471  	case *js_ast.SFor:
  8472  		return (s.InitOrNil.Data != nil && shouldKeepStmtInDeadControlFlow(s.InitOrNil)) || shouldKeepStmtInDeadControlFlow(s.Body)
  8473  
  8474  	case *js_ast.SForIn:
  8475  		return shouldKeepStmtInDeadControlFlow(s.Init) || shouldKeepStmtInDeadControlFlow(s.Body)
  8476  
  8477  	case *js_ast.SForOf:
  8478  		return shouldKeepStmtInDeadControlFlow(s.Init) || shouldKeepStmtInDeadControlFlow(s.Body)
  8479  
  8480  	case *js_ast.SLabel:
  8481  		return shouldKeepStmtInDeadControlFlow(s.Stmt)
  8482  
  8483  	default:
  8484  		// Everything else must be kept
  8485  		return true
  8486  	}
  8487  }
  8488  
  8489  type prependTempRefsOpts struct {
  8490  	fnBodyLoc *logger.Loc
  8491  	kind      stmtsKind
  8492  }
  8493  
  8494  func (p *parser) visitStmtsAndPrependTempRefs(stmts []js_ast.Stmt, opts prependTempRefsOpts) []js_ast.Stmt {
  8495  	oldTempRefs := p.tempRefsToDeclare
  8496  	oldTempRefCount := p.tempRefCount
  8497  	p.tempRefsToDeclare = nil
  8498  	p.tempRefCount = 0
  8499  
  8500  	stmts = p.visitStmts(stmts, opts.kind)
  8501  
  8502  	// Prepend values for "this" and "arguments"
  8503  	if opts.fnBodyLoc != nil {
  8504  		// Capture "this"
  8505  		if ref := p.fnOnlyDataVisit.thisCaptureRef; ref != nil {
  8506  			p.tempRefsToDeclare = append(p.tempRefsToDeclare, tempRef{
  8507  				ref:        *ref,
  8508  				valueOrNil: js_ast.Expr{Loc: *opts.fnBodyLoc, Data: js_ast.EThisShared},
  8509  			})
  8510  			p.currentScope.Generated = append(p.currentScope.Generated, *ref)
  8511  		}
  8512  
  8513  		// Capture "arguments"
  8514  		if ref := p.fnOnlyDataVisit.argumentsCaptureRef; ref != nil {
  8515  			p.tempRefsToDeclare = append(p.tempRefsToDeclare, tempRef{
  8516  				ref:        *ref,
  8517  				valueOrNil: js_ast.Expr{Loc: *opts.fnBodyLoc, Data: &js_ast.EIdentifier{Ref: *p.fnOnlyDataVisit.argumentsRef}},
  8518  			})
  8519  			p.currentScope.Generated = append(p.currentScope.Generated, *ref)
  8520  		}
  8521  	}
  8522  
  8523  	// There may also be special top-level-only temporaries to declare
  8524  	if p.currentScope == p.moduleScope && p.topLevelTempRefsToDeclare != nil {
  8525  		p.tempRefsToDeclare = append(p.tempRefsToDeclare, p.topLevelTempRefsToDeclare...)
  8526  		p.topLevelTempRefsToDeclare = nil
  8527  	}
  8528  
  8529  	// Prepend the generated temporary variables to the beginning of the statement list
  8530  	decls := []js_ast.Decl{}
  8531  	for _, temp := range p.tempRefsToDeclare {
  8532  		if p.symbols[temp.ref.InnerIndex].UseCountEstimate > 0 {
  8533  			decls = append(decls, js_ast.Decl{Binding: js_ast.Binding{Data: &js_ast.BIdentifier{Ref: temp.ref}}, ValueOrNil: temp.valueOrNil})
  8534  			p.recordDeclaredSymbol(temp.ref)
  8535  		}
  8536  	}
  8537  	if len(decls) > 0 {
  8538  		// Skip past leading directives and comments
  8539  		split := 0
  8540  		for split < len(stmts) {
  8541  			switch stmts[split].Data.(type) {
  8542  			case *js_ast.SComment, *js_ast.SDirective:
  8543  				split++
  8544  				continue
  8545  			}
  8546  			break
  8547  		}
  8548  		stmts = append(
  8549  			append(
  8550  				append(
  8551  					[]js_ast.Stmt{},
  8552  					stmts[:split]...),
  8553  				js_ast.Stmt{Data: &js_ast.SLocal{Kind: js_ast.LocalVar, Decls: decls}}),
  8554  			stmts[split:]...)
  8555  	}
  8556  
  8557  	p.tempRefsToDeclare = oldTempRefs
  8558  	p.tempRefCount = oldTempRefCount
  8559  	return stmts
  8560  }
  8561  
  8562  type stmtsKind uint8
  8563  
  8564  const (
  8565  	stmtsNormal stmtsKind = iota
  8566  	stmtsSwitch
  8567  	stmtsLoopBody
  8568  	stmtsFnBody
  8569  )
  8570  
  8571  func (p *parser) visitStmts(stmts []js_ast.Stmt, kind stmtsKind) []js_ast.Stmt {
  8572  	// Save the current control-flow liveness. This represents if we are
  8573  	// currently inside an "if (false) { ... }" block.
  8574  	oldIsControlFlowDead := p.isControlFlowDead
  8575  
  8576  	oldTempLetsToDeclare := p.tempLetsToDeclare
  8577  	p.tempLetsToDeclare = nil
  8578  
  8579  	// Visit all statements first
  8580  	visited := make([]js_ast.Stmt, 0, len(stmts))
  8581  	var before []js_ast.Stmt
  8582  	var after []js_ast.Stmt
  8583  	var preprocessedEnums map[int][]js_ast.Stmt
  8584  	if p.scopesInOrderForEnum != nil {
  8585  		// Preprocess TypeScript enums to improve code generation. Otherwise
  8586  		// uses of an enum before that enum has been declared won't be inlined:
  8587  		//
  8588  		//   console.log(Foo.FOO) // We want "FOO" to be inlined here
  8589  		//   const enum Foo { FOO = 0 }
  8590  		//
  8591  		// The TypeScript compiler itself contains code with this pattern, so
  8592  		// it's important to implement this optimization.
  8593  		for i, stmt := range stmts {
  8594  			if _, ok := stmt.Data.(*js_ast.SEnum); ok {
  8595  				if preprocessedEnums == nil {
  8596  					preprocessedEnums = make(map[int][]js_ast.Stmt)
  8597  				}
  8598  				oldScopesInOrder := p.scopesInOrder
  8599  				p.scopesInOrder = p.scopesInOrderForEnum[stmt.Loc]
  8600  				preprocessedEnums[i] = p.visitAndAppendStmt(nil, stmt)
  8601  				p.scopesInOrder = oldScopesInOrder
  8602  			}
  8603  		}
  8604  	}
  8605  	for i, stmt := range stmts {
  8606  		switch s := stmt.Data.(type) {
  8607  		case *js_ast.SExportEquals:
  8608  			// TypeScript "export = value;" becomes "module.exports = value;". This
  8609  			// must happen at the end after everything is parsed because TypeScript
  8610  			// moves this statement to the end when it generates code.
  8611  			after = p.visitAndAppendStmt(after, stmt)
  8612  			continue
  8613  
  8614  		case *js_ast.SFunction:
  8615  			// Manually hoist block-level function declarations to preserve semantics.
  8616  			// This is only done for function declarations that are not generators
  8617  			// or async functions, since this is a backwards-compatibility hack from
  8618  			// Annex B of the JavaScript standard.
  8619  			if !p.currentScope.Kind.StopsHoisting() && p.symbols[int(s.Fn.Name.Ref.InnerIndex)].Kind == ast.SymbolHoistedFunction {
  8620  				before = p.visitAndAppendStmt(before, stmt)
  8621  				continue
  8622  			}
  8623  
  8624  		case *js_ast.SEnum:
  8625  			visited = append(visited, preprocessedEnums[i]...)
  8626  			p.scopesInOrder = p.scopesInOrder[len(p.scopesInOrderForEnum[stmt.Loc]):]
  8627  			continue
  8628  		}
  8629  		visited = p.visitAndAppendStmt(visited, stmt)
  8630  	}
  8631  
  8632  	// This is used for temporary variables that could be captured in a closure,
  8633  	// and therefore need to be generated inside the nearest enclosing block in
  8634  	// case they are generated inside a loop.
  8635  	if len(p.tempLetsToDeclare) > 0 {
  8636  		decls := make([]js_ast.Decl, 0, len(p.tempLetsToDeclare))
  8637  		for _, ref := range p.tempLetsToDeclare {
  8638  			decls = append(decls, js_ast.Decl{Binding: js_ast.Binding{Data: &js_ast.BIdentifier{Ref: ref}}})
  8639  		}
  8640  		before = append(before, js_ast.Stmt{Data: &js_ast.SLocal{Kind: js_ast.LocalLet, Decls: decls}})
  8641  	}
  8642  	p.tempLetsToDeclare = oldTempLetsToDeclare
  8643  
  8644  	// Transform block-level function declarations into variable declarations
  8645  	if len(before) > 0 {
  8646  		var letDecls []js_ast.Decl
  8647  		var varDecls []js_ast.Decl
  8648  		var nonFnStmts []js_ast.Stmt
  8649  		fnStmts := make(map[ast.Ref]int)
  8650  		for _, stmt := range before {
  8651  			s, ok := stmt.Data.(*js_ast.SFunction)
  8652  			if !ok {
  8653  				// We may get non-function statements here in certain scenarios such as when "KeepNames" is enabled
  8654  				nonFnStmts = append(nonFnStmts, stmt)
  8655  				continue
  8656  			}
  8657  
  8658  			// This transformation of function declarations in nested scopes is
  8659  			// intended to preserve the hoisting semantics of the original code. In
  8660  			// JavaScript, function hoisting works differently in strict mode vs.
  8661  			// sloppy mode code. We want the code we generate to use the semantics of
  8662  			// the original environment, not the generated environment. However, if
  8663  			// direct "eval" is present then it's not possible to preserve the
  8664  			// semantics because we need two identifiers to do that and direct "eval"
  8665  			// means neither identifier can be renamed to something else. So in that
  8666  			// case we give up and do not preserve the semantics of the original code.
  8667  			if p.currentScope.ContainsDirectEval {
  8668  				if hoistedRef, ok := p.hoistedRefForSloppyModeBlockFn[s.Fn.Name.Ref]; ok {
  8669  					// Merge the two identifiers back into a single one
  8670  					p.symbols[hoistedRef.InnerIndex].Link = s.Fn.Name.Ref
  8671  				}
  8672  				nonFnStmts = append(nonFnStmts, stmt)
  8673  				continue
  8674  			}
  8675  
  8676  			index, ok := fnStmts[s.Fn.Name.Ref]
  8677  			if !ok {
  8678  				index = len(letDecls)
  8679  				fnStmts[s.Fn.Name.Ref] = index
  8680  				letDecls = append(letDecls, js_ast.Decl{Binding: js_ast.Binding{
  8681  					Loc: s.Fn.Name.Loc, Data: &js_ast.BIdentifier{Ref: s.Fn.Name.Ref}}})
  8682  
  8683  				// Also write the function to the hoisted sibling symbol if applicable
  8684  				if hoistedRef, ok := p.hoistedRefForSloppyModeBlockFn[s.Fn.Name.Ref]; ok {
  8685  					p.recordDeclaredSymbol(hoistedRef)
  8686  					p.recordUsage(s.Fn.Name.Ref)
  8687  					varDecls = append(varDecls, js_ast.Decl{
  8688  						Binding:    js_ast.Binding{Loc: s.Fn.Name.Loc, Data: &js_ast.BIdentifier{Ref: hoistedRef}},
  8689  						ValueOrNil: js_ast.Expr{Loc: s.Fn.Name.Loc, Data: &js_ast.EIdentifier{Ref: s.Fn.Name.Ref}},
  8690  					})
  8691  				}
  8692  			}
  8693  
  8694  			// The last function statement for a given symbol wins
  8695  			s.Fn.Name = nil
  8696  			letDecls[index].ValueOrNil = js_ast.Expr{Loc: stmt.Loc, Data: &js_ast.EFunction{Fn: s.Fn}}
  8697  		}
  8698  
  8699  		// Reuse memory from "before"
  8700  		before = before[:0]
  8701  		kind := js_ast.LocalLet
  8702  		if p.options.unsupportedJSFeatures.Has(compat.ConstAndLet) {
  8703  			kind = js_ast.LocalVar
  8704  		}
  8705  		if len(letDecls) > 0 {
  8706  			before = append(before, js_ast.Stmt{Loc: letDecls[0].ValueOrNil.Loc, Data: &js_ast.SLocal{Kind: kind, Decls: letDecls}})
  8707  		}
  8708  		if len(varDecls) > 0 {
  8709  			// Potentially relocate "var" declarations to the top level
  8710  			if assign, ok := p.maybeRelocateVarsToTopLevel(varDecls, relocateVarsNormal); ok {
  8711  				if assign.Data != nil {
  8712  					before = append(before, assign)
  8713  				}
  8714  			} else {
  8715  				before = append(before, js_ast.Stmt{Loc: varDecls[0].ValueOrNil.Loc, Data: &js_ast.SLocal{Kind: js_ast.LocalVar, Decls: varDecls}})
  8716  			}
  8717  		}
  8718  		before = append(before, nonFnStmts...)
  8719  		visited = append(before, visited...)
  8720  	}
  8721  
  8722  	// Move TypeScript "export =" statements to the end
  8723  	visited = append(visited, after...)
  8724  
  8725  	// Restore the current control-flow liveness if it was changed inside the
  8726  	// loop above. This is important because the caller will not restore it.
  8727  	p.isControlFlowDead = oldIsControlFlowDead
  8728  
  8729  	// Lower using declarations
  8730  	if kind != stmtsSwitch && p.shouldLowerUsingDeclarations(visited) {
  8731  		ctx := p.lowerUsingDeclarationContext()
  8732  		ctx.scanStmts(p, visited)
  8733  		visited = ctx.finalize(p, visited, p.currentScope.Parent == nil)
  8734  	}
  8735  
  8736  	// Stop now if we're not mangling
  8737  	if !p.options.minifySyntax {
  8738  		return visited
  8739  	}
  8740  
  8741  	// If this is in a dead branch, trim as much dead code as we can
  8742  	if p.isControlFlowDead {
  8743  		end := 0
  8744  		for _, stmt := range visited {
  8745  			if !shouldKeepStmtInDeadControlFlow(stmt) {
  8746  				continue
  8747  			}
  8748  
  8749  			// Merge adjacent var statements
  8750  			if s, ok := stmt.Data.(*js_ast.SLocal); ok && s.Kind == js_ast.LocalVar && end > 0 {
  8751  				prevStmt := visited[end-1]
  8752  				if prevS, ok := prevStmt.Data.(*js_ast.SLocal); ok && prevS.Kind == js_ast.LocalVar && s.IsExport == prevS.IsExport {
  8753  					prevS.Decls = append(prevS.Decls, s.Decls...)
  8754  					continue
  8755  				}
  8756  			}
  8757  
  8758  			visited[end] = stmt
  8759  			end++
  8760  		}
  8761  		return visited[:end]
  8762  	}
  8763  
  8764  	return p.mangleStmts(visited, kind)
  8765  }
  8766  
  8767  func (p *parser) mangleStmts(stmts []js_ast.Stmt, kind stmtsKind) []js_ast.Stmt {
  8768  	// Remove inlined constants now that we know whether any of these statements
  8769  	// contained a direct eval() or not. This can't be done earlier when we
  8770  	// encounter the constant because we haven't encountered the eval() yet.
  8771  	// Inlined constants are not removed if they are in a top-level scope or
  8772  	// if they are exported (which could be in a nested TypeScript namespace).
  8773  	if p.currentScope.Parent != nil && !p.currentScope.ContainsDirectEval {
  8774  		for i, stmt := range stmts {
  8775  			switch s := stmt.Data.(type) {
  8776  			case *js_ast.SEmpty, *js_ast.SComment, *js_ast.SDirective, *js_ast.SDebugger, *js_ast.STypeScript:
  8777  				continue
  8778  
  8779  			case *js_ast.SLocal:
  8780  				if !s.IsExport {
  8781  					end := 0
  8782  					for _, d := range s.Decls {
  8783  						if id, ok := d.Binding.Data.(*js_ast.BIdentifier); ok {
  8784  							if _, ok := p.constValues[id.Ref]; ok && p.symbols[id.Ref.InnerIndex].UseCountEstimate == 0 {
  8785  								continue
  8786  							}
  8787  						}
  8788  						s.Decls[end] = d
  8789  						end++
  8790  					}
  8791  					if end == 0 {
  8792  						stmts[i].Data = js_ast.SEmptyShared
  8793  					} else {
  8794  						s.Decls = s.Decls[:end]
  8795  					}
  8796  				}
  8797  				continue
  8798  			}
  8799  			break
  8800  		}
  8801  	}
  8802  
  8803  	// Merge adjacent statements during mangling
  8804  	result := make([]js_ast.Stmt, 0, len(stmts))
  8805  	isControlFlowDead := false
  8806  	for i, stmt := range stmts {
  8807  		if isControlFlowDead && !shouldKeepStmtInDeadControlFlow(stmt) {
  8808  			// Strip unnecessary statements if the control flow is dead here
  8809  			continue
  8810  		}
  8811  
  8812  		// Inline single-use variable declarations where possible:
  8813  		//
  8814  		//   // Before
  8815  		//   let x = fn();
  8816  		//   return x.y();
  8817  		//
  8818  		//   // After
  8819  		//   return fn().y();
  8820  		//
  8821  		// The declaration must not be exported. We can't just check for the
  8822  		// "export" keyword because something might do "export {id};" later on.
  8823  		// Instead we just ignore all top-level declarations for now. That means
  8824  		// this optimization currently only applies in nested scopes.
  8825  		//
  8826  		// Ignore declarations if the scope is shadowed by a direct "eval" call.
  8827  		// The eval'd code may indirectly reference this symbol and the actual
  8828  		// use count may be greater than 1.
  8829  		if p.currentScope != p.moduleScope && !p.currentScope.ContainsDirectEval {
  8830  			// Keep inlining variables until a failure or until there are none left.
  8831  			// That handles cases like this:
  8832  			//
  8833  			//   // Before
  8834  			//   let x = fn();
  8835  			//   let y = x.prop;
  8836  			//   return y;
  8837  			//
  8838  			//   // After
  8839  			//   return fn().prop;
  8840  			//
  8841  			for len(result) > 0 {
  8842  				// Ignore "var" declarations since those have function-level scope and
  8843  				// we may not have visited all of their uses yet by this point. We
  8844  				// should have visited all the uses of "let" and "const" declarations
  8845  				// by now since they are scoped to this block which we just finished
  8846  				// visiting.
  8847  				if prevS, ok := result[len(result)-1].Data.(*js_ast.SLocal); ok && prevS.Kind != js_ast.LocalVar {
  8848  					last := prevS.Decls[len(prevS.Decls)-1]
  8849  
  8850  					// The binding must be an identifier that is only used once.
  8851  					// Ignore destructuring bindings since that's not the simple case.
  8852  					// Destructuring bindings could potentially execute side-effecting
  8853  					// code which would invalidate reordering.
  8854  					if id, ok := last.Binding.Data.(*js_ast.BIdentifier); ok {
  8855  						// Don't do this if "__name" was called on this symbol. In that
  8856  						// case there is actually more than one use even though it says
  8857  						// there is only one. The "__name" use isn't counted so that
  8858  						// tree shaking still works when names are kept.
  8859  						if symbol := p.symbols[id.Ref.InnerIndex]; symbol.UseCountEstimate == 1 && !symbol.Flags.Has(ast.DidKeepName) {
  8860  							replacement := last.ValueOrNil
  8861  
  8862  							// The variable must be initialized, since we will be substituting
  8863  							// the value into the usage.
  8864  							if replacement.Data == nil {
  8865  								replacement = js_ast.Expr{Loc: last.Binding.Loc, Data: js_ast.EUndefinedShared}
  8866  							}
  8867  
  8868  							// Try to substitute the identifier with the initializer. This will
  8869  							// fail if something with side effects is in between the declaration
  8870  							// and the usage.
  8871  							if p.substituteSingleUseSymbolInStmt(stmt, id.Ref, replacement) {
  8872  								// Remove the previous declaration, since the substitution was
  8873  								// successful.
  8874  								if len(prevS.Decls) == 1 {
  8875  									result = result[:len(result)-1]
  8876  								} else {
  8877  									prevS.Decls = prevS.Decls[:len(prevS.Decls)-1]
  8878  								}
  8879  
  8880  								// Loop back to try again
  8881  								continue
  8882  							}
  8883  						}
  8884  					}
  8885  				}
  8886  
  8887  				// Substitution failed so stop trying
  8888  				break
  8889  			}
  8890  		}
  8891  
  8892  		switch s := stmt.Data.(type) {
  8893  		case *js_ast.SEmpty:
  8894  			// Strip empty statements
  8895  			continue
  8896  
  8897  		case *js_ast.SLocal:
  8898  			// Merge adjacent local statements
  8899  			if len(result) > 0 {
  8900  				prevStmt := result[len(result)-1]
  8901  				if prevS, ok := prevStmt.Data.(*js_ast.SLocal); ok && s.Kind == prevS.Kind && s.IsExport == prevS.IsExport {
  8902  					prevS.Decls = append(prevS.Decls, s.Decls...)
  8903  					continue
  8904  				}
  8905  			}
  8906  
  8907  		case *js_ast.SExpr:
  8908  			// Merge adjacent expression statements
  8909  			if len(result) > 0 {
  8910  				prevStmt := result[len(result)-1]
  8911  				if prevS, ok := prevStmt.Data.(*js_ast.SExpr); ok {
  8912  					if !s.IsFromClassOrFnThatCanBeRemovedIfUnused {
  8913  						prevS.IsFromClassOrFnThatCanBeRemovedIfUnused = false
  8914  					}
  8915  					prevS.Value = js_ast.JoinWithComma(prevS.Value, s.Value)
  8916  					continue
  8917  				}
  8918  			}
  8919  
  8920  		case *js_ast.SSwitch:
  8921  			// Absorb a previous expression statement
  8922  			if len(result) > 0 {
  8923  				prevStmt := result[len(result)-1]
  8924  				if prevS, ok := prevStmt.Data.(*js_ast.SExpr); ok {
  8925  					s.Test = js_ast.JoinWithComma(prevS.Value, s.Test)
  8926  					result = result[:len(result)-1]
  8927  				}
  8928  			}
  8929  
  8930  		case *js_ast.SIf:
  8931  			// Absorb a previous expression statement
  8932  			if len(result) > 0 {
  8933  				prevStmt := result[len(result)-1]
  8934  				if prevS, ok := prevStmt.Data.(*js_ast.SExpr); ok {
  8935  					s.Test = js_ast.JoinWithComma(prevS.Value, s.Test)
  8936  					result = result[:len(result)-1]
  8937  				}
  8938  			}
  8939  
  8940  			if isJumpStatement(s.Yes.Data) {
  8941  				optimizeImplicitJump := false
  8942  
  8943  				// Absorb a previous if statement
  8944  				if len(result) > 0 {
  8945  					prevStmt := result[len(result)-1]
  8946  					if prevS, ok := prevStmt.Data.(*js_ast.SIf); ok && prevS.NoOrNil.Data == nil && jumpStmtsLookTheSame(prevS.Yes.Data, s.Yes.Data) {
  8947  						// "if (a) break c; if (b) break c;" => "if (a || b) break c;"
  8948  						// "if (a) continue c; if (b) continue c;" => "if (a || b) continue c;"
  8949  						// "if (a) return c; if (b) return c;" => "if (a || b) return c;"
  8950  						// "if (a) throw c; if (b) throw c;" => "if (a || b) throw c;"
  8951  						s.Test = js_ast.JoinWithLeftAssociativeOp(js_ast.BinOpLogicalOr, prevS.Test, s.Test)
  8952  						result = result[:len(result)-1]
  8953  					}
  8954  				}
  8955  
  8956  				// "while (x) { if (y) continue; z(); }" => "while (x) { if (!y) z(); }"
  8957  				// "while (x) { if (y) continue; else z(); w(); }" => "while (x) { if (!y) { z(); w(); } }" => "for (; x;) !y && (z(), w());"
  8958  				if kind == stmtsLoopBody {
  8959  					if continueS, ok := s.Yes.Data.(*js_ast.SContinue); ok && continueS.Label == nil {
  8960  						optimizeImplicitJump = true
  8961  					}
  8962  				}
  8963  
  8964  				// "let x = () => { if (y) return; z(); };" => "let x = () => { if (!y) z(); };"
  8965  				// "let x = () => { if (y) return; else z(); w(); };" => "let x = () => { if (!y) { z(); w(); } };" => "let x = () => { !y && (z(), w()); };"
  8966  				if kind == stmtsFnBody {
  8967  					if returnS, ok := s.Yes.Data.(*js_ast.SReturn); ok && returnS.ValueOrNil.Data == nil {
  8968  						optimizeImplicitJump = true
  8969  					}
  8970  				}
  8971  
  8972  				if optimizeImplicitJump {
  8973  					var body []js_ast.Stmt
  8974  					if s.NoOrNil.Data != nil {
  8975  						body = append(body, s.NoOrNil)
  8976  					}
  8977  					body = append(body, stmts[i+1:]...)
  8978  
  8979  					// Don't do this transformation if the branch condition could
  8980  					// potentially access symbols declared later on on this scope below.
  8981  					// If so, inverting the branch condition and nesting statements after
  8982  					// this in a block would break that access which is a behavior change.
  8983  					//
  8984  					//   // This transformation is incorrect
  8985  					//   if (a()) return; function a() {}
  8986  					//   if (!a()) { function a() {} }
  8987  					//
  8988  					//   // This transformation is incorrect
  8989  					//   if (a(() => b)) return; let b;
  8990  					//   if (a(() => b)) { let b; }
  8991  					//
  8992  					canMoveBranchConditionOutsideScope := true
  8993  					for _, stmt := range body {
  8994  						if statementCaresAboutScope(stmt) {
  8995  							canMoveBranchConditionOutsideScope = false
  8996  							break
  8997  						}
  8998  					}
  8999  
  9000  					if canMoveBranchConditionOutsideScope {
  9001  						body = p.mangleStmts(body, kind)
  9002  						bodyLoc := s.Yes.Loc
  9003  						if len(body) > 0 {
  9004  							bodyLoc = body[0].Loc
  9005  						}
  9006  						return p.mangleIf(result, stmt.Loc, &js_ast.SIf{
  9007  							Test: p.astHelpers.SimplifyBooleanExpr(js_ast.Not(s.Test)),
  9008  							Yes:  stmtsToSingleStmt(bodyLoc, body, logger.Loc{}),
  9009  						})
  9010  					}
  9011  				}
  9012  
  9013  				if s.NoOrNil.Data != nil {
  9014  					// "if (a) return b; else if (c) return d; else return e;" => "if (a) return b; if (c) return d; return e;"
  9015  					for {
  9016  						result = append(result, stmt)
  9017  						stmt = s.NoOrNil
  9018  						s.NoOrNil = js_ast.Stmt{}
  9019  						var ok bool
  9020  						s, ok = stmt.Data.(*js_ast.SIf)
  9021  						if !ok || !isJumpStatement(s.Yes.Data) || s.NoOrNil.Data == nil {
  9022  							break
  9023  						}
  9024  					}
  9025  					result = appendIfOrLabelBodyPreservingScope(result, stmt)
  9026  					if isJumpStatement(stmt.Data) {
  9027  						isControlFlowDead = true
  9028  					}
  9029  					continue
  9030  				}
  9031  			}
  9032  
  9033  		case *js_ast.SReturn:
  9034  			// Merge return statements with the previous expression statement
  9035  			if len(result) > 0 && s.ValueOrNil.Data != nil {
  9036  				prevStmt := result[len(result)-1]
  9037  				if prevS, ok := prevStmt.Data.(*js_ast.SExpr); ok {
  9038  					result[len(result)-1] = js_ast.Stmt{Loc: prevStmt.Loc,
  9039  						Data: &js_ast.SReturn{ValueOrNil: js_ast.JoinWithComma(prevS.Value, s.ValueOrNil)}}
  9040  					continue
  9041  				}
  9042  			}
  9043  
  9044  			isControlFlowDead = true
  9045  
  9046  		case *js_ast.SThrow:
  9047  			// Merge throw statements with the previous expression statement
  9048  			if len(result) > 0 {
  9049  				prevStmt := result[len(result)-1]
  9050  				if prevS, ok := prevStmt.Data.(*js_ast.SExpr); ok {
  9051  					result[len(result)-1] = js_ast.Stmt{Loc: prevStmt.Loc, Data: &js_ast.SThrow{Value: js_ast.JoinWithComma(prevS.Value, s.Value)}}
  9052  					continue
  9053  				}
  9054  			}
  9055  
  9056  			isControlFlowDead = true
  9057  
  9058  		case *js_ast.SBreak, *js_ast.SContinue:
  9059  			isControlFlowDead = true
  9060  
  9061  		case *js_ast.SFor:
  9062  			if len(result) > 0 {
  9063  				prevStmt := result[len(result)-1]
  9064  				if prevS, ok := prevStmt.Data.(*js_ast.SExpr); ok {
  9065  					// Insert the previous expression into the for loop initializer
  9066  					if s.InitOrNil.Data == nil {
  9067  						result[len(result)-1] = stmt
  9068  						s.InitOrNil = js_ast.Stmt{Loc: prevStmt.Loc, Data: &js_ast.SExpr{Value: prevS.Value}}
  9069  						continue
  9070  					} else if s2, ok := s.InitOrNil.Data.(*js_ast.SExpr); ok {
  9071  						result[len(result)-1] = stmt
  9072  						s.InitOrNil = js_ast.Stmt{Loc: prevStmt.Loc, Data: &js_ast.SExpr{Value: js_ast.JoinWithComma(prevS.Value, s2.Value)}}
  9073  						continue
  9074  					}
  9075  				} else {
  9076  					// Insert the previous variable declaration into the for loop
  9077  					// initializer if it's a "var" declaration, since the scope
  9078  					// doesn't matter due to scope hoisting
  9079  					if s.InitOrNil.Data == nil {
  9080  						if s2, ok := prevStmt.Data.(*js_ast.SLocal); ok && s2.Kind == js_ast.LocalVar && !s2.IsExport {
  9081  							result[len(result)-1] = stmt
  9082  							s.InitOrNil = prevStmt
  9083  							continue
  9084  						}
  9085  					} else {
  9086  						if s2, ok := prevStmt.Data.(*js_ast.SLocal); ok && s2.Kind == js_ast.LocalVar && !s2.IsExport {
  9087  							if s3, ok := s.InitOrNil.Data.(*js_ast.SLocal); ok && s3.Kind == js_ast.LocalVar {
  9088  								result[len(result)-1] = stmt
  9089  								s.InitOrNil.Data = &js_ast.SLocal{Kind: js_ast.LocalVar, Decls: append(s2.Decls, s3.Decls...)}
  9090  								continue
  9091  							}
  9092  						}
  9093  					}
  9094  				}
  9095  			}
  9096  
  9097  		case *js_ast.STry:
  9098  			// Drop an unused identifier binding if the optional catch binding feature is supported
  9099  			if !p.options.unsupportedJSFeatures.Has(compat.OptionalCatchBinding) && s.Catch != nil {
  9100  				if id, ok := s.Catch.BindingOrNil.Data.(*js_ast.BIdentifier); ok {
  9101  					if symbol := p.symbols[id.Ref.InnerIndex]; symbol.UseCountEstimate == 0 {
  9102  						if symbol.Link != ast.InvalidRef {
  9103  							// We cannot transform "try { x() } catch (y) { var y = 1 }" into
  9104  							// "try { x() } catch { var y = 1 }" even though "y" is never used
  9105  							// because the hoisted variable "y" would have different values
  9106  							// after the statement ends due to a strange JavaScript quirk:
  9107  							//
  9108  							//   try { x() } catch (y) { var y = 1 }
  9109  							//   console.log(y) // undefined
  9110  							//
  9111  							//   try { x() } catch { var y = 1 }
  9112  							//   console.log(y) // 1
  9113  							//
  9114  						} else if p.currentScope.ContainsDirectEval {
  9115  							// We cannot transform "try { x() } catch (y) { eval('z = y') }"
  9116  							// into "try { x() } catch { eval('z = y') }" because the variable
  9117  							// "y" is actually still used.
  9118  						} else {
  9119  							// "try { x() } catch (y) {}" => "try { x() } catch {}"
  9120  							s.Catch.BindingOrNil.Data = nil
  9121  						}
  9122  					}
  9123  				}
  9124  			}
  9125  		}
  9126  
  9127  		result = append(result, stmt)
  9128  	}
  9129  
  9130  	// Drop a trailing unconditional jump statement if applicable
  9131  	if len(result) > 0 {
  9132  		switch kind {
  9133  		case stmtsLoopBody:
  9134  			// "while (x) { y(); continue; }" => "while (x) { y(); }"
  9135  			if continueS, ok := result[len(result)-1].Data.(*js_ast.SContinue); ok && continueS.Label == nil {
  9136  				result = result[:len(result)-1]
  9137  			}
  9138  
  9139  		case stmtsFnBody:
  9140  			// "function f() { x(); return; }" => "function f() { x(); }"
  9141  			if returnS, ok := result[len(result)-1].Data.(*js_ast.SReturn); ok && returnS.ValueOrNil.Data == nil {
  9142  				result = result[:len(result)-1]
  9143  			}
  9144  		}
  9145  	}
  9146  
  9147  	// Merge certain statements in reverse order
  9148  	if len(result) >= 2 {
  9149  		lastStmt := result[len(result)-1]
  9150  
  9151  		if lastReturn, ok := lastStmt.Data.(*js_ast.SReturn); ok {
  9152  			// "if (a) return b; if (c) return d; return e;" => "return a ? b : c ? d : e;"
  9153  		returnLoop:
  9154  			for len(result) >= 2 {
  9155  				prevIndex := len(result) - 2
  9156  				prevStmt := result[prevIndex]
  9157  
  9158  				switch prevS := prevStmt.Data.(type) {
  9159  				case *js_ast.SExpr:
  9160  					// This return statement must have a value
  9161  					if lastReturn.ValueOrNil.Data == nil {
  9162  						break returnLoop
  9163  					}
  9164  
  9165  					// "a(); return b;" => "return a(), b;"
  9166  					lastReturn = &js_ast.SReturn{ValueOrNil: js_ast.JoinWithComma(prevS.Value, lastReturn.ValueOrNil)}
  9167  
  9168  					// Merge the last two statements
  9169  					lastStmt = js_ast.Stmt{Loc: prevStmt.Loc, Data: lastReturn}
  9170  					result[prevIndex] = lastStmt
  9171  					result = result[:len(result)-1]
  9172  
  9173  				case *js_ast.SIf:
  9174  					// The previous statement must be an if statement with no else clause
  9175  					if prevS.NoOrNil.Data != nil {
  9176  						break returnLoop
  9177  					}
  9178  
  9179  					// The then clause must be a return
  9180  					prevReturn, ok := prevS.Yes.Data.(*js_ast.SReturn)
  9181  					if !ok {
  9182  						break returnLoop
  9183  					}
  9184  
  9185  					// Handle some or all of the values being undefined
  9186  					left := prevReturn.ValueOrNil
  9187  					right := lastReturn.ValueOrNil
  9188  					if left.Data == nil {
  9189  						// "if (a) return; return b;" => "return a ? void 0 : b;"
  9190  						left = js_ast.Expr{Loc: prevS.Yes.Loc, Data: js_ast.EUndefinedShared}
  9191  					}
  9192  					if right.Data == nil {
  9193  						// "if (a) return a; return;" => "return a ? b : void 0;"
  9194  						right = js_ast.Expr{Loc: lastStmt.Loc, Data: js_ast.EUndefinedShared}
  9195  					}
  9196  
  9197  					// "if (!a) return b; return c;" => "return a ? c : b;"
  9198  					if not, ok := prevS.Test.Data.(*js_ast.EUnary); ok && not.Op == js_ast.UnOpNot {
  9199  						prevS.Test = not.Value
  9200  						left, right = right, left
  9201  					}
  9202  
  9203  					if comma, ok := prevS.Test.Data.(*js_ast.EBinary); ok && comma.Op == js_ast.BinOpComma {
  9204  						// "if (a, b) return c; return d;" => "return a, b ? c : d;"
  9205  						lastReturn = &js_ast.SReturn{ValueOrNil: js_ast.JoinWithComma(comma.Left,
  9206  							p.astHelpers.MangleIfExpr(comma.Right.Loc, &js_ast.EIf{Test: comma.Right, Yes: left, No: right}, p.options.unsupportedJSFeatures))}
  9207  					} else {
  9208  						// "if (a) return b; return c;" => "return a ? b : c;"
  9209  						lastReturn = &js_ast.SReturn{ValueOrNil: p.astHelpers.MangleIfExpr(
  9210  							prevS.Test.Loc, &js_ast.EIf{Test: prevS.Test, Yes: left, No: right}, p.options.unsupportedJSFeatures)}
  9211  					}
  9212  
  9213  					// Merge the last two statements
  9214  					lastStmt = js_ast.Stmt{Loc: prevStmt.Loc, Data: lastReturn}
  9215  					result[prevIndex] = lastStmt
  9216  					result = result[:len(result)-1]
  9217  
  9218  				default:
  9219  					break returnLoop
  9220  				}
  9221  			}
  9222  		} else if lastThrow, ok := lastStmt.Data.(*js_ast.SThrow); ok {
  9223  			// "if (a) throw b; if (c) throw d; throw e;" => "throw a ? b : c ? d : e;"
  9224  		throwLoop:
  9225  			for len(result) >= 2 {
  9226  				prevIndex := len(result) - 2
  9227  				prevStmt := result[prevIndex]
  9228  
  9229  				switch prevS := prevStmt.Data.(type) {
  9230  				case *js_ast.SExpr:
  9231  					// "a(); throw b;" => "throw a(), b;"
  9232  					lastThrow = &js_ast.SThrow{Value: js_ast.JoinWithComma(prevS.Value, lastThrow.Value)}
  9233  
  9234  					// Merge the last two statements
  9235  					lastStmt = js_ast.Stmt{Loc: prevStmt.Loc, Data: lastThrow}
  9236  					result[prevIndex] = lastStmt
  9237  					result = result[:len(result)-1]
  9238  
  9239  				case *js_ast.SIf:
  9240  					// The previous statement must be an if statement with no else clause
  9241  					if prevS.NoOrNil.Data != nil {
  9242  						break throwLoop
  9243  					}
  9244  
  9245  					// The then clause must be a throw
  9246  					prevThrow, ok := prevS.Yes.Data.(*js_ast.SThrow)
  9247  					if !ok {
  9248  						break throwLoop
  9249  					}
  9250  
  9251  					left := prevThrow.Value
  9252  					right := lastThrow.Value
  9253  
  9254  					// "if (!a) throw b; throw c;" => "throw a ? c : b;"
  9255  					if not, ok := prevS.Test.Data.(*js_ast.EUnary); ok && not.Op == js_ast.UnOpNot {
  9256  						prevS.Test = not.Value
  9257  						left, right = right, left
  9258  					}
  9259  
  9260  					// Merge the last two statements
  9261  					if comma, ok := prevS.Test.Data.(*js_ast.EBinary); ok && comma.Op == js_ast.BinOpComma {
  9262  						// "if (a, b) return c; return d;" => "return a, b ? c : d;"
  9263  						lastThrow = &js_ast.SThrow{Value: js_ast.JoinWithComma(comma.Left,
  9264  							p.astHelpers.MangleIfExpr(comma.Right.Loc, &js_ast.EIf{Test: comma.Right, Yes: left, No: right}, p.options.unsupportedJSFeatures))}
  9265  					} else {
  9266  						// "if (a) return b; return c;" => "return a ? b : c;"
  9267  						lastThrow = &js_ast.SThrow{
  9268  							Value: p.astHelpers.MangleIfExpr(prevS.Test.Loc, &js_ast.EIf{Test: prevS.Test, Yes: left, No: right}, p.options.unsupportedJSFeatures)}
  9269  					}
  9270  					lastStmt = js_ast.Stmt{Loc: prevStmt.Loc, Data: lastThrow}
  9271  					result[prevIndex] = lastStmt
  9272  					result = result[:len(result)-1]
  9273  
  9274  				default:
  9275  					break throwLoop
  9276  				}
  9277  			}
  9278  		}
  9279  	}
  9280  
  9281  	return result
  9282  }
  9283  
  9284  func (p *parser) substituteSingleUseSymbolInStmt(stmt js_ast.Stmt, ref ast.Ref, replacement js_ast.Expr) bool {
  9285  	var expr *js_ast.Expr
  9286  
  9287  	switch s := stmt.Data.(type) {
  9288  	case *js_ast.SExpr:
  9289  		expr = &s.Value
  9290  	case *js_ast.SThrow:
  9291  		expr = &s.Value
  9292  	case *js_ast.SReturn:
  9293  		expr = &s.ValueOrNil
  9294  	case *js_ast.SIf:
  9295  		expr = &s.Test
  9296  	case *js_ast.SSwitch:
  9297  		expr = &s.Test
  9298  	case *js_ast.SLocal:
  9299  		// Only try substituting into the initializer for the first declaration
  9300  		if first := &s.Decls[0]; first.ValueOrNil.Data != nil {
  9301  			// Make sure there isn't destructuring, which could evaluate code
  9302  			if _, ok := first.Binding.Data.(*js_ast.BIdentifier); ok {
  9303  				expr = &first.ValueOrNil
  9304  			}
  9305  		}
  9306  	}
  9307  
  9308  	if expr != nil {
  9309  		// Only continue trying to insert this replacement into sub-expressions
  9310  		// after the first one if the replacement has no side effects:
  9311  		//
  9312  		//   // Substitution is ok
  9313  		//   let replacement = 123;
  9314  		//   return x + replacement;
  9315  		//
  9316  		//   // Substitution is not ok because "fn()" may change "x"
  9317  		//   let replacement = fn();
  9318  		//   return x + replacement;
  9319  		//
  9320  		//   // Substitution is not ok because "x == x" may change "x" due to "valueOf()" evaluation
  9321  		//   let replacement = [x];
  9322  		//   return (x == x) + replacement;
  9323  		//
  9324  		replacementCanBeRemoved := p.astHelpers.ExprCanBeRemovedIfUnused(replacement)
  9325  
  9326  		if new, status := p.substituteSingleUseSymbolInExpr(*expr, ref, replacement, replacementCanBeRemoved); status == substituteSuccess {
  9327  			*expr = new
  9328  			return true
  9329  		}
  9330  	}
  9331  
  9332  	return false
  9333  }
  9334  
  9335  type substituteStatus uint8
  9336  
  9337  const (
  9338  	substituteContinue substituteStatus = iota
  9339  	substituteSuccess
  9340  	substituteFailure
  9341  )
  9342  
  9343  func (p *parser) substituteSingleUseSymbolInExpr(
  9344  	expr js_ast.Expr,
  9345  	ref ast.Ref,
  9346  	replacement js_ast.Expr,
  9347  	replacementCanBeRemoved bool,
  9348  ) (js_ast.Expr, substituteStatus) {
  9349  	switch e := expr.Data.(type) {
  9350  	case *js_ast.EIdentifier:
  9351  		if e.Ref == ref {
  9352  			p.ignoreUsage(ref)
  9353  			return replacement, substituteSuccess
  9354  		}
  9355  
  9356  	case *js_ast.ESpread:
  9357  		if value, status := p.substituteSingleUseSymbolInExpr(e.Value, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9358  			e.Value = value
  9359  			return expr, status
  9360  		}
  9361  
  9362  	case *js_ast.EAwait:
  9363  		if value, status := p.substituteSingleUseSymbolInExpr(e.Value, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9364  			e.Value = value
  9365  			return expr, status
  9366  		}
  9367  
  9368  	case *js_ast.EYield:
  9369  		if e.ValueOrNil.Data != nil {
  9370  			if value, status := p.substituteSingleUseSymbolInExpr(e.ValueOrNil, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9371  				e.ValueOrNil = value
  9372  				return expr, status
  9373  			}
  9374  		}
  9375  
  9376  	case *js_ast.EImportCall:
  9377  		if value, status := p.substituteSingleUseSymbolInExpr(e.Expr, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9378  			e.Expr = value
  9379  			return expr, status
  9380  		}
  9381  
  9382  		// The "import()" expression has side effects but the side effects are
  9383  		// always asynchronous so there is no way for the side effects to modify
  9384  		// the replacement value. So it's ok to reorder the replacement value
  9385  		// past the "import()" expression assuming everything else checks out.
  9386  		if replacementCanBeRemoved && p.astHelpers.ExprCanBeRemovedIfUnused(e.Expr) {
  9387  			return expr, substituteContinue
  9388  		}
  9389  
  9390  	case *js_ast.EUnary:
  9391  		switch e.Op {
  9392  		case js_ast.UnOpPreInc, js_ast.UnOpPostInc, js_ast.UnOpPreDec, js_ast.UnOpPostDec, js_ast.UnOpDelete:
  9393  			// Do not substitute into an assignment position
  9394  
  9395  		default:
  9396  			if value, status := p.substituteSingleUseSymbolInExpr(e.Value, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9397  				e.Value = value
  9398  				return expr, status
  9399  			}
  9400  		}
  9401  
  9402  	case *js_ast.EDot:
  9403  		if value, status := p.substituteSingleUseSymbolInExpr(e.Target, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9404  			e.Target = value
  9405  			return expr, status
  9406  		}
  9407  
  9408  	case *js_ast.EBinary:
  9409  		// Do not substitute into an assignment position
  9410  		if e.Op.BinaryAssignTarget() == js_ast.AssignTargetNone {
  9411  			if value, status := p.substituteSingleUseSymbolInExpr(e.Left, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9412  				e.Left = value
  9413  				return expr, status
  9414  			}
  9415  		} else if !p.astHelpers.ExprCanBeRemovedIfUnused(e.Left) {
  9416  			// Do not reorder past a side effect in an assignment target, as that may
  9417  			// change the replacement value. For example, "fn()" may change "a" here:
  9418  			//
  9419  			//   let a = 1;
  9420  			//   foo[fn()] = a;
  9421  			//
  9422  			return expr, substituteFailure
  9423  		} else if e.Op.BinaryAssignTarget() == js_ast.AssignTargetUpdate && !replacementCanBeRemoved {
  9424  			// If this is a read-modify-write assignment and the replacement has side
  9425  			// effects, don't reorder it past the assignment target. The assignment
  9426  			// target is being read so it may be changed by the side effect. For
  9427  			// example, "fn()" may change "foo" here:
  9428  			//
  9429  			//   let a = fn();
  9430  			//   foo += a;
  9431  			//
  9432  			return expr, substituteFailure
  9433  		}
  9434  
  9435  		// If we get here then it should be safe to attempt to substitute the
  9436  		// replacement past the left operand into the right operand.
  9437  		if value, status := p.substituteSingleUseSymbolInExpr(e.Right, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9438  			e.Right = value
  9439  			return expr, status
  9440  		}
  9441  
  9442  	case *js_ast.EIf:
  9443  		if value, status := p.substituteSingleUseSymbolInExpr(e.Test, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9444  			e.Test = value
  9445  			return expr, status
  9446  		}
  9447  
  9448  		// Do not substitute our unconditionally-executed value into a branch
  9449  		// unless the value itself has no side effects
  9450  		if replacementCanBeRemoved {
  9451  			// Unlike other branches in this function such as "a && b" or "a?.[b]",
  9452  			// the "a ? b : c" form has potential code evaluation along both control
  9453  			// flow paths. Handle this by allowing substitution into either branch.
  9454  			// Side effects in one branch should not prevent the substitution into
  9455  			// the other branch.
  9456  
  9457  			yesValue, yesStatus := p.substituteSingleUseSymbolInExpr(e.Yes, ref, replacement, replacementCanBeRemoved)
  9458  			if yesStatus == substituteSuccess {
  9459  				e.Yes = yesValue
  9460  				return expr, yesStatus
  9461  			}
  9462  
  9463  			noValue, noStatus := p.substituteSingleUseSymbolInExpr(e.No, ref, replacement, replacementCanBeRemoved)
  9464  			if noStatus == substituteSuccess {
  9465  				e.No = noValue
  9466  				return expr, noStatus
  9467  			}
  9468  
  9469  			// Side effects in either branch should stop us from continuing to try to
  9470  			// substitute the replacement after the control flow branches merge again.
  9471  			if yesStatus != substituteContinue || noStatus != substituteContinue {
  9472  				return expr, substituteFailure
  9473  			}
  9474  		}
  9475  
  9476  	case *js_ast.EIndex:
  9477  		if value, status := p.substituteSingleUseSymbolInExpr(e.Target, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9478  			e.Target = value
  9479  			return expr, status
  9480  		}
  9481  
  9482  		// Do not substitute our unconditionally-executed value into a branch
  9483  		// unless the value itself has no side effects
  9484  		if replacementCanBeRemoved || e.OptionalChain == js_ast.OptionalChainNone {
  9485  			if value, status := p.substituteSingleUseSymbolInExpr(e.Index, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9486  				e.Index = value
  9487  				return expr, status
  9488  			}
  9489  		}
  9490  
  9491  	case *js_ast.ECall:
  9492  		// Don't substitute something into a call target that could change "this"
  9493  		_, isDot := replacement.Data.(*js_ast.EDot)
  9494  		_, isIndex := replacement.Data.(*js_ast.EIndex)
  9495  		if isDot || isIndex {
  9496  			if id, ok := e.Target.Data.(*js_ast.EIdentifier); ok && id.Ref == ref {
  9497  				break
  9498  			}
  9499  		}
  9500  
  9501  		if value, status := p.substituteSingleUseSymbolInExpr(e.Target, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9502  			e.Target = value
  9503  			return expr, status
  9504  		}
  9505  
  9506  		// Do not substitute our unconditionally-executed value into a branch
  9507  		// unless the value itself has no side effects
  9508  		if replacementCanBeRemoved || e.OptionalChain == js_ast.OptionalChainNone {
  9509  			for i, arg := range e.Args {
  9510  				if value, status := p.substituteSingleUseSymbolInExpr(arg, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9511  					e.Args[i] = value
  9512  					return expr, status
  9513  				}
  9514  			}
  9515  		}
  9516  
  9517  	case *js_ast.EArray:
  9518  		for i, item := range e.Items {
  9519  			if value, status := p.substituteSingleUseSymbolInExpr(item, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9520  				e.Items[i] = value
  9521  				return expr, status
  9522  			}
  9523  		}
  9524  
  9525  	case *js_ast.EObject:
  9526  		for i, property := range e.Properties {
  9527  			// Check the key
  9528  			if property.Flags.Has(js_ast.PropertyIsComputed) {
  9529  				if value, status := p.substituteSingleUseSymbolInExpr(property.Key, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9530  					e.Properties[i].Key = value
  9531  					return expr, status
  9532  				}
  9533  
  9534  				// Stop now because both computed keys and property spread have side effects
  9535  				return expr, substituteFailure
  9536  			}
  9537  
  9538  			// Check the value
  9539  			if property.ValueOrNil.Data != nil {
  9540  				if value, status := p.substituteSingleUseSymbolInExpr(property.ValueOrNil, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9541  					e.Properties[i].ValueOrNil = value
  9542  					return expr, status
  9543  				}
  9544  			}
  9545  		}
  9546  
  9547  	case *js_ast.ETemplate:
  9548  		if e.TagOrNil.Data != nil {
  9549  			if value, status := p.substituteSingleUseSymbolInExpr(e.TagOrNil, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9550  				e.TagOrNil = value
  9551  				return expr, status
  9552  			}
  9553  		}
  9554  
  9555  		for i, part := range e.Parts {
  9556  			if value, status := p.substituteSingleUseSymbolInExpr(part.Value, ref, replacement, replacementCanBeRemoved); status != substituteContinue {
  9557  				e.Parts[i].Value = value
  9558  
  9559  				// If we substituted a primitive, merge it into the template
  9560  				if js_ast.IsPrimitiveLiteral(value.Data) {
  9561  					expr = js_ast.InlinePrimitivesIntoTemplate(expr.Loc, e)
  9562  				}
  9563  				return expr, status
  9564  			}
  9565  		}
  9566  	}
  9567  
  9568  	// If both the replacement and this expression have no observable side
  9569  	// effects, then we can reorder the replacement past this expression
  9570  	if replacementCanBeRemoved && p.astHelpers.ExprCanBeRemovedIfUnused(expr) {
  9571  		return expr, substituteContinue
  9572  	}
  9573  
  9574  	// We can always reorder past primitive values
  9575  	if js_ast.IsPrimitiveLiteral(expr.Data) || js_ast.IsPrimitiveLiteral(replacement.Data) {
  9576  		return expr, substituteContinue
  9577  	}
  9578  
  9579  	// Otherwise we should stop trying to substitute past this point
  9580  	return expr, substituteFailure
  9581  }
  9582  
  9583  func (p *parser) visitLoopBody(stmt js_ast.Stmt) js_ast.Stmt {
  9584  	oldIsInsideLoop := p.fnOrArrowDataVisit.isInsideLoop
  9585  	p.fnOrArrowDataVisit.isInsideLoop = true
  9586  	p.loopBody = stmt.Data
  9587  	stmt = p.visitSingleStmt(stmt, stmtsLoopBody)
  9588  	p.fnOrArrowDataVisit.isInsideLoop = oldIsInsideLoop
  9589  	return stmt
  9590  }
  9591  
  9592  func (p *parser) visitSingleStmt(stmt js_ast.Stmt, kind stmtsKind) js_ast.Stmt {
  9593  	// To reduce stack depth, special-case blocks and process their children directly
  9594  	if block, ok := stmt.Data.(*js_ast.SBlock); ok {
  9595  		p.pushScopeForVisitPass(js_ast.ScopeBlock, stmt.Loc)
  9596  		block.Stmts = p.visitStmts(block.Stmts, kind)
  9597  		p.popScope()
  9598  		if p.options.minifySyntax {
  9599  			stmt = stmtsToSingleStmt(stmt.Loc, block.Stmts, block.CloseBraceLoc)
  9600  		}
  9601  		return stmt
  9602  	}
  9603  
  9604  	// Introduce a fake block scope for function declarations inside if statements
  9605  	fn, ok := stmt.Data.(*js_ast.SFunction)
  9606  	hasIfScope := ok && fn.Fn.HasIfScope
  9607  	if hasIfScope {
  9608  		p.pushScopeForVisitPass(js_ast.ScopeBlock, stmt.Loc)
  9609  		if p.isStrictMode() {
  9610  			p.markStrictModeFeature(ifElseFunctionStmt, js_lexer.RangeOfIdentifier(p.source, stmt.Loc), "")
  9611  		}
  9612  	}
  9613  
  9614  	stmts := p.visitStmts([]js_ast.Stmt{stmt}, kind)
  9615  
  9616  	// Balance the fake block scope introduced above
  9617  	if hasIfScope {
  9618  		p.popScope()
  9619  	}
  9620  
  9621  	return stmtsToSingleStmt(stmt.Loc, stmts, logger.Loc{})
  9622  }
  9623  
  9624  // One statement could potentially expand to several statements
  9625  func stmtsToSingleStmt(loc logger.Loc, stmts []js_ast.Stmt, closeBraceLoc logger.Loc) js_ast.Stmt {
  9626  	if len(stmts) == 0 {
  9627  		return js_ast.Stmt{Loc: loc, Data: js_ast.SEmptyShared}
  9628  	}
  9629  	if len(stmts) == 1 && !statementCaresAboutScope(stmts[0]) {
  9630  		return stmts[0]
  9631  	}
  9632  	return js_ast.Stmt{Loc: loc, Data: &js_ast.SBlock{Stmts: stmts, CloseBraceLoc: closeBraceLoc}}
  9633  }
  9634  
  9635  func (p *parser) visitForLoopInit(stmt js_ast.Stmt, isInOrOf bool) js_ast.Stmt {
  9636  	switch s := stmt.Data.(type) {
  9637  	case *js_ast.SExpr:
  9638  		assignTarget := js_ast.AssignTargetNone
  9639  		if isInOrOf {
  9640  			assignTarget = js_ast.AssignTargetReplace
  9641  		}
  9642  		p.stmtExprValue = s.Value.Data
  9643  		s.Value, _ = p.visitExprInOut(s.Value, exprIn{assignTarget: assignTarget})
  9644  
  9645  	case *js_ast.SLocal:
  9646  		for i := range s.Decls {
  9647  			d := &s.Decls[i]
  9648  			p.visitBinding(d.Binding, bindingOpts{})
  9649  			if d.ValueOrNil.Data != nil {
  9650  				d.ValueOrNil = p.visitExpr(d.ValueOrNil)
  9651  			}
  9652  		}
  9653  		s.Decls = p.lowerObjectRestInDecls(s.Decls)
  9654  		s.Kind = p.selectLocalKind(s.Kind)
  9655  
  9656  	default:
  9657  		panic("Internal error")
  9658  	}
  9659  
  9660  	return stmt
  9661  }
  9662  
  9663  func (p *parser) recordDeclaredSymbol(ref ast.Ref) {
  9664  	p.declaredSymbols = append(p.declaredSymbols, js_ast.DeclaredSymbol{
  9665  		Ref:        ref,
  9666  		IsTopLevel: p.currentScope == p.moduleScope,
  9667  	})
  9668  }
  9669  
  9670  type bindingOpts struct {
  9671  	duplicateArgCheck map[string]logger.Range
  9672  }
  9673  
  9674  func (p *parser) visitBinding(binding js_ast.Binding, opts bindingOpts) {
  9675  	switch b := binding.Data.(type) {
  9676  	case *js_ast.BMissing:
  9677  
  9678  	case *js_ast.BIdentifier:
  9679  		p.recordDeclaredSymbol(b.Ref)
  9680  		name := p.symbols[b.Ref.InnerIndex].OriginalName
  9681  		p.validateDeclaredSymbolName(binding.Loc, name)
  9682  		if opts.duplicateArgCheck != nil {
  9683  			r := js_lexer.RangeOfIdentifier(p.source, binding.Loc)
  9684  			if firstRange := opts.duplicateArgCheck[name]; firstRange.Len > 0 {
  9685  				p.log.AddErrorWithNotes(&p.tracker, r,
  9686  					fmt.Sprintf("%q cannot be bound multiple times in the same parameter list", name),
  9687  					[]logger.MsgData{p.tracker.MsgData(firstRange, fmt.Sprintf("The name %q was originally bound here:", name))})
  9688  			} else {
  9689  				opts.duplicateArgCheck[name] = r
  9690  			}
  9691  		}
  9692  
  9693  	case *js_ast.BArray:
  9694  		for i := range b.Items {
  9695  			item := &b.Items[i]
  9696  			p.visitBinding(item.Binding, opts)
  9697  			if item.DefaultValueOrNil.Data != nil {
  9698  				// Propagate the name to keep from the binding into the initializer
  9699  				if id, ok := item.Binding.Data.(*js_ast.BIdentifier); ok {
  9700  					p.nameToKeep = p.symbols[id.Ref.InnerIndex].OriginalName
  9701  					p.nameToKeepIsFor = item.DefaultValueOrNil.Data
  9702  				}
  9703  
  9704  				item.DefaultValueOrNil = p.visitExpr(item.DefaultValueOrNil)
  9705  			}
  9706  		}
  9707  
  9708  	case *js_ast.BObject:
  9709  		for i, property := range b.Properties {
  9710  			if !property.IsSpread {
  9711  				property.Key, _ = p.visitExprInOut(property.Key, exprIn{
  9712  					shouldMangleStringsAsProps: true,
  9713  				})
  9714  			}
  9715  			p.visitBinding(property.Value, opts)
  9716  			if property.DefaultValueOrNil.Data != nil {
  9717  				// Propagate the name to keep from the binding into the initializer
  9718  				if id, ok := property.Value.Data.(*js_ast.BIdentifier); ok {
  9719  					p.nameToKeep = p.symbols[id.Ref.InnerIndex].OriginalName
  9720  					p.nameToKeepIsFor = property.DefaultValueOrNil.Data
  9721  				}
  9722  
  9723  				property.DefaultValueOrNil = p.visitExpr(property.DefaultValueOrNil)
  9724  			}
  9725  			b.Properties[i] = property
  9726  		}
  9727  
  9728  	default:
  9729  		panic("Internal error")
  9730  	}
  9731  }
  9732  
  9733  func statementCaresAboutScope(stmt js_ast.Stmt) bool {
  9734  	switch s := stmt.Data.(type) {
  9735  	case *js_ast.SBlock, *js_ast.SEmpty, *js_ast.SDebugger, *js_ast.SExpr, *js_ast.SIf,
  9736  		*js_ast.SFor, *js_ast.SForIn, *js_ast.SForOf, *js_ast.SDoWhile, *js_ast.SWhile,
  9737  		*js_ast.SWith, *js_ast.STry, *js_ast.SSwitch, *js_ast.SReturn, *js_ast.SThrow,
  9738  		*js_ast.SBreak, *js_ast.SContinue, *js_ast.SDirective, *js_ast.SLabel:
  9739  		return false
  9740  
  9741  	case *js_ast.SLocal:
  9742  		return s.Kind != js_ast.LocalVar
  9743  
  9744  	default:
  9745  		return true
  9746  	}
  9747  }
  9748  
  9749  func dropFirstStatement(body js_ast.Stmt, replaceOrNil js_ast.Stmt) js_ast.Stmt {
  9750  	if block, ok := body.Data.(*js_ast.SBlock); ok && len(block.Stmts) > 0 {
  9751  		if replaceOrNil.Data != nil {
  9752  			block.Stmts[0] = replaceOrNil
  9753  		} else if len(block.Stmts) == 2 && !statementCaresAboutScope(block.Stmts[1]) {
  9754  			return block.Stmts[1]
  9755  		} else {
  9756  			block.Stmts = block.Stmts[1:]
  9757  		}
  9758  		return body
  9759  	}
  9760  	if replaceOrNil.Data != nil {
  9761  		return replaceOrNil
  9762  	}
  9763  	return js_ast.Stmt{Loc: body.Loc, Data: js_ast.SEmptyShared}
  9764  }
  9765  
  9766  func mangleFor(s *js_ast.SFor) {
  9767  	// Get the first statement in the loop
  9768  	first := s.Body
  9769  	if block, ok := first.Data.(*js_ast.SBlock); ok && len(block.Stmts) > 0 {
  9770  		first = block.Stmts[0]
  9771  	}
  9772  
  9773  	if ifS, ok := first.Data.(*js_ast.SIf); ok {
  9774  		// "for (;;) if (x) break;" => "for (; !x;) ;"
  9775  		// "for (; a;) if (x) break;" => "for (; a && !x;) ;"
  9776  		// "for (;;) if (x) break; else y();" => "for (; !x;) y();"
  9777  		// "for (; a;) if (x) break; else y();" => "for (; a && !x;) y();"
  9778  		if breakS, ok := ifS.Yes.Data.(*js_ast.SBreak); ok && breakS.Label == nil {
  9779  			var not js_ast.Expr
  9780  			if unary, ok := ifS.Test.Data.(*js_ast.EUnary); ok && unary.Op == js_ast.UnOpNot {
  9781  				not = unary.Value
  9782  			} else {
  9783  				not = js_ast.Not(ifS.Test)
  9784  			}
  9785  			if s.TestOrNil.Data != nil {
  9786  				s.TestOrNil = js_ast.Expr{Loc: s.TestOrNil.Loc, Data: &js_ast.EBinary{
  9787  					Op:    js_ast.BinOpLogicalAnd,
  9788  					Left:  s.TestOrNil,
  9789  					Right: not,
  9790  				}}
  9791  			} else {
  9792  				s.TestOrNil = not
  9793  			}
  9794  			s.Body = dropFirstStatement(s.Body, ifS.NoOrNil)
  9795  			return
  9796  		}
  9797  
  9798  		// "for (;;) if (x) y(); else break;" => "for (; x;) y();"
  9799  		// "for (; a;) if (x) y(); else break;" => "for (; a && x;) y();"
  9800  		if ifS.NoOrNil.Data != nil {
  9801  			if breakS, ok := ifS.NoOrNil.Data.(*js_ast.SBreak); ok && breakS.Label == nil {
  9802  				if s.TestOrNil.Data != nil {
  9803  					s.TestOrNil = js_ast.Expr{Loc: s.TestOrNil.Loc, Data: &js_ast.EBinary{
  9804  						Op:    js_ast.BinOpLogicalAnd,
  9805  						Left:  s.TestOrNil,
  9806  						Right: ifS.Test,
  9807  					}}
  9808  				} else {
  9809  					s.TestOrNil = ifS.Test
  9810  				}
  9811  				s.Body = dropFirstStatement(s.Body, ifS.Yes)
  9812  				return
  9813  			}
  9814  		}
  9815  	}
  9816  }
  9817  
  9818  func appendIfOrLabelBodyPreservingScope(stmts []js_ast.Stmt, body js_ast.Stmt) []js_ast.Stmt {
  9819  	if block, ok := body.Data.(*js_ast.SBlock); ok {
  9820  		keepBlock := false
  9821  		for _, stmt := range block.Stmts {
  9822  			if statementCaresAboutScope(stmt) {
  9823  				keepBlock = true
  9824  				break
  9825  			}
  9826  		}
  9827  		if !keepBlock {
  9828  			return append(stmts, block.Stmts...)
  9829  		}
  9830  	}
  9831  
  9832  	if statementCaresAboutScope(body) {
  9833  		return append(stmts, js_ast.Stmt{Loc: body.Loc, Data: &js_ast.SBlock{Stmts: []js_ast.Stmt{body}}})
  9834  	}
  9835  
  9836  	return append(stmts, body)
  9837  }
  9838  
  9839  func (p *parser) mangleIf(stmts []js_ast.Stmt, loc logger.Loc, s *js_ast.SIf) []js_ast.Stmt {
  9840  	// Constant folding using the test expression
  9841  	if boolean, sideEffects, ok := js_ast.ToBooleanWithSideEffects(s.Test.Data); ok {
  9842  		if boolean {
  9843  			// The test is truthy
  9844  			if s.NoOrNil.Data == nil || !shouldKeepStmtInDeadControlFlow(s.NoOrNil) {
  9845  				// We can drop the "no" branch
  9846  				if sideEffects == js_ast.CouldHaveSideEffects {
  9847  					// Keep the condition if it could have side effects (but is still known to be truthy)
  9848  					if test := p.astHelpers.SimplifyUnusedExpr(s.Test, p.options.unsupportedJSFeatures); test.Data != nil {
  9849  						stmts = append(stmts, js_ast.Stmt{Loc: s.Test.Loc, Data: &js_ast.SExpr{Value: test}})
  9850  					}
  9851  				}
  9852  				return appendIfOrLabelBodyPreservingScope(stmts, s.Yes)
  9853  			} else {
  9854  				// We have to keep the "no" branch
  9855  			}
  9856  		} else {
  9857  			// The test is falsy
  9858  			if !shouldKeepStmtInDeadControlFlow(s.Yes) {
  9859  				// We can drop the "yes" branch
  9860  				if sideEffects == js_ast.CouldHaveSideEffects {
  9861  					// Keep the condition if it could have side effects (but is still known to be falsy)
  9862  					if test := p.astHelpers.SimplifyUnusedExpr(s.Test, p.options.unsupportedJSFeatures); test.Data != nil {
  9863  						stmts = append(stmts, js_ast.Stmt{Loc: s.Test.Loc, Data: &js_ast.SExpr{Value: test}})
  9864  					}
  9865  				}
  9866  				if s.NoOrNil.Data == nil {
  9867  					return stmts
  9868  				}
  9869  				return appendIfOrLabelBodyPreservingScope(stmts, s.NoOrNil)
  9870  			} else {
  9871  				// We have to keep the "yes" branch
  9872  			}
  9873  		}
  9874  
  9875  		// Use "1" and "0" instead of "true" and "false" to be shorter
  9876  		if sideEffects == js_ast.NoSideEffects {
  9877  			if boolean {
  9878  				s.Test.Data = &js_ast.ENumber{Value: 1}
  9879  			} else {
  9880  				s.Test.Data = &js_ast.ENumber{Value: 0}
  9881  			}
  9882  		}
  9883  	}
  9884  
  9885  	var expr js_ast.Expr
  9886  
  9887  	if yes, ok := s.Yes.Data.(*js_ast.SExpr); ok {
  9888  		// "yes" is an expression
  9889  		if s.NoOrNil.Data == nil {
  9890  			if not, ok := s.Test.Data.(*js_ast.EUnary); ok && not.Op == js_ast.UnOpNot {
  9891  				// "if (!a) b();" => "a || b();"
  9892  				expr = js_ast.JoinWithLeftAssociativeOp(js_ast.BinOpLogicalOr, not.Value, yes.Value)
  9893  			} else {
  9894  				// "if (a) b();" => "a && b();"
  9895  				expr = js_ast.JoinWithLeftAssociativeOp(js_ast.BinOpLogicalAnd, s.Test, yes.Value)
  9896  			}
  9897  		} else if no, ok := s.NoOrNil.Data.(*js_ast.SExpr); ok {
  9898  			// "if (a) b(); else c();" => "a ? b() : c();"
  9899  			expr = p.astHelpers.MangleIfExpr(loc, &js_ast.EIf{
  9900  				Test: s.Test,
  9901  				Yes:  yes.Value,
  9902  				No:   no.Value,
  9903  			}, p.options.unsupportedJSFeatures)
  9904  		}
  9905  	} else if _, ok := s.Yes.Data.(*js_ast.SEmpty); ok {
  9906  		// "yes" is missing
  9907  		if s.NoOrNil.Data == nil {
  9908  			// "yes" and "no" are both missing
  9909  			if p.astHelpers.ExprCanBeRemovedIfUnused(s.Test) {
  9910  				// "if (1) {}" => ""
  9911  				return stmts
  9912  			} else {
  9913  				// "if (a) {}" => "a;"
  9914  				expr = s.Test
  9915  			}
  9916  		} else if no, ok := s.NoOrNil.Data.(*js_ast.SExpr); ok {
  9917  			if not, ok := s.Test.Data.(*js_ast.EUnary); ok && not.Op == js_ast.UnOpNot {
  9918  				// "if (!a) {} else b();" => "a && b();"
  9919  				expr = js_ast.JoinWithLeftAssociativeOp(js_ast.BinOpLogicalAnd, not.Value, no.Value)
  9920  			} else {
  9921  				// "if (a) {} else b();" => "a || b();"
  9922  				expr = js_ast.JoinWithLeftAssociativeOp(js_ast.BinOpLogicalOr, s.Test, no.Value)
  9923  			}
  9924  		} else {
  9925  			// "yes" is missing and "no" is not missing (and is not an expression)
  9926  			if not, ok := s.Test.Data.(*js_ast.EUnary); ok && not.Op == js_ast.UnOpNot {
  9927  				// "if (!a) {} else throw b;" => "if (a) throw b;"
  9928  				s.Test = not.Value
  9929  				s.Yes = s.NoOrNil
  9930  				s.NoOrNil = js_ast.Stmt{}
  9931  			} else {
  9932  				// "if (a) {} else throw b;" => "if (!a) throw b;"
  9933  				s.Test = js_ast.Not(s.Test)
  9934  				s.Yes = s.NoOrNil
  9935  				s.NoOrNil = js_ast.Stmt{}
  9936  			}
  9937  		}
  9938  	} else {
  9939  		// "yes" is not missing (and is not an expression)
  9940  		if s.NoOrNil.Data != nil {
  9941  			// "yes" is not missing (and is not an expression) and "no" is not missing
  9942  			if not, ok := s.Test.Data.(*js_ast.EUnary); ok && not.Op == js_ast.UnOpNot {
  9943  				// "if (!a) return b; else return c;" => "if (a) return c; else return b;"
  9944  				s.Test = not.Value
  9945  				s.Yes, s.NoOrNil = s.NoOrNil, s.Yes
  9946  			}
  9947  		} else {
  9948  			// "no" is missing
  9949  			if s2, ok := s.Yes.Data.(*js_ast.SIf); ok && s2.NoOrNil.Data == nil {
  9950  				// "if (a) if (b) return c;" => "if (a && b) return c;"
  9951  				s.Test = js_ast.JoinWithLeftAssociativeOp(js_ast.BinOpLogicalAnd, s.Test, s2.Test)
  9952  				s.Yes = s2.Yes
  9953  			}
  9954  		}
  9955  	}
  9956  
  9957  	// Return an expression if we replaced the if statement with an expression above
  9958  	if expr.Data != nil {
  9959  		expr = p.astHelpers.SimplifyUnusedExpr(expr, p.options.unsupportedJSFeatures)
  9960  		return append(stmts, js_ast.Stmt{Loc: loc, Data: &js_ast.SExpr{Value: expr}})
  9961  	}
  9962  
  9963  	return append(stmts, js_ast.Stmt{Loc: loc, Data: s})
  9964  }
  9965  
  9966  func (p *parser) keepExprSymbolName(value js_ast.Expr, name string) js_ast.Expr {
  9967  	value = p.callRuntime(value.Loc, "__name", []js_ast.Expr{value,
  9968  		{Loc: value.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(name)}},
  9969  	})
  9970  
  9971  	// Make sure tree shaking removes this if the function is never used
  9972  	value.Data.(*js_ast.ECall).CanBeUnwrappedIfUnused = true
  9973  	return value
  9974  }
  9975  
  9976  func (p *parser) keepClassOrFnSymbolName(loc logger.Loc, expr js_ast.Expr, name string) js_ast.Stmt {
  9977  	return js_ast.Stmt{Loc: loc, Data: &js_ast.SExpr{
  9978  		Value: p.callRuntime(loc, "__name", []js_ast.Expr{
  9979  			expr,
  9980  			{Loc: loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(name)}},
  9981  		}),
  9982  		IsFromClassOrFnThatCanBeRemovedIfUnused: true,
  9983  	}}
  9984  }
  9985  
  9986  func (p *parser) visitAndAppendStmt(stmts []js_ast.Stmt, stmt js_ast.Stmt) []js_ast.Stmt {
  9987  	// By default any statement ends the const local prefix
  9988  	wasAfterAfterConstLocalPrefix := p.currentScope.IsAfterConstLocalPrefix
  9989  	p.currentScope.IsAfterConstLocalPrefix = true
  9990  
  9991  	switch s := stmt.Data.(type) {
  9992  	case *js_ast.SEmpty, *js_ast.SComment:
  9993  		// Comments do not end the const local prefix
  9994  		p.currentScope.IsAfterConstLocalPrefix = wasAfterAfterConstLocalPrefix
  9995  
  9996  	case *js_ast.SDebugger:
  9997  		// Debugger statements do not end the const local prefix
  9998  		p.currentScope.IsAfterConstLocalPrefix = wasAfterAfterConstLocalPrefix
  9999  
 10000  		if p.options.dropDebugger {
 10001  			return stmts
 10002  		}
 10003  
 10004  	case *js_ast.STypeScript:
 10005  		// Type annotations do not end the const local prefix
 10006  		p.currentScope.IsAfterConstLocalPrefix = wasAfterAfterConstLocalPrefix
 10007  
 10008  		// Erase TypeScript constructs from the output completely
 10009  		return stmts
 10010  
 10011  	case *js_ast.SDirective:
 10012  		// Directives do not end the const local prefix
 10013  		p.currentScope.IsAfterConstLocalPrefix = wasAfterAfterConstLocalPrefix
 10014  
 10015  		if p.isStrictMode() && s.LegacyOctalLoc.Start > 0 {
 10016  			p.markStrictModeFeature(legacyOctalEscape, p.source.RangeOfLegacyOctalEscape(s.LegacyOctalLoc), "")
 10017  		}
 10018  
 10019  	case *js_ast.SImport:
 10020  		p.recordDeclaredSymbol(s.NamespaceRef)
 10021  
 10022  		if s.DefaultName != nil {
 10023  			p.recordDeclaredSymbol(s.DefaultName.Ref)
 10024  		}
 10025  
 10026  		if s.Items != nil {
 10027  			for _, item := range *s.Items {
 10028  				p.recordDeclaredSymbol(item.Name.Ref)
 10029  			}
 10030  		}
 10031  
 10032  	case *js_ast.SExportClause:
 10033  		// "export {foo}"
 10034  		end := 0
 10035  		for _, item := range s.Items {
 10036  			name := p.loadNameFromRef(item.Name.Ref)
 10037  			ref := p.findSymbol(item.AliasLoc, name).ref
 10038  
 10039  			if p.symbols[ref.InnerIndex].Kind == ast.SymbolUnbound {
 10040  				// Silently strip exports of non-local symbols in TypeScript, since
 10041  				// those likely correspond to type-only exports. But report exports of
 10042  				// non-local symbols as errors in JavaScript.
 10043  				if !p.options.ts.Parse {
 10044  					r := js_lexer.RangeOfIdentifier(p.source, item.Name.Loc)
 10045  					p.log.AddError(&p.tracker, r, fmt.Sprintf("%q is not declared in this file", name))
 10046  				}
 10047  				continue
 10048  			}
 10049  
 10050  			item.Name.Ref = ref
 10051  			s.Items[end] = item
 10052  			end++
 10053  		}
 10054  
 10055  		// Note: do not remove empty export statements since TypeScript uses them as module markers
 10056  		s.Items = s.Items[:end]
 10057  
 10058  	case *js_ast.SExportFrom:
 10059  		// "export {foo} from 'path'"
 10060  		name := p.loadNameFromRef(s.NamespaceRef)
 10061  		s.NamespaceRef = p.newSymbol(ast.SymbolOther, name)
 10062  		p.currentScope.Generated = append(p.currentScope.Generated, s.NamespaceRef)
 10063  		p.recordDeclaredSymbol(s.NamespaceRef)
 10064  
 10065  		// This is a re-export and the symbols created here are used to reference
 10066  		// names in another file. This means the symbols are really aliases.
 10067  		for i, item := range s.Items {
 10068  			name := p.loadNameFromRef(item.Name.Ref)
 10069  			ref := p.newSymbol(ast.SymbolOther, name)
 10070  			p.currentScope.Generated = append(p.currentScope.Generated, ref)
 10071  			p.recordDeclaredSymbol(ref)
 10072  			s.Items[i].Name.Ref = ref
 10073  		}
 10074  
 10075  	case *js_ast.SExportStar:
 10076  		// "export * from 'path'"
 10077  		// "export * as ns from 'path'"
 10078  		name := p.loadNameFromRef(s.NamespaceRef)
 10079  		s.NamespaceRef = p.newSymbol(ast.SymbolOther, name)
 10080  		p.currentScope.Generated = append(p.currentScope.Generated, s.NamespaceRef)
 10081  		p.recordDeclaredSymbol(s.NamespaceRef)
 10082  
 10083  		// "export * as ns from 'path'"
 10084  		if s.Alias != nil {
 10085  			// "import * as ns from 'path'"
 10086  			// "export {ns}"
 10087  			if p.options.unsupportedJSFeatures.Has(compat.ExportStarAs) {
 10088  				p.recordUsage(s.NamespaceRef)
 10089  				return append(stmts,
 10090  					js_ast.Stmt{Loc: stmt.Loc, Data: &js_ast.SImport{
 10091  						NamespaceRef:      s.NamespaceRef,
 10092  						StarNameLoc:       &s.Alias.Loc,
 10093  						ImportRecordIndex: s.ImportRecordIndex,
 10094  					}},
 10095  					js_ast.Stmt{Loc: stmt.Loc, Data: &js_ast.SExportClause{
 10096  						Items: []js_ast.ClauseItem{{
 10097  							Alias:        s.Alias.OriginalName,
 10098  							OriginalName: s.Alias.OriginalName,
 10099  							AliasLoc:     s.Alias.Loc,
 10100  							Name:         ast.LocRef{Loc: s.Alias.Loc, Ref: s.NamespaceRef},
 10101  						}},
 10102  						IsSingleLine: true,
 10103  					}},
 10104  				)
 10105  			}
 10106  		}
 10107  
 10108  	case *js_ast.SExportDefault:
 10109  		p.recordDeclaredSymbol(s.DefaultName.Ref)
 10110  
 10111  		switch s2 := s.Value.Data.(type) {
 10112  		case *js_ast.SExpr:
 10113  			// Propagate the name to keep from the export into the value
 10114  			p.nameToKeep = "default"
 10115  			p.nameToKeepIsFor = s2.Value.Data
 10116  
 10117  			s2.Value = p.visitExpr(s2.Value)
 10118  
 10119  			// Discard type-only export default statements
 10120  			if p.options.ts.Parse {
 10121  				if id, ok := s2.Value.Data.(*js_ast.EIdentifier); ok {
 10122  					symbol := p.symbols[id.Ref.InnerIndex]
 10123  					if symbol.Kind == ast.SymbolUnbound && p.localTypeNames[symbol.OriginalName] {
 10124  						return stmts
 10125  					}
 10126  				}
 10127  			}
 10128  
 10129  			// If there are lowered "using" declarations, change this into a "var"
 10130  			if p.currentScope.Parent == nil && p.willWrapModuleInTryCatchForUsing {
 10131  				stmts = append(stmts,
 10132  					js_ast.Stmt{Loc: stmt.Loc, Data: &js_ast.SLocal{
 10133  						Decls: []js_ast.Decl{{
 10134  							Binding:    js_ast.Binding{Loc: s.DefaultName.Loc, Data: &js_ast.BIdentifier{Ref: s.DefaultName.Ref}},
 10135  							ValueOrNil: s2.Value,
 10136  						}},
 10137  					}},
 10138  					js_ast.Stmt{Loc: stmt.Loc, Data: &js_ast.SExportClause{Items: []js_ast.ClauseItem{{
 10139  						Alias:    "default",
 10140  						AliasLoc: s.DefaultName.Loc,
 10141  						Name:     s.DefaultName,
 10142  					}}}},
 10143  				)
 10144  				break
 10145  			}
 10146  
 10147  			stmts = append(stmts, stmt)
 10148  
 10149  		case *js_ast.SFunction:
 10150  			// If we need to preserve the name but there is no name, generate a name
 10151  			var name string
 10152  			if p.options.keepNames {
 10153  				if s2.Fn.Name == nil {
 10154  					clone := s.DefaultName
 10155  					s2.Fn.Name = &clone
 10156  					name = "default"
 10157  				} else {
 10158  					name = p.symbols[s2.Fn.Name.Ref.InnerIndex].OriginalName
 10159  				}
 10160  			}
 10161  
 10162  			p.visitFn(&s2.Fn, s2.Fn.OpenParenLoc, visitFnOpts{})
 10163  			stmts = append(stmts, stmt)
 10164  
 10165  			// Optionally preserve the name
 10166  			if p.options.keepNames {
 10167  				p.symbols[s2.Fn.Name.Ref.InnerIndex].Flags |= ast.DidKeepName
 10168  				fn := js_ast.Expr{Loc: s2.Fn.Name.Loc, Data: &js_ast.EIdentifier{Ref: s2.Fn.Name.Ref}}
 10169  				stmts = append(stmts, p.keepClassOrFnSymbolName(s2.Fn.Name.Loc, fn, name))
 10170  			}
 10171  
 10172  		case *js_ast.SClass:
 10173  			result := p.visitClass(s.Value.Loc, &s2.Class, s.DefaultName.Ref, "default")
 10174  
 10175  			// Lower class field syntax for browsers that don't support it
 10176  			classStmts, _ := p.lowerClass(stmt, js_ast.Expr{}, result, "")
 10177  
 10178  			// Remember if the class was side-effect free before lowering
 10179  			if result.canBeRemovedIfUnused {
 10180  				for _, classStmt := range classStmts {
 10181  					if s2, ok := classStmt.Data.(*js_ast.SExpr); ok {
 10182  						s2.IsFromClassOrFnThatCanBeRemovedIfUnused = true
 10183  					}
 10184  				}
 10185  			}
 10186  
 10187  			stmts = append(stmts, classStmts...)
 10188  
 10189  		default:
 10190  			panic("Internal error")
 10191  		}
 10192  
 10193  		// Use a more friendly name than "default" now that "--keep-names" has
 10194  		// been applied and has made sure to enforce the name "default"
 10195  		if p.symbols[s.DefaultName.Ref.InnerIndex].OriginalName == "default" {
 10196  			p.symbols[s.DefaultName.Ref.InnerIndex].OriginalName = p.source.IdentifierName + "_default"
 10197  		}
 10198  
 10199  		return stmts
 10200  
 10201  	case *js_ast.SExportEquals:
 10202  		// "module.exports = value"
 10203  		stmts = append(stmts, js_ast.AssignStmt(
 10204  			js_ast.Expr{Loc: stmt.Loc, Data: &js_ast.EDot{
 10205  				Target:  js_ast.Expr{Loc: stmt.Loc, Data: &js_ast.EIdentifier{Ref: p.moduleRef}},
 10206  				Name:    "exports",
 10207  				NameLoc: stmt.Loc,
 10208  			}},
 10209  			p.visitExpr(s.Value),
 10210  		))
 10211  		p.recordUsage(p.moduleRef)
 10212  		return stmts
 10213  
 10214  	case *js_ast.SBreak:
 10215  		if s.Label != nil {
 10216  			name := p.loadNameFromRef(s.Label.Ref)
 10217  			s.Label.Ref, _, _ = p.findLabelSymbol(s.Label.Loc, name)
 10218  		} else if !p.fnOrArrowDataVisit.isInsideLoop && !p.fnOrArrowDataVisit.isInsideSwitch {
 10219  			r := js_lexer.RangeOfIdentifier(p.source, stmt.Loc)
 10220  			p.log.AddError(&p.tracker, r, "Cannot use \"break\" here:")
 10221  		}
 10222  
 10223  	case *js_ast.SContinue:
 10224  		if s.Label != nil {
 10225  			name := p.loadNameFromRef(s.Label.Ref)
 10226  			var isLoop, ok bool
 10227  			s.Label.Ref, isLoop, ok = p.findLabelSymbol(s.Label.Loc, name)
 10228  			if ok && !isLoop {
 10229  				r := js_lexer.RangeOfIdentifier(p.source, s.Label.Loc)
 10230  				p.log.AddError(&p.tracker, r, fmt.Sprintf("Cannot continue to label \"%s\"", name))
 10231  			}
 10232  		} else if !p.fnOrArrowDataVisit.isInsideLoop {
 10233  			r := js_lexer.RangeOfIdentifier(p.source, stmt.Loc)
 10234  			p.log.AddError(&p.tracker, r, "Cannot use \"continue\" here:")
 10235  		}
 10236  
 10237  	case *js_ast.SLabel:
 10238  		// Forbid functions inside labels in strict mode
 10239  		if p.isStrictMode() {
 10240  			if _, ok := s.Stmt.Data.(*js_ast.SFunction); ok {
 10241  				p.markStrictModeFeature(labelFunctionStmt, js_lexer.RangeOfIdentifier(p.source, s.Stmt.Loc), "")
 10242  			}
 10243  		}
 10244  
 10245  		p.pushScopeForVisitPass(js_ast.ScopeLabel, stmt.Loc)
 10246  		name := p.loadNameFromRef(s.Name.Ref)
 10247  		if js_lexer.StrictModeReservedWords[name] {
 10248  			p.markStrictModeFeature(reservedWord, js_lexer.RangeOfIdentifier(p.source, s.Name.Loc), name)
 10249  		}
 10250  		ref := p.newSymbol(ast.SymbolLabel, name)
 10251  		s.Name.Ref = ref
 10252  
 10253  		// Duplicate labels are an error
 10254  		for scope := p.currentScope.Parent; scope != nil; scope = scope.Parent {
 10255  			if scope.Label.Ref != ast.InvalidRef && name == p.symbols[scope.Label.Ref.InnerIndex].OriginalName {
 10256  				p.log.AddErrorWithNotes(&p.tracker, js_lexer.RangeOfIdentifier(p.source, s.Name.Loc),
 10257  					fmt.Sprintf("Duplicate label %q", name),
 10258  					[]logger.MsgData{p.tracker.MsgData(js_lexer.RangeOfIdentifier(p.source, scope.Label.Loc),
 10259  						fmt.Sprintf("The original label %q is here:", name))})
 10260  				break
 10261  			}
 10262  			if scope.Kind == js_ast.ScopeFunctionBody {
 10263  				// Labels are only visible within the function they are defined in.
 10264  				break
 10265  			}
 10266  		}
 10267  
 10268  		p.currentScope.Label = ast.LocRef{Loc: s.Name.Loc, Ref: ref}
 10269  		switch s.Stmt.Data.(type) {
 10270  		case *js_ast.SFor, *js_ast.SForIn, *js_ast.SForOf, *js_ast.SWhile, *js_ast.SDoWhile:
 10271  			p.currentScope.LabelStmtIsLoop = true
 10272  		}
 10273  
 10274  		// If we're dropping this statement, consider control flow to be dead
 10275  		_, shouldDropLabel := p.dropLabelsMap[name]
 10276  		old := p.isControlFlowDead
 10277  		if shouldDropLabel {
 10278  			p.isControlFlowDead = true
 10279  		}
 10280  
 10281  		s.Stmt = p.visitSingleStmt(s.Stmt, stmtsNormal)
 10282  		p.popScope()
 10283  
 10284  		// Drop this entire statement if requested
 10285  		if shouldDropLabel {
 10286  			p.isControlFlowDead = old
 10287  			return stmts
 10288  		}
 10289  
 10290  		if p.options.minifySyntax {
 10291  			// Optimize "x: break x" which some people apparently write by hand
 10292  			if child, ok := s.Stmt.Data.(*js_ast.SBreak); ok && child.Label != nil && child.Label.Ref == s.Name.Ref {
 10293  				return stmts
 10294  			}
 10295  
 10296  			// Remove the label if it's not necessary
 10297  			if p.symbols[ref.InnerIndex].UseCountEstimate == 0 {
 10298  				return appendIfOrLabelBodyPreservingScope(stmts, s.Stmt)
 10299  			}
 10300  		}
 10301  
 10302  		// Handle "for await" that has been lowered by moving this label inside the "try"
 10303  		if try, ok := s.Stmt.Data.(*js_ast.STry); ok && len(try.Block.Stmts) > 0 {
 10304  			if _, ok := try.Block.Stmts[0].Data.(*js_ast.SFor); ok {
 10305  				try.Block.Stmts[0] = js_ast.Stmt{Loc: stmt.Loc, Data: &js_ast.SLabel{
 10306  					Stmt:             try.Block.Stmts[0],
 10307  					Name:             s.Name,
 10308  					IsSingleLineStmt: s.IsSingleLineStmt,
 10309  				}}
 10310  				return append(stmts, s.Stmt)
 10311  			}
 10312  		}
 10313  
 10314  	case *js_ast.SLocal:
 10315  		// Silently remove unsupported top-level "await" in dead code branches
 10316  		if s.Kind == js_ast.LocalAwaitUsing && p.fnOrArrowDataVisit.isOutsideFnOrArrow {
 10317  			if p.isControlFlowDead && (p.options.unsupportedJSFeatures.Has(compat.TopLevelAwait) || !p.options.outputFormat.KeepESMImportExportSyntax()) {
 10318  				s.Kind = js_ast.LocalUsing
 10319  			} else {
 10320  				p.liveTopLevelAwaitKeyword = logger.Range{Loc: stmt.Loc, Len: 5}
 10321  				p.markSyntaxFeature(compat.TopLevelAwait, logger.Range{Loc: stmt.Loc, Len: 5})
 10322  			}
 10323  		}
 10324  
 10325  		// Local statements do not end the const local prefix
 10326  		p.currentScope.IsAfterConstLocalPrefix = wasAfterAfterConstLocalPrefix
 10327  
 10328  		for i := range s.Decls {
 10329  			d := &s.Decls[i]
 10330  			p.visitBinding(d.Binding, bindingOpts{})
 10331  
 10332  			// Visit the initializer
 10333  			if d.ValueOrNil.Data != nil {
 10334  				// Fold numeric constants in the initializer
 10335  				oldShouldFoldTypeScriptConstantExpressions := p.shouldFoldTypeScriptConstantExpressions
 10336  				p.shouldFoldTypeScriptConstantExpressions = p.options.minifySyntax && !p.currentScope.IsAfterConstLocalPrefix
 10337  
 10338  				// Propagate the name to keep from the binding into the initializer
 10339  				if id, ok := d.Binding.Data.(*js_ast.BIdentifier); ok {
 10340  					p.nameToKeep = p.symbols[id.Ref.InnerIndex].OriginalName
 10341  					p.nameToKeepIsFor = d.ValueOrNil.Data
 10342  				}
 10343  
 10344  				d.ValueOrNil = p.visitExpr(d.ValueOrNil)
 10345  
 10346  				p.shouldFoldTypeScriptConstantExpressions = oldShouldFoldTypeScriptConstantExpressions
 10347  
 10348  				// Initializing to undefined is implicit, but be careful to not
 10349  				// accidentally cause a syntax error or behavior change by removing
 10350  				// the value
 10351  				//
 10352  				// Good:
 10353  				//   "let a = undefined;" => "let a;"
 10354  				//
 10355  				// Bad (a syntax error):
 10356  				//   "let {} = undefined;" => "let {};"
 10357  				//
 10358  				// Bad (a behavior change):
 10359  				//   "a = 123; var a = undefined;" => "a = 123; var a;"
 10360  				//
 10361  				if p.options.minifySyntax && s.Kind == js_ast.LocalLet {
 10362  					if _, ok := d.Binding.Data.(*js_ast.BIdentifier); ok {
 10363  						if _, ok := d.ValueOrNil.Data.(*js_ast.EUndefined); ok {
 10364  							d.ValueOrNil = js_ast.Expr{}
 10365  						}
 10366  					}
 10367  				}
 10368  
 10369  				// Yarn's PnP data may be stored in a variable: https://github.com/yarnpkg/berry/pull/4320
 10370  				if p.options.decodeHydrateRuntimeStateYarnPnP {
 10371  					if str, ok := d.ValueOrNil.Data.(*js_ast.EString); ok {
 10372  						if id, ok := d.Binding.Data.(*js_ast.BIdentifier); ok {
 10373  							if p.stringLocalsForYarnPnP == nil {
 10374  								p.stringLocalsForYarnPnP = make(map[ast.Ref]stringLocalForYarnPnP)
 10375  							}
 10376  							p.stringLocalsForYarnPnP[id.Ref] = stringLocalForYarnPnP{value: str.Value, loc: d.ValueOrNil.Loc}
 10377  						}
 10378  					}
 10379  				}
 10380  			}
 10381  
 10382  			// Attempt to continue the const local prefix
 10383  			if p.options.minifySyntax && !p.currentScope.IsAfterConstLocalPrefix {
 10384  				if id, ok := d.Binding.Data.(*js_ast.BIdentifier); ok {
 10385  					if s.Kind == js_ast.LocalConst && d.ValueOrNil.Data != nil {
 10386  						if value := js_ast.ExprToConstValue(d.ValueOrNil); value.Kind != js_ast.ConstValueNone {
 10387  							if p.constValues == nil {
 10388  								p.constValues = make(map[ast.Ref]js_ast.ConstValue)
 10389  							}
 10390  							p.constValues[id.Ref] = value
 10391  							continue
 10392  						}
 10393  					}
 10394  
 10395  					if d.ValueOrNil.Data != nil && !isSafeForConstLocalPrefix(d.ValueOrNil) {
 10396  						p.currentScope.IsAfterConstLocalPrefix = true
 10397  					}
 10398  				} else {
 10399  					// A non-identifier binding ends the const local prefix
 10400  					p.currentScope.IsAfterConstLocalPrefix = true
 10401  				}
 10402  			}
 10403  		}
 10404  
 10405  		// Handle being exported inside a namespace
 10406  		if s.IsExport && p.enclosingNamespaceArgRef != nil {
 10407  			wrapIdentifier := func(loc logger.Loc, ref ast.Ref) js_ast.Expr {
 10408  				p.recordUsage(*p.enclosingNamespaceArgRef)
 10409  				return js_ast.Expr{Loc: loc, Data: p.dotOrMangledPropVisit(
 10410  					js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: *p.enclosingNamespaceArgRef}},
 10411  					p.symbols[ref.InnerIndex].OriginalName,
 10412  					loc,
 10413  				)}
 10414  			}
 10415  			for _, decl := range s.Decls {
 10416  				if decl.ValueOrNil.Data != nil {
 10417  					target := js_ast.ConvertBindingToExpr(decl.Binding, wrapIdentifier)
 10418  					if result, ok := p.lowerAssign(target, decl.ValueOrNil, objRestReturnValueIsUnused); ok {
 10419  						target = result
 10420  					} else {
 10421  						target = js_ast.Assign(target, decl.ValueOrNil)
 10422  					}
 10423  					stmts = append(stmts, js_ast.Stmt{Loc: stmt.Loc, Data: &js_ast.SExpr{Value: target}})
 10424  				}
 10425  			}
 10426  			return stmts
 10427  		}
 10428  
 10429  		s.Decls = p.lowerObjectRestInDecls(s.Decls)
 10430  
 10431  		// Optimization: Avoid unnecessary "using" machinery by changing ones
 10432  		// initialized to "null" or "undefined" into a normal variable. Note that
 10433  		// "await using" still needs the "await", so we can't do it for those.
 10434  		if p.options.minifySyntax && s.Kind == js_ast.LocalUsing {
 10435  			s.Kind = js_ast.LocalConst
 10436  			for _, decl := range s.Decls {
 10437  				if t := js_ast.KnownPrimitiveType(decl.ValueOrNil.Data); t != js_ast.PrimitiveNull && t != js_ast.PrimitiveUndefined {
 10438  					s.Kind = js_ast.LocalUsing
 10439  					break
 10440  				}
 10441  			}
 10442  		}
 10443  
 10444  		s.Kind = p.selectLocalKind(s.Kind)
 10445  
 10446  		// Potentially relocate "var" declarations to the top level
 10447  		if s.Kind == js_ast.LocalVar {
 10448  			if assign, ok := p.maybeRelocateVarsToTopLevel(s.Decls, relocateVarsNormal); ok {
 10449  				if assign.Data != nil {
 10450  					stmts = append(stmts, assign)
 10451  				}
 10452  				return stmts
 10453  			}
 10454  		}
 10455  
 10456  	case *js_ast.SExpr:
 10457  		shouldTrimUnsightlyPrimitives := !p.options.minifySyntax && !isUnsightlyPrimitive(s.Value.Data)
 10458  		p.stmtExprValue = s.Value.Data
 10459  		s.Value = p.visitExpr(s.Value)
 10460  
 10461  		// Expressions that have been simplified down to a single primitive don't
 10462  		// have any effect, and are automatically removed during minification.
 10463  		// However, some people are really bothered by seeing them. Remove them
 10464  		// so we don't bother these people.
 10465  		if shouldTrimUnsightlyPrimitives && isUnsightlyPrimitive(s.Value.Data) {
 10466  			return stmts
 10467  		}
 10468  
 10469  		// Trim expressions without side effects
 10470  		if p.options.minifySyntax {
 10471  			s.Value = p.astHelpers.SimplifyUnusedExpr(s.Value, p.options.unsupportedJSFeatures)
 10472  			if s.Value.Data == nil {
 10473  				return stmts
 10474  			}
 10475  		}
 10476  
 10477  	case *js_ast.SThrow:
 10478  		s.Value = p.visitExpr(s.Value)
 10479  
 10480  	case *js_ast.SReturn:
 10481  		// Forbid top-level return inside modules with ECMAScript syntax
 10482  		if p.fnOrArrowDataVisit.isOutsideFnOrArrow {
 10483  			if p.isFileConsideredESM {
 10484  				_, notes := p.whyESModule()
 10485  				p.log.AddErrorWithNotes(&p.tracker, js_lexer.RangeOfIdentifier(p.source, stmt.Loc),
 10486  					"Top-level return cannot be used inside an ECMAScript module", notes)
 10487  			} else {
 10488  				p.hasTopLevelReturn = true
 10489  			}
 10490  		}
 10491  
 10492  		if s.ValueOrNil.Data != nil {
 10493  			s.ValueOrNil = p.visitExpr(s.ValueOrNil)
 10494  
 10495  			// Returning undefined is implicit except when inside an async generator
 10496  			// function, where "return undefined" behaves like "return await undefined"
 10497  			// but just "return" has no "await".
 10498  			if p.options.minifySyntax && (!p.fnOrArrowDataVisit.isAsync || !p.fnOrArrowDataVisit.isGenerator) {
 10499  				if _, ok := s.ValueOrNil.Data.(*js_ast.EUndefined); ok {
 10500  					s.ValueOrNil = js_ast.Expr{}
 10501  				}
 10502  			}
 10503  		}
 10504  
 10505  	case *js_ast.SBlock:
 10506  		p.pushScopeForVisitPass(js_ast.ScopeBlock, stmt.Loc)
 10507  
 10508  		// Pass the "is loop body" status on to the direct children of a block used
 10509  		// as a loop body. This is used to enable optimizations specific to the
 10510  		// topmost scope in a loop body block.
 10511  		if p.loopBody == s {
 10512  			s.Stmts = p.visitStmts(s.Stmts, stmtsLoopBody)
 10513  		} else {
 10514  			s.Stmts = p.visitStmts(s.Stmts, stmtsNormal)
 10515  		}
 10516  
 10517  		p.popScope()
 10518  
 10519  		if p.options.minifySyntax {
 10520  			if len(s.Stmts) == 1 && !statementCaresAboutScope(s.Stmts[0]) {
 10521  				// Unwrap blocks containing a single statement
 10522  				stmt = s.Stmts[0]
 10523  			} else if len(s.Stmts) == 0 {
 10524  				// Trim empty blocks
 10525  				stmt = js_ast.Stmt{Loc: stmt.Loc, Data: js_ast.SEmptyShared}
 10526  			}
 10527  		}
 10528  
 10529  	case *js_ast.SWith:
 10530  		p.markStrictModeFeature(withStatement, js_lexer.RangeOfIdentifier(p.source, stmt.Loc), "")
 10531  		s.Value = p.visitExpr(s.Value)
 10532  		p.pushScopeForVisitPass(js_ast.ScopeWith, s.BodyLoc)
 10533  		s.Body = p.visitSingleStmt(s.Body, stmtsNormal)
 10534  		p.popScope()
 10535  
 10536  	case *js_ast.SWhile:
 10537  		s.Test = p.visitExpr(s.Test)
 10538  		s.Body = p.visitLoopBody(s.Body)
 10539  
 10540  		if p.options.minifySyntax {
 10541  			s.Test = p.astHelpers.SimplifyBooleanExpr(s.Test)
 10542  
 10543  			// A true value is implied
 10544  			testOrNil := s.Test
 10545  			if boolean, sideEffects, ok := js_ast.ToBooleanWithSideEffects(s.Test.Data); ok && boolean && sideEffects == js_ast.NoSideEffects {
 10546  				testOrNil = js_ast.Expr{}
 10547  			}
 10548  
 10549  			// "while (a) {}" => "for (;a;) {}"
 10550  			forS := &js_ast.SFor{TestOrNil: testOrNil, Body: s.Body, IsSingleLineBody: s.IsSingleLineBody}
 10551  			mangleFor(forS)
 10552  			stmt = js_ast.Stmt{Loc: stmt.Loc, Data: forS}
 10553  		}
 10554  
 10555  	case *js_ast.SDoWhile:
 10556  		s.Body = p.visitLoopBody(s.Body)
 10557  		s.Test = p.visitExpr(s.Test)
 10558  
 10559  		if p.options.minifySyntax {
 10560  			s.Test = p.astHelpers.SimplifyBooleanExpr(s.Test)
 10561  		}
 10562  
 10563  	case *js_ast.SIf:
 10564  		s.Test = p.visitExpr(s.Test)
 10565  
 10566  		if p.options.minifySyntax {
 10567  			s.Test = p.astHelpers.SimplifyBooleanExpr(s.Test)
 10568  		}
 10569  
 10570  		// Fold constants
 10571  		boolean, _, ok := js_ast.ToBooleanWithSideEffects(s.Test.Data)
 10572  
 10573  		// Mark the control flow as dead if the branch is never taken
 10574  		if ok && !boolean {
 10575  			old := p.isControlFlowDead
 10576  			p.isControlFlowDead = true
 10577  			s.Yes = p.visitSingleStmt(s.Yes, stmtsNormal)
 10578  			p.isControlFlowDead = old
 10579  		} else {
 10580  			s.Yes = p.visitSingleStmt(s.Yes, stmtsNormal)
 10581  		}
 10582  
 10583  		// The "else" clause is optional
 10584  		if s.NoOrNil.Data != nil {
 10585  			// Mark the control flow as dead if the branch is never taken
 10586  			if ok && boolean {
 10587  				old := p.isControlFlowDead
 10588  				p.isControlFlowDead = true
 10589  				s.NoOrNil = p.visitSingleStmt(s.NoOrNil, stmtsNormal)
 10590  				p.isControlFlowDead = old
 10591  			} else {
 10592  				s.NoOrNil = p.visitSingleStmt(s.NoOrNil, stmtsNormal)
 10593  			}
 10594  
 10595  			// Trim unnecessary "else" clauses
 10596  			if p.options.minifySyntax {
 10597  				if _, ok := s.NoOrNil.Data.(*js_ast.SEmpty); ok {
 10598  					s.NoOrNil = js_ast.Stmt{}
 10599  				}
 10600  			}
 10601  		}
 10602  
 10603  		if p.options.minifySyntax {
 10604  			return p.mangleIf(stmts, stmt.Loc, s)
 10605  		}
 10606  
 10607  	case *js_ast.SFor:
 10608  		p.pushScopeForVisitPass(js_ast.ScopeBlock, stmt.Loc)
 10609  		if s.InitOrNil.Data != nil {
 10610  			p.visitForLoopInit(s.InitOrNil, false)
 10611  		}
 10612  
 10613  		if s.TestOrNil.Data != nil {
 10614  			s.TestOrNil = p.visitExpr(s.TestOrNil)
 10615  
 10616  			if p.options.minifySyntax {
 10617  				s.TestOrNil = p.astHelpers.SimplifyBooleanExpr(s.TestOrNil)
 10618  
 10619  				// A true value is implied
 10620  				if boolean, sideEffects, ok := js_ast.ToBooleanWithSideEffects(s.TestOrNil.Data); ok && boolean && sideEffects == js_ast.NoSideEffects {
 10621  					s.TestOrNil = js_ast.Expr{}
 10622  				}
 10623  			}
 10624  		}
 10625  
 10626  		if s.UpdateOrNil.Data != nil {
 10627  			s.UpdateOrNil = p.visitExpr(s.UpdateOrNil)
 10628  		}
 10629  		s.Body = p.visitLoopBody(s.Body)
 10630  
 10631  		// Potentially relocate "var" declarations to the top level. Note that this
 10632  		// must be done inside the scope of the for loop or they won't be relocated.
 10633  		if s.InitOrNil.Data != nil {
 10634  			if init, ok := s.InitOrNil.Data.(*js_ast.SLocal); ok && init.Kind == js_ast.LocalVar {
 10635  				if assign, ok := p.maybeRelocateVarsToTopLevel(init.Decls, relocateVarsNormal); ok {
 10636  					if assign.Data != nil {
 10637  						s.InitOrNil = assign
 10638  					} else {
 10639  						s.InitOrNil = js_ast.Stmt{}
 10640  					}
 10641  				}
 10642  			}
 10643  		}
 10644  
 10645  		p.popScope()
 10646  
 10647  		if p.options.minifySyntax {
 10648  			mangleFor(s)
 10649  		}
 10650  
 10651  	case *js_ast.SForIn:
 10652  		p.pushScopeForVisitPass(js_ast.ScopeBlock, stmt.Loc)
 10653  		p.visitForLoopInit(s.Init, true)
 10654  		s.Value = p.visitExpr(s.Value)
 10655  		s.Body = p.visitLoopBody(s.Body)
 10656  
 10657  		// Check for a variable initializer
 10658  		if local, ok := s.Init.Data.(*js_ast.SLocal); ok && local.Kind == js_ast.LocalVar && len(local.Decls) == 1 {
 10659  			decl := &local.Decls[0]
 10660  			if id, ok := decl.Binding.Data.(*js_ast.BIdentifier); ok && decl.ValueOrNil.Data != nil {
 10661  				p.markStrictModeFeature(forInVarInit, p.source.RangeOfOperatorBefore(decl.ValueOrNil.Loc, "="), "")
 10662  
 10663  				// Lower for-in variable initializers in case the output is used in strict mode
 10664  				stmts = append(stmts, js_ast.Stmt{Loc: stmt.Loc, Data: &js_ast.SExpr{Value: js_ast.Assign(
 10665  					js_ast.Expr{Loc: decl.Binding.Loc, Data: &js_ast.EIdentifier{Ref: id.Ref}},
 10666  					decl.ValueOrNil,
 10667  				)}})
 10668  				decl.ValueOrNil = js_ast.Expr{}
 10669  			}
 10670  		}
 10671  
 10672  		// Potentially relocate "var" declarations to the top level. Note that this
 10673  		// must be done inside the scope of the for loop or they won't be relocated.
 10674  		if init, ok := s.Init.Data.(*js_ast.SLocal); ok && init.Kind == js_ast.LocalVar {
 10675  			if replacement, ok := p.maybeRelocateVarsToTopLevel(init.Decls, relocateVarsForInOrForOf); ok {
 10676  				s.Init = replacement
 10677  			}
 10678  		}
 10679  
 10680  		p.popScope()
 10681  
 10682  		p.lowerObjectRestInForLoopInit(s.Init, &s.Body)
 10683  
 10684  	case *js_ast.SForOf:
 10685  		// Silently remove unsupported top-level "await" in dead code branches
 10686  		if s.Await.Len > 0 && p.fnOrArrowDataVisit.isOutsideFnOrArrow {
 10687  			if p.isControlFlowDead && (p.options.unsupportedJSFeatures.Has(compat.TopLevelAwait) || !p.options.outputFormat.KeepESMImportExportSyntax()) {
 10688  				s.Await = logger.Range{}
 10689  			} else {
 10690  				p.liveTopLevelAwaitKeyword = s.Await
 10691  				p.markSyntaxFeature(compat.TopLevelAwait, s.Await)
 10692  			}
 10693  		}
 10694  
 10695  		p.pushScopeForVisitPass(js_ast.ScopeBlock, stmt.Loc)
 10696  		p.visitForLoopInit(s.Init, true)
 10697  		s.Value = p.visitExpr(s.Value)
 10698  		s.Body = p.visitLoopBody(s.Body)
 10699  
 10700  		// Potentially relocate "var" declarations to the top level. Note that this
 10701  		// must be done inside the scope of the for loop or they won't be relocated.
 10702  		if init, ok := s.Init.Data.(*js_ast.SLocal); ok && init.Kind == js_ast.LocalVar {
 10703  			if replacement, ok := p.maybeRelocateVarsToTopLevel(init.Decls, relocateVarsForInOrForOf); ok {
 10704  				s.Init = replacement
 10705  			}
 10706  		}
 10707  
 10708  		// Handle "for (using x of y)" and "for (await using x of y)"
 10709  		if local, ok := s.Init.Data.(*js_ast.SLocal); ok {
 10710  			if local.Kind == js_ast.LocalUsing && p.options.unsupportedJSFeatures.Has(compat.Using) {
 10711  				p.lowerUsingDeclarationInForOf(s.Init.Loc, local, &s.Body)
 10712  			} else if local.Kind == js_ast.LocalAwaitUsing {
 10713  				if p.fnOrArrowDataVisit.isOutsideFnOrArrow {
 10714  					if p.isControlFlowDead && (p.options.unsupportedJSFeatures.Has(compat.TopLevelAwait) || !p.options.outputFormat.KeepESMImportExportSyntax()) {
 10715  						// Silently remove unsupported top-level "await" in dead code branches
 10716  						local.Kind = js_ast.LocalUsing
 10717  					} else {
 10718  						p.liveTopLevelAwaitKeyword = logger.Range{Loc: s.Init.Loc, Len: 5}
 10719  						p.markSyntaxFeature(compat.TopLevelAwait, p.liveTopLevelAwaitKeyword)
 10720  					}
 10721  					if p.options.unsupportedJSFeatures.Has(compat.Using) {
 10722  						p.lowerUsingDeclarationInForOf(s.Init.Loc, local, &s.Body)
 10723  					}
 10724  				} else if p.options.unsupportedJSFeatures.Has(compat.Using) || p.options.unsupportedJSFeatures.Has(compat.AsyncAwait) ||
 10725  					(p.options.unsupportedJSFeatures.Has(compat.AsyncGenerator) && p.fnOrArrowDataVisit.isGenerator) {
 10726  					p.lowerUsingDeclarationInForOf(s.Init.Loc, local, &s.Body)
 10727  				}
 10728  			}
 10729  		}
 10730  
 10731  		p.popScope()
 10732  
 10733  		p.lowerObjectRestInForLoopInit(s.Init, &s.Body)
 10734  
 10735  		// Lower "for await" if it's unsupported if it's in a lowered async generator
 10736  		if s.Await.Len > 0 && (p.options.unsupportedJSFeatures.Has(compat.ForAwait) ||
 10737  			(p.options.unsupportedJSFeatures.Has(compat.AsyncGenerator) && p.fnOrArrowDataVisit.isGenerator)) {
 10738  			return p.lowerForAwaitLoop(stmt.Loc, s, stmts)
 10739  		}
 10740  
 10741  	case *js_ast.STry:
 10742  		p.pushScopeForVisitPass(js_ast.ScopeBlock, stmt.Loc)
 10743  		if p.fnOrArrowDataVisit.tryBodyCount == 0 {
 10744  			if s.Catch != nil {
 10745  				p.fnOrArrowDataVisit.tryCatchLoc = s.Catch.Loc
 10746  			} else {
 10747  				p.fnOrArrowDataVisit.tryCatchLoc = stmt.Loc
 10748  			}
 10749  		}
 10750  		p.fnOrArrowDataVisit.tryBodyCount++
 10751  		s.Block.Stmts = p.visitStmts(s.Block.Stmts, stmtsNormal)
 10752  		p.fnOrArrowDataVisit.tryBodyCount--
 10753  		p.popScope()
 10754  
 10755  		if s.Catch != nil {
 10756  			p.pushScopeForVisitPass(js_ast.ScopeCatchBinding, s.Catch.Loc)
 10757  			if s.Catch.BindingOrNil.Data != nil {
 10758  				p.visitBinding(s.Catch.BindingOrNil, bindingOpts{})
 10759  			}
 10760  
 10761  			p.pushScopeForVisitPass(js_ast.ScopeBlock, s.Catch.BlockLoc)
 10762  			s.Catch.Block.Stmts = p.visitStmts(s.Catch.Block.Stmts, stmtsNormal)
 10763  			p.popScope()
 10764  
 10765  			p.lowerObjectRestInCatchBinding(s.Catch)
 10766  			p.popScope()
 10767  		}
 10768  
 10769  		if s.Finally != nil {
 10770  			p.pushScopeForVisitPass(js_ast.ScopeBlock, s.Finally.Loc)
 10771  			s.Finally.Block.Stmts = p.visitStmts(s.Finally.Block.Stmts, stmtsNormal)
 10772  			p.popScope()
 10773  		}
 10774  
 10775  	case *js_ast.SSwitch:
 10776  		s.Test = p.visitExpr(s.Test)
 10777  		p.pushScopeForVisitPass(js_ast.ScopeBlock, s.BodyLoc)
 10778  		oldIsInsideSwitch := p.fnOrArrowDataVisit.isInsideSwitch
 10779  		p.fnOrArrowDataVisit.isInsideSwitch = true
 10780  		for i, c := range s.Cases {
 10781  			if c.ValueOrNil.Data != nil {
 10782  				c.ValueOrNil = p.visitExpr(c.ValueOrNil)
 10783  				p.warnAboutEqualityCheck("case", c.ValueOrNil, c.ValueOrNil.Loc)
 10784  				p.warnAboutTypeofAndString(s.Test, c.ValueOrNil, onlyCheckOriginalOrder)
 10785  			}
 10786  			c.Body = p.visitStmts(c.Body, stmtsSwitch)
 10787  
 10788  			// Make sure the assignment to the body above is preserved
 10789  			s.Cases[i] = c
 10790  		}
 10791  		p.fnOrArrowDataVisit.isInsideSwitch = oldIsInsideSwitch
 10792  		p.popScope()
 10793  
 10794  		// Check for duplicate case values
 10795  		p.duplicateCaseChecker.reset()
 10796  		for _, c := range s.Cases {
 10797  			if c.ValueOrNil.Data != nil {
 10798  				p.duplicateCaseChecker.check(p, c.ValueOrNil)
 10799  			}
 10800  		}
 10801  
 10802  		// Unwrap switch statements in dead code
 10803  		if p.options.minifySyntax && p.isControlFlowDead {
 10804  			for _, c := range s.Cases {
 10805  				stmts = append(stmts, c.Body...)
 10806  			}
 10807  			return stmts
 10808  		}
 10809  
 10810  		// "using" declarations inside switch statements must be special-cased
 10811  		if lowered := p.maybeLowerUsingDeclarationsInSwitch(stmt.Loc, s); lowered != nil {
 10812  			return append(stmts, lowered...)
 10813  		}
 10814  
 10815  	case *js_ast.SFunction:
 10816  		p.visitFn(&s.Fn, s.Fn.OpenParenLoc, visitFnOpts{})
 10817  
 10818  		// Strip this function declaration if it was overwritten
 10819  		if p.symbols[s.Fn.Name.Ref.InnerIndex].Flags.Has(ast.RemoveOverwrittenFunctionDeclaration) && !s.IsExport {
 10820  			return stmts
 10821  		}
 10822  
 10823  		if p.options.minifySyntax && !s.Fn.IsGenerator && !s.Fn.IsAsync && !s.Fn.HasRestArg && s.Fn.Name != nil {
 10824  			if len(s.Fn.Body.Block.Stmts) == 0 {
 10825  				// Mark if this function is an empty function
 10826  				hasSideEffectFreeArguments := true
 10827  				for _, arg := range s.Fn.Args {
 10828  					if _, ok := arg.Binding.Data.(*js_ast.BIdentifier); !ok {
 10829  						hasSideEffectFreeArguments = false
 10830  						break
 10831  					}
 10832  				}
 10833  				if hasSideEffectFreeArguments {
 10834  					p.symbols[s.Fn.Name.Ref.InnerIndex].Flags |= ast.IsEmptyFunction
 10835  				}
 10836  			} else if len(s.Fn.Args) == 1 && len(s.Fn.Body.Block.Stmts) == 1 {
 10837  				// Mark if this function is an identity function
 10838  				if arg := s.Fn.Args[0]; arg.DefaultOrNil.Data == nil {
 10839  					if id, ok := arg.Binding.Data.(*js_ast.BIdentifier); ok {
 10840  						if ret, ok := s.Fn.Body.Block.Stmts[0].Data.(*js_ast.SReturn); ok {
 10841  							if retID, ok := ret.ValueOrNil.Data.(*js_ast.EIdentifier); ok && id.Ref == retID.Ref {
 10842  								p.symbols[s.Fn.Name.Ref.InnerIndex].Flags |= ast.IsIdentityFunction
 10843  							}
 10844  						}
 10845  					}
 10846  				}
 10847  			}
 10848  		}
 10849  
 10850  		// Handle exporting this function from a namespace
 10851  		if s.IsExport && p.enclosingNamespaceArgRef != nil {
 10852  			s.IsExport = false
 10853  			stmts = append(stmts, stmt, js_ast.AssignStmt(
 10854  				js_ast.Expr{Loc: stmt.Loc, Data: p.dotOrMangledPropVisit(
 10855  					js_ast.Expr{Loc: stmt.Loc, Data: &js_ast.EIdentifier{Ref: *p.enclosingNamespaceArgRef}},
 10856  					p.symbols[s.Fn.Name.Ref.InnerIndex].OriginalName,
 10857  					s.Fn.Name.Loc,
 10858  				)},
 10859  				js_ast.Expr{Loc: s.Fn.Name.Loc, Data: &js_ast.EIdentifier{Ref: s.Fn.Name.Ref}},
 10860  			))
 10861  		} else {
 10862  			stmts = append(stmts, stmt)
 10863  		}
 10864  
 10865  		// Optionally preserve the name
 10866  		if p.options.keepNames {
 10867  			symbol := &p.symbols[s.Fn.Name.Ref.InnerIndex]
 10868  			symbol.Flags |= ast.DidKeepName
 10869  			fn := js_ast.Expr{Loc: s.Fn.Name.Loc, Data: &js_ast.EIdentifier{Ref: s.Fn.Name.Ref}}
 10870  			stmts = append(stmts, p.keepClassOrFnSymbolName(s.Fn.Name.Loc, fn, symbol.OriginalName))
 10871  		}
 10872  		return stmts
 10873  
 10874  	case *js_ast.SClass:
 10875  		result := p.visitClass(stmt.Loc, &s.Class, ast.InvalidRef, "")
 10876  
 10877  		// Remove the export flag inside a namespace
 10878  		var nameToExport string
 10879  		wasExportInsideNamespace := s.IsExport && p.enclosingNamespaceArgRef != nil
 10880  		if wasExportInsideNamespace {
 10881  			nameToExport = p.symbols[s.Class.Name.Ref.InnerIndex].OriginalName
 10882  			s.IsExport = false
 10883  		}
 10884  
 10885  		// Lower class field syntax for browsers that don't support it
 10886  		classStmts, _ := p.lowerClass(stmt, js_ast.Expr{}, result, "")
 10887  
 10888  		// Remember if the class was side-effect free before lowering
 10889  		if result.canBeRemovedIfUnused {
 10890  			for _, classStmt := range classStmts {
 10891  				if s2, ok := classStmt.Data.(*js_ast.SExpr); ok {
 10892  					s2.IsFromClassOrFnThatCanBeRemovedIfUnused = true
 10893  				}
 10894  			}
 10895  		}
 10896  
 10897  		stmts = append(stmts, classStmts...)
 10898  
 10899  		// Handle exporting this class from a namespace
 10900  		if wasExportInsideNamespace {
 10901  			stmts = append(stmts, js_ast.AssignStmt(
 10902  				js_ast.Expr{Loc: stmt.Loc, Data: p.dotOrMangledPropVisit(
 10903  					js_ast.Expr{Loc: stmt.Loc, Data: &js_ast.EIdentifier{Ref: *p.enclosingNamespaceArgRef}},
 10904  					nameToExport,
 10905  					s.Class.Name.Loc,
 10906  				)},
 10907  				js_ast.Expr{Loc: s.Class.Name.Loc, Data: &js_ast.EIdentifier{Ref: s.Class.Name.Ref}},
 10908  			))
 10909  		}
 10910  
 10911  		return stmts
 10912  
 10913  	case *js_ast.SEnum:
 10914  		// Do not end the const local prefix after TypeScript enums. We process
 10915  		// them first within their scope so that they are inlined into all code in
 10916  		// that scope. We don't want that to cause the const local prefix to end.
 10917  		p.currentScope.IsAfterConstLocalPrefix = wasAfterAfterConstLocalPrefix
 10918  
 10919  		// Track cross-module enum constants during bundling
 10920  		var tsTopLevelEnumValues map[string]js_ast.TSEnumValue
 10921  		if p.currentScope == p.moduleScope && p.options.mode == config.ModeBundle {
 10922  			tsTopLevelEnumValues = make(map[string]js_ast.TSEnumValue)
 10923  		}
 10924  
 10925  		p.recordDeclaredSymbol(s.Name.Ref)
 10926  		p.pushScopeForVisitPass(js_ast.ScopeEntry, stmt.Loc)
 10927  		p.recordDeclaredSymbol(s.Arg)
 10928  
 10929  		// Scan ahead for any variables inside this namespace. This must be done
 10930  		// ahead of time before visiting any statements inside the namespace
 10931  		// because we may end up visiting the uses before the declarations.
 10932  		// We need to convert the uses into property accesses on the namespace.
 10933  		for _, value := range s.Values {
 10934  			if value.Ref != ast.InvalidRef {
 10935  				p.isExportedInsideNamespace[value.Ref] = s.Arg
 10936  			}
 10937  		}
 10938  
 10939  		// Values without initializers are initialized to one more than the
 10940  		// previous value if the previous value is numeric. Otherwise values
 10941  		// without initializers are initialized to undefined.
 10942  		nextNumericValue := float64(0)
 10943  		hasNumericValue := true
 10944  		valueExprs := []js_ast.Expr{}
 10945  		allValuesArePure := true
 10946  
 10947  		// Update the exported members of this enum as we constant fold each one
 10948  		exportedMembers := p.currentScope.TSNamespace.ExportedMembers
 10949  
 10950  		// We normally don't fold numeric constants because they might increase code
 10951  		// size, but it's important to fold numeric constants inside enums since
 10952  		// that's what the TypeScript compiler does.
 10953  		oldShouldFoldTypeScriptConstantExpressions := p.shouldFoldTypeScriptConstantExpressions
 10954  		p.shouldFoldTypeScriptConstantExpressions = true
 10955  
 10956  		// Create an assignment for each enum value
 10957  		for _, value := range s.Values {
 10958  			name := helpers.UTF16ToString(value.Name)
 10959  			var assignTarget js_ast.Expr
 10960  			hasStringValue := false
 10961  
 10962  			if value.ValueOrNil.Data != nil {
 10963  				value.ValueOrNil = p.visitExpr(value.ValueOrNil)
 10964  				hasNumericValue = false
 10965  
 10966  				// "See through" any wrapped comments
 10967  				underlyingValue := value.ValueOrNil
 10968  				if inlined, ok := value.ValueOrNil.Data.(*js_ast.EInlinedEnum); ok {
 10969  					underlyingValue = inlined.Value
 10970  				}
 10971  
 10972  				switch e := underlyingValue.Data.(type) {
 10973  				case *js_ast.ENumber:
 10974  					if tsTopLevelEnumValues != nil {
 10975  						tsTopLevelEnumValues[name] = js_ast.TSEnumValue{Number: e.Value}
 10976  					}
 10977  					member := exportedMembers[name]
 10978  					member.Data = &js_ast.TSNamespaceMemberEnumNumber{Value: e.Value}
 10979  					exportedMembers[name] = member
 10980  					p.refToTSNamespaceMemberData[value.Ref] = member.Data
 10981  					hasNumericValue = true
 10982  					nextNumericValue = e.Value + 1
 10983  
 10984  				case *js_ast.EString:
 10985  					if tsTopLevelEnumValues != nil {
 10986  						tsTopLevelEnumValues[name] = js_ast.TSEnumValue{String: e.Value}
 10987  					}
 10988  					member := exportedMembers[name]
 10989  					member.Data = &js_ast.TSNamespaceMemberEnumString{Value: e.Value}
 10990  					exportedMembers[name] = member
 10991  					p.refToTSNamespaceMemberData[value.Ref] = member.Data
 10992  					hasStringValue = true
 10993  
 10994  				default:
 10995  					if js_ast.KnownPrimitiveType(underlyingValue.Data) == js_ast.PrimitiveString {
 10996  						hasStringValue = true
 10997  					}
 10998  					if !p.astHelpers.ExprCanBeRemovedIfUnused(underlyingValue) {
 10999  						allValuesArePure = false
 11000  					}
 11001  				}
 11002  			} else if hasNumericValue {
 11003  				if tsTopLevelEnumValues != nil {
 11004  					tsTopLevelEnumValues[name] = js_ast.TSEnumValue{Number: nextNumericValue}
 11005  				}
 11006  				member := exportedMembers[name]
 11007  				member.Data = &js_ast.TSNamespaceMemberEnumNumber{Value: nextNumericValue}
 11008  				exportedMembers[name] = member
 11009  				p.refToTSNamespaceMemberData[value.Ref] = member.Data
 11010  				value.ValueOrNil = js_ast.Expr{Loc: value.Loc, Data: &js_ast.ENumber{Value: nextNumericValue}}
 11011  				nextNumericValue++
 11012  			} else {
 11013  				value.ValueOrNil = js_ast.Expr{Loc: value.Loc, Data: js_ast.EUndefinedShared}
 11014  			}
 11015  
 11016  			if p.options.minifySyntax && js_ast.IsIdentifier(name) {
 11017  				// "Enum.Name = value"
 11018  				assignTarget = js_ast.Assign(
 11019  					js_ast.Expr{Loc: value.Loc, Data: &js_ast.EDot{
 11020  						Target:  js_ast.Expr{Loc: value.Loc, Data: &js_ast.EIdentifier{Ref: s.Arg}},
 11021  						Name:    name,
 11022  						NameLoc: value.Loc,
 11023  					}},
 11024  					value.ValueOrNil,
 11025  				)
 11026  			} else {
 11027  				// "Enum['Name'] = value"
 11028  				assignTarget = js_ast.Assign(
 11029  					js_ast.Expr{Loc: value.Loc, Data: &js_ast.EIndex{
 11030  						Target: js_ast.Expr{Loc: value.Loc, Data: &js_ast.EIdentifier{Ref: s.Arg}},
 11031  						Index:  js_ast.Expr{Loc: value.Loc, Data: &js_ast.EString{Value: value.Name}},
 11032  					}},
 11033  					value.ValueOrNil,
 11034  				)
 11035  			}
 11036  			p.recordUsage(s.Arg)
 11037  
 11038  			// String-valued enums do not form a two-way map
 11039  			if hasStringValue {
 11040  				valueExprs = append(valueExprs, assignTarget)
 11041  			} else {
 11042  				// "Enum[assignTarget] = 'Name'"
 11043  				valueExprs = append(valueExprs, js_ast.Assign(
 11044  					js_ast.Expr{Loc: value.Loc, Data: &js_ast.EIndex{
 11045  						Target: js_ast.Expr{Loc: value.Loc, Data: &js_ast.EIdentifier{Ref: s.Arg}},
 11046  						Index:  assignTarget,
 11047  					}},
 11048  					js_ast.Expr{Loc: value.Loc, Data: &js_ast.EString{Value: value.Name}},
 11049  				))
 11050  				p.recordUsage(s.Arg)
 11051  			}
 11052  		}
 11053  
 11054  		p.popScope()
 11055  		p.shouldFoldTypeScriptConstantExpressions = oldShouldFoldTypeScriptConstantExpressions
 11056  
 11057  		// Track all exported top-level enums for cross-module inlining
 11058  		if tsTopLevelEnumValues != nil {
 11059  			if p.tsEnums == nil {
 11060  				p.tsEnums = make(map[ast.Ref]map[string]js_ast.TSEnumValue)
 11061  			}
 11062  			p.tsEnums[s.Name.Ref] = tsTopLevelEnumValues
 11063  		}
 11064  
 11065  		// Wrap this enum definition in a closure
 11066  		stmts = p.generateClosureForTypeScriptEnum(
 11067  			stmts, stmt.Loc, s.IsExport, s.Name.Loc, s.Name.Ref, s.Arg, valueExprs, allValuesArePure)
 11068  		return stmts
 11069  
 11070  	case *js_ast.SNamespace:
 11071  		p.recordDeclaredSymbol(s.Name.Ref)
 11072  
 11073  		// Scan ahead for any variables inside this namespace. This must be done
 11074  		// ahead of time before visiting any statements inside the namespace
 11075  		// because we may end up visiting the uses before the declarations.
 11076  		// We need to convert the uses into property accesses on the namespace.
 11077  		for _, childStmt := range s.Stmts {
 11078  			if local, ok := childStmt.Data.(*js_ast.SLocal); ok {
 11079  				if local.IsExport {
 11080  					js_ast.ForEachIdentifierBindingInDecls(local.Decls, func(loc logger.Loc, b *js_ast.BIdentifier) {
 11081  						p.isExportedInsideNamespace[b.Ref] = s.Arg
 11082  					})
 11083  				}
 11084  			}
 11085  		}
 11086  
 11087  		oldEnclosingNamespaceArgRef := p.enclosingNamespaceArgRef
 11088  		p.enclosingNamespaceArgRef = &s.Arg
 11089  		p.pushScopeForVisitPass(js_ast.ScopeEntry, stmt.Loc)
 11090  		p.recordDeclaredSymbol(s.Arg)
 11091  		stmtsInsideNamespace := p.visitStmtsAndPrependTempRefs(s.Stmts, prependTempRefsOpts{kind: stmtsFnBody})
 11092  		p.popScope()
 11093  		p.enclosingNamespaceArgRef = oldEnclosingNamespaceArgRef
 11094  
 11095  		// Generate a closure for this namespace
 11096  		stmts = p.generateClosureForTypeScriptNamespaceOrEnum(
 11097  			stmts, stmt.Loc, s.IsExport, s.Name.Loc, s.Name.Ref, s.Arg, stmtsInsideNamespace)
 11098  		return stmts
 11099  
 11100  	default:
 11101  		panic("Internal error")
 11102  	}
 11103  
 11104  	stmts = append(stmts, stmt)
 11105  	return stmts
 11106  }
 11107  
 11108  func isUnsightlyPrimitive(data js_ast.E) bool {
 11109  	switch data.(type) {
 11110  	case *js_ast.EBoolean, *js_ast.ENull, *js_ast.EUndefined, *js_ast.ENumber, *js_ast.EBigInt, *js_ast.EString:
 11111  		return true
 11112  	}
 11113  	return false
 11114  }
 11115  
 11116  // If we encounter a variable initializer that could possibly trigger access to
 11117  // a constant declared later on, then we need to end the const local prefix.
 11118  // We want to avoid situations like this:
 11119  //
 11120  //	const x = y; // This is supposed to throw due to TDZ
 11121  //	const y = 1;
 11122  //
 11123  // or this:
 11124  //
 11125  //	const x = 1;
 11126  //	const y = foo(); // This is supposed to throw due to TDZ
 11127  //	const z = 2;
 11128  //	const foo = () => z;
 11129  //
 11130  // But a situation like this is ok:
 11131  //
 11132  //	const x = 1;
 11133  //	const y = [() => x + z];
 11134  //	const z = 2;
 11135  func isSafeForConstLocalPrefix(expr js_ast.Expr) bool {
 11136  	switch e := expr.Data.(type) {
 11137  	case *js_ast.EMissing, *js_ast.EString, *js_ast.ERegExp, *js_ast.EBigInt, *js_ast.EFunction, *js_ast.EArrow:
 11138  		return true
 11139  
 11140  	case *js_ast.EArray:
 11141  		for _, item := range e.Items {
 11142  			if !isSafeForConstLocalPrefix(item) {
 11143  				return false
 11144  			}
 11145  		}
 11146  		return true
 11147  
 11148  	case *js_ast.EObject:
 11149  		// For now just allow "{}" and forbid everything else
 11150  		return len(e.Properties) == 0
 11151  	}
 11152  
 11153  	return false
 11154  }
 11155  
 11156  type relocateVarsMode uint8
 11157  
 11158  const (
 11159  	relocateVarsNormal relocateVarsMode = iota
 11160  	relocateVarsForInOrForOf
 11161  )
 11162  
 11163  // If we are currently in a hoisted child of the module scope, relocate these
 11164  // declarations to the top level and return an equivalent assignment statement.
 11165  // Make sure to check that the declaration kind is "var" before calling this.
 11166  // And make sure to check that the returned statement is not the zero value.
 11167  //
 11168  // This is done to make it easier to traverse top-level declarations in the linker
 11169  // during bundling. Now it is sufficient to just scan the top-level statements
 11170  // instead of having to traverse recursively into the statement tree.
 11171  func (p *parser) maybeRelocateVarsToTopLevel(decls []js_ast.Decl, mode relocateVarsMode) (js_ast.Stmt, bool) {
 11172  	// Only do this when bundling, and not when the scope is already top-level
 11173  	if p.options.mode != config.ModeBundle || p.currentScope == p.moduleScope {
 11174  		return js_ast.Stmt{}, false
 11175  	}
 11176  
 11177  	// Only do this if we're not inside a function
 11178  	scope := p.currentScope
 11179  	for !scope.Kind.StopsHoisting() {
 11180  		scope = scope.Parent
 11181  	}
 11182  	if scope != p.moduleScope {
 11183  		return js_ast.Stmt{}, false
 11184  	}
 11185  
 11186  	// Convert the declarations to assignments
 11187  	wrapIdentifier := func(loc logger.Loc, ref ast.Ref) js_ast.Expr {
 11188  		p.relocatedTopLevelVars = append(p.relocatedTopLevelVars, ast.LocRef{Loc: loc, Ref: ref})
 11189  		p.recordUsage(ref)
 11190  		return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}}
 11191  	}
 11192  	var value js_ast.Expr
 11193  	for _, decl := range decls {
 11194  		binding := js_ast.ConvertBindingToExpr(decl.Binding, wrapIdentifier)
 11195  		if decl.ValueOrNil.Data != nil {
 11196  			value = js_ast.JoinWithComma(value, js_ast.Assign(binding, decl.ValueOrNil))
 11197  		} else if mode == relocateVarsForInOrForOf {
 11198  			value = js_ast.JoinWithComma(value, binding)
 11199  		}
 11200  	}
 11201  	if value.Data == nil {
 11202  		// If none of the variables had any initializers, just remove the declarations
 11203  		return js_ast.Stmt{}, true
 11204  	}
 11205  	return js_ast.Stmt{Loc: value.Loc, Data: &js_ast.SExpr{Value: value}}, true
 11206  }
 11207  
 11208  func (p *parser) markExprAsParenthesized(value js_ast.Expr, openParenLoc logger.Loc, isAsync bool) {
 11209  	// Don't lose comments due to parentheses. For example, we don't want to lose
 11210  	// the comment here:
 11211  	//
 11212  	//   ( /* comment */ (foo) );
 11213  	//
 11214  	if !isAsync {
 11215  		if comments, ok := p.exprComments[openParenLoc]; ok {
 11216  			delete(p.exprComments, openParenLoc)
 11217  			p.exprComments[value.Loc] = append(comments, p.exprComments[value.Loc]...)
 11218  		}
 11219  	}
 11220  
 11221  	switch e := value.Data.(type) {
 11222  	case *js_ast.EArray:
 11223  		e.IsParenthesized = true
 11224  	case *js_ast.EObject:
 11225  		e.IsParenthesized = true
 11226  	}
 11227  }
 11228  
 11229  func (p *parser) maybeTransposeIfExprChain(expr js_ast.Expr, visit func(js_ast.Expr) js_ast.Expr) js_ast.Expr {
 11230  	if e, ok := expr.Data.(*js_ast.EIf); ok {
 11231  		e.Yes = p.maybeTransposeIfExprChain(e.Yes, visit)
 11232  		e.No = p.maybeTransposeIfExprChain(e.No, visit)
 11233  		return expr
 11234  	}
 11235  	return visit(expr)
 11236  }
 11237  
 11238  func (p *parser) iifeCanBeRemovedIfUnused(args []js_ast.Arg, body js_ast.FnBody) bool {
 11239  	for _, arg := range args {
 11240  		if arg.DefaultOrNil.Data != nil && !p.astHelpers.ExprCanBeRemovedIfUnused(arg.DefaultOrNil) {
 11241  			// The default value has a side effect
 11242  			return false
 11243  		}
 11244  
 11245  		if _, ok := arg.Binding.Data.(*js_ast.BIdentifier); !ok {
 11246  			// Destructuring is a side effect (due to property access)
 11247  			return false
 11248  		}
 11249  	}
 11250  
 11251  	// Check whether any statements have side effects or not. Consider return
 11252  	// statements as not having side effects because if the IIFE can be removed
 11253  	// then we know the return value is unused, so we know that returning the
 11254  	// value has no side effects.
 11255  	return p.astHelpers.StmtsCanBeRemovedIfUnused(body.Block.Stmts, js_ast.ReturnCanBeRemovedIfUnused)
 11256  }
 11257  
 11258  type captureValueMode uint8
 11259  
 11260  const (
 11261  	valueDefinitelyNotMutated captureValueMode = iota
 11262  	valueCouldBeMutated
 11263  )
 11264  
 11265  // This is a helper function to use when you need to capture a value that may
 11266  // have side effects so you can use it multiple times. It guarantees that the
 11267  // side effects take place exactly once.
 11268  //
 11269  // Example usage:
 11270  //
 11271  //	// "value" => "value + value"
 11272  //	// "value()" => "(_a = value(), _a + _a)"
 11273  //	valueFunc, wrapFunc := p.captureValueWithPossibleSideEffects(loc, 2, value)
 11274  //	return wrapFunc(js_ast.Expr{Loc: loc, Data: &js_ast.EBinary{
 11275  //	  Op: js_ast.BinOpAdd,
 11276  //	  Left: valueFunc(),
 11277  //	  Right: valueFunc(),
 11278  //	}})
 11279  //
 11280  // This returns a function for generating references instead of a raw reference
 11281  // because AST nodes are supposed to be unique in memory, not aliases of other
 11282  // AST nodes. That way you can mutate one during lowering without having to
 11283  // worry about messing up other nodes.
 11284  func (p *parser) captureValueWithPossibleSideEffects(
 11285  	loc logger.Loc, // The location to use for the generated references
 11286  	count int, // The expected number of references to generate
 11287  	value js_ast.Expr, // The value that might have side effects
 11288  	mode captureValueMode, // Say if "value" might be mutated and must be captured
 11289  ) (
 11290  	func() js_ast.Expr, // Generates reference expressions "_a"
 11291  	func(js_ast.Expr) js_ast.Expr, // Call this on the final expression
 11292  ) {
 11293  	wrapFunc := func(expr js_ast.Expr) js_ast.Expr {
 11294  		// Make sure side effects still happen if no expression was generated
 11295  		if expr.Data == nil {
 11296  			return value
 11297  		}
 11298  		return expr
 11299  	}
 11300  
 11301  	// Referencing certain expressions more than once has no side effects, so we
 11302  	// can just create them inline without capturing them in a temporary variable
 11303  	var valueFunc func() js_ast.Expr
 11304  	switch e := value.Data.(type) {
 11305  	case *js_ast.ENull:
 11306  		valueFunc = func() js_ast.Expr { return js_ast.Expr{Loc: loc, Data: js_ast.ENullShared} }
 11307  	case *js_ast.EUndefined:
 11308  		valueFunc = func() js_ast.Expr { return js_ast.Expr{Loc: loc, Data: js_ast.EUndefinedShared} }
 11309  	case *js_ast.EThis:
 11310  		valueFunc = func() js_ast.Expr { return js_ast.Expr{Loc: loc, Data: js_ast.EThisShared} }
 11311  	case *js_ast.EBoolean:
 11312  		valueFunc = func() js_ast.Expr { return js_ast.Expr{Loc: loc, Data: &js_ast.EBoolean{Value: e.Value}} }
 11313  	case *js_ast.ENumber:
 11314  		valueFunc = func() js_ast.Expr { return js_ast.Expr{Loc: loc, Data: &js_ast.ENumber{Value: e.Value}} }
 11315  	case *js_ast.EBigInt:
 11316  		valueFunc = func() js_ast.Expr { return js_ast.Expr{Loc: loc, Data: &js_ast.EBigInt{Value: e.Value}} }
 11317  	case *js_ast.EString:
 11318  		valueFunc = func() js_ast.Expr { return js_ast.Expr{Loc: loc, Data: &js_ast.EString{Value: e.Value}} }
 11319  	case *js_ast.EPrivateIdentifier:
 11320  		valueFunc = func() js_ast.Expr { return js_ast.Expr{Loc: loc, Data: &js_ast.EPrivateIdentifier{Ref: e.Ref}} }
 11321  	case *js_ast.EIdentifier:
 11322  		if mode == valueDefinitelyNotMutated {
 11323  			valueFunc = func() js_ast.Expr {
 11324  				// Make sure we record this usage in the usage count so that duplicating
 11325  				// a single-use reference means it's no longer considered a single-use
 11326  				// reference. Otherwise the single-use reference inlining code may
 11327  				// incorrectly inline the initializer into the first reference, leaving
 11328  				// the second reference without a definition.
 11329  				p.recordUsage(e.Ref)
 11330  				return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: e.Ref}}
 11331  			}
 11332  		}
 11333  	}
 11334  	if valueFunc != nil {
 11335  		return valueFunc, wrapFunc
 11336  	}
 11337  
 11338  	// We don't need to worry about side effects if the value won't be used
 11339  	// multiple times. This special case lets us avoid generating a temporary
 11340  	// reference.
 11341  	if count < 2 {
 11342  		return func() js_ast.Expr {
 11343  			return value
 11344  		}, wrapFunc
 11345  	}
 11346  
 11347  	// Otherwise, fall back to generating a temporary reference
 11348  	tempRef := ast.InvalidRef
 11349  
 11350  	// If we're in a function argument scope, then we won't be able to generate
 11351  	// symbols in this scope to store stuff, since there's nowhere to put the
 11352  	// variable declaration. We don't want to put the variable declaration
 11353  	// outside the function since some code in the argument list may cause the
 11354  	// function to be reentrant, and we can't put the variable declaration in
 11355  	// the function body since that's not accessible by the argument list.
 11356  	//
 11357  	// Instead, we use an immediately-invoked arrow function to create a new
 11358  	// symbol inline by introducing a new scope. Make sure to only use it for
 11359  	// symbol declaration and still initialize the variable inline to preserve
 11360  	// side effect order.
 11361  	if p.currentScope.Kind == js_ast.ScopeFunctionArgs {
 11362  		return func() js_ast.Expr {
 11363  				if tempRef == ast.InvalidRef {
 11364  					tempRef = p.generateTempRef(tempRefNoDeclare, "")
 11365  
 11366  					// Assign inline so the order of side effects remains the same
 11367  					p.recordUsage(tempRef)
 11368  					return js_ast.Assign(js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: tempRef}}, value)
 11369  				}
 11370  				p.recordUsage(tempRef)
 11371  				return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: tempRef}}
 11372  			}, func(expr js_ast.Expr) js_ast.Expr {
 11373  				// Make sure side effects still happen if no expression was generated
 11374  				if expr.Data == nil {
 11375  					return value
 11376  				}
 11377  
 11378  				// Generate a new variable using an arrow function to avoid messing with "this"
 11379  				return js_ast.Expr{Loc: loc, Data: &js_ast.ECall{
 11380  					Target: js_ast.Expr{Loc: loc, Data: &js_ast.EArrow{
 11381  						Args:       []js_ast.Arg{{Binding: js_ast.Binding{Loc: loc, Data: &js_ast.BIdentifier{Ref: tempRef}}}},
 11382  						PreferExpr: true,
 11383  						Body:       js_ast.FnBody{Loc: loc, Block: js_ast.SBlock{Stmts: []js_ast.Stmt{{Loc: loc, Data: &js_ast.SReturn{ValueOrNil: expr}}}}},
 11384  					}},
 11385  				}}
 11386  			}
 11387  	}
 11388  
 11389  	return func() js_ast.Expr {
 11390  		if tempRef == ast.InvalidRef {
 11391  			tempRef = p.generateTempRef(tempRefNeedsDeclare, "")
 11392  			p.recordUsage(tempRef)
 11393  			return js_ast.Assign(js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: tempRef}}, value)
 11394  		}
 11395  		p.recordUsage(tempRef)
 11396  		return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: tempRef}}
 11397  	}, wrapFunc
 11398  }
 11399  
 11400  func (p *parser) visitDecorators(decorators []js_ast.Decorator, decoratorScope *js_ast.Scope) []js_ast.Decorator {
 11401  	if decorators != nil {
 11402  		// Decorators cause us to temporarily revert to the scope that encloses the
 11403  		// class declaration, since that's where the generated code for decorators
 11404  		// will be inserted. I believe this currently only matters for parameter
 11405  		// decorators, where the scope should not be within the argument list.
 11406  		oldScope := p.currentScope
 11407  		p.currentScope = decoratorScope
 11408  
 11409  		for i, decorator := range decorators {
 11410  			decorators[i].Value = p.visitExpr(decorator.Value)
 11411  		}
 11412  
 11413  		// Avoid "popScope" because this decorator scope is not hierarchical
 11414  		p.currentScope = oldScope
 11415  	}
 11416  
 11417  	return decorators
 11418  }
 11419  
 11420  type visitClassResult struct {
 11421  	bodyScope         *js_ast.Scope
 11422  	innerClassNameRef ast.Ref
 11423  	superCtorRef      ast.Ref
 11424  
 11425  	// If true, the class was determined to be safe to remove if the class is
 11426  	// never used (i.e. the class definition is side-effect free). This is
 11427  	// determined after visiting but before lowering since lowering may generate
 11428  	// class mutations that cannot be automatically analyzed as side-effect free.
 11429  	canBeRemovedIfUnused bool
 11430  }
 11431  
 11432  func (p *parser) visitClass(nameScopeLoc logger.Loc, class *js_ast.Class, defaultNameRef ast.Ref, nameToKeep string) (result visitClassResult) {
 11433  	class.Decorators = p.visitDecorators(class.Decorators, p.currentScope)
 11434  
 11435  	if class.Name != nil {
 11436  		p.recordDeclaredSymbol(class.Name.Ref)
 11437  		if p.options.keepNames {
 11438  			nameToKeep = p.symbols[class.Name.Ref.InnerIndex].OriginalName
 11439  		}
 11440  	}
 11441  
 11442  	// Replace "this" with a reference to the class inside static field
 11443  	// initializers if static fields are being lowered, since that relocates the
 11444  	// field initializers outside of the class body and "this" will no longer
 11445  	// reference the same thing.
 11446  	classLoweringInfo := p.computeClassLoweringInfo(class)
 11447  	recomputeClassLoweringInfo := false
 11448  
 11449  	// Sometimes we need to lower private members even though they are supported.
 11450  	// This flags them for lowering so that we lower references to them as we
 11451  	// traverse the class body.
 11452  	//
 11453  	// We don't need to worry about possible references to the class shadowing
 11454  	// symbol inside the class body changing our decision to lower private members
 11455  	// later on because that shouldn't be possible.
 11456  	if classLoweringInfo.lowerAllStaticFields {
 11457  		for _, prop := range class.Properties {
 11458  			// We need to lower all private members if fields of that type are lowered,
 11459  			// not just private fields (methods and accessors too):
 11460  			//
 11461  			//   class Foo {
 11462  			//     get #foo() {}
 11463  			//     static bar = new Foo().#foo
 11464  			//   }
 11465  			//
 11466  			// We can't transform that to this:
 11467  			//
 11468  			//   class Foo {
 11469  			//     get #foo() {}
 11470  			//   }
 11471  			//   Foo.bar = new Foo().#foo;
 11472  			//
 11473  			// The private getter must be lowered too.
 11474  			if private, ok := prop.Key.Data.(*js_ast.EPrivateIdentifier); ok {
 11475  				p.symbols[private.Ref.InnerIndex].Flags |= ast.PrivateSymbolMustBeLowered
 11476  				recomputeClassLoweringInfo = true
 11477  			}
 11478  		}
 11479  	}
 11480  
 11481  	// Conservatively lower all private names that have been used in a private
 11482  	// brand check anywhere in the file. See the comment on this map for details.
 11483  	if p.lowerAllOfThesePrivateNames != nil {
 11484  		for _, prop := range class.Properties {
 11485  			if private, ok := prop.Key.Data.(*js_ast.EPrivateIdentifier); ok {
 11486  				if symbol := &p.symbols[private.Ref.InnerIndex]; p.lowerAllOfThesePrivateNames[symbol.OriginalName] {
 11487  					symbol.Flags |= ast.PrivateSymbolMustBeLowered
 11488  					recomputeClassLoweringInfo = true
 11489  				}
 11490  			}
 11491  		}
 11492  	}
 11493  
 11494  	// If we changed private symbol lowering decisions, then recompute class
 11495  	// lowering info because that may have changed other decisions too
 11496  	if recomputeClassLoweringInfo {
 11497  		classLoweringInfo = p.computeClassLoweringInfo(class)
 11498  	}
 11499  
 11500  	p.pushScopeForVisitPass(js_ast.ScopeClassName, nameScopeLoc)
 11501  	oldEnclosingClassKeyword := p.enclosingClassKeyword
 11502  	p.enclosingClassKeyword = class.ClassKeyword
 11503  	p.currentScope.RecursiveSetStrictMode(js_ast.ImplicitStrictModeClass)
 11504  	if class.Name != nil {
 11505  		p.validateDeclaredSymbolName(class.Name.Loc, p.symbols[class.Name.Ref.InnerIndex].OriginalName)
 11506  	}
 11507  
 11508  	// Create the "__super" symbol if necessary. This will cause us to replace
 11509  	// all "super()" call expressions with a call to this symbol, which will
 11510  	// then be inserted into the "constructor" method.
 11511  	result.superCtorRef = ast.InvalidRef
 11512  	if classLoweringInfo.shimSuperCtorCalls {
 11513  		result.superCtorRef = p.newSymbol(ast.SymbolOther, "__super")
 11514  		p.currentScope.Generated = append(p.currentScope.Generated, result.superCtorRef)
 11515  		p.recordDeclaredSymbol(result.superCtorRef)
 11516  	}
 11517  	oldSuperCtorRef := p.superCtorRef
 11518  	p.superCtorRef = result.superCtorRef
 11519  
 11520  	// Insert an immutable inner name that spans the whole class to match
 11521  	// JavaScript's semantics specifically the "CreateImmutableBinding" here:
 11522  	// https://262.ecma-international.org/6.0/#sec-runtime-semantics-classdefinitionevaluation
 11523  	// The class body (and extends clause) "captures" the original value of the
 11524  	// class name. This matters for class statements because the symbol can be
 11525  	// re-assigned to something else later. The captured values must be the
 11526  	// original value of the name, not the re-assigned value. Use "const" for
 11527  	// this symbol to match JavaScript run-time semantics. You are not allowed
 11528  	// to assign to this symbol (it throws a TypeError).
 11529  	if class.Name != nil {
 11530  		name := p.symbols[class.Name.Ref.InnerIndex].OriginalName
 11531  		result.innerClassNameRef = p.newSymbol(ast.SymbolConst, "_"+name)
 11532  		p.currentScope.Members[name] = js_ast.ScopeMember{Loc: class.Name.Loc, Ref: result.innerClassNameRef}
 11533  	} else {
 11534  		name := "_this"
 11535  		if defaultNameRef != ast.InvalidRef {
 11536  			name = "_" + p.source.IdentifierName + "_default"
 11537  		}
 11538  		result.innerClassNameRef = p.newSymbol(ast.SymbolConst, name)
 11539  	}
 11540  	p.recordDeclaredSymbol(result.innerClassNameRef)
 11541  
 11542  	if class.ExtendsOrNil.Data != nil {
 11543  		class.ExtendsOrNil = p.visitExpr(class.ExtendsOrNil)
 11544  	}
 11545  
 11546  	// A scope is needed for private identifiers
 11547  	p.pushScopeForVisitPass(js_ast.ScopeClassBody, class.BodyLoc)
 11548  	result.bodyScope = p.currentScope
 11549  
 11550  	for i := range class.Properties {
 11551  		property := &class.Properties[i]
 11552  
 11553  		if property.Kind == js_ast.PropertyClassStaticBlock {
 11554  			oldFnOrArrowData := p.fnOrArrowDataVisit
 11555  			oldFnOnlyDataVisit := p.fnOnlyDataVisit
 11556  
 11557  			p.fnOrArrowDataVisit = fnOrArrowDataVisit{}
 11558  			p.fnOnlyDataVisit = fnOnlyDataVisit{
 11559  				isThisNested:           true,
 11560  				isNewTargetAllowed:     true,
 11561  				isInStaticClassContext: true,
 11562  				innerClassNameRef:      &result.innerClassNameRef,
 11563  			}
 11564  
 11565  			if classLoweringInfo.lowerAllStaticFields {
 11566  				// Need to lower "this" and "super" since they won't be valid outside the class body
 11567  				p.fnOnlyDataVisit.shouldReplaceThisWithInnerClassNameRef = true
 11568  				p.fnOrArrowDataVisit.shouldLowerSuperPropertyAccess = true
 11569  			}
 11570  
 11571  			p.pushScopeForVisitPass(js_ast.ScopeClassStaticInit, property.ClassStaticBlock.Loc)
 11572  
 11573  			// Make it an error to use "arguments" in a static class block
 11574  			p.currentScope.ForbidArguments = true
 11575  
 11576  			property.ClassStaticBlock.Block.Stmts = p.visitStmts(property.ClassStaticBlock.Block.Stmts, stmtsFnBody)
 11577  			p.popScope()
 11578  
 11579  			p.fnOrArrowDataVisit = oldFnOrArrowData
 11580  			p.fnOnlyDataVisit = oldFnOnlyDataVisit
 11581  			continue
 11582  		}
 11583  
 11584  		property.Decorators = p.visitDecorators(property.Decorators, result.bodyScope)
 11585  
 11586  		// Visit the property key
 11587  		if private, ok := property.Key.Data.(*js_ast.EPrivateIdentifier); ok {
 11588  			// Special-case private identifiers here
 11589  			p.recordDeclaredSymbol(private.Ref)
 11590  		} else {
 11591  			// It's forbidden to reference the class name in a computed key
 11592  			if property.Flags.Has(js_ast.PropertyIsComputed) && class.Name != nil {
 11593  				p.symbols[result.innerClassNameRef.InnerIndex].Kind = ast.SymbolClassInComputedPropertyKey
 11594  			}
 11595  
 11596  			key, _ := p.visitExprInOut(property.Key, exprIn{
 11597  				shouldMangleStringsAsProps: true,
 11598  			})
 11599  			property.Key = key
 11600  
 11601  			// Re-allow using the class name after visiting a computed key
 11602  			if property.Flags.Has(js_ast.PropertyIsComputed) && class.Name != nil {
 11603  				p.symbols[result.innerClassNameRef.InnerIndex].Kind = ast.SymbolConst
 11604  			}
 11605  
 11606  			if p.options.minifySyntax {
 11607  				if inlined, ok := key.Data.(*js_ast.EInlinedEnum); ok {
 11608  					switch inlined.Value.Data.(type) {
 11609  					case *js_ast.EString, *js_ast.ENumber:
 11610  						key.Data = inlined.Value.Data
 11611  						property.Key.Data = key.Data
 11612  					}
 11613  				}
 11614  				switch k := key.Data.(type) {
 11615  				case *js_ast.ENumber, *js_ast.ENameOfSymbol:
 11616  					// "class { [123] }" => "class { 123 }"
 11617  					property.Flags &= ^js_ast.PropertyIsComputed
 11618  				case *js_ast.EString:
 11619  					if numberValue, ok := js_ast.StringToEquivalentNumberValue(k.Value); ok && numberValue >= 0 {
 11620  						// "class { '123' }" => "class { 123 }"
 11621  						property.Key.Data = &js_ast.ENumber{Value: numberValue}
 11622  						property.Flags &= ^js_ast.PropertyIsComputed
 11623  					} else if property.Flags.Has(js_ast.PropertyIsComputed) {
 11624  						// "class {['x'] = y}" => "class {'x' = y}"
 11625  						isInvalidConstructor := false
 11626  						if helpers.UTF16EqualsString(k.Value, "constructor") {
 11627  							if !property.Kind.IsMethodDefinition() {
 11628  								// "constructor" is an invalid name for both instance and static fields
 11629  								isInvalidConstructor = true
 11630  							} else if !property.Flags.Has(js_ast.PropertyIsStatic) {
 11631  								// Calling an instance method "constructor" is problematic so avoid that too
 11632  								isInvalidConstructor = true
 11633  							}
 11634  						}
 11635  
 11636  						// A static property must not be called "prototype"
 11637  						isInvalidPrototype := property.Flags.Has(js_ast.PropertyIsStatic) && helpers.UTF16EqualsString(k.Value, "prototype")
 11638  
 11639  						if !isInvalidConstructor && !isInvalidPrototype {
 11640  							property.Flags &= ^js_ast.PropertyIsComputed
 11641  						}
 11642  					}
 11643  				}
 11644  			}
 11645  		}
 11646  
 11647  		// Make it an error to use "arguments" in a class body
 11648  		p.currentScope.ForbidArguments = true
 11649  
 11650  		// The value of "this" and "super" is shadowed inside property values
 11651  		oldFnOnlyDataVisit := p.fnOnlyDataVisit
 11652  		oldShouldLowerSuperPropertyAccess := p.fnOrArrowDataVisit.shouldLowerSuperPropertyAccess
 11653  		p.fnOrArrowDataVisit.shouldLowerSuperPropertyAccess = false
 11654  		p.fnOnlyDataVisit.shouldReplaceThisWithInnerClassNameRef = false
 11655  		p.fnOnlyDataVisit.isThisNested = true
 11656  		p.fnOnlyDataVisit.isNewTargetAllowed = true
 11657  		p.fnOnlyDataVisit.isInStaticClassContext = property.Flags.Has(js_ast.PropertyIsStatic)
 11658  		p.fnOnlyDataVisit.innerClassNameRef = &result.innerClassNameRef
 11659  
 11660  		// We need to explicitly assign the name to the property initializer if it
 11661  		// will be transformed such that it is no longer an inline initializer.
 11662  		nameToKeep := ""
 11663  		isLoweredPrivateMethod := false
 11664  		if private, ok := property.Key.Data.(*js_ast.EPrivateIdentifier); ok {
 11665  			if !property.Kind.IsMethodDefinition() || p.privateSymbolNeedsToBeLowered(private) {
 11666  				nameToKeep = p.symbols[private.Ref.InnerIndex].OriginalName
 11667  			}
 11668  
 11669  			// Lowered private methods (both instance and static) are initialized
 11670  			// outside of the class body, so we must rewrite "super" property
 11671  			// accesses inside them. Lowered private instance fields are initialized
 11672  			// inside the constructor where "super" is valid, so those don't need to
 11673  			// be rewritten.
 11674  			if property.Kind.IsMethodDefinition() && p.privateSymbolNeedsToBeLowered(private) {
 11675  				isLoweredPrivateMethod = true
 11676  			}
 11677  		} else if !property.Kind.IsMethodDefinition() && !property.Flags.Has(js_ast.PropertyIsComputed) {
 11678  			if str, ok := property.Key.Data.(*js_ast.EString); ok {
 11679  				nameToKeep = helpers.UTF16ToString(str.Value)
 11680  			}
 11681  		}
 11682  
 11683  		// Handle methods
 11684  		if property.ValueOrNil.Data != nil {
 11685  			p.propMethodDecoratorScope = result.bodyScope
 11686  
 11687  			// Propagate the name to keep from the method into the initializer
 11688  			if nameToKeep != "" {
 11689  				p.nameToKeep = nameToKeep
 11690  				p.nameToKeepIsFor = property.ValueOrNil.Data
 11691  			}
 11692  
 11693  			// Propagate whether we're in a derived class constructor
 11694  			if class.ExtendsOrNil.Data != nil && !property.Flags.Has(js_ast.PropertyIsComputed) {
 11695  				if str, ok := property.Key.Data.(*js_ast.EString); ok && helpers.UTF16EqualsString(str.Value, "constructor") {
 11696  					p.propDerivedCtorValue = property.ValueOrNil.Data
 11697  				}
 11698  			}
 11699  
 11700  			property.ValueOrNil, _ = p.visitExprInOut(property.ValueOrNil, exprIn{
 11701  				isMethod:               true,
 11702  				isLoweredPrivateMethod: isLoweredPrivateMethod,
 11703  			})
 11704  		}
 11705  
 11706  		// Handle initialized fields
 11707  		if property.InitializerOrNil.Data != nil {
 11708  			if property.Flags.Has(js_ast.PropertyIsStatic) && classLoweringInfo.lowerAllStaticFields {
 11709  				// Need to lower "this" and "super" since they won't be valid outside the class body
 11710  				p.fnOnlyDataVisit.shouldReplaceThisWithInnerClassNameRef = true
 11711  				p.fnOrArrowDataVisit.shouldLowerSuperPropertyAccess = true
 11712  			}
 11713  
 11714  			// Propagate the name to keep from the field into the initializer
 11715  			if nameToKeep != "" {
 11716  				p.nameToKeep = nameToKeep
 11717  				p.nameToKeepIsFor = property.InitializerOrNil.Data
 11718  			}
 11719  
 11720  			property.InitializerOrNil = p.visitExpr(property.InitializerOrNil)
 11721  		}
 11722  
 11723  		// Restore "this" so it will take the inherited value in property keys
 11724  		p.fnOnlyDataVisit = oldFnOnlyDataVisit
 11725  		p.fnOrArrowDataVisit.shouldLowerSuperPropertyAccess = oldShouldLowerSuperPropertyAccess
 11726  
 11727  		// Restore the ability to use "arguments" in decorators and computed properties
 11728  		p.currentScope.ForbidArguments = false
 11729  	}
 11730  
 11731  	// Check for and warn about duplicate keys in class bodies
 11732  	if !p.suppressWarningsAboutWeirdCode {
 11733  		p.warnAboutDuplicateProperties(class.Properties, duplicatePropertiesInClass)
 11734  	}
 11735  
 11736  	// Analyze side effects before adding the name keeping call
 11737  	result.canBeRemovedIfUnused = p.astHelpers.ClassCanBeRemovedIfUnused(*class)
 11738  
 11739  	// Implement name keeping using a static block at the start of the class body
 11740  	if p.options.keepNames && nameToKeep != "" {
 11741  		propertyPreventsKeepNames := false
 11742  		for _, prop := range class.Properties {
 11743  			// A static property called "name" shadows the automatically-generated name
 11744  			if prop.Flags.Has(js_ast.PropertyIsStatic) {
 11745  				if str, ok := prop.Key.Data.(*js_ast.EString); ok && helpers.UTF16EqualsString(str.Value, "name") {
 11746  					propertyPreventsKeepNames = true
 11747  					break
 11748  				}
 11749  			}
 11750  		}
 11751  		if !propertyPreventsKeepNames {
 11752  			var this js_ast.Expr
 11753  			if classLoweringInfo.lowerAllStaticFields {
 11754  				p.recordUsage(result.innerClassNameRef)
 11755  				this = js_ast.Expr{Loc: class.BodyLoc, Data: &js_ast.EIdentifier{Ref: result.innerClassNameRef}}
 11756  			} else {
 11757  				this = js_ast.Expr{Loc: class.BodyLoc, Data: js_ast.EThisShared}
 11758  			}
 11759  			properties := make([]js_ast.Property, 0, 1+len(class.Properties))
 11760  			properties = append(properties, js_ast.Property{
 11761  				Kind: js_ast.PropertyClassStaticBlock,
 11762  				ClassStaticBlock: &js_ast.ClassStaticBlock{Loc: class.BodyLoc, Block: js_ast.SBlock{Stmts: []js_ast.Stmt{
 11763  					p.keepClassOrFnSymbolName(class.BodyLoc, this, nameToKeep),
 11764  				}}},
 11765  			})
 11766  			class.Properties = append(properties, class.Properties...)
 11767  		}
 11768  	}
 11769  
 11770  	p.enclosingClassKeyword = oldEnclosingClassKeyword
 11771  	p.superCtorRef = oldSuperCtorRef
 11772  	p.popScope()
 11773  
 11774  	if p.symbols[result.innerClassNameRef.InnerIndex].UseCountEstimate == 0 {
 11775  		// Don't generate a shadowing name if one isn't needed
 11776  		result.innerClassNameRef = ast.InvalidRef
 11777  	} else if class.Name == nil {
 11778  		// If there was originally no class name but something inside needed one
 11779  		// (e.g. there was a static property initializer that referenced "this"),
 11780  		// populate the class name. If this is an "export default class" statement,
 11781  		// use the existing default name so that things will work as expected if
 11782  		// this is turned into a regular class statement later on.
 11783  		classNameRef := defaultNameRef
 11784  		if classNameRef == ast.InvalidRef {
 11785  			classNameRef = p.newSymbol(ast.SymbolOther, "_this")
 11786  			p.currentScope.Generated = append(p.currentScope.Generated, classNameRef)
 11787  			p.recordDeclaredSymbol(classNameRef)
 11788  		}
 11789  		class.Name = &ast.LocRef{Loc: nameScopeLoc, Ref: classNameRef}
 11790  	}
 11791  
 11792  	p.popScope()
 11793  
 11794  	// Sanity check that the class lowering info hasn't changed before and after
 11795  	// visiting. The class transform relies on this because lowering assumes that
 11796  	// must be able to expect that visiting has done certain things.
 11797  	if classLoweringInfo != p.computeClassLoweringInfo(class) {
 11798  		panic("Internal error")
 11799  	}
 11800  
 11801  	return
 11802  }
 11803  
 11804  func isSimpleParameterList(args []js_ast.Arg, hasRestArg bool) bool {
 11805  	if hasRestArg {
 11806  		return false
 11807  	}
 11808  	for _, arg := range args {
 11809  		if _, ok := arg.Binding.Data.(*js_ast.BIdentifier); !ok || arg.DefaultOrNil.Data != nil {
 11810  			return false
 11811  		}
 11812  	}
 11813  	return true
 11814  }
 11815  
 11816  func fnBodyContainsUseStrict(body []js_ast.Stmt) (logger.Loc, bool) {
 11817  	for _, stmt := range body {
 11818  		switch s := stmt.Data.(type) {
 11819  		case *js_ast.SComment:
 11820  			continue
 11821  		case *js_ast.SDirective:
 11822  			if helpers.UTF16EqualsString(s.Value, "use strict") {
 11823  				return stmt.Loc, true
 11824  			}
 11825  		default:
 11826  			return logger.Loc{}, false
 11827  		}
 11828  	}
 11829  	return logger.Loc{}, false
 11830  }
 11831  
 11832  type visitArgsOpts struct {
 11833  	body           []js_ast.Stmt
 11834  	decoratorScope *js_ast.Scope
 11835  	hasRestArg     bool
 11836  
 11837  	// This is true if the function is an arrow function or a method
 11838  	isUniqueFormalParameters bool
 11839  }
 11840  
 11841  func (p *parser) visitArgs(args []js_ast.Arg, opts visitArgsOpts) {
 11842  	var duplicateArgCheck map[string]logger.Range
 11843  	useStrictLoc, hasUseStrict := fnBodyContainsUseStrict(opts.body)
 11844  	hasSimpleArgs := isSimpleParameterList(args, opts.hasRestArg)
 11845  
 11846  	// Section 15.2.1 Static Semantics: Early Errors: "It is a Syntax Error if
 11847  	// FunctionBodyContainsUseStrict of FunctionBody is true and
 11848  	// IsSimpleParameterList of FormalParameters is false."
 11849  	if hasUseStrict && !hasSimpleArgs {
 11850  		p.log.AddError(&p.tracker, p.source.RangeOfString(useStrictLoc),
 11851  			"Cannot use a \"use strict\" directive in a function with a non-simple parameter list")
 11852  	}
 11853  
 11854  	// Section 15.1.1 Static Semantics: Early Errors: "Multiple occurrences of
 11855  	// the same BindingIdentifier in a FormalParameterList is only allowed for
 11856  	// functions which have simple parameter lists and which are not defined in
 11857  	// strict mode code."
 11858  	if opts.isUniqueFormalParameters || hasUseStrict || !hasSimpleArgs || p.isStrictMode() {
 11859  		duplicateArgCheck = make(map[string]logger.Range)
 11860  	}
 11861  
 11862  	for i := range args {
 11863  		arg := &args[i]
 11864  		arg.Decorators = p.visitDecorators(arg.Decorators, opts.decoratorScope)
 11865  		p.visitBinding(arg.Binding, bindingOpts{
 11866  			duplicateArgCheck: duplicateArgCheck,
 11867  		})
 11868  		if arg.DefaultOrNil.Data != nil {
 11869  			arg.DefaultOrNil = p.visitExpr(arg.DefaultOrNil)
 11870  		}
 11871  	}
 11872  }
 11873  
 11874  func (p *parser) isDotOrIndexDefineMatch(expr js_ast.Expr, parts []string) bool {
 11875  	switch e := expr.Data.(type) {
 11876  	case *js_ast.EDot:
 11877  		if len(parts) > 1 {
 11878  			// Intermediates must be dot expressions
 11879  			last := len(parts) - 1
 11880  			return parts[last] == e.Name && p.isDotOrIndexDefineMatch(e.Target, parts[:last])
 11881  		}
 11882  
 11883  	case *js_ast.EIndex:
 11884  		if len(parts) > 1 {
 11885  			if str, ok := e.Index.Data.(*js_ast.EString); ok {
 11886  				// Intermediates must be dot expressions
 11887  				last := len(parts) - 1
 11888  				return parts[last] == helpers.UTF16ToString(str.Value) && p.isDotOrIndexDefineMatch(e.Target, parts[:last])
 11889  			}
 11890  		}
 11891  
 11892  	case *js_ast.EThis:
 11893  		// Allow matching on top-level "this"
 11894  		if !p.fnOnlyDataVisit.isThisNested {
 11895  			return len(parts) == 1 && parts[0] == "this"
 11896  		}
 11897  
 11898  	case *js_ast.EImportMeta:
 11899  		// Allow matching on "import.meta"
 11900  		return len(parts) == 2 && parts[0] == "import" && parts[1] == "meta"
 11901  
 11902  	case *js_ast.EIdentifier:
 11903  		// The last expression must be an identifier
 11904  		if len(parts) == 1 {
 11905  			// The name must match
 11906  			name := p.loadNameFromRef(e.Ref)
 11907  			if name != parts[0] {
 11908  				return false
 11909  			}
 11910  
 11911  			result := p.findSymbol(expr.Loc, name)
 11912  
 11913  			// The "findSymbol" function also marks this symbol as used. But that's
 11914  			// never what we want here because we're just peeking to see what kind of
 11915  			// symbol it is to see if it's a match. If it's not a match, it will be
 11916  			// re-resolved again later and marked as used there. So we don't want to
 11917  			// mark it as used twice.
 11918  			p.ignoreUsage(result.ref)
 11919  
 11920  			// We must not be in a "with" statement scope
 11921  			if result.isInsideWithScope {
 11922  				return false
 11923  			}
 11924  
 11925  			// The last symbol must be unbound or injected
 11926  			return p.symbols[result.ref.InnerIndex].Kind.IsUnboundOrInjected()
 11927  		}
 11928  	}
 11929  
 11930  	return false
 11931  }
 11932  
 11933  func (p *parser) instantiateDefineExpr(loc logger.Loc, expr config.DefineExpr, opts identifierOpts) js_ast.Expr {
 11934  	if expr.Constant != nil {
 11935  		return js_ast.Expr{Loc: loc, Data: expr.Constant}
 11936  	}
 11937  
 11938  	if expr.InjectedDefineIndex.IsValid() {
 11939  		ref := p.injectedDefineSymbols[expr.InjectedDefineIndex.GetIndex()]
 11940  		p.recordUsage(ref)
 11941  		return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}}
 11942  	}
 11943  
 11944  	parts := expr.Parts
 11945  	if len(parts) == 0 {
 11946  		return js_ast.Expr{}
 11947  	}
 11948  
 11949  	// Check both user-specified defines and known globals
 11950  	if opts.matchAgainstDefines {
 11951  		// Make sure define resolution is not recursive
 11952  		opts.matchAgainstDefines = false
 11953  
 11954  		// Substitute user-specified defines
 11955  		if defines, ok := p.options.defines.DotDefines[parts[len(parts)-1]]; ok {
 11956  			for _, define := range defines {
 11957  				if define.Data.DefineExpr != nil && helpers.StringArraysEqual(define.Parts, parts) {
 11958  					return p.instantiateDefineExpr(loc, *define.Data.DefineExpr, opts)
 11959  				}
 11960  			}
 11961  		}
 11962  	}
 11963  
 11964  	// Check injected dot names
 11965  	if names, ok := p.injectedDotNames[parts[len(parts)-1]]; ok {
 11966  		for _, name := range names {
 11967  			if helpers.StringArraysEqual(name.parts, parts) {
 11968  				return p.instantiateInjectDotName(loc, name, opts.assignTarget)
 11969  			}
 11970  		}
 11971  	}
 11972  
 11973  	// Generate an identifier for the first part
 11974  	var value js_ast.Expr
 11975  	firstPart := parts[0]
 11976  	parts = parts[1:]
 11977  	switch firstPart {
 11978  	case "NaN":
 11979  		value = js_ast.Expr{Loc: loc, Data: &js_ast.ENumber{Value: math.NaN()}}
 11980  
 11981  	case "Infinity":
 11982  		value = js_ast.Expr{Loc: loc, Data: &js_ast.ENumber{Value: math.Inf(1)}}
 11983  
 11984  	case "null":
 11985  		value = js_ast.Expr{Loc: loc, Data: js_ast.ENullShared}
 11986  
 11987  	case "undefined":
 11988  		value = js_ast.Expr{Loc: loc, Data: js_ast.EUndefinedShared}
 11989  
 11990  	case "this":
 11991  		if thisValue, ok := p.valueForThis(loc, false /* shouldLog */, js_ast.AssignTargetNone, false, false); ok {
 11992  			value = thisValue
 11993  		} else {
 11994  			value = js_ast.Expr{Loc: loc, Data: js_ast.EThisShared}
 11995  		}
 11996  
 11997  	default:
 11998  		if firstPart == "import" && len(parts) > 0 && parts[0] == "meta" {
 11999  			if importMeta, ok := p.valueForImportMeta(loc); ok {
 12000  				value = importMeta
 12001  			} else {
 12002  				value = js_ast.Expr{Loc: loc, Data: &js_ast.EImportMeta{}}
 12003  			}
 12004  			parts = parts[1:]
 12005  			break
 12006  		}
 12007  
 12008  		result := p.findSymbol(loc, firstPart)
 12009  		value = p.handleIdentifier(loc, &js_ast.EIdentifier{
 12010  			Ref:                   result.ref,
 12011  			MustKeepDueToWithStmt: result.isInsideWithScope,
 12012  
 12013  			// Enable tree shaking
 12014  			CanBeRemovedIfUnused: true,
 12015  		}, opts)
 12016  	}
 12017  
 12018  	// Build up a chain of property access expressions for subsequent parts
 12019  	for _, part := range parts {
 12020  		if expr, ok := p.maybeRewritePropertyAccess(loc, js_ast.AssignTargetNone, false, value, part, loc, false, false, false); ok {
 12021  			value = expr
 12022  		} else if p.isMangledProp(part) {
 12023  			value = js_ast.Expr{Loc: loc, Data: &js_ast.EIndex{
 12024  				Target: value,
 12025  				Index:  js_ast.Expr{Loc: loc, Data: &js_ast.ENameOfSymbol{Ref: p.symbolForMangledProp(part)}},
 12026  			}}
 12027  		} else {
 12028  			value = js_ast.Expr{Loc: loc, Data: &js_ast.EDot{
 12029  				Target:  value,
 12030  				Name:    part,
 12031  				NameLoc: loc,
 12032  
 12033  				// Enable tree shaking
 12034  				CanBeRemovedIfUnused: true,
 12035  			}}
 12036  		}
 12037  	}
 12038  
 12039  	return value
 12040  }
 12041  
 12042  func (p *parser) instantiateInjectDotName(loc logger.Loc, name injectedDotName, assignTarget js_ast.AssignTarget) js_ast.Expr {
 12043  	// Note: We don't need to "ignoreRef" on the underlying identifier
 12044  	// because we have only parsed it but not visited it yet
 12045  	ref := p.injectedDefineSymbols[name.injectedDefineIndex]
 12046  	p.recordUsage(ref)
 12047  
 12048  	if assignTarget != js_ast.AssignTargetNone {
 12049  		if where, ok := p.injectedSymbolSources[ref]; ok {
 12050  			r := js_lexer.RangeOfIdentifier(p.source, loc)
 12051  			tracker := logger.MakeLineColumnTracker(&where.source)
 12052  			joined := strings.Join(name.parts, ".")
 12053  			p.log.AddErrorWithNotes(&p.tracker, r,
 12054  				fmt.Sprintf("Cannot assign to %q because it's an import from an injected file", joined),
 12055  				[]logger.MsgData{tracker.MsgData(js_lexer.RangeOfIdentifier(where.source, where.loc),
 12056  					fmt.Sprintf("The symbol %q was exported from %q here:", joined, where.source.PrettyPath))})
 12057  		}
 12058  	}
 12059  
 12060  	return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: ref}}
 12061  }
 12062  
 12063  func (p *parser) checkForUnrepresentableIdentifier(loc logger.Loc, name string) {
 12064  	if p.options.asciiOnly && p.options.unsupportedJSFeatures.Has(compat.UnicodeEscapes) &&
 12065  		helpers.ContainsNonBMPCodePoint(name) {
 12066  		if p.unrepresentableIdentifiers == nil {
 12067  			p.unrepresentableIdentifiers = make(map[string]bool)
 12068  		}
 12069  		if !p.unrepresentableIdentifiers[name] {
 12070  			p.unrepresentableIdentifiers[name] = true
 12071  			where := config.PrettyPrintTargetEnvironment(p.options.originalTargetEnv, p.options.unsupportedJSFeatureOverridesMask)
 12072  			r := js_lexer.RangeOfIdentifier(p.source, loc)
 12073  			p.log.AddError(&p.tracker, r, fmt.Sprintf("%q cannot be escaped in %s but you "+
 12074  				"can set the charset to \"utf8\" to allow unescaped Unicode characters", name, where))
 12075  		}
 12076  	}
 12077  }
 12078  
 12079  type typeofStringOrder uint8
 12080  
 12081  const (
 12082  	onlyCheckOriginalOrder typeofStringOrder = iota
 12083  	checkBothOrders
 12084  )
 12085  
 12086  func (p *parser) warnAboutTypeofAndString(a js_ast.Expr, b js_ast.Expr, order typeofStringOrder) {
 12087  	if order == checkBothOrders {
 12088  		if _, ok := a.Data.(*js_ast.EString); ok {
 12089  			a, b = b, a
 12090  		}
 12091  	}
 12092  
 12093  	if typeof, ok := a.Data.(*js_ast.EUnary); ok && typeof.Op == js_ast.UnOpTypeof {
 12094  		if str, ok := b.Data.(*js_ast.EString); ok {
 12095  			value := helpers.UTF16ToString(str.Value)
 12096  			switch value {
 12097  			case "undefined", "object", "boolean", "number", "bigint", "string", "symbol", "function", "unknown":
 12098  			default:
 12099  				// Warn about typeof comparisons with values that will never be
 12100  				// returned. Here's an example of code with this problem:
 12101  				// https://github.com/olifolkerd/tabulator/issues/2962
 12102  				r := p.source.RangeOfString(b.Loc)
 12103  				text := fmt.Sprintf("The \"typeof\" operator will never evaluate to %q", value)
 12104  				kind := logger.Warning
 12105  				if p.suppressWarningsAboutWeirdCode {
 12106  					kind = logger.Debug
 12107  				}
 12108  				var notes []logger.MsgData
 12109  				if value == "null" {
 12110  					notes = append(notes, logger.MsgData{
 12111  						Text: "The expression \"typeof x\" actually evaluates to \"object\" in JavaScript, not \"null\". " +
 12112  							"You need to use \"x === null\" to test for null.",
 12113  					})
 12114  				}
 12115  				p.log.AddIDWithNotes(logger.MsgID_JS_ImpossibleTypeof, kind, &p.tracker, r, text, notes)
 12116  			}
 12117  		}
 12118  	}
 12119  }
 12120  
 12121  func (p *parser) warnAboutEqualityCheck(op string, value js_ast.Expr, afterOpLoc logger.Loc) bool {
 12122  	switch e := value.Data.(type) {
 12123  	case *js_ast.ENumber:
 12124  		// "0 === -0" is true in JavaScript. Here's an example of code with this
 12125  		// problem: https://github.com/mrdoob/three.js/pull/11183
 12126  		if e.Value == 0 && math.Signbit(e.Value) {
 12127  			r := logger.Range{Loc: value.Loc, Len: 0}
 12128  			if int(r.Loc.Start) < len(p.source.Contents) && p.source.Contents[r.Loc.Start] == '-' {
 12129  				zeroRange := p.source.RangeOfNumber(logger.Loc{Start: r.Loc.Start + 1})
 12130  				r.Len = zeroRange.Len + 1
 12131  			}
 12132  			text := fmt.Sprintf("Comparison with -0 using the %q operator will also match 0", op)
 12133  			if op == "case" {
 12134  				text = "Comparison with -0 using a case clause will also match 0"
 12135  			}
 12136  			kind := logger.Warning
 12137  			if p.suppressWarningsAboutWeirdCode {
 12138  				kind = logger.Debug
 12139  			}
 12140  			p.log.AddIDWithNotes(logger.MsgID_JS_EqualsNegativeZero, kind, &p.tracker, r, text,
 12141  				[]logger.MsgData{{Text: "Floating-point equality is defined such that 0 and -0 are equal, so \"x === -0\" returns true for both 0 and -0. " +
 12142  					"You need to use \"Object.is(x, -0)\" instead to test for -0."}})
 12143  			return true
 12144  		}
 12145  
 12146  		// "NaN === NaN" is false in JavaScript
 12147  		if math.IsNaN(e.Value) {
 12148  			text := fmt.Sprintf("Comparison with NaN using the %q operator here is always %v", op, op[0] == '!')
 12149  			if op == "case" {
 12150  				text = "This case clause will never be evaluated because equality with NaN is always false"
 12151  			}
 12152  			r := p.source.RangeOfOperatorBefore(afterOpLoc, op)
 12153  			kind := logger.Warning
 12154  			if p.suppressWarningsAboutWeirdCode {
 12155  				kind = logger.Debug
 12156  			}
 12157  			p.log.AddIDWithNotes(logger.MsgID_JS_EqualsNaN, kind, &p.tracker, r, text,
 12158  				[]logger.MsgData{{Text: "Floating-point equality is defined such that NaN is never equal to anything, so \"x === NaN\" always returns false. " +
 12159  					"You need to use \"Number.isNaN(x)\" instead to test for NaN."}})
 12160  			return true
 12161  		}
 12162  
 12163  	case *js_ast.EArray, *js_ast.EArrow, *js_ast.EClass,
 12164  		*js_ast.EFunction, *js_ast.EObject, *js_ast.ERegExp:
 12165  		// This warning only applies to strict equality because loose equality can
 12166  		// cause string conversions. For example, "x == []" is true if x is the
 12167  		// empty string. Here's an example of code with this problem:
 12168  		// https://github.com/aws/aws-sdk-js/issues/3325
 12169  		if len(op) > 2 {
 12170  			text := fmt.Sprintf("Comparison using the %q operator here is always %v", op, op[0] == '!')
 12171  			if op == "case" {
 12172  				text = "This case clause will never be evaluated because the comparison is always false"
 12173  			}
 12174  			r := p.source.RangeOfOperatorBefore(afterOpLoc, op)
 12175  			kind := logger.Warning
 12176  			if p.suppressWarningsAboutWeirdCode {
 12177  				kind = logger.Debug
 12178  			}
 12179  			p.log.AddIDWithNotes(logger.MsgID_JS_EqualsNewObject, kind, &p.tracker, r, text,
 12180  				[]logger.MsgData{{Text: "Equality with a new object is always false in JavaScript because the equality operator tests object identity. " +
 12181  					"You need to write code to compare the contents of the object instead. " +
 12182  					"For example, use \"Array.isArray(x) && x.length === 0\" instead of \"x === []\" to test for an empty array."}})
 12183  			return true
 12184  		}
 12185  	}
 12186  
 12187  	return false
 12188  }
 12189  
 12190  // EDot nodes represent a property access. This function may return an
 12191  // expression to replace the property access with. It assumes that the
 12192  // target of the EDot expression has already been visited.
 12193  func (p *parser) maybeRewritePropertyAccess(
 12194  	loc logger.Loc,
 12195  	assignTarget js_ast.AssignTarget,
 12196  	isDeleteTarget bool,
 12197  	target js_ast.Expr,
 12198  	name string,
 12199  	nameLoc logger.Loc,
 12200  	isCallTarget bool,
 12201  	isTemplateTag bool,
 12202  	preferQuotedKey bool,
 12203  ) (js_ast.Expr, bool) {
 12204  	if id, ok := target.Data.(*js_ast.EIdentifier); ok {
 12205  		// Rewrite property accesses on explicit namespace imports as an identifier.
 12206  		// This lets us replace them easily in the printer to rebind them to
 12207  		// something else without paying the cost of a whole-tree traversal during
 12208  		// module linking just to rewrite these EDot expressions.
 12209  		if p.options.mode == config.ModeBundle {
 12210  			if importItems, ok := p.importItemsForNamespace[id.Ref]; ok {
 12211  				// Cache translation so each property access resolves to the same import
 12212  				item, ok := importItems.entries[name]
 12213  				if !ok {
 12214  					// Replace non-default imports with "undefined" for JSON import assertions
 12215  					if record := &p.importRecords[importItems.importRecordIndex]; (record.Flags&ast.AssertTypeJSON) != 0 && name != "default" {
 12216  						kind := logger.Warning
 12217  						if p.suppressWarningsAboutWeirdCode {
 12218  							kind = logger.Debug
 12219  						}
 12220  						p.log.AddIDWithNotes(logger.MsgID_JS_AssertTypeJSON, kind, &p.tracker, js_lexer.RangeOfIdentifier(p.source, nameLoc),
 12221  							fmt.Sprintf("Non-default import %q is undefined with a JSON import assertion", name),
 12222  							p.notesForAssertTypeJSON(record, name))
 12223  						p.ignoreUsage(id.Ref)
 12224  						return js_ast.Expr{Loc: loc, Data: js_ast.EUndefinedShared}, true
 12225  					}
 12226  
 12227  					// Generate a new import item symbol in the module scope
 12228  					item = ast.LocRef{Loc: nameLoc, Ref: p.newSymbol(ast.SymbolImport, name)}
 12229  					p.moduleScope.Generated = append(p.moduleScope.Generated, item.Ref)
 12230  
 12231  					// Link the namespace import and the import item together
 12232  					importItems.entries[name] = item
 12233  					p.isImportItem[item.Ref] = true
 12234  
 12235  					symbol := &p.symbols[item.Ref.InnerIndex]
 12236  					if p.options.mode == config.ModePassThrough {
 12237  						// Make sure the printer prints this as a property access
 12238  						symbol.NamespaceAlias = &ast.NamespaceAlias{
 12239  							NamespaceRef: id.Ref,
 12240  							Alias:        name,
 12241  						}
 12242  					} else {
 12243  						// Mark this as generated in case it's missing. We don't want to
 12244  						// generate errors for missing import items that are automatically
 12245  						// generated.
 12246  						symbol.ImportItemStatus = ast.ImportItemGenerated
 12247  					}
 12248  				}
 12249  
 12250  				// Undo the usage count for the namespace itself. This is used later
 12251  				// to detect whether the namespace symbol has ever been "captured"
 12252  				// or whether it has just been used to read properties off of.
 12253  				//
 12254  				// The benefit of doing this is that if both this module and the
 12255  				// imported module end up in the same module group and the namespace
 12256  				// symbol has never been captured, then we don't need to generate
 12257  				// any code for the namespace at all.
 12258  				p.ignoreUsage(id.Ref)
 12259  
 12260  				// Track how many times we've referenced this symbol
 12261  				p.recordUsage(item.Ref)
 12262  				return p.handleIdentifier(nameLoc, &js_ast.EIdentifier{Ref: item.Ref}, identifierOpts{
 12263  					assignTarget:    assignTarget,
 12264  					isCallTarget:    isCallTarget,
 12265  					isDeleteTarget:  isDeleteTarget,
 12266  					preferQuotedKey: preferQuotedKey,
 12267  
 12268  					// If this expression is used as the target of a call expression, make
 12269  					// sure the value of "this" is preserved.
 12270  					wasOriginallyIdentifier: false,
 12271  				}), true
 12272  			}
 12273  
 12274  			// Rewrite "module.require()" to "require()" for Webpack compatibility.
 12275  			// See https://github.com/webpack/webpack/pull/7750 for more info.
 12276  			if isCallTarget && id.Ref == p.moduleRef && name == "require" {
 12277  				p.ignoreUsage(p.moduleRef)
 12278  
 12279  				// This uses "require" instead of a reference to our "__require"
 12280  				// function so that the code coming up that detects calls to
 12281  				// "require" will recognize it.
 12282  				p.recordUsage(p.requireRef)
 12283  				return js_ast.Expr{Loc: nameLoc, Data: &js_ast.EIdentifier{Ref: p.requireRef}}, true
 12284  			}
 12285  		}
 12286  	}
 12287  
 12288  	// Attempt to simplify statically-determined object literal property accesses
 12289  	if !isCallTarget && !isTemplateTag && p.options.minifySyntax && assignTarget == js_ast.AssignTargetNone {
 12290  		if object, ok := target.Data.(*js_ast.EObject); ok {
 12291  			var replace js_ast.Expr
 12292  			hasProtoNull := false
 12293  			isUnsafe := false
 12294  
 12295  			// Check that doing this is safe
 12296  			for _, prop := range object.Properties {
 12297  				// "{ ...a }.a" must be preserved
 12298  				// "new ({ a() {} }.a)" must throw
 12299  				// "{ get a() {} }.a" must be preserved
 12300  				// "{ set a(b) {} }.a = 1" must be preserved
 12301  				// "{ a: 1, [String.fromCharCode(97)]: 2 }.a" must be 2
 12302  				if prop.Kind == js_ast.PropertySpread || prop.Flags.Has(js_ast.PropertyIsComputed) || prop.Kind.IsMethodDefinition() {
 12303  					isUnsafe = true
 12304  					break
 12305  				}
 12306  
 12307  				// Do not attempt to compare against numeric keys
 12308  				key, ok := prop.Key.Data.(*js_ast.EString)
 12309  				if !ok {
 12310  					isUnsafe = true
 12311  					break
 12312  				}
 12313  
 12314  				// The "__proto__" key has special behavior
 12315  				if helpers.UTF16EqualsString(key.Value, "__proto__") {
 12316  					if _, ok := prop.ValueOrNil.Data.(*js_ast.ENull); ok {
 12317  						// Replacing "{__proto__: null}.a" with undefined should be safe
 12318  						hasProtoNull = true
 12319  					}
 12320  				}
 12321  
 12322  				// This entire object literal must have no side effects
 12323  				if !p.astHelpers.ExprCanBeRemovedIfUnused(prop.ValueOrNil) {
 12324  					isUnsafe = true
 12325  					break
 12326  				}
 12327  
 12328  				// Note that we need to take the last value if there are duplicate keys
 12329  				if helpers.UTF16EqualsString(key.Value, name) {
 12330  					replace = prop.ValueOrNil
 12331  				}
 12332  			}
 12333  
 12334  			if !isUnsafe {
 12335  				// If the key was found, return the value for that key. Note
 12336  				// that "{__proto__: null}.__proto__" is undefined, not null.
 12337  				if replace.Data != nil && name != "__proto__" {
 12338  					return replace, true
 12339  				}
 12340  
 12341  				// We can only return "undefined" when a key is missing if the prototype is null
 12342  				if hasProtoNull {
 12343  					return js_ast.Expr{Loc: target.Loc, Data: js_ast.EUndefinedShared}, true
 12344  				}
 12345  			}
 12346  		}
 12347  	}
 12348  
 12349  	// Handle references to namespaces or namespace members
 12350  	if target.Data == p.tsNamespaceTarget && assignTarget == js_ast.AssignTargetNone && !isDeleteTarget {
 12351  		if ns, ok := p.tsNamespaceMemberData.(*js_ast.TSNamespaceMemberNamespace); ok {
 12352  			if member, ok := ns.ExportedMembers[name]; ok {
 12353  				switch m := member.Data.(type) {
 12354  				case *js_ast.TSNamespaceMemberEnumNumber:
 12355  					p.ignoreUsageOfIdentifierInDotChain(target)
 12356  					return p.wrapInlinedEnum(js_ast.Expr{Loc: loc, Data: &js_ast.ENumber{Value: m.Value}}, name), true
 12357  
 12358  				case *js_ast.TSNamespaceMemberEnumString:
 12359  					p.ignoreUsageOfIdentifierInDotChain(target)
 12360  					return p.wrapInlinedEnum(js_ast.Expr{Loc: loc, Data: &js_ast.EString{Value: m.Value}}, name), true
 12361  
 12362  				case *js_ast.TSNamespaceMemberNamespace:
 12363  					// If this isn't a constant, return a clone of this property access
 12364  					// but with the namespace member data associated with it so that
 12365  					// more property accesses off of this property access are recognized.
 12366  					if preferQuotedKey || !js_ast.IsIdentifier(name) {
 12367  						p.tsNamespaceTarget = &js_ast.EIndex{
 12368  							Target: target,
 12369  							Index:  js_ast.Expr{Loc: nameLoc, Data: &js_ast.EString{Value: helpers.StringToUTF16(name)}},
 12370  						}
 12371  					} else {
 12372  						p.tsNamespaceTarget = p.dotOrMangledPropVisit(target, name, nameLoc)
 12373  					}
 12374  					p.tsNamespaceMemberData = member.Data
 12375  					return js_ast.Expr{Loc: loc, Data: p.tsNamespaceTarget}, true
 12376  				}
 12377  			}
 12378  		}
 12379  	}
 12380  
 12381  	// Symbol uses due to a property access off of an imported symbol are tracked
 12382  	// specially. This lets us do tree shaking for cross-file TypeScript enums.
 12383  	if p.options.mode == config.ModeBundle && !p.isControlFlowDead {
 12384  		if id, ok := target.Data.(*js_ast.EImportIdentifier); ok {
 12385  			// Remove the normal symbol use
 12386  			use := p.symbolUses[id.Ref]
 12387  			use.CountEstimate--
 12388  			if use.CountEstimate == 0 {
 12389  				delete(p.symbolUses, id.Ref)
 12390  			} else {
 12391  				p.symbolUses[id.Ref] = use
 12392  			}
 12393  
 12394  			// Add a special symbol use instead
 12395  			if p.importSymbolPropertyUses == nil {
 12396  				p.importSymbolPropertyUses = make(map[ast.Ref]map[string]js_ast.SymbolUse)
 12397  			}
 12398  			properties := p.importSymbolPropertyUses[id.Ref]
 12399  			if properties == nil {
 12400  				properties = make(map[string]js_ast.SymbolUse)
 12401  				p.importSymbolPropertyUses[id.Ref] = properties
 12402  			}
 12403  			use = properties[name]
 12404  			use.CountEstimate++
 12405  			properties[name] = use
 12406  		}
 12407  	}
 12408  
 12409  	// Minify "foo".length
 12410  	if p.options.minifySyntax && assignTarget == js_ast.AssignTargetNone {
 12411  		switch t := target.Data.(type) {
 12412  		case *js_ast.EString:
 12413  			if name == "length" {
 12414  				return js_ast.Expr{Loc: loc, Data: &js_ast.ENumber{Value: float64(len(t.Value))}}, true
 12415  			}
 12416  		case *js_ast.EInlinedEnum:
 12417  			if s, ok := t.Value.Data.(*js_ast.EString); ok && name == "length" {
 12418  				return js_ast.Expr{Loc: loc, Data: &js_ast.ENumber{Value: float64(len(s.Value))}}, true
 12419  			}
 12420  		}
 12421  	}
 12422  
 12423  	return js_ast.Expr{}, false
 12424  }
 12425  
 12426  type exprIn struct {
 12427  	isMethod               bool
 12428  	isLoweredPrivateMethod bool
 12429  
 12430  	// This tells us if there are optional chain expressions (EDot, EIndex, or
 12431  	// ECall) that are chained on to this expression. Because of the way the AST
 12432  	// works, chaining expressions on to this expression means they are our
 12433  	// parent expressions.
 12434  	//
 12435  	// Some examples:
 12436  	//
 12437  	//   a?.b.c  // EDot
 12438  	//   a?.b[c] // EIndex
 12439  	//   a?.b()  // ECall
 12440  	//
 12441  	// Note that this is false if our parent is a node with a OptionalChain
 12442  	// value of OptionalChainStart. That means it's the start of a new chain, so
 12443  	// it's not considered part of this one.
 12444  	//
 12445  	// Some examples:
 12446  	//
 12447  	//   a?.b?.c   // EDot
 12448  	//   a?.b?.[c] // EIndex
 12449  	//   a?.b?.()  // ECall
 12450  	//
 12451  	// Also note that this is false if our parent is a node with a OptionalChain
 12452  	// value of OptionalChainNone. That means it's outside parentheses, which
 12453  	// means it's no longer part of the chain.
 12454  	//
 12455  	// Some examples:
 12456  	//
 12457  	//   (a?.b).c  // EDot
 12458  	//   (a?.b)[c] // EIndex
 12459  	//   (a?.b)()  // ECall
 12460  	//
 12461  	hasChainParent bool
 12462  
 12463  	// If our parent is an ECall node with an OptionalChain value of
 12464  	// OptionalChainStart, then we will need to store the value for the "this" of
 12465  	// that call somewhere if the current expression is an optional chain that
 12466  	// ends in a property access. That's because the value for "this" will be
 12467  	// used twice: once for the inner optional chain and once for the outer
 12468  	// optional chain.
 12469  	//
 12470  	// Example:
 12471  	//
 12472  	//   // Original
 12473  	//   a?.b?.();
 12474  	//
 12475  	//   // Lowered
 12476  	//   var _a;
 12477  	//   (_a = a == null ? void 0 : a.b) == null ? void 0 : _a.call(a);
 12478  	//
 12479  	// In the example above we need to store "a" as the value for "this" so we
 12480  	// can substitute it back in when we call "_a" if "_a" is indeed present.
 12481  	// See also "thisArgFunc" and "thisArgWrapFunc" in "exprOut".
 12482  	storeThisArgForParentOptionalChain bool
 12483  
 12484  	// If true, string literals that match the current property mangling pattern
 12485  	// should be turned into ENameOfSymbol expressions, which will cause us to
 12486  	// rename them in the linker.
 12487  	shouldMangleStringsAsProps bool
 12488  
 12489  	// Certain substitutions of identifiers are disallowed for assignment targets.
 12490  	// For example, we shouldn't transform "undefined = 1" into "void 0 = 1". This
 12491  	// isn't something real-world code would do but it matters for conformance
 12492  	// tests.
 12493  	assignTarget js_ast.AssignTarget
 12494  }
 12495  
 12496  type exprOut struct {
 12497  	// If our parent is an ECall node with an OptionalChain value of
 12498  	// OptionalChainContinue, then we may need to return the value for "this"
 12499  	// from this node or one of this node's children so that the parent that is
 12500  	// the end of the optional chain can use it.
 12501  	//
 12502  	// Example:
 12503  	//
 12504  	//   // Original
 12505  	//   a?.b?.().c();
 12506  	//
 12507  	//   // Lowered
 12508  	//   var _a;
 12509  	//   (_a = a == null ? void 0 : a.b) == null ? void 0 : _a.call(a).c();
 12510  	//
 12511  	// The value "_a" for "this" must be passed all the way up to the call to
 12512  	// ".c()" which is where the optional chain is lowered. From there it must
 12513  	// be substituted as the value for "this" in the call to ".b?.()". See also
 12514  	// "storeThisArgForParentOptionalChain" in "exprIn".
 12515  	thisArgFunc     func() js_ast.Expr
 12516  	thisArgWrapFunc func(js_ast.Expr) js_ast.Expr
 12517  
 12518  	// True if the child node is an optional chain node (EDot, EIndex, or ECall
 12519  	// with an IsOptionalChain value of true)
 12520  	childContainsOptionalChain bool
 12521  
 12522  	// If true and this is used as a call target, the whole call expression
 12523  	// must be replaced with undefined.
 12524  	methodCallMustBeReplacedWithUndefined bool
 12525  }
 12526  
 12527  func (p *parser) visitExpr(expr js_ast.Expr) js_ast.Expr {
 12528  	expr, _ = p.visitExprInOut(expr, exprIn{})
 12529  	return expr
 12530  }
 12531  
 12532  func (p *parser) valueForThis(
 12533  	loc logger.Loc,
 12534  	shouldLog bool,
 12535  	assignTarget js_ast.AssignTarget,
 12536  	isCallTarget bool,
 12537  	isDeleteTarget bool,
 12538  ) (js_ast.Expr, bool) {
 12539  	// Substitute "this" if we're inside a static class context
 12540  	if p.fnOnlyDataVisit.shouldReplaceThisWithInnerClassNameRef {
 12541  		p.recordUsage(*p.fnOnlyDataVisit.innerClassNameRef)
 12542  		return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: *p.fnOnlyDataVisit.innerClassNameRef}}, true
 12543  	}
 12544  
 12545  	// Is this a top-level use of "this"?
 12546  	if !p.fnOnlyDataVisit.isThisNested {
 12547  		// Substitute user-specified defines
 12548  		if data, ok := p.options.defines.IdentifierDefines["this"]; ok {
 12549  			if data.DefineExpr != nil {
 12550  				return p.instantiateDefineExpr(loc, *data.DefineExpr, identifierOpts{
 12551  					assignTarget:   assignTarget,
 12552  					isCallTarget:   isCallTarget,
 12553  					isDeleteTarget: isDeleteTarget,
 12554  				}), true
 12555  			}
 12556  		}
 12557  
 12558  		// Otherwise, replace top-level "this" with either "undefined" or "exports"
 12559  		if p.isFileConsideredToHaveESMExports {
 12560  			// Warn about "this" becoming undefined, but only once per file
 12561  			if shouldLog && !p.messageAboutThisIsUndefined && !p.fnOnlyDataVisit.silenceMessageAboutThisBeingUndefined {
 12562  				p.messageAboutThisIsUndefined = true
 12563  				kind := logger.Debug
 12564  				data := p.tracker.MsgData(js_lexer.RangeOfIdentifier(p.source, loc),
 12565  					"Top-level \"this\" will be replaced with undefined since this file is an ECMAScript module")
 12566  				data.Location.Suggestion = "undefined"
 12567  				_, notes := p.whyESModule()
 12568  				p.log.AddMsgID(logger.MsgID_JS_ThisIsUndefinedInESM, logger.Msg{Kind: kind, Data: data, Notes: notes})
 12569  			}
 12570  
 12571  			// In an ES6 module, "this" is supposed to be undefined. Instead of
 12572  			// doing this at runtime using "fn.call(undefined)", we do it at
 12573  			// compile time using expression substitution here.
 12574  			return js_ast.Expr{Loc: loc, Data: js_ast.EUndefinedShared}, true
 12575  		} else if p.options.mode != config.ModePassThrough {
 12576  			// In a CommonJS module, "this" is supposed to be the same as "exports".
 12577  			// Instead of doing this at runtime using "fn.call(module.exports)", we
 12578  			// do it at compile time using expression substitution here.
 12579  			p.recordUsage(p.exportsRef)
 12580  			return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: p.exportsRef}}, true
 12581  		}
 12582  	}
 12583  
 12584  	return js_ast.Expr{}, false
 12585  }
 12586  
 12587  func (p *parser) valueForImportMeta(loc logger.Loc) (js_ast.Expr, bool) {
 12588  	if p.options.unsupportedJSFeatures.Has(compat.ImportMeta) ||
 12589  		(p.options.mode != config.ModePassThrough && !p.options.outputFormat.KeepESMImportExportSyntax()) {
 12590  		// Generate the variable if it doesn't exist yet
 12591  		if p.importMetaRef == ast.InvalidRef {
 12592  			p.importMetaRef = p.newSymbol(ast.SymbolOther, "import_meta")
 12593  			p.moduleScope.Generated = append(p.moduleScope.Generated, p.importMetaRef)
 12594  		}
 12595  
 12596  		// Replace "import.meta" with a reference to the symbol
 12597  		p.recordUsage(p.importMetaRef)
 12598  		return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: p.importMetaRef}}, true
 12599  	}
 12600  
 12601  	return js_ast.Expr{}, false
 12602  }
 12603  
 12604  func locAfterOp(e *js_ast.EBinary) logger.Loc {
 12605  	if e.Left.Loc.Start < e.Right.Loc.Start {
 12606  		return e.Right.Loc
 12607  	} else {
 12608  		// Handle the case when we have transposed the operands
 12609  		return e.Left.Loc
 12610  	}
 12611  }
 12612  
 12613  // This function exists to tie all of these checks together in one place
 12614  func isEvalOrArguments(name string) bool {
 12615  	return name == "eval" || name == "arguments"
 12616  }
 12617  
 12618  func (p *parser) reportPrivateNameUsage(name string) {
 12619  	if p.parseExperimentalDecoratorNesting > 0 {
 12620  		if p.lowerAllOfThesePrivateNames == nil {
 12621  			p.lowerAllOfThesePrivateNames = make(map[string]bool)
 12622  		}
 12623  		p.lowerAllOfThesePrivateNames[name] = true
 12624  	}
 12625  }
 12626  
 12627  func (p *parser) isValidAssignmentTarget(expr js_ast.Expr) bool {
 12628  	switch e := expr.Data.(type) {
 12629  	case *js_ast.EIdentifier:
 12630  		if p.isStrictMode() {
 12631  			if name := p.loadNameFromRef(e.Ref); isEvalOrArguments(name) {
 12632  				return false
 12633  			}
 12634  		}
 12635  		return true
 12636  	case *js_ast.EDot:
 12637  		return e.OptionalChain == js_ast.OptionalChainNone
 12638  	case *js_ast.EIndex:
 12639  		return e.OptionalChain == js_ast.OptionalChainNone
 12640  
 12641  	// Don't worry about recursive checking for objects and arrays. This will
 12642  	// already be handled naturally by passing down the assign target flag.
 12643  	case *js_ast.EObject:
 12644  		return !e.IsParenthesized
 12645  	case *js_ast.EArray:
 12646  		return !e.IsParenthesized
 12647  	}
 12648  	return false
 12649  }
 12650  
 12651  func containsClosingScriptTag(text string) bool {
 12652  	for {
 12653  		i := strings.Index(text, "</")
 12654  		if i < 0 {
 12655  			break
 12656  		}
 12657  		text = text[i+2:]
 12658  		if len(text) >= 6 && strings.EqualFold(text[:6], "script") {
 12659  			return true
 12660  		}
 12661  	}
 12662  	return false
 12663  }
 12664  
 12665  func (p *parser) isUnsupportedRegularExpression(loc logger.Loc, value string) (pattern string, flags string, isUnsupported bool) {
 12666  	var what string
 12667  	var r logger.Range
 12668  
 12669  	end := strings.LastIndexByte(value, '/')
 12670  	pattern = value[1:end]
 12671  	flags = value[end+1:]
 12672  	isUnicode := strings.IndexByte(flags, 'u') >= 0
 12673  	parenDepth := 0
 12674  	i := 0
 12675  
 12676  	// Do a simple scan for unsupported features assuming the regular expression
 12677  	// is valid. This doesn't do a full validation of the regular expression
 12678  	// because regular expression grammar is complicated. If it contains a syntax
 12679  	// error that we don't catch, then we will just generate output code with a
 12680  	// syntax error. Garbage in, garbage out.
 12681  pattern:
 12682  	for i < len(pattern) {
 12683  		c := pattern[i]
 12684  		i++
 12685  
 12686  		switch c {
 12687  		case '[':
 12688  		class:
 12689  			for i < len(pattern) {
 12690  				c := pattern[i]
 12691  				i++
 12692  
 12693  				switch c {
 12694  				case ']':
 12695  					break class
 12696  
 12697  				case '\\':
 12698  					i++ // Skip the escaped character
 12699  				}
 12700  			}
 12701  
 12702  		case '(':
 12703  			tail := pattern[i:]
 12704  
 12705  			if strings.HasPrefix(tail, "?<=") || strings.HasPrefix(tail, "?<!") {
 12706  				if p.options.unsupportedJSFeatures.Has(compat.RegexpLookbehindAssertions) {
 12707  					what = "Lookbehind assertions in regular expressions are not available"
 12708  					r = logger.Range{Loc: logger.Loc{Start: loc.Start + int32(i) + 1}, Len: 3}
 12709  					isUnsupported = true
 12710  					break pattern
 12711  				}
 12712  			} else if strings.HasPrefix(tail, "?<") {
 12713  				if p.options.unsupportedJSFeatures.Has(compat.RegexpNamedCaptureGroups) {
 12714  					if end := strings.IndexByte(tail, '>'); end >= 0 {
 12715  						what = "Named capture groups in regular expressions are not available"
 12716  						r = logger.Range{Loc: logger.Loc{Start: loc.Start + int32(i) + 1}, Len: int32(end) + 1}
 12717  						isUnsupported = true
 12718  						break pattern
 12719  					}
 12720  				}
 12721  			}
 12722  
 12723  			parenDepth++
 12724  
 12725  		case ')':
 12726  			if parenDepth == 0 {
 12727  				r := logger.Range{Loc: logger.Loc{Start: loc.Start + int32(i)}, Len: 1}
 12728  				p.log.AddError(&p.tracker, r, "Unexpected \")\" in regular expression")
 12729  				return
 12730  			}
 12731  
 12732  			parenDepth--
 12733  
 12734  		case '\\':
 12735  			tail := pattern[i:]
 12736  
 12737  			if isUnicode && (strings.HasPrefix(tail, "p{") || strings.HasPrefix(tail, "P{")) {
 12738  				if p.options.unsupportedJSFeatures.Has(compat.RegexpUnicodePropertyEscapes) {
 12739  					if end := strings.IndexByte(tail, '}'); end >= 0 {
 12740  						what = "Unicode property escapes in regular expressions are not available"
 12741  						r = logger.Range{Loc: logger.Loc{Start: loc.Start + int32(i)}, Len: int32(end) + 2}
 12742  						isUnsupported = true
 12743  						break pattern
 12744  					}
 12745  				}
 12746  			}
 12747  
 12748  			i++ // Skip the escaped character
 12749  		}
 12750  	}
 12751  
 12752  	if !isUnsupported {
 12753  		for i, c := range flags {
 12754  			switch c {
 12755  			case 'g', 'i', 'm':
 12756  				continue // These are part of ES5 and are always supported
 12757  
 12758  			case 's':
 12759  				if !p.options.unsupportedJSFeatures.Has(compat.RegexpDotAllFlag) {
 12760  					continue // This is part of ES2018
 12761  				}
 12762  
 12763  			case 'y', 'u':
 12764  				if !p.options.unsupportedJSFeatures.Has(compat.RegexpStickyAndUnicodeFlags) {
 12765  					continue // These are part of ES2018
 12766  				}
 12767  
 12768  			case 'd':
 12769  				if !p.options.unsupportedJSFeatures.Has(compat.RegexpMatchIndices) {
 12770  					continue // This is part of ES2022
 12771  				}
 12772  
 12773  			case 'v':
 12774  				if !p.options.unsupportedJSFeatures.Has(compat.RegexpSetNotation) {
 12775  					continue // This is from a proposal: https://github.com/tc39/proposal-regexp-v-flag
 12776  				}
 12777  
 12778  			default:
 12779  				// Unknown flags are never supported
 12780  			}
 12781  
 12782  			r = logger.Range{Loc: logger.Loc{Start: loc.Start + int32(end+1) + int32(i)}, Len: 1}
 12783  			what = fmt.Sprintf("The regular expression flag \"%c\" is not available", c)
 12784  			isUnsupported = true
 12785  			break
 12786  		}
 12787  	}
 12788  
 12789  	if isUnsupported {
 12790  		where := config.PrettyPrintTargetEnvironment(p.options.originalTargetEnv, p.options.unsupportedJSFeatureOverridesMask)
 12791  		p.log.AddIDWithNotes(logger.MsgID_JS_UnsupportedRegExp, logger.Debug, &p.tracker, r, fmt.Sprintf("%s in %s", what, where), []logger.MsgData{{
 12792  			Text: "This regular expression literal has been converted to a \"new RegExp()\" constructor " +
 12793  				"to avoid generating code with a syntax error. However, you will need to include a " +
 12794  				"polyfill for \"RegExp\" for your code to have the correct behavior at run-time."}})
 12795  	}
 12796  
 12797  	return
 12798  }
 12799  
 12800  // This function takes "exprIn" as input from the caller and produces "exprOut"
 12801  // for the caller to pass along extra data. This is mostly for optional chaining.
 12802  func (p *parser) visitExprInOut(expr js_ast.Expr, in exprIn) (js_ast.Expr, exprOut) {
 12803  	if in.assignTarget != js_ast.AssignTargetNone && !p.isValidAssignmentTarget(expr) {
 12804  		p.log.AddError(&p.tracker, logger.Range{Loc: expr.Loc}, "Invalid assignment target")
 12805  	}
 12806  
 12807  	// Note: Anything added before or after this switch statement will be bypassed
 12808  	// when visiting nested "EBinary" nodes due to stack overflow mitigations for
 12809  	// deeply-nested ASTs. If anything like that is added, care must be taken that
 12810  	// it doesn't affect these mitigations by ensuring that the mitigations are not
 12811  	// applied in those cases (e.g. by adding an additional conditional check).
 12812  	switch e := expr.Data.(type) {
 12813  	case *js_ast.ENull, *js_ast.ESuper, *js_ast.EBoolean, *js_ast.EBigInt, *js_ast.EUndefined, *js_ast.EJSXText:
 12814  
 12815  	case *js_ast.ENameOfSymbol:
 12816  		e.Ref = p.symbolForMangledProp(p.loadNameFromRef(e.Ref))
 12817  
 12818  	case *js_ast.ERegExp:
 12819  		// "/pattern/flags" => "new RegExp('pattern', 'flags')"
 12820  		if pattern, flags, ok := p.isUnsupportedRegularExpression(expr.Loc, e.Value); ok {
 12821  			args := []js_ast.Expr{{
 12822  				Loc:  logger.Loc{Start: expr.Loc.Start + 1},
 12823  				Data: &js_ast.EString{Value: helpers.StringToUTF16(pattern)},
 12824  			}}
 12825  			if flags != "" {
 12826  				args = append(args, js_ast.Expr{
 12827  					Loc:  logger.Loc{Start: expr.Loc.Start + int32(len(pattern)) + 2},
 12828  					Data: &js_ast.EString{Value: helpers.StringToUTF16(flags)},
 12829  				})
 12830  			}
 12831  			regExpRef := p.makeRegExpRef()
 12832  			p.recordUsage(regExpRef)
 12833  			return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ENew{
 12834  				Target:        js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EIdentifier{Ref: regExpRef}},
 12835  				Args:          args,
 12836  				CloseParenLoc: logger.Loc{Start: expr.Loc.Start + int32(len(e.Value))},
 12837  			}}, exprOut{}
 12838  		}
 12839  
 12840  	case *js_ast.ENewTarget:
 12841  		if !p.fnOnlyDataVisit.isNewTargetAllowed {
 12842  			p.log.AddError(&p.tracker, e.Range, "Cannot use \"new.target\" here:")
 12843  		}
 12844  
 12845  	case *js_ast.EString:
 12846  		if e.LegacyOctalLoc.Start > 0 {
 12847  			if e.PreferTemplate {
 12848  				p.log.AddError(&p.tracker, p.source.RangeOfLegacyOctalEscape(e.LegacyOctalLoc),
 12849  					"Legacy octal escape sequences cannot be used in template literals")
 12850  			} else if p.isStrictMode() {
 12851  				p.markStrictModeFeature(legacyOctalEscape, p.source.RangeOfLegacyOctalEscape(e.LegacyOctalLoc), "")
 12852  			}
 12853  		}
 12854  
 12855  		if in.shouldMangleStringsAsProps && p.options.mangleQuoted && !e.PreferTemplate {
 12856  			if name := helpers.UTF16ToString(e.Value); p.isMangledProp(name) {
 12857  				return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ENameOfSymbol{
 12858  					Ref: p.symbolForMangledProp(name),
 12859  				}}, exprOut{}
 12860  			}
 12861  		}
 12862  
 12863  	case *js_ast.ENumber:
 12864  		if p.legacyOctalLiterals != nil && p.isStrictMode() {
 12865  			if r, ok := p.legacyOctalLiterals[expr.Data]; ok {
 12866  				p.markStrictModeFeature(legacyOctalLiteral, r, "")
 12867  			}
 12868  		}
 12869  
 12870  	case *js_ast.EThis:
 12871  		isDeleteTarget := e == p.deleteTarget
 12872  		isCallTarget := e == p.callTarget
 12873  
 12874  		if value, ok := p.valueForThis(expr.Loc, true /* shouldLog */, in.assignTarget, isDeleteTarget, isCallTarget); ok {
 12875  			return value, exprOut{}
 12876  		}
 12877  
 12878  		// Capture "this" inside arrow functions that will be lowered into normal
 12879  		// function expressions for older language environments
 12880  		if p.fnOrArrowDataVisit.isArrow && p.options.unsupportedJSFeatures.Has(compat.Arrow) && p.fnOnlyDataVisit.isThisNested {
 12881  			return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EIdentifier{Ref: p.captureThis()}}, exprOut{}
 12882  		}
 12883  
 12884  	case *js_ast.EImportMeta:
 12885  		isDeleteTarget := e == p.deleteTarget
 12886  		isCallTarget := e == p.callTarget
 12887  
 12888  		// Check both user-specified defines and known globals
 12889  		if defines, ok := p.options.defines.DotDefines["meta"]; ok {
 12890  			for _, define := range defines {
 12891  				if p.isDotOrIndexDefineMatch(expr, define.Parts) {
 12892  					// Substitute user-specified defines
 12893  					if define.Data.DefineExpr != nil {
 12894  						return p.instantiateDefineExpr(expr.Loc, *define.Data.DefineExpr, identifierOpts{
 12895  							assignTarget:   in.assignTarget,
 12896  							isCallTarget:   isCallTarget,
 12897  							isDeleteTarget: isDeleteTarget,
 12898  						}), exprOut{}
 12899  					}
 12900  				}
 12901  			}
 12902  		}
 12903  
 12904  		// Check injected dot names
 12905  		if names, ok := p.injectedDotNames["meta"]; ok {
 12906  			for _, name := range names {
 12907  				if p.isDotOrIndexDefineMatch(expr, name.parts) {
 12908  					// Note: We don't need to "ignoreRef" on the underlying identifier
 12909  					// because we have only parsed it but not visited it yet
 12910  					return p.instantiateInjectDotName(expr.Loc, name, in.assignTarget), exprOut{}
 12911  				}
 12912  			}
 12913  		}
 12914  
 12915  		// Warn about "import.meta" if it's not replaced by a define
 12916  		if p.options.unsupportedJSFeatures.Has(compat.ImportMeta) {
 12917  			r := logger.Range{Loc: expr.Loc, Len: e.RangeLen}
 12918  			p.markSyntaxFeature(compat.ImportMeta, r)
 12919  		} else if p.options.mode != config.ModePassThrough && !p.options.outputFormat.KeepESMImportExportSyntax() {
 12920  			r := logger.Range{Loc: expr.Loc, Len: e.RangeLen}
 12921  			kind := logger.Warning
 12922  			if p.suppressWarningsAboutWeirdCode || p.fnOrArrowDataVisit.tryBodyCount > 0 {
 12923  				kind = logger.Debug
 12924  			}
 12925  			p.log.AddIDWithNotes(logger.MsgID_JS_EmptyImportMeta, kind, &p.tracker, r, fmt.Sprintf(
 12926  				"\"import.meta\" is not available with the %q output format and will be empty", p.options.outputFormat.String()),
 12927  				[]logger.MsgData{{Text: "You need to set the output format to \"esm\" for \"import.meta\" to work correctly."}})
 12928  		}
 12929  
 12930  		// Convert "import.meta" to a variable if it's not supported in the output format
 12931  		if importMeta, ok := p.valueForImportMeta(expr.Loc); ok {
 12932  			return importMeta, exprOut{}
 12933  		}
 12934  
 12935  	case *js_ast.ESpread:
 12936  		e.Value = p.visitExpr(e.Value)
 12937  
 12938  	case *js_ast.EIdentifier:
 12939  		isCallTarget := e == p.callTarget
 12940  		isDeleteTarget := e == p.deleteTarget
 12941  		name := p.loadNameFromRef(e.Ref)
 12942  		if p.isStrictMode() && js_lexer.StrictModeReservedWords[name] {
 12943  			p.markStrictModeFeature(reservedWord, js_lexer.RangeOfIdentifier(p.source, expr.Loc), name)
 12944  		}
 12945  		result := p.findSymbol(expr.Loc, name)
 12946  		e.MustKeepDueToWithStmt = result.isInsideWithScope
 12947  		e.Ref = result.ref
 12948  
 12949  		// Handle referencing a class name within that class's computed property
 12950  		// key. This is not allowed, and must fail at run-time:
 12951  		//
 12952  		//   class Foo {
 12953  		//     static foo = 'bar'
 12954  		//     static [Foo.foo] = 'foo'
 12955  		//   }
 12956  		//
 12957  		if p.symbols[result.ref.InnerIndex].Kind == ast.SymbolClassInComputedPropertyKey {
 12958  			p.log.AddID(logger.MsgID_JS_ClassNameWillThrow, logger.Warning, &p.tracker, js_lexer.RangeOfIdentifier(p.source, expr.Loc),
 12959  				fmt.Sprintf("Accessing class %q before initialization will throw", name))
 12960  			return p.callRuntime(expr.Loc, "__earlyAccess", []js_ast.Expr{{Loc: expr.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(name)}}}), exprOut{}
 12961  		}
 12962  
 12963  		// Handle assigning to a constant
 12964  		if in.assignTarget != js_ast.AssignTargetNone {
 12965  			switch p.symbols[result.ref.InnerIndex].Kind {
 12966  			case ast.SymbolConst:
 12967  				r := js_lexer.RangeOfIdentifier(p.source, expr.Loc)
 12968  				notes := []logger.MsgData{p.tracker.MsgData(js_lexer.RangeOfIdentifier(p.source, result.declareLoc),
 12969  					fmt.Sprintf("The symbol %q was declared a constant here:", name))}
 12970  
 12971  				// Make this an error when bundling because we may need to convert this
 12972  				// "const" into a "var" during bundling. Also make this an error when
 12973  				// the constant is inlined because we will otherwise generate code with
 12974  				// a syntax error.
 12975  				if _, isInlinedConstant := p.constValues[result.ref]; isInlinedConstant || p.options.mode == config.ModeBundle ||
 12976  					(p.currentScope.Parent == nil && p.willWrapModuleInTryCatchForUsing) {
 12977  					p.log.AddErrorWithNotes(&p.tracker, r,
 12978  						fmt.Sprintf("Cannot assign to %q because it is a constant", name), notes)
 12979  				} else {
 12980  					p.log.AddIDWithNotes(logger.MsgID_JS_AssignToConstant, logger.Warning, &p.tracker, r,
 12981  						fmt.Sprintf("This assignment will throw because %q is a constant", name), notes)
 12982  				}
 12983  
 12984  			case ast.SymbolInjected:
 12985  				if where, ok := p.injectedSymbolSources[result.ref]; ok {
 12986  					r := js_lexer.RangeOfIdentifier(p.source, expr.Loc)
 12987  					tracker := logger.MakeLineColumnTracker(&where.source)
 12988  					p.log.AddErrorWithNotes(&p.tracker, r,
 12989  						fmt.Sprintf("Cannot assign to %q because it's an import from an injected file", name),
 12990  						[]logger.MsgData{tracker.MsgData(js_lexer.RangeOfIdentifier(where.source, where.loc),
 12991  							fmt.Sprintf("The symbol %q was exported from %q here:", name, where.source.PrettyPath))})
 12992  				}
 12993  			}
 12994  		}
 12995  
 12996  		// Substitute user-specified defines for unbound or injected symbols
 12997  		methodCallMustBeReplacedWithUndefined := false
 12998  		if p.symbols[e.Ref.InnerIndex].Kind.IsUnboundOrInjected() && !result.isInsideWithScope && e != p.deleteTarget {
 12999  			if data, ok := p.options.defines.IdentifierDefines[name]; ok {
 13000  				if data.DefineExpr != nil {
 13001  					new := p.instantiateDefineExpr(expr.Loc, *data.DefineExpr, identifierOpts{
 13002  						assignTarget:   in.assignTarget,
 13003  						isCallTarget:   isCallTarget,
 13004  						isDeleteTarget: isDeleteTarget,
 13005  					})
 13006  					if in.assignTarget == js_ast.AssignTargetNone || defineValueCanBeUsedInAssignTarget(new.Data) {
 13007  						p.ignoreUsage(e.Ref)
 13008  						return new, exprOut{}
 13009  					} else {
 13010  						p.logAssignToDefine(js_lexer.RangeOfIdentifier(p.source, expr.Loc), name, js_ast.Expr{})
 13011  					}
 13012  				}
 13013  
 13014  				// Copy the side effect flags over in case this expression is unused
 13015  				if data.Flags.Has(config.CanBeRemovedIfUnused) {
 13016  					e.CanBeRemovedIfUnused = true
 13017  				}
 13018  				if data.Flags.Has(config.CallCanBeUnwrappedIfUnused) && !p.options.ignoreDCEAnnotations {
 13019  					e.CallCanBeUnwrappedIfUnused = true
 13020  				}
 13021  				if data.Flags.Has(config.MethodCallsMustBeReplacedWithUndefined) {
 13022  					methodCallMustBeReplacedWithUndefined = true
 13023  				}
 13024  			}
 13025  		}
 13026  
 13027  		return p.handleIdentifier(expr.Loc, e, identifierOpts{
 13028  				assignTarget:            in.assignTarget,
 13029  				isCallTarget:            isCallTarget,
 13030  				isDeleteTarget:          isDeleteTarget,
 13031  				wasOriginallyIdentifier: true,
 13032  			}), exprOut{
 13033  				methodCallMustBeReplacedWithUndefined: methodCallMustBeReplacedWithUndefined,
 13034  			}
 13035  
 13036  	case *js_ast.EJSXElement:
 13037  		propsLoc := expr.Loc
 13038  
 13039  		// Resolving the location index to a specific line and column in
 13040  		// development mode is not too expensive because we seek from the
 13041  		// previous JSX element. It amounts to at most a single additional
 13042  		// scan over the source code. Note that this has to happen before
 13043  		// we visit anything about this JSX element to make sure that we
 13044  		// only ever need to scan forward, not backward.
 13045  		var jsxSourceLine int
 13046  		var jsxSourceColumn int
 13047  		if p.options.jsx.Development && p.options.jsx.AutomaticRuntime {
 13048  			for p.jsxSourceLoc < int(propsLoc.Start) {
 13049  				r, size := utf8.DecodeRuneInString(p.source.Contents[p.jsxSourceLoc:])
 13050  				p.jsxSourceLoc += size
 13051  				if r == '\n' || r == '\r' || r == '\u2028' || r == '\u2029' {
 13052  					if r == '\r' && p.jsxSourceLoc < len(p.source.Contents) && p.source.Contents[p.jsxSourceLoc] == '\n' {
 13053  						p.jsxSourceLoc++ // Handle Windows-style CRLF newlines
 13054  					}
 13055  					p.jsxSourceLine++
 13056  					p.jsxSourceColumn = 0
 13057  				} else {
 13058  					// Babel and TypeScript count columns in UTF-16 code units
 13059  					if r < 0xFFFF {
 13060  						p.jsxSourceColumn++
 13061  					} else {
 13062  						p.jsxSourceColumn += 2
 13063  					}
 13064  				}
 13065  			}
 13066  			jsxSourceLine = p.jsxSourceLine
 13067  			jsxSourceColumn = p.jsxSourceColumn
 13068  		}
 13069  
 13070  		if e.TagOrNil.Data != nil {
 13071  			propsLoc = e.TagOrNil.Loc
 13072  			e.TagOrNil = p.visitExpr(e.TagOrNil)
 13073  			p.warnAboutImportNamespaceCall(e.TagOrNil, exprKindJSXTag)
 13074  		}
 13075  
 13076  		// Visit properties
 13077  		hasSpread := false
 13078  		for i, property := range e.Properties {
 13079  			if property.Kind == js_ast.PropertySpread {
 13080  				hasSpread = true
 13081  			} else {
 13082  				if mangled, ok := property.Key.Data.(*js_ast.ENameOfSymbol); ok {
 13083  					mangled.Ref = p.symbolForMangledProp(p.loadNameFromRef(mangled.Ref))
 13084  				} else {
 13085  					property.Key = p.visitExpr(property.Key)
 13086  				}
 13087  			}
 13088  			if property.ValueOrNil.Data != nil {
 13089  				property.ValueOrNil = p.visitExpr(property.ValueOrNil)
 13090  			}
 13091  			if property.InitializerOrNil.Data != nil {
 13092  				property.InitializerOrNil = p.visitExpr(property.InitializerOrNil)
 13093  			}
 13094  			e.Properties[i] = property
 13095  		}
 13096  
 13097  		// "{a, ...{b, c}, d}" => "{a, b, c, d}"
 13098  		if p.options.minifySyntax && hasSpread {
 13099  			e.Properties = js_ast.MangleObjectSpread(e.Properties)
 13100  		}
 13101  
 13102  		// Visit children
 13103  		if len(e.NullableChildren) > 0 {
 13104  			for i, childOrNil := range e.NullableChildren {
 13105  				if childOrNil.Data != nil {
 13106  					e.NullableChildren[i] = p.visitExpr(childOrNil)
 13107  				}
 13108  			}
 13109  		}
 13110  
 13111  		if p.options.jsx.Preserve {
 13112  			// If the tag is an identifier, mark it as needing to be upper-case
 13113  			switch tag := e.TagOrNil.Data.(type) {
 13114  			case *js_ast.EIdentifier:
 13115  				p.symbols[tag.Ref.InnerIndex].Flags |= ast.MustStartWithCapitalLetterForJSX
 13116  
 13117  			case *js_ast.EImportIdentifier:
 13118  				p.symbols[tag.Ref.InnerIndex].Flags |= ast.MustStartWithCapitalLetterForJSX
 13119  			}
 13120  		} else {
 13121  			// Remove any nil children in the array (in place) before iterating over it
 13122  			children := e.NullableChildren
 13123  			{
 13124  				end := 0
 13125  				for _, childOrNil := range children {
 13126  					if childOrNil.Data != nil {
 13127  						children[end] = childOrNil
 13128  						end++
 13129  					}
 13130  				}
 13131  				children = children[:end]
 13132  			}
 13133  
 13134  			// A missing tag is a fragment
 13135  			if e.TagOrNil.Data == nil {
 13136  				if p.options.jsx.AutomaticRuntime {
 13137  					e.TagOrNil = p.importJSXSymbol(expr.Loc, JSXImportFragment)
 13138  				} else {
 13139  					e.TagOrNil = p.instantiateDefineExpr(expr.Loc, p.options.jsx.Fragment, identifierOpts{
 13140  						wasOriginallyIdentifier: true,
 13141  						matchAgainstDefines:     true, // Allow defines to rewrite the JSX fragment factory
 13142  					})
 13143  				}
 13144  			}
 13145  
 13146  			shouldUseCreateElement := !p.options.jsx.AutomaticRuntime
 13147  			if !shouldUseCreateElement {
 13148  				// Even for runtime="automatic", <div {...props} key={key} /> is special cased to createElement
 13149  				// See https://github.com/babel/babel/blob/e482c763466ba3f44cb9e3467583b78b7f030b4a/packages/babel-plugin-transform-react-jsx/src/create-plugin.ts#L352
 13150  				seenPropsSpread := false
 13151  				for _, property := range e.Properties {
 13152  					if seenPropsSpread && property.Kind == js_ast.PropertyField {
 13153  						if str, ok := property.Key.Data.(*js_ast.EString); ok && helpers.UTF16EqualsString(str.Value, "key") {
 13154  							shouldUseCreateElement = true
 13155  							break
 13156  						}
 13157  					} else if property.Kind == js_ast.PropertySpread {
 13158  						seenPropsSpread = true
 13159  					}
 13160  				}
 13161  			}
 13162  
 13163  			if shouldUseCreateElement {
 13164  				// Arguments to createElement()
 13165  				args := []js_ast.Expr{e.TagOrNil}
 13166  				if len(e.Properties) > 0 {
 13167  					args = append(args, p.lowerObjectSpread(propsLoc, &js_ast.EObject{
 13168  						Properties:   e.Properties,
 13169  						IsSingleLine: e.IsTagSingleLine,
 13170  					}))
 13171  				} else {
 13172  					args = append(args, js_ast.Expr{Loc: propsLoc, Data: js_ast.ENullShared})
 13173  				}
 13174  				if len(children) > 0 {
 13175  					args = append(args, children...)
 13176  				}
 13177  
 13178  				// Call createElement()
 13179  				var target js_ast.Expr
 13180  				kind := js_ast.NormalCall
 13181  				if p.options.jsx.AutomaticRuntime {
 13182  					target = p.importJSXSymbol(expr.Loc, JSXImportCreateElement)
 13183  				} else {
 13184  					target = p.instantiateDefineExpr(expr.Loc, p.options.jsx.Factory, identifierOpts{
 13185  						wasOriginallyIdentifier: true,
 13186  						matchAgainstDefines:     true, // Allow defines to rewrite the JSX factory
 13187  					})
 13188  					if js_ast.IsPropertyAccess(target) {
 13189  						kind = js_ast.TargetWasOriginallyPropertyAccess
 13190  					}
 13191  					p.warnAboutImportNamespaceCall(target, exprKindCall)
 13192  				}
 13193  				return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ECall{
 13194  					Target:        target,
 13195  					Args:          args,
 13196  					CloseParenLoc: e.CloseLoc,
 13197  					IsMultiLine:   !e.IsTagSingleLine,
 13198  					Kind:          kind,
 13199  
 13200  					// Enable tree shaking
 13201  					CanBeUnwrappedIfUnused: !p.options.ignoreDCEAnnotations && !p.options.jsx.SideEffects,
 13202  				}}, exprOut{}
 13203  			} else {
 13204  				// Arguments to jsx()
 13205  				args := []js_ast.Expr{e.TagOrNil}
 13206  
 13207  				// Props argument
 13208  				properties := make([]js_ast.Property, 0, len(e.Properties)+1)
 13209  
 13210  				// For jsx(), "key" is passed in as a separate argument, so filter it out
 13211  				// from the props here. Also, check for __source and __self, which might have
 13212  				// been added by some upstream plugin. Their presence here would represent a
 13213  				// configuration error.
 13214  				hasKey := false
 13215  				keyProperty := js_ast.Expr{Loc: expr.Loc, Data: js_ast.EUndefinedShared}
 13216  				for _, property := range e.Properties {
 13217  					if str, ok := property.Key.Data.(*js_ast.EString); ok {
 13218  						propName := helpers.UTF16ToString(str.Value)
 13219  						switch propName {
 13220  						case "key":
 13221  							if boolean, ok := property.ValueOrNil.Data.(*js_ast.EBoolean); ok && boolean.Value && property.Flags.Has(js_ast.PropertyWasShorthand) {
 13222  								r := js_lexer.RangeOfIdentifier(p.source, property.Loc)
 13223  								msg := logger.Msg{
 13224  									Kind:  logger.Error,
 13225  									Data:  p.tracker.MsgData(r, "Please provide an explicit value for \"key\":"),
 13226  									Notes: []logger.MsgData{{Text: "Using \"key\" as a shorthand for \"key={true}\" is not allowed when using React's \"automatic\" JSX transform."}},
 13227  								}
 13228  								msg.Data.Location.Suggestion = "key={true}"
 13229  								p.log.AddMsg(msg)
 13230  							} else {
 13231  								keyProperty = property.ValueOrNil
 13232  								hasKey = true
 13233  							}
 13234  							continue
 13235  
 13236  						case "__source", "__self":
 13237  							r := js_lexer.RangeOfIdentifier(p.source, property.Loc)
 13238  							p.log.AddErrorWithNotes(&p.tracker, r,
 13239  								fmt.Sprintf("Duplicate \"%s\" prop found:", propName),
 13240  								[]logger.MsgData{{Text: "Both \"__source\" and \"__self\" are set automatically by esbuild when using React's \"automatic\" JSX transform. " +
 13241  									"This duplicate prop may have come from a plugin."}})
 13242  							continue
 13243  						}
 13244  					}
 13245  					properties = append(properties, property)
 13246  				}
 13247  
 13248  				isStaticChildren := len(children) > 1
 13249  
 13250  				// Children are passed in as an explicit prop
 13251  				if len(children) > 0 {
 13252  					childrenValue := children[0]
 13253  
 13254  					if len(children) > 1 {
 13255  						childrenValue.Data = &js_ast.EArray{Items: children}
 13256  					} else if _, ok := childrenValue.Data.(*js_ast.ESpread); ok {
 13257  						// TypeScript considers spread children to be static, but Babel considers
 13258  						// it to be an error ("Spread children are not supported in React.").
 13259  						// We'll follow TypeScript's behavior here because spread children may be
 13260  						// valid with non-React source runtimes.
 13261  						childrenValue.Data = &js_ast.EArray{Items: []js_ast.Expr{childrenValue}}
 13262  						isStaticChildren = true
 13263  					}
 13264  
 13265  					properties = append(properties, js_ast.Property{
 13266  						Key: js_ast.Expr{
 13267  							Data: &js_ast.EString{Value: helpers.StringToUTF16("children")},
 13268  							Loc:  childrenValue.Loc,
 13269  						},
 13270  						ValueOrNil: childrenValue,
 13271  						Kind:       js_ast.PropertyField,
 13272  						Loc:        childrenValue.Loc,
 13273  					})
 13274  				}
 13275  
 13276  				args = append(args, p.lowerObjectSpread(propsLoc, &js_ast.EObject{
 13277  					Properties:   properties,
 13278  					IsSingleLine: e.IsTagSingleLine,
 13279  				}))
 13280  
 13281  				// "key"
 13282  				if hasKey || p.options.jsx.Development {
 13283  					args = append(args, keyProperty)
 13284  				}
 13285  
 13286  				if p.options.jsx.Development {
 13287  					// "isStaticChildren"
 13288  					args = append(args, js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EBoolean{Value: isStaticChildren}})
 13289  
 13290  					// "__source"
 13291  					args = append(args, js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EObject{
 13292  						Properties: []js_ast.Property{
 13293  							{
 13294  								Kind:       js_ast.PropertyField,
 13295  								Key:        js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16("fileName")}},
 13296  								ValueOrNil: js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(p.source.PrettyPath)}},
 13297  							},
 13298  							{
 13299  								Kind:       js_ast.PropertyField,
 13300  								Key:        js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16("lineNumber")}},
 13301  								ValueOrNil: js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ENumber{Value: float64(jsxSourceLine + 1)}}, // 1-based lines
 13302  							},
 13303  							{
 13304  								Kind:       js_ast.PropertyField,
 13305  								Key:        js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16("columnNumber")}},
 13306  								ValueOrNil: js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ENumber{Value: float64(jsxSourceColumn + 1)}}, // 1-based columns
 13307  							},
 13308  						},
 13309  					}})
 13310  
 13311  					// "__self"
 13312  					__self := js_ast.Expr{Loc: expr.Loc, Data: js_ast.EThisShared}
 13313  					{
 13314  						if p.fnOnlyDataVisit.shouldReplaceThisWithInnerClassNameRef {
 13315  							// Substitute "this" if we're inside a static class context
 13316  							p.recordUsage(*p.fnOnlyDataVisit.innerClassNameRef)
 13317  							__self.Data = &js_ast.EIdentifier{Ref: *p.fnOnlyDataVisit.innerClassNameRef}
 13318  						} else if !p.fnOnlyDataVisit.isThisNested && p.options.mode != config.ModePassThrough {
 13319  							// Replace top-level "this" with "undefined" if there's an output format
 13320  							__self.Data = js_ast.EUndefinedShared
 13321  						} else if p.fnOrArrowDataVisit.isDerivedClassCtor {
 13322  							// We can't use "this" here in case it comes before "super()"
 13323  							__self.Data = js_ast.EUndefinedShared
 13324  						}
 13325  					}
 13326  					if _, ok := __self.Data.(*js_ast.EUndefined); !ok {
 13327  						// Omit "__self" entirely if it's undefined
 13328  						args = append(args, __self)
 13329  					}
 13330  				}
 13331  
 13332  				jsx := JSXImportJSX
 13333  				if isStaticChildren {
 13334  					jsx = JSXImportJSXS
 13335  				}
 13336  
 13337  				return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ECall{
 13338  					Target:        p.importJSXSymbol(expr.Loc, jsx),
 13339  					Args:          args,
 13340  					CloseParenLoc: e.CloseLoc,
 13341  					IsMultiLine:   !e.IsTagSingleLine,
 13342  
 13343  					// Enable tree shaking
 13344  					CanBeUnwrappedIfUnused: !p.options.ignoreDCEAnnotations && !p.options.jsx.SideEffects,
 13345  				}}, exprOut{}
 13346  			}
 13347  		}
 13348  
 13349  	case *js_ast.ETemplate:
 13350  		if e.LegacyOctalLoc.Start > 0 {
 13351  			p.log.AddError(&p.tracker, p.source.RangeOfLegacyOctalEscape(e.LegacyOctalLoc),
 13352  				"Legacy octal escape sequences cannot be used in template literals")
 13353  		}
 13354  
 13355  		var tagThisFunc func() js_ast.Expr
 13356  		var tagWrapFunc func(js_ast.Expr) js_ast.Expr
 13357  
 13358  		if e.TagOrNil.Data != nil {
 13359  			// Capture the value for "this" if the tag is a lowered optional chain.
 13360  			// We'll need to manually apply this value later to preserve semantics.
 13361  			tagIsLoweredOptionalChain := false
 13362  			if p.options.unsupportedJSFeatures.Has(compat.OptionalChain) {
 13363  				switch target := e.TagOrNil.Data.(type) {
 13364  				case *js_ast.EDot:
 13365  					tagIsLoweredOptionalChain = target.OptionalChain != js_ast.OptionalChainNone
 13366  				case *js_ast.EIndex:
 13367  					tagIsLoweredOptionalChain = target.OptionalChain != js_ast.OptionalChainNone
 13368  				}
 13369  			}
 13370  
 13371  			p.templateTag = e.TagOrNil.Data
 13372  			tag, tagOut := p.visitExprInOut(e.TagOrNil, exprIn{storeThisArgForParentOptionalChain: tagIsLoweredOptionalChain})
 13373  			e.TagOrNil = tag
 13374  			tagThisFunc = tagOut.thisArgFunc
 13375  			tagWrapFunc = tagOut.thisArgWrapFunc
 13376  
 13377  			// Copy the call side effect flag over if this is a known target
 13378  			if id, ok := tag.Data.(*js_ast.EIdentifier); ok && p.symbols[id.Ref.InnerIndex].Flags.Has(ast.CallCanBeUnwrappedIfUnused) {
 13379  				e.CanBeUnwrappedIfUnused = true
 13380  			}
 13381  
 13382  			// The value of "this" must be manually preserved for private member
 13383  			// accesses inside template tag expressions such as "this.#foo``".
 13384  			// The private member "this.#foo" must see the value of "this".
 13385  			if target, loc, private := p.extractPrivateIndex(e.TagOrNil); private != nil {
 13386  				// "foo.#bar`123`" => "__privateGet(_a = foo, #bar).bind(_a)`123`"
 13387  				targetFunc, targetWrapFunc := p.captureValueWithPossibleSideEffects(target.Loc, 2, target, valueCouldBeMutated)
 13388  				e.TagOrNil = targetWrapFunc(js_ast.Expr{Loc: target.Loc, Data: &js_ast.ECall{
 13389  					Target: js_ast.Expr{Loc: target.Loc, Data: &js_ast.EDot{
 13390  						Target:  p.lowerPrivateGet(targetFunc(), loc, private),
 13391  						Name:    "bind",
 13392  						NameLoc: target.Loc,
 13393  					}},
 13394  					Args: []js_ast.Expr{targetFunc()},
 13395  					Kind: js_ast.TargetWasOriginallyPropertyAccess,
 13396  				}})
 13397  			}
 13398  		}
 13399  
 13400  		for i, part := range e.Parts {
 13401  			e.Parts[i].Value = p.visitExpr(part.Value)
 13402  		}
 13403  
 13404  		// When mangling, inline string values into the template literal. Note that
 13405  		// it may no longer be a template literal after this point (it may turn into
 13406  		// a plain string literal instead).
 13407  		if p.shouldFoldTypeScriptConstantExpressions || p.options.minifySyntax {
 13408  			expr = js_ast.InlinePrimitivesIntoTemplate(expr.Loc, e)
 13409  		}
 13410  
 13411  		shouldLowerTemplateLiteral := p.options.unsupportedJSFeatures.Has(compat.TemplateLiteral)
 13412  
 13413  		// If the tag was originally an optional chaining property access, then
 13414  		// we'll need to lower this template literal as well to preserve the value
 13415  		// for "this".
 13416  		if tagThisFunc != nil {
 13417  			shouldLowerTemplateLiteral = true
 13418  		}
 13419  
 13420  		// Lower tagged template literals that include "</script"
 13421  		// since we won't be able to escape it without lowering it
 13422  		if !shouldLowerTemplateLiteral && !p.options.unsupportedJSFeatures.Has(compat.InlineScript) && e.TagOrNil.Data != nil {
 13423  			if containsClosingScriptTag(e.HeadRaw) {
 13424  				shouldLowerTemplateLiteral = true
 13425  			} else {
 13426  				for _, part := range e.Parts {
 13427  					if containsClosingScriptTag(part.TailRaw) {
 13428  						shouldLowerTemplateLiteral = true
 13429  						break
 13430  					}
 13431  				}
 13432  			}
 13433  		}
 13434  
 13435  		// Convert template literals to older syntax if this is still a template literal
 13436  		if shouldLowerTemplateLiteral {
 13437  			if e, ok := expr.Data.(*js_ast.ETemplate); ok {
 13438  				return p.lowerTemplateLiteral(expr.Loc, e, tagThisFunc, tagWrapFunc), exprOut{}
 13439  			}
 13440  		}
 13441  
 13442  	case *js_ast.EBinary:
 13443  		// The handling of binary expressions is convoluted because we're using
 13444  		// iteration on the heap instead of recursion on the call stack to avoid
 13445  		// stack overflow for deeply-nested ASTs. See the comment before the
 13446  		// definition of "binaryExprVisitor" for details.
 13447  		v := binaryExprVisitor{
 13448  			e:   e,
 13449  			loc: expr.Loc,
 13450  			in:  in,
 13451  		}
 13452  
 13453  		// Everything uses a single stack to reduce allocation overhead. This stack
 13454  		// should almost always be very small, and almost all visits should reuse
 13455  		// existing memory without allocating anything.
 13456  		stackBottom := len(p.binaryExprStack)
 13457  
 13458  		// Iterate down into the AST along the left node of the binary operation.
 13459  		// Continue iterating until we encounter something that's not a binary node.
 13460  		for {
 13461  			// Check whether this node is a special case. If it is, a result will be
 13462  			// provided which ends our iteration. Otherwise, the visitor object will
 13463  			// be prepared for visiting.
 13464  			if result := v.checkAndPrepare(p); result.Data != nil {
 13465  				expr = result
 13466  				break
 13467  			}
 13468  
 13469  			// Grab the arguments to our nested "visitExprInOut" call for the left
 13470  			// node. We only care about deeply-nested left nodes because most binary
 13471  			// operators in JavaScript are left-associative and the problematic edge
 13472  			// cases we're trying to avoid crashing on have lots of left-associative
 13473  			// binary operators chained together without parentheses (e.g. "1+2+...").
 13474  			left := v.e.Left
 13475  			leftIn := v.leftIn
 13476  			leftBinary, ok := left.Data.(*js_ast.EBinary)
 13477  
 13478  			// Stop iterating if iteration doesn't apply to the left node. This checks
 13479  			// the assignment target because "visitExprInOut" has additional behavior
 13480  			// in that case that we don't want to miss (before the top-level "switch"
 13481  			// statement).
 13482  			if !ok || leftIn.assignTarget != js_ast.AssignTargetNone {
 13483  				v.e.Left, _ = p.visitExprInOut(left, leftIn)
 13484  				expr = v.visitRightAndFinish(p)
 13485  				break
 13486  			}
 13487  
 13488  			// Note that we only append to the stack (and therefore allocate memory
 13489  			// on the heap) when there are nested binary expressions. A single binary
 13490  			// expression doesn't add anything to the stack.
 13491  			p.binaryExprStack = append(p.binaryExprStack, v)
 13492  			v = binaryExprVisitor{
 13493  				e:   leftBinary,
 13494  				loc: left.Loc,
 13495  				in:  leftIn,
 13496  			}
 13497  		}
 13498  
 13499  		// Process all binary operations from the deepest-visited node back toward
 13500  		// our original top-level binary operation.
 13501  		for {
 13502  			n := len(p.binaryExprStack) - 1
 13503  			if n < stackBottom {
 13504  				break
 13505  			}
 13506  			v := p.binaryExprStack[n]
 13507  			p.binaryExprStack = p.binaryExprStack[:n]
 13508  			v.e.Left = expr
 13509  			expr = v.visitRightAndFinish(p)
 13510  		}
 13511  
 13512  		return expr, exprOut{}
 13513  
 13514  	case *js_ast.EDot:
 13515  		isDeleteTarget := e == p.deleteTarget
 13516  		isCallTarget := e == p.callTarget
 13517  		isTemplateTag := e == p.templateTag
 13518  
 13519  		// Check both user-specified defines and known globals
 13520  		if defines, ok := p.options.defines.DotDefines[e.Name]; ok {
 13521  			for _, define := range defines {
 13522  				if p.isDotOrIndexDefineMatch(expr, define.Parts) {
 13523  					// Substitute user-specified defines
 13524  					if define.Data.DefineExpr != nil {
 13525  						new := p.instantiateDefineExpr(expr.Loc, *define.Data.DefineExpr, identifierOpts{
 13526  							assignTarget:   in.assignTarget,
 13527  							isCallTarget:   isCallTarget,
 13528  							isDeleteTarget: isDeleteTarget,
 13529  						})
 13530  						if in.assignTarget == js_ast.AssignTargetNone || defineValueCanBeUsedInAssignTarget(new.Data) {
 13531  							// Note: We don't need to "ignoreRef" on the underlying identifier
 13532  							// because we have only parsed it but not visited it yet
 13533  							return new, exprOut{}
 13534  						} else {
 13535  							r := logger.Range{Loc: expr.Loc, Len: js_lexer.RangeOfIdentifier(p.source, e.NameLoc).End() - expr.Loc.Start}
 13536  							p.logAssignToDefine(r, "", expr)
 13537  						}
 13538  					}
 13539  
 13540  					// Copy the side effect flags over in case this expression is unused
 13541  					if define.Data.Flags.Has(config.CanBeRemovedIfUnused) {
 13542  						e.CanBeRemovedIfUnused = true
 13543  					}
 13544  					if define.Data.Flags.Has(config.CallCanBeUnwrappedIfUnused) && !p.options.ignoreDCEAnnotations {
 13545  						e.CallCanBeUnwrappedIfUnused = true
 13546  					}
 13547  					if define.Data.Flags.Has(config.IsSymbolInstance) {
 13548  						e.IsSymbolInstance = true
 13549  					}
 13550  					break
 13551  				}
 13552  			}
 13553  		}
 13554  
 13555  		// Check injected dot names
 13556  		if names, ok := p.injectedDotNames[e.Name]; ok {
 13557  			for _, name := range names {
 13558  				if p.isDotOrIndexDefineMatch(expr, name.parts) {
 13559  					// Note: We don't need to "ignoreRef" on the underlying identifier
 13560  					// because we have only parsed it but not visited it yet
 13561  					return p.instantiateInjectDotName(expr.Loc, name, in.assignTarget), exprOut{}
 13562  				}
 13563  			}
 13564  		}
 13565  
 13566  		// Track ".then().catch()" chains
 13567  		if isCallTarget && p.thenCatchChain.nextTarget == e {
 13568  			if e.Name == "catch" {
 13569  				p.thenCatchChain = thenCatchChain{
 13570  					nextTarget: e.Target.Data,
 13571  					hasCatch:   true,
 13572  					catchLoc:   e.NameLoc,
 13573  				}
 13574  			} else if e.Name == "then" {
 13575  				p.thenCatchChain = thenCatchChain{
 13576  					nextTarget: e.Target.Data,
 13577  					hasCatch:   p.thenCatchChain.hasCatch || p.thenCatchChain.hasMultipleArgs,
 13578  					catchLoc:   p.thenCatchChain.catchLoc,
 13579  				}
 13580  			}
 13581  		}
 13582  
 13583  		p.dotOrIndexTarget = e.Target.Data
 13584  		target, out := p.visitExprInOut(e.Target, exprIn{
 13585  			hasChainParent: e.OptionalChain == js_ast.OptionalChainContinue,
 13586  		})
 13587  		e.Target = target
 13588  
 13589  		// Lower "super.prop" if necessary
 13590  		if e.OptionalChain == js_ast.OptionalChainNone && in.assignTarget == js_ast.AssignTargetNone &&
 13591  			!isCallTarget && p.shouldLowerSuperPropertyAccess(e.Target) {
 13592  			// "super.foo" => "__superGet('foo')"
 13593  			key := js_ast.Expr{Loc: e.NameLoc, Data: &js_ast.EString{Value: helpers.StringToUTF16(e.Name)}}
 13594  			value := p.lowerSuperPropertyGet(expr.Loc, key)
 13595  			if isTemplateTag {
 13596  				value.Data = &js_ast.ECall{
 13597  					Target: js_ast.Expr{Loc: value.Loc, Data: &js_ast.EDot{
 13598  						Target:  value,
 13599  						Name:    "bind",
 13600  						NameLoc: value.Loc,
 13601  					}},
 13602  					Args: []js_ast.Expr{{Loc: value.Loc, Data: js_ast.EThisShared}},
 13603  					Kind: js_ast.TargetWasOriginallyPropertyAccess,
 13604  				}
 13605  			}
 13606  			return value, exprOut{}
 13607  		}
 13608  
 13609  		// Lower optional chaining if we're the top of the chain
 13610  		containsOptionalChain := e.OptionalChain == js_ast.OptionalChainStart ||
 13611  			(e.OptionalChain == js_ast.OptionalChainContinue && out.childContainsOptionalChain)
 13612  		if containsOptionalChain && !in.hasChainParent {
 13613  			return p.lowerOptionalChain(expr, in, out)
 13614  		}
 13615  
 13616  		// Potentially rewrite this property access
 13617  		out = exprOut{
 13618  			childContainsOptionalChain:            containsOptionalChain,
 13619  			methodCallMustBeReplacedWithUndefined: out.methodCallMustBeReplacedWithUndefined,
 13620  			thisArgFunc:                           out.thisArgFunc,
 13621  			thisArgWrapFunc:                       out.thisArgWrapFunc,
 13622  		}
 13623  		if !in.hasChainParent {
 13624  			out.thisArgFunc = nil
 13625  			out.thisArgWrapFunc = nil
 13626  		}
 13627  		if e.OptionalChain == js_ast.OptionalChainNone {
 13628  			if value, ok := p.maybeRewritePropertyAccess(expr.Loc, in.assignTarget,
 13629  				isDeleteTarget, e.Target, e.Name, e.NameLoc, isCallTarget, isTemplateTag, false); ok {
 13630  				return value, out
 13631  			}
 13632  		}
 13633  		return js_ast.Expr{Loc: expr.Loc, Data: e}, out
 13634  
 13635  	case *js_ast.EIndex:
 13636  		isCallTarget := e == p.callTarget
 13637  		isTemplateTag := e == p.templateTag
 13638  		isDeleteTarget := e == p.deleteTarget
 13639  
 13640  		// Check both user-specified defines and known globals
 13641  		if str, ok := e.Index.Data.(*js_ast.EString); ok {
 13642  			if defines, ok := p.options.defines.DotDefines[helpers.UTF16ToString(str.Value)]; ok {
 13643  				for _, define := range defines {
 13644  					if p.isDotOrIndexDefineMatch(expr, define.Parts) {
 13645  						// Substitute user-specified defines
 13646  						if define.Data.DefineExpr != nil {
 13647  							new := p.instantiateDefineExpr(expr.Loc, *define.Data.DefineExpr, identifierOpts{
 13648  								assignTarget:   in.assignTarget,
 13649  								isCallTarget:   isCallTarget,
 13650  								isDeleteTarget: isDeleteTarget,
 13651  							})
 13652  							if in.assignTarget == js_ast.AssignTargetNone || defineValueCanBeUsedInAssignTarget(new.Data) {
 13653  								// Note: We don't need to "ignoreRef" on the underlying identifier
 13654  								// because we have only parsed it but not visited it yet
 13655  								return new, exprOut{}
 13656  							} else {
 13657  								r := logger.Range{Loc: expr.Loc}
 13658  								afterIndex := logger.Loc{Start: p.source.RangeOfString(e.Index.Loc).End()}
 13659  								if closeBracket := p.source.RangeOfOperatorAfter(afterIndex, "]"); closeBracket.Len > 0 {
 13660  									r.Len = closeBracket.End() - r.Loc.Start
 13661  								}
 13662  								p.logAssignToDefine(r, "", expr)
 13663  							}
 13664  						}
 13665  
 13666  						// Copy the side effect flags over in case this expression is unused
 13667  						if define.Data.Flags.Has(config.CanBeRemovedIfUnused) {
 13668  							e.CanBeRemovedIfUnused = true
 13669  						}
 13670  						if define.Data.Flags.Has(config.CallCanBeUnwrappedIfUnused) && !p.options.ignoreDCEAnnotations {
 13671  							e.CallCanBeUnwrappedIfUnused = true
 13672  						}
 13673  						if define.Data.Flags.Has(config.IsSymbolInstance) {
 13674  							e.IsSymbolInstance = true
 13675  						}
 13676  						break
 13677  					}
 13678  				}
 13679  			}
 13680  		}
 13681  
 13682  		// "a['b']" => "a.b"
 13683  		if p.options.minifySyntax {
 13684  			if str, ok := e.Index.Data.(*js_ast.EString); ok && js_ast.IsIdentifierUTF16(str.Value) {
 13685  				dot := p.dotOrMangledPropParse(e.Target, js_lexer.MaybeSubstring{String: helpers.UTF16ToString(str.Value)}, e.Index.Loc, e.OptionalChain, wasOriginallyIndex)
 13686  				if isCallTarget {
 13687  					p.callTarget = dot
 13688  				}
 13689  				if isTemplateTag {
 13690  					p.templateTag = dot
 13691  				}
 13692  				if isDeleteTarget {
 13693  					p.deleteTarget = dot
 13694  				}
 13695  				return p.visitExprInOut(js_ast.Expr{Loc: expr.Loc, Data: dot}, in)
 13696  			}
 13697  		}
 13698  
 13699  		p.dotOrIndexTarget = e.Target.Data
 13700  		target, out := p.visitExprInOut(e.Target, exprIn{
 13701  			hasChainParent: e.OptionalChain == js_ast.OptionalChainContinue,
 13702  		})
 13703  		e.Target = target
 13704  
 13705  		// Special-case private identifiers
 13706  		if private, ok := e.Index.Data.(*js_ast.EPrivateIdentifier); ok {
 13707  			name := p.loadNameFromRef(private.Ref)
 13708  			result := p.findSymbol(e.Index.Loc, name)
 13709  			private.Ref = result.ref
 13710  
 13711  			// Unlike regular identifiers, there are no unbound private identifiers
 13712  			kind := p.symbols[result.ref.InnerIndex].Kind
 13713  			if !kind.IsPrivate() {
 13714  				r := logger.Range{Loc: e.Index.Loc, Len: int32(len(name))}
 13715  				p.log.AddError(&p.tracker, r, fmt.Sprintf("Private name %q must be declared in an enclosing class", name))
 13716  			} else {
 13717  				var r logger.Range
 13718  				var text string
 13719  				if in.assignTarget != js_ast.AssignTargetNone && (kind == ast.SymbolPrivateMethod || kind == ast.SymbolPrivateStaticMethod) {
 13720  					r = logger.Range{Loc: e.Index.Loc, Len: int32(len(name))}
 13721  					text = fmt.Sprintf("Writing to read-only method %q will throw", name)
 13722  				} else if in.assignTarget != js_ast.AssignTargetNone && (kind == ast.SymbolPrivateGet || kind == ast.SymbolPrivateStaticGet) {
 13723  					r = logger.Range{Loc: e.Index.Loc, Len: int32(len(name))}
 13724  					text = fmt.Sprintf("Writing to getter-only property %q will throw", name)
 13725  				} else if in.assignTarget != js_ast.AssignTargetReplace && (kind == ast.SymbolPrivateSet || kind == ast.SymbolPrivateStaticSet) {
 13726  					r = logger.Range{Loc: e.Index.Loc, Len: int32(len(name))}
 13727  					text = fmt.Sprintf("Reading from setter-only property %q will throw", name)
 13728  				}
 13729  				if text != "" {
 13730  					kind := logger.Warning
 13731  					if p.suppressWarningsAboutWeirdCode {
 13732  						kind = logger.Debug
 13733  					}
 13734  					p.log.AddID(logger.MsgID_JS_PrivateNameWillThrow, kind, &p.tracker, r, text)
 13735  				}
 13736  			}
 13737  
 13738  			// Lower private member access only if we're sure the target isn't needed
 13739  			// for the value of "this" for a call expression. All other cases will be
 13740  			// taken care of by the enclosing call expression.
 13741  			if p.privateSymbolNeedsToBeLowered(private) && e.OptionalChain == js_ast.OptionalChainNone &&
 13742  				in.assignTarget == js_ast.AssignTargetNone && !isCallTarget && !isTemplateTag {
 13743  				// "foo.#bar" => "__privateGet(foo, #bar)"
 13744  				return p.lowerPrivateGet(e.Target, e.Index.Loc, private), exprOut{}
 13745  			}
 13746  		} else {
 13747  			e.Index, _ = p.visitExprInOut(e.Index, exprIn{
 13748  				shouldMangleStringsAsProps: true,
 13749  			})
 13750  		}
 13751  
 13752  		// Lower "super[prop]" if necessary
 13753  		if e.OptionalChain == js_ast.OptionalChainNone && in.assignTarget == js_ast.AssignTargetNone &&
 13754  			!isCallTarget && p.shouldLowerSuperPropertyAccess(e.Target) {
 13755  			// "super[foo]" => "__superGet(foo)"
 13756  			value := p.lowerSuperPropertyGet(expr.Loc, e.Index)
 13757  			if isTemplateTag {
 13758  				value.Data = &js_ast.ECall{
 13759  					Target: js_ast.Expr{Loc: value.Loc, Data: &js_ast.EDot{
 13760  						Target:  value,
 13761  						Name:    "bind",
 13762  						NameLoc: value.Loc,
 13763  					}},
 13764  					Args: []js_ast.Expr{{Loc: value.Loc, Data: js_ast.EThisShared}},
 13765  					Kind: js_ast.TargetWasOriginallyPropertyAccess,
 13766  				}
 13767  			}
 13768  			return value, exprOut{}
 13769  		}
 13770  
 13771  		// Lower optional chaining if we're the top of the chain
 13772  		containsOptionalChain := e.OptionalChain == js_ast.OptionalChainStart ||
 13773  			(e.OptionalChain == js_ast.OptionalChainContinue && out.childContainsOptionalChain)
 13774  		if containsOptionalChain && !in.hasChainParent {
 13775  			return p.lowerOptionalChain(expr, in, out)
 13776  		}
 13777  
 13778  		// Potentially rewrite this property access
 13779  		out = exprOut{
 13780  			childContainsOptionalChain:            containsOptionalChain,
 13781  			methodCallMustBeReplacedWithUndefined: out.methodCallMustBeReplacedWithUndefined,
 13782  			thisArgFunc:                           out.thisArgFunc,
 13783  			thisArgWrapFunc:                       out.thisArgWrapFunc,
 13784  		}
 13785  		if !in.hasChainParent {
 13786  			out.thisArgFunc = nil
 13787  			out.thisArgWrapFunc = nil
 13788  		}
 13789  		if str, ok := e.Index.Data.(*js_ast.EString); ok && e.OptionalChain == js_ast.OptionalChainNone {
 13790  			preferQuotedKey := !p.options.minifySyntax
 13791  			if value, ok := p.maybeRewritePropertyAccess(expr.Loc, in.assignTarget, isDeleteTarget,
 13792  				e.Target, helpers.UTF16ToString(str.Value), e.Index.Loc, isCallTarget, isTemplateTag, preferQuotedKey); ok {
 13793  				return value, out
 13794  			}
 13795  		}
 13796  
 13797  		// Create an error for assigning to an import namespace when bundling. Even
 13798  		// though this is a run-time error, we make it a compile-time error when
 13799  		// bundling because scope hoisting means these will no longer be run-time
 13800  		// errors.
 13801  		if p.options.mode == config.ModeBundle && (in.assignTarget != js_ast.AssignTargetNone || isDeleteTarget) {
 13802  			if id, ok := e.Target.Data.(*js_ast.EIdentifier); ok && p.symbols[id.Ref.InnerIndex].Kind == ast.SymbolImport {
 13803  				r := js_lexer.RangeOfIdentifier(p.source, e.Target.Loc)
 13804  				p.log.AddErrorWithNotes(&p.tracker, r,
 13805  					fmt.Sprintf("Cannot assign to property on import %q", p.symbols[id.Ref.InnerIndex].OriginalName),
 13806  					[]logger.MsgData{{Text: "Imports are immutable in JavaScript. " +
 13807  						"To modify the value of this import, you must export a setter function in the " +
 13808  						"imported file and then import and call that function here instead."}})
 13809  
 13810  			}
 13811  		}
 13812  
 13813  		if p.options.minifySyntax {
 13814  			switch index := e.Index.Data.(type) {
 13815  			case *js_ast.EString:
 13816  				// "a['x' + 'y']" => "a.xy" (this is done late to allow for constant folding)
 13817  				if js_ast.IsIdentifierUTF16(index.Value) {
 13818  					return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EDot{
 13819  						Target:                     e.Target,
 13820  						Name:                       helpers.UTF16ToString(index.Value),
 13821  						NameLoc:                    e.Index.Loc,
 13822  						OptionalChain:              e.OptionalChain,
 13823  						CanBeRemovedIfUnused:       e.CanBeRemovedIfUnused,
 13824  						CallCanBeUnwrappedIfUnused: e.CallCanBeUnwrappedIfUnused,
 13825  					}}, out
 13826  				}
 13827  
 13828  				// "a['123']" => "a[123]" (this is done late to allow "'123'" to be mangled)
 13829  				if numberValue, ok := js_ast.StringToEquivalentNumberValue(index.Value); ok {
 13830  					e.Index.Data = &js_ast.ENumber{Value: numberValue}
 13831  				}
 13832  
 13833  			case *js_ast.ENumber:
 13834  				// "'abc'[1]" => "'b'"
 13835  				if target, ok := e.Target.Data.(*js_ast.EString); ok {
 13836  					if intValue := math.Floor(index.Value); index.Value == intValue && intValue >= 0 && intValue < float64(len(target.Value)) {
 13837  						return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EString{Value: []uint16{target.Value[int(intValue)]}}}, out
 13838  					}
 13839  				}
 13840  			}
 13841  		}
 13842  
 13843  		return js_ast.Expr{Loc: expr.Loc, Data: e}, out
 13844  
 13845  	case *js_ast.EUnary:
 13846  		switch e.Op {
 13847  		case js_ast.UnOpTypeof:
 13848  			e.Value, _ = p.visitExprInOut(e.Value, exprIn{assignTarget: e.Op.UnaryAssignTarget()})
 13849  
 13850  			// Compile-time "typeof" evaluation
 13851  			if typeof, ok := js_ast.TypeofWithoutSideEffects(e.Value.Data); ok {
 13852  				return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(typeof)}}, exprOut{}
 13853  			}
 13854  
 13855  		case js_ast.UnOpDelete:
 13856  			// Warn about code that tries to do "delete super.foo"
 13857  			var superPropLoc logger.Loc
 13858  			switch e2 := e.Value.Data.(type) {
 13859  			case *js_ast.EDot:
 13860  				if _, ok := e2.Target.Data.(*js_ast.ESuper); ok {
 13861  					superPropLoc = e2.Target.Loc
 13862  				}
 13863  			case *js_ast.EIndex:
 13864  				if _, ok := e2.Target.Data.(*js_ast.ESuper); ok {
 13865  					superPropLoc = e2.Target.Loc
 13866  				}
 13867  			case *js_ast.EIdentifier:
 13868  				p.markStrictModeFeature(deleteBareName, js_lexer.RangeOfIdentifier(p.source, e.Value.Loc), "")
 13869  			}
 13870  			if superPropLoc.Start != 0 {
 13871  				r := js_lexer.RangeOfIdentifier(p.source, superPropLoc)
 13872  				text := "Attempting to delete a property of \"super\" will throw a ReferenceError"
 13873  				kind := logger.Warning
 13874  				if p.suppressWarningsAboutWeirdCode {
 13875  					kind = logger.Debug
 13876  				}
 13877  				p.log.AddID(logger.MsgID_JS_DeleteSuperProperty, kind, &p.tracker, r, text)
 13878  			}
 13879  
 13880  			p.deleteTarget = e.Value.Data
 13881  			value, out := p.visitExprInOut(e.Value, exprIn{hasChainParent: true})
 13882  			e.Value = value
 13883  
 13884  			// Lower optional chaining if present since we're guaranteed to be the
 13885  			// end of the chain
 13886  			if out.childContainsOptionalChain {
 13887  				return p.lowerOptionalChain(expr, in, out)
 13888  			}
 13889  
 13890  		default:
 13891  			e.Value, _ = p.visitExprInOut(e.Value, exprIn{assignTarget: e.Op.UnaryAssignTarget()})
 13892  
 13893  			// Post-process the unary expression
 13894  			switch e.Op {
 13895  			case js_ast.UnOpNot:
 13896  				if p.options.minifySyntax {
 13897  					e.Value = p.astHelpers.SimplifyBooleanExpr(e.Value)
 13898  				}
 13899  
 13900  				if boolean, sideEffects, ok := js_ast.ToBooleanWithSideEffects(e.Value.Data); ok && sideEffects == js_ast.NoSideEffects {
 13901  					return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EBoolean{Value: !boolean}}, exprOut{}
 13902  				}
 13903  
 13904  				if p.options.minifySyntax {
 13905  					if result, ok := js_ast.MaybeSimplifyNot(e.Value); ok {
 13906  						return result, exprOut{}
 13907  					}
 13908  				}
 13909  
 13910  			case js_ast.UnOpVoid:
 13911  				if p.astHelpers.ExprCanBeRemovedIfUnused(e.Value) {
 13912  					return js_ast.Expr{Loc: expr.Loc, Data: js_ast.EUndefinedShared}, exprOut{}
 13913  				}
 13914  
 13915  			case js_ast.UnOpPos:
 13916  				if number, ok := js_ast.ToNumberWithoutSideEffects(e.Value.Data); ok {
 13917  					return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ENumber{Value: number}}, exprOut{}
 13918  				}
 13919  
 13920  			case js_ast.UnOpNeg:
 13921  				if number, ok := js_ast.ToNumberWithoutSideEffects(e.Value.Data); ok {
 13922  					return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ENumber{Value: -number}}, exprOut{}
 13923  				}
 13924  
 13925  			case js_ast.UnOpCpl:
 13926  				if p.shouldFoldTypeScriptConstantExpressions || p.options.minifySyntax {
 13927  					// Minification folds complement operations since they are unlikely to result in larger output
 13928  					if number, ok := js_ast.ToNumberWithoutSideEffects(e.Value.Data); ok {
 13929  						return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ENumber{Value: float64(^js_ast.ToInt32(number))}}, exprOut{}
 13930  					}
 13931  				}
 13932  
 13933  				////////////////////////////////////////////////////////////////////////////////
 13934  				// All assignment operators below here
 13935  
 13936  			case js_ast.UnOpPreDec, js_ast.UnOpPreInc, js_ast.UnOpPostDec, js_ast.UnOpPostInc:
 13937  				if target, loc, private := p.extractPrivateIndex(e.Value); private != nil {
 13938  					return p.lowerPrivateSetUnOp(target, loc, private, e.Op), exprOut{}
 13939  				}
 13940  				if property := p.extractSuperProperty(e.Value); property.Data != nil {
 13941  					e.Value = p.callSuperPropertyWrapper(expr.Loc, property)
 13942  				}
 13943  			}
 13944  		}
 13945  
 13946  		// "-(a, b)" => "a, -b"
 13947  		if p.options.minifySyntax && e.Op != js_ast.UnOpDelete && e.Op != js_ast.UnOpTypeof {
 13948  			if comma, ok := e.Value.Data.(*js_ast.EBinary); ok && comma.Op == js_ast.BinOpComma {
 13949  				return js_ast.JoinWithComma(comma.Left, js_ast.Expr{
 13950  					Loc: comma.Right.Loc,
 13951  					Data: &js_ast.EUnary{
 13952  						Op:    e.Op,
 13953  						Value: comma.Right,
 13954  					},
 13955  				}), exprOut{}
 13956  			}
 13957  		}
 13958  
 13959  	case *js_ast.EIf:
 13960  		e.Test = p.visitExpr(e.Test)
 13961  
 13962  		if p.options.minifySyntax {
 13963  			e.Test = p.astHelpers.SimplifyBooleanExpr(e.Test)
 13964  		}
 13965  
 13966  		// Propagate these flags into the branches
 13967  		childIn := exprIn{
 13968  			shouldMangleStringsAsProps: in.shouldMangleStringsAsProps,
 13969  		}
 13970  
 13971  		// Fold constants
 13972  		if boolean, sideEffects, ok := js_ast.ToBooleanWithSideEffects(e.Test.Data); !ok {
 13973  			e.Yes, _ = p.visitExprInOut(e.Yes, childIn)
 13974  			e.No, _ = p.visitExprInOut(e.No, childIn)
 13975  		} else {
 13976  			// Mark the control flow as dead if the branch is never taken
 13977  			if boolean {
 13978  				// "true ? live : dead"
 13979  				e.Yes, _ = p.visitExprInOut(e.Yes, childIn)
 13980  				old := p.isControlFlowDead
 13981  				p.isControlFlowDead = true
 13982  				e.No, _ = p.visitExprInOut(e.No, childIn)
 13983  				p.isControlFlowDead = old
 13984  
 13985  				if p.options.minifySyntax {
 13986  					// "(a, true) ? b : c" => "a, b"
 13987  					if sideEffects == js_ast.CouldHaveSideEffects {
 13988  						return js_ast.JoinWithComma(p.astHelpers.SimplifyUnusedExpr(e.Test, p.options.unsupportedJSFeatures), e.Yes), exprOut{}
 13989  					}
 13990  
 13991  					return e.Yes, exprOut{}
 13992  				}
 13993  			} else {
 13994  				// "false ? dead : live"
 13995  				old := p.isControlFlowDead
 13996  				p.isControlFlowDead = true
 13997  				e.Yes, _ = p.visitExprInOut(e.Yes, childIn)
 13998  				p.isControlFlowDead = old
 13999  				e.No, _ = p.visitExprInOut(e.No, childIn)
 14000  
 14001  				if p.options.minifySyntax {
 14002  					// "(a, false) ? b : c" => "a, c"
 14003  					if sideEffects == js_ast.CouldHaveSideEffects {
 14004  						return js_ast.JoinWithComma(p.astHelpers.SimplifyUnusedExpr(e.Test, p.options.unsupportedJSFeatures), e.No), exprOut{}
 14005  					}
 14006  
 14007  					return e.No, exprOut{}
 14008  				}
 14009  			}
 14010  		}
 14011  
 14012  		if p.options.minifySyntax {
 14013  			return p.astHelpers.MangleIfExpr(expr.Loc, e, p.options.unsupportedJSFeatures), exprOut{}
 14014  		}
 14015  
 14016  	case *js_ast.EAwait:
 14017  		// Silently remove unsupported top-level "await" in dead code branches
 14018  		if p.fnOrArrowDataVisit.isOutsideFnOrArrow {
 14019  			if p.isControlFlowDead && (p.options.unsupportedJSFeatures.Has(compat.TopLevelAwait) || !p.options.outputFormat.KeepESMImportExportSyntax()) {
 14020  				return p.visitExprInOut(e.Value, in)
 14021  			} else {
 14022  				p.liveTopLevelAwaitKeyword = logger.Range{Loc: expr.Loc, Len: 5}
 14023  				p.markSyntaxFeature(compat.TopLevelAwait, logger.Range{Loc: expr.Loc, Len: 5})
 14024  			}
 14025  		}
 14026  
 14027  		p.awaitTarget = e.Value.Data
 14028  		e.Value = p.visitExpr(e.Value)
 14029  
 14030  		// "await" expressions turn into "yield" expressions when lowering
 14031  		return p.maybeLowerAwait(expr.Loc, e), exprOut{}
 14032  
 14033  	case *js_ast.EYield:
 14034  		if e.ValueOrNil.Data != nil {
 14035  			e.ValueOrNil = p.visitExpr(e.ValueOrNil)
 14036  		}
 14037  
 14038  		// "yield* x" turns into "yield* __yieldStar(x)" when lowering async generator functions
 14039  		if e.IsStar && p.options.unsupportedJSFeatures.Has(compat.AsyncGenerator) && p.fnOrArrowDataVisit.isGenerator {
 14040  			e.ValueOrNil = p.callRuntime(expr.Loc, "__yieldStar", []js_ast.Expr{e.ValueOrNil})
 14041  		}
 14042  
 14043  	case *js_ast.EArray:
 14044  		if in.assignTarget != js_ast.AssignTargetNone {
 14045  			if e.CommaAfterSpread.Start != 0 {
 14046  				p.log.AddError(&p.tracker, logger.Range{Loc: e.CommaAfterSpread, Len: 1}, "Unexpected \",\" after rest pattern")
 14047  			}
 14048  			p.markSyntaxFeature(compat.Destructuring, logger.Range{Loc: expr.Loc, Len: 1})
 14049  		}
 14050  		hasSpread := false
 14051  		for i, item := range e.Items {
 14052  			switch e2 := item.Data.(type) {
 14053  			case *js_ast.EMissing:
 14054  			case *js_ast.ESpread:
 14055  				e2.Value, _ = p.visitExprInOut(e2.Value, exprIn{assignTarget: in.assignTarget})
 14056  				hasSpread = true
 14057  			case *js_ast.EBinary:
 14058  				if in.assignTarget != js_ast.AssignTargetNone && e2.Op == js_ast.BinOpAssign {
 14059  					e2.Left, _ = p.visitExprInOut(e2.Left, exprIn{assignTarget: js_ast.AssignTargetReplace})
 14060  
 14061  					// Propagate the name to keep from the binding into the initializer
 14062  					if id, ok := e2.Left.Data.(*js_ast.EIdentifier); ok {
 14063  						p.nameToKeep = p.symbols[id.Ref.InnerIndex].OriginalName
 14064  						p.nameToKeepIsFor = e2.Right.Data
 14065  					}
 14066  
 14067  					e2.Right = p.visitExpr(e2.Right)
 14068  				} else {
 14069  					item, _ = p.visitExprInOut(item, exprIn{assignTarget: in.assignTarget})
 14070  				}
 14071  			default:
 14072  				item, _ = p.visitExprInOut(item, exprIn{assignTarget: in.assignTarget})
 14073  			}
 14074  			e.Items[i] = item
 14075  		}
 14076  
 14077  		// "[1, ...[2, 3], 4]" => "[1, 2, 3, 4]"
 14078  		if p.options.minifySyntax && hasSpread && in.assignTarget == js_ast.AssignTargetNone {
 14079  			e.Items = js_ast.InlineSpreadsOfArrayLiterals(e.Items)
 14080  		}
 14081  
 14082  	case *js_ast.EObject:
 14083  		if in.assignTarget != js_ast.AssignTargetNone {
 14084  			if e.CommaAfterSpread.Start != 0 {
 14085  				p.log.AddError(&p.tracker, logger.Range{Loc: e.CommaAfterSpread, Len: 1}, "Unexpected \",\" after rest pattern")
 14086  			}
 14087  			p.markSyntaxFeature(compat.Destructuring, logger.Range{Loc: expr.Loc, Len: 1})
 14088  		}
 14089  
 14090  		hasSpread := false
 14091  		protoRange := logger.Range{}
 14092  		innerClassNameRef := ast.InvalidRef
 14093  
 14094  		for i := range e.Properties {
 14095  			property := &e.Properties[i]
 14096  
 14097  			if property.Kind != js_ast.PropertySpread {
 14098  				key := property.Key
 14099  				if mangled, ok := key.Data.(*js_ast.ENameOfSymbol); ok {
 14100  					mangled.Ref = p.symbolForMangledProp(p.loadNameFromRef(mangled.Ref))
 14101  				} else {
 14102  					key, _ = p.visitExprInOut(property.Key, exprIn{
 14103  						shouldMangleStringsAsProps: true,
 14104  					})
 14105  					property.Key = key
 14106  				}
 14107  
 14108  				// Forbid duplicate "__proto__" properties according to the specification
 14109  				if !property.Flags.Has(js_ast.PropertyIsComputed) && !property.Flags.Has(js_ast.PropertyWasShorthand) &&
 14110  					property.Kind == js_ast.PropertyField && in.assignTarget == js_ast.AssignTargetNone {
 14111  					if str, ok := key.Data.(*js_ast.EString); ok && helpers.UTF16EqualsString(str.Value, "__proto__") {
 14112  						r := js_lexer.RangeOfIdentifier(p.source, key.Loc)
 14113  						if protoRange.Len > 0 {
 14114  							p.log.AddErrorWithNotes(&p.tracker, r,
 14115  								"Cannot specify the \"__proto__\" property more than once per object",
 14116  								[]logger.MsgData{p.tracker.MsgData(protoRange, "The earlier \"__proto__\" property is here:")})
 14117  						} else {
 14118  							protoRange = r
 14119  						}
 14120  					}
 14121  				}
 14122  
 14123  				// "{['x']: y}" => "{x: y}"
 14124  				if p.options.minifySyntax && property.Flags.Has(js_ast.PropertyIsComputed) {
 14125  					if inlined, ok := key.Data.(*js_ast.EInlinedEnum); ok {
 14126  						switch inlined.Value.Data.(type) {
 14127  						case *js_ast.EString, *js_ast.ENumber:
 14128  							key.Data = inlined.Value.Data
 14129  							property.Key.Data = key.Data
 14130  						}
 14131  					}
 14132  					switch k := key.Data.(type) {
 14133  					case *js_ast.ENumber, *js_ast.ENameOfSymbol:
 14134  						property.Flags &= ^js_ast.PropertyIsComputed
 14135  					case *js_ast.EString:
 14136  						if !helpers.UTF16EqualsString(k.Value, "__proto__") {
 14137  							property.Flags &= ^js_ast.PropertyIsComputed
 14138  						}
 14139  					}
 14140  				}
 14141  			} else {
 14142  				hasSpread = true
 14143  			}
 14144  
 14145  			// Extract the initializer for expressions like "({ a: b = c } = d)"
 14146  			if in.assignTarget != js_ast.AssignTargetNone && property.InitializerOrNil.Data == nil && property.ValueOrNil.Data != nil {
 14147  				if binary, ok := property.ValueOrNil.Data.(*js_ast.EBinary); ok && binary.Op == js_ast.BinOpAssign {
 14148  					property.InitializerOrNil = binary.Right
 14149  					property.ValueOrNil = binary.Left
 14150  				}
 14151  			}
 14152  
 14153  			if property.ValueOrNil.Data != nil {
 14154  				oldIsInStaticClassContext := p.fnOnlyDataVisit.isInStaticClassContext
 14155  				oldInnerClassNameRef := p.fnOnlyDataVisit.innerClassNameRef
 14156  
 14157  				// If this is an async method and async methods are unsupported,
 14158  				// generate a temporary variable in case this async method contains a
 14159  				// "super" property reference. If that happens, the "super" expression
 14160  				// must be lowered which will need a reference to this object literal.
 14161  				if property.Kind == js_ast.PropertyMethod && p.options.unsupportedJSFeatures.Has(compat.AsyncAwait) {
 14162  					if fn, ok := property.ValueOrNil.Data.(*js_ast.EFunction); ok && fn.Fn.IsAsync {
 14163  						if innerClassNameRef == ast.InvalidRef {
 14164  							innerClassNameRef = p.generateTempRef(tempRefNeedsDeclareMayBeCapturedInsideLoop, "")
 14165  						}
 14166  						p.fnOnlyDataVisit.isInStaticClassContext = true
 14167  						p.fnOnlyDataVisit.innerClassNameRef = &innerClassNameRef
 14168  					}
 14169  				}
 14170  
 14171  				// Propagate the name to keep from the property into the value
 14172  				if str, ok := property.Key.Data.(*js_ast.EString); ok {
 14173  					p.nameToKeep = helpers.UTF16ToString(str.Value)
 14174  					p.nameToKeepIsFor = property.ValueOrNil.Data
 14175  				}
 14176  
 14177  				property.ValueOrNil, _ = p.visitExprInOut(property.ValueOrNil, exprIn{
 14178  					isMethod:     property.Kind.IsMethodDefinition(),
 14179  					assignTarget: in.assignTarget,
 14180  				})
 14181  
 14182  				p.fnOnlyDataVisit.innerClassNameRef = oldInnerClassNameRef
 14183  				p.fnOnlyDataVisit.isInStaticClassContext = oldIsInStaticClassContext
 14184  			}
 14185  
 14186  			if property.InitializerOrNil.Data != nil {
 14187  				// Propagate the name to keep from the binding into the initializer
 14188  				if id, ok := property.ValueOrNil.Data.(*js_ast.EIdentifier); ok {
 14189  					p.nameToKeep = p.symbols[id.Ref.InnerIndex].OriginalName
 14190  					p.nameToKeepIsFor = property.InitializerOrNil.Data
 14191  				}
 14192  
 14193  				property.InitializerOrNil = p.visitExpr(property.InitializerOrNil)
 14194  			}
 14195  
 14196  			// "{ '123': 4 }" => "{ 123: 4 }" (this is done late to allow "'123'" to be mangled)
 14197  			if p.options.minifySyntax {
 14198  				if str, ok := property.Key.Data.(*js_ast.EString); ok {
 14199  					if numberValue, ok := js_ast.StringToEquivalentNumberValue(str.Value); ok && numberValue >= 0 {
 14200  						property.Key.Data = &js_ast.ENumber{Value: numberValue}
 14201  					}
 14202  				}
 14203  			}
 14204  		}
 14205  
 14206  		// Check for and warn about duplicate keys in object literals
 14207  		if !p.suppressWarningsAboutWeirdCode {
 14208  			p.warnAboutDuplicateProperties(e.Properties, duplicatePropertiesInObject)
 14209  		}
 14210  
 14211  		if in.assignTarget == js_ast.AssignTargetNone {
 14212  			// "{a, ...{b, c}, d}" => "{a, b, c, d}"
 14213  			if p.options.minifySyntax && hasSpread {
 14214  				e.Properties = js_ast.MangleObjectSpread(e.Properties)
 14215  			}
 14216  
 14217  			// Object expressions represent both object literals and binding patterns.
 14218  			// Only lower object spread if we're an object literal, not a binding pattern.
 14219  			value := p.lowerObjectSpread(expr.Loc, e)
 14220  
 14221  			// If we generated and used the temporary variable for a lowered "super"
 14222  			// property reference inside a lowered "async" method, then initialize
 14223  			// the temporary with this object literal.
 14224  			if innerClassNameRef != ast.InvalidRef && p.symbols[innerClassNameRef.InnerIndex].UseCountEstimate > 0 {
 14225  				p.recordUsage(innerClassNameRef)
 14226  				value = js_ast.Assign(js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EIdentifier{Ref: innerClassNameRef}}, value)
 14227  			}
 14228  
 14229  			return value, exprOut{}
 14230  		}
 14231  
 14232  	case *js_ast.EImportCall:
 14233  		isAwaitTarget := e == p.awaitTarget
 14234  		isThenCatchTarget := e == p.thenCatchChain.nextTarget && p.thenCatchChain.hasCatch
 14235  		e.Expr = p.visitExpr(e.Expr)
 14236  
 14237  		var assertOrWith *ast.ImportAssertOrWith
 14238  		var flags ast.ImportRecordFlags
 14239  		if e.OptionsOrNil.Data != nil {
 14240  			e.OptionsOrNil = p.visitExpr(e.OptionsOrNil)
 14241  
 14242  			// If there's an additional argument, this can't be split because the
 14243  			// additional argument requires evaluation and our AST nodes can't be
 14244  			// reused in different places in the AST (e.g. function scopes must be
 14245  			// unique). Also the additional argument may have side effects and we
 14246  			// don't currently account for that.
 14247  			why := "the second argument was not an object literal"
 14248  			whyLoc := e.OptionsOrNil.Loc
 14249  
 14250  			// However, make a special case for an additional argument that contains
 14251  			// only an "assert" or a "with" clause. In that case we can split this
 14252  			// AST node.
 14253  			if object, ok := e.OptionsOrNil.Data.(*js_ast.EObject); ok {
 14254  				if len(object.Properties) == 1 {
 14255  					if prop := object.Properties[0]; prop.Kind == js_ast.PropertyField && !prop.Flags.Has(js_ast.PropertyIsComputed) {
 14256  						if str, ok := prop.Key.Data.(*js_ast.EString); ok && (helpers.UTF16EqualsString(str.Value, "assert") || helpers.UTF16EqualsString(str.Value, "with")) {
 14257  							keyword := ast.WithKeyword
 14258  							if helpers.UTF16EqualsString(str.Value, "assert") {
 14259  								keyword = ast.AssertKeyword
 14260  							}
 14261  							if value, ok := prop.ValueOrNil.Data.(*js_ast.EObject); ok {
 14262  								entries := []ast.AssertOrWithEntry{}
 14263  								for _, p := range value.Properties {
 14264  									if p.Kind == js_ast.PropertyField && !p.Flags.Has(js_ast.PropertyIsComputed) {
 14265  										if key, ok := p.Key.Data.(*js_ast.EString); ok {
 14266  											if value, ok := p.ValueOrNil.Data.(*js_ast.EString); ok {
 14267  												entries = append(entries, ast.AssertOrWithEntry{
 14268  													Key:             key.Value,
 14269  													KeyLoc:          p.Key.Loc,
 14270  													Value:           value.Value,
 14271  													ValueLoc:        p.ValueOrNil.Loc,
 14272  													PreferQuotedKey: p.Flags.Has(js_ast.PropertyPreferQuotedKey),
 14273  												})
 14274  												if keyword == ast.AssertKeyword && helpers.UTF16EqualsString(key.Value, "type") && helpers.UTF16EqualsString(value.Value, "json") {
 14275  													flags |= ast.AssertTypeJSON
 14276  												}
 14277  												continue
 14278  											} else {
 14279  												why = fmt.Sprintf("the value for the property %q was not a string literal",
 14280  													helpers.UTF16ToString(key.Value))
 14281  												whyLoc = p.ValueOrNil.Loc
 14282  											}
 14283  										} else {
 14284  											why = "this property was not a string literal"
 14285  											whyLoc = p.Key.Loc
 14286  										}
 14287  									} else {
 14288  										why = "this property was invalid"
 14289  										whyLoc = p.Key.Loc
 14290  									}
 14291  									entries = nil
 14292  									break
 14293  								}
 14294  								if entries != nil {
 14295  									if keyword == ast.AssertKeyword {
 14296  										p.maybeWarnAboutAssertKeyword(prop.Key.Loc)
 14297  									}
 14298  									assertOrWith = &ast.ImportAssertOrWith{
 14299  										Entries:            entries,
 14300  										Keyword:            keyword,
 14301  										KeywordLoc:         prop.Key.Loc,
 14302  										InnerOpenBraceLoc:  prop.ValueOrNil.Loc,
 14303  										InnerCloseBraceLoc: value.CloseBraceLoc,
 14304  										OuterOpenBraceLoc:  e.OptionsOrNil.Loc,
 14305  										OuterCloseBraceLoc: object.CloseBraceLoc,
 14306  									}
 14307  									why = ""
 14308  								}
 14309  							} else {
 14310  								why = "the value for \"assert\" was not an object literal"
 14311  								whyLoc = prop.ValueOrNil.Loc
 14312  							}
 14313  						} else {
 14314  							why = "this property was not called \"assert\" or \"with\""
 14315  							whyLoc = prop.Key.Loc
 14316  						}
 14317  					} else {
 14318  						why = "this property was invalid"
 14319  						whyLoc = prop.Key.Loc
 14320  					}
 14321  				} else {
 14322  					why = "the second argument was not an object literal with a single property called \"assert\" or \"with\""
 14323  					whyLoc = e.OptionsOrNil.Loc
 14324  				}
 14325  			}
 14326  
 14327  			// Handle the case that isn't just an import assertion or attribute clause
 14328  			if why != "" {
 14329  				// Only warn when bundling
 14330  				if p.options.mode == config.ModeBundle {
 14331  					text := "This \"import()\" was not recognized because " + why
 14332  					kind := logger.Warning
 14333  					if p.suppressWarningsAboutWeirdCode {
 14334  						kind = logger.Debug
 14335  					}
 14336  					p.log.AddID(logger.MsgID_JS_UnsupportedDynamicImport, kind, &p.tracker, logger.Range{Loc: whyLoc}, text)
 14337  				}
 14338  
 14339  				// If import assertions and/attributes are both not supported in the
 14340  				// target platform, then "import()" cannot accept a second argument
 14341  				// and keeping them would be a syntax error, so we need to get rid of
 14342  				// them. We can't just not print them because they may have important
 14343  				// side effects. Attempt to discard them without changing side effects
 14344  				// and generate an error if that isn't possible.
 14345  				if p.options.unsupportedJSFeatures.Has(compat.ImportAssertions) && p.options.unsupportedJSFeatures.Has(compat.ImportAttributes) {
 14346  					if p.astHelpers.ExprCanBeRemovedIfUnused(e.OptionsOrNil) {
 14347  						e.OptionsOrNil = js_ast.Expr{}
 14348  					} else {
 14349  						p.markSyntaxFeature(compat.ImportAttributes, logger.Range{Loc: e.OptionsOrNil.Loc})
 14350  					}
 14351  				}
 14352  
 14353  				// Stop now so we don't try to split "?:" expressions below and
 14354  				// potentially end up with an AST node reused multiple times
 14355  				break
 14356  			}
 14357  		}
 14358  
 14359  		return p.maybeTransposeIfExprChain(e.Expr, func(arg js_ast.Expr) js_ast.Expr {
 14360  			// The argument must be a string
 14361  			if str, ok := arg.Data.(*js_ast.EString); ok {
 14362  				// Ignore calls to import() if the control flow is provably dead here.
 14363  				// We don't want to spend time scanning the required files if they will
 14364  				// never be used.
 14365  				if p.isControlFlowDead {
 14366  					return js_ast.Expr{Loc: arg.Loc, Data: js_ast.ENullShared}
 14367  				}
 14368  
 14369  				importRecordIndex := p.addImportRecord(ast.ImportDynamic, p.source.RangeOfString(arg.Loc), helpers.UTF16ToString(str.Value), assertOrWith, flags)
 14370  				if isAwaitTarget && p.fnOrArrowDataVisit.tryBodyCount != 0 {
 14371  					record := &p.importRecords[importRecordIndex]
 14372  					record.Flags |= ast.HandlesImportErrors
 14373  					record.ErrorHandlerLoc = p.fnOrArrowDataVisit.tryCatchLoc
 14374  				} else if isThenCatchTarget {
 14375  					record := &p.importRecords[importRecordIndex]
 14376  					record.Flags |= ast.HandlesImportErrors
 14377  					record.ErrorHandlerLoc = p.thenCatchChain.catchLoc
 14378  				}
 14379  				p.importRecordsForCurrentPart = append(p.importRecordsForCurrentPart, importRecordIndex)
 14380  				return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EImportString{
 14381  					ImportRecordIndex: importRecordIndex,
 14382  					CloseParenLoc:     e.CloseParenLoc,
 14383  				}}
 14384  			}
 14385  
 14386  			// Handle glob patterns
 14387  			if p.options.mode == config.ModeBundle {
 14388  				if value := p.handleGlobPattern(arg, ast.ImportDynamic, "globImport", assertOrWith); value.Data != nil {
 14389  					return value
 14390  				}
 14391  			}
 14392  
 14393  			// Use a debug log so people can see this if they want to
 14394  			r := js_lexer.RangeOfIdentifier(p.source, expr.Loc)
 14395  			p.log.AddID(logger.MsgID_JS_UnsupportedDynamicImport, logger.Debug, &p.tracker, r,
 14396  				"This \"import\" expression will not be bundled because the argument is not a string literal")
 14397  
 14398  			// We need to convert this into a call to "require()" if ES6 syntax is
 14399  			// not supported in the current output format. The full conversion:
 14400  			//
 14401  			//   Before:
 14402  			//     import(foo)
 14403  			//
 14404  			//   After:
 14405  			//     Promise.resolve().then(() => __toESM(require(foo)))
 14406  			//
 14407  			// This is normally done by the printer since we don't know during the
 14408  			// parsing stage whether this module is external or not. However, it's
 14409  			// guaranteed to be external if the argument isn't a string. We handle
 14410  			// this case here instead of in the printer because both the printer
 14411  			// and the linker currently need an import record to handle this case
 14412  			// correctly, and you need a string literal to get an import record.
 14413  			if p.options.unsupportedJSFeatures.Has(compat.DynamicImport) {
 14414  				var then js_ast.Expr
 14415  				value := p.callRuntime(arg.Loc, "__toESM", []js_ast.Expr{{Loc: expr.Loc, Data: &js_ast.ECall{
 14416  					Target:        p.valueToSubstituteForRequire(expr.Loc),
 14417  					Args:          []js_ast.Expr{arg},
 14418  					CloseParenLoc: e.CloseParenLoc,
 14419  				}}})
 14420  				body := js_ast.FnBody{Loc: expr.Loc, Block: js_ast.SBlock{Stmts: []js_ast.Stmt{{Loc: expr.Loc, Data: &js_ast.SReturn{ValueOrNil: value}}}}}
 14421  				if p.options.unsupportedJSFeatures.Has(compat.Arrow) {
 14422  					then = js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EFunction{Fn: js_ast.Fn{Body: body}}}
 14423  				} else {
 14424  					then = js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EArrow{Body: body, PreferExpr: true}}
 14425  				}
 14426  				return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ECall{
 14427  					Target: js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EDot{
 14428  						Target: js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ECall{
 14429  							Target: js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EDot{
 14430  								Target:  js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EIdentifier{Ref: p.makePromiseRef()}},
 14431  								Name:    "resolve",
 14432  								NameLoc: expr.Loc,
 14433  							}},
 14434  							Kind: js_ast.TargetWasOriginallyPropertyAccess,
 14435  						}},
 14436  						Name:    "then",
 14437  						NameLoc: expr.Loc,
 14438  					}},
 14439  					Args: []js_ast.Expr{then},
 14440  					Kind: js_ast.TargetWasOriginallyPropertyAccess,
 14441  				}}
 14442  			}
 14443  
 14444  			return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EImportCall{
 14445  				Expr:          arg,
 14446  				OptionsOrNil:  e.OptionsOrNil,
 14447  				CloseParenLoc: e.CloseParenLoc,
 14448  			}}
 14449  		}), exprOut{}
 14450  
 14451  	case *js_ast.ECall:
 14452  		p.callTarget = e.Target.Data
 14453  
 14454  		// Track ".then().catch()" chains
 14455  		p.thenCatchChain = thenCatchChain{
 14456  			nextTarget:      e.Target.Data,
 14457  			hasMultipleArgs: len(e.Args) >= 2,
 14458  			hasCatch:        p.thenCatchChain.nextTarget == e && p.thenCatchChain.hasCatch,
 14459  			catchLoc:        p.thenCatchChain.catchLoc,
 14460  		}
 14461  		if p.thenCatchChain.hasMultipleArgs {
 14462  			p.thenCatchChain.catchLoc = e.Args[1].Loc
 14463  		}
 14464  
 14465  		// Prepare to recognize "require.resolve()" and "Object.create" calls
 14466  		couldBeRequireResolve := false
 14467  		couldBeObjectCreate := false
 14468  		if len(e.Args) == 1 {
 14469  			if dot, ok := e.Target.Data.(*js_ast.EDot); ok && dot.OptionalChain == js_ast.OptionalChainNone {
 14470  				if p.options.mode != config.ModePassThrough && dot.Name == "resolve" {
 14471  					couldBeRequireResolve = true
 14472  				} else if dot.Name == "create" {
 14473  					couldBeObjectCreate = true
 14474  				}
 14475  			}
 14476  		}
 14477  
 14478  		wasIdentifierBeforeVisit := false
 14479  		isParenthesizedOptionalChain := false
 14480  		switch e2 := e.Target.Data.(type) {
 14481  		case *js_ast.EIdentifier:
 14482  			wasIdentifierBeforeVisit = true
 14483  		case *js_ast.EDot:
 14484  			isParenthesizedOptionalChain = e.OptionalChain == js_ast.OptionalChainNone && e2.OptionalChain != js_ast.OptionalChainNone
 14485  		case *js_ast.EIndex:
 14486  			isParenthesizedOptionalChain = e.OptionalChain == js_ast.OptionalChainNone && e2.OptionalChain != js_ast.OptionalChainNone
 14487  		}
 14488  		target, out := p.visitExprInOut(e.Target, exprIn{
 14489  			hasChainParent: e.OptionalChain == js_ast.OptionalChainContinue,
 14490  
 14491  			// Signal to our child if this is an ECall at the start of an optional
 14492  			// chain. If so, the child will need to stash the "this" context for us
 14493  			// that we need for the ".call(this, ...args)".
 14494  			storeThisArgForParentOptionalChain: e.OptionalChain == js_ast.OptionalChainStart || isParenthesizedOptionalChain,
 14495  		})
 14496  		e.Target = target
 14497  		p.warnAboutImportNamespaceCall(e.Target, exprKindCall)
 14498  
 14499  		hasSpread := false
 14500  		oldIsControlFlowDead := p.isControlFlowDead
 14501  
 14502  		// If we're removing this call, don't count any arguments as symbol uses
 14503  		if out.methodCallMustBeReplacedWithUndefined {
 14504  			if js_ast.IsPropertyAccess(e.Target) {
 14505  				p.isControlFlowDead = true
 14506  			} else {
 14507  				out.methodCallMustBeReplacedWithUndefined = false
 14508  			}
 14509  		}
 14510  
 14511  		// Visit the arguments
 14512  		for i, arg := range e.Args {
 14513  			arg = p.visitExpr(arg)
 14514  			if _, ok := arg.Data.(*js_ast.ESpread); ok {
 14515  				hasSpread = true
 14516  			}
 14517  			e.Args[i] = arg
 14518  		}
 14519  
 14520  		// Mark side-effect free IIFEs with "/* @__PURE__ */"
 14521  		if !e.CanBeUnwrappedIfUnused {
 14522  			switch target := e.Target.Data.(type) {
 14523  			case *js_ast.EArrow:
 14524  				if !target.IsAsync && p.iifeCanBeRemovedIfUnused(target.Args, target.Body) {
 14525  					e.CanBeUnwrappedIfUnused = true
 14526  				}
 14527  			case *js_ast.EFunction:
 14528  				if !target.Fn.IsAsync && !target.Fn.IsGenerator && p.iifeCanBeRemovedIfUnused(target.Fn.Args, target.Fn.Body) {
 14529  					e.CanBeUnwrappedIfUnused = true
 14530  				}
 14531  			}
 14532  		}
 14533  
 14534  		// Our hack for reading Yarn PnP files is implemented here:
 14535  		if p.options.decodeHydrateRuntimeStateYarnPnP {
 14536  			if id, ok := e.Target.Data.(*js_ast.EIdentifier); ok && p.symbols[id.Ref.InnerIndex].OriginalName == "hydrateRuntimeState" && len(e.Args) >= 1 {
 14537  				switch arg := e.Args[0].Data.(type) {
 14538  				case *js_ast.EObject:
 14539  					// "hydrateRuntimeState(<object literal>)"
 14540  					if arg := e.Args[0]; isValidJSON(arg) {
 14541  						p.manifestForYarnPnP = arg
 14542  					}
 14543  
 14544  				case *js_ast.ECall:
 14545  					// "hydrateRuntimeState(JSON.parse(<something>))"
 14546  					if len(arg.Args) == 1 {
 14547  						if dot, ok := arg.Target.Data.(*js_ast.EDot); ok && dot.Name == "parse" {
 14548  							if id, ok := dot.Target.Data.(*js_ast.EIdentifier); ok {
 14549  								if symbol := &p.symbols[id.Ref.InnerIndex]; symbol.Kind == ast.SymbolUnbound && symbol.OriginalName == "JSON" {
 14550  									arg := arg.Args[0]
 14551  									switch a := arg.Data.(type) {
 14552  									case *js_ast.EString:
 14553  										// "hydrateRuntimeState(JSON.parse(<string literal>))"
 14554  										source := logger.Source{KeyPath: p.source.KeyPath, Contents: helpers.UTF16ToString(a.Value)}
 14555  										stringInJSTable := logger.GenerateStringInJSTable(p.source.Contents, arg.Loc, source.Contents)
 14556  										log := logger.NewStringInJSLog(p.log, &p.tracker, stringInJSTable)
 14557  										p.manifestForYarnPnP, _ = ParseJSON(log, source, JSONOptions{})
 14558  										remapExprLocsInJSON(&p.manifestForYarnPnP, stringInJSTable)
 14559  
 14560  									case *js_ast.EIdentifier:
 14561  										// "hydrateRuntimeState(JSON.parse(<identifier>))"
 14562  										if data, ok := p.stringLocalsForYarnPnP[a.Ref]; ok {
 14563  											source := logger.Source{KeyPath: p.source.KeyPath, Contents: helpers.UTF16ToString(data.value)}
 14564  											stringInJSTable := logger.GenerateStringInJSTable(p.source.Contents, data.loc, source.Contents)
 14565  											log := logger.NewStringInJSLog(p.log, &p.tracker, stringInJSTable)
 14566  											p.manifestForYarnPnP, _ = ParseJSON(log, source, JSONOptions{})
 14567  											remapExprLocsInJSON(&p.manifestForYarnPnP, stringInJSTable)
 14568  										}
 14569  									}
 14570  								}
 14571  							}
 14572  						}
 14573  					}
 14574  				}
 14575  			}
 14576  		}
 14577  
 14578  		// Stop now if this call must be removed
 14579  		if out.methodCallMustBeReplacedWithUndefined {
 14580  			p.isControlFlowDead = oldIsControlFlowDead
 14581  			return js_ast.Expr{Loc: expr.Loc, Data: js_ast.EUndefinedShared}, exprOut{}
 14582  		}
 14583  
 14584  		// "foo(1, ...[2, 3], 4)" => "foo(1, 2, 3, 4)"
 14585  		if p.options.minifySyntax && hasSpread {
 14586  			e.Args = js_ast.InlineSpreadsOfArrayLiterals(e.Args)
 14587  		}
 14588  
 14589  		switch t := target.Data.(type) {
 14590  		case *js_ast.EImportIdentifier:
 14591  			// If this function is inlined, allow it to be tree-shaken
 14592  			if p.options.minifySyntax && !p.isControlFlowDead {
 14593  				p.convertSymbolUseToCall(t.Ref, len(e.Args) == 1 && !hasSpread)
 14594  			}
 14595  
 14596  		case *js_ast.EIdentifier:
 14597  			// Detect if this is a direct eval. Note that "(1 ? eval : 0)(x)" will
 14598  			// become "eval(x)" after we visit the target due to dead code elimination,
 14599  			// but that doesn't mean it should become a direct eval.
 14600  			//
 14601  			// Note that "eval?.(x)" is considered an indirect eval. There was debate
 14602  			// about this after everyone implemented it as a direct eval, but the
 14603  			// language committee said it was indirect and everyone had to change it:
 14604  			// https://github.com/tc39/ecma262/issues/2062.
 14605  			if e.OptionalChain == js_ast.OptionalChainNone {
 14606  				symbol := p.symbols[t.Ref.InnerIndex]
 14607  				if wasIdentifierBeforeVisit && symbol.OriginalName == "eval" {
 14608  					e.Kind = js_ast.DirectEval
 14609  
 14610  					// Pessimistically assume that if this looks like a CommonJS module
 14611  					// (e.g. no "export" keywords), a direct call to "eval" means that
 14612  					// code could potentially access "module" or "exports".
 14613  					if p.options.mode == config.ModeBundle && !p.isFileConsideredToHaveESMExports {
 14614  						p.recordUsage(p.moduleRef)
 14615  						p.recordUsage(p.exportsRef)
 14616  					}
 14617  
 14618  					// Mark this scope and all parent scopes as containing a direct eval.
 14619  					// This will prevent us from renaming any symbols.
 14620  					for s := p.currentScope; s != nil; s = s.Parent {
 14621  						s.ContainsDirectEval = true
 14622  					}
 14623  
 14624  					// Warn when direct eval is used in an ESM file. There is no way we
 14625  					// can guarantee that this will work correctly for top-level imported
 14626  					// and exported symbols due to scope hoisting. Except don't warn when
 14627  					// this code is in a 3rd-party library because there's nothing people
 14628  					// will be able to do about the warning.
 14629  					text := "Using direct eval with a bundler is not recommended and may cause problems"
 14630  					kind := logger.Debug
 14631  					if p.options.mode == config.ModeBundle && p.isFileConsideredESM && !p.suppressWarningsAboutWeirdCode {
 14632  						kind = logger.Warning
 14633  					}
 14634  					p.log.AddIDWithNotes(logger.MsgID_JS_DirectEval, kind, &p.tracker, js_lexer.RangeOfIdentifier(p.source, e.Target.Loc), text,
 14635  						[]logger.MsgData{{Text: "You can read more about direct eval and bundling here: https://esbuild.github.io/link/direct-eval"}})
 14636  				} else if symbol.Flags.Has(ast.CallCanBeUnwrappedIfUnused) {
 14637  					// Automatically add a "/* @__PURE__ */" comment to file-local calls
 14638  					// of functions declared with a "/* @__NO_SIDE_EFFECTS__ */" comment
 14639  					t.CallCanBeUnwrappedIfUnused = true
 14640  				}
 14641  			}
 14642  
 14643  			// Optimize references to global constructors
 14644  			if p.options.minifySyntax && t.CanBeRemovedIfUnused && len(e.Args) <= 1 && !hasSpread {
 14645  				if symbol := &p.symbols[t.Ref.InnerIndex]; symbol.Kind == ast.SymbolUnbound {
 14646  					// Note: We construct expressions by assigning to "expr.Data" so
 14647  					// that the source map position for the constructor is preserved
 14648  					switch symbol.OriginalName {
 14649  					case "Boolean":
 14650  						if len(e.Args) == 0 {
 14651  							return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EBoolean{Value: false}}, exprOut{}
 14652  						} else {
 14653  							expr.Data = &js_ast.EUnary{Value: p.astHelpers.SimplifyBooleanExpr(e.Args[0]), Op: js_ast.UnOpNot}
 14654  							return js_ast.Not(expr), exprOut{}
 14655  						}
 14656  
 14657  					case "Number":
 14658  						if len(e.Args) == 0 {
 14659  							return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ENumber{Value: 0}}, exprOut{}
 14660  						} else {
 14661  							arg := e.Args[0]
 14662  
 14663  							switch js_ast.KnownPrimitiveType(arg.Data) {
 14664  							case js_ast.PrimitiveNumber:
 14665  								return arg, exprOut{}
 14666  
 14667  							case
 14668  								js_ast.PrimitiveUndefined, // NaN
 14669  								js_ast.PrimitiveNull,      // 0
 14670  								js_ast.PrimitiveBoolean,   // 0 or 1
 14671  								js_ast.PrimitiveString:    // StringToNumber
 14672  								if number, ok := js_ast.ToNumberWithoutSideEffects(arg.Data); ok {
 14673  									expr.Data = &js_ast.ENumber{Value: number}
 14674  								} else {
 14675  									expr.Data = &js_ast.EUnary{Value: arg, Op: js_ast.UnOpPos}
 14676  								}
 14677  								return expr, exprOut{}
 14678  							}
 14679  						}
 14680  
 14681  					case "String":
 14682  						if len(e.Args) == 0 {
 14683  							return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EString{Value: nil}}, exprOut{}
 14684  						} else {
 14685  							arg := e.Args[0]
 14686  
 14687  							switch js_ast.KnownPrimitiveType(arg.Data) {
 14688  							case js_ast.PrimitiveString:
 14689  								return arg, exprOut{}
 14690  							}
 14691  						}
 14692  
 14693  					case "BigInt":
 14694  						if len(e.Args) == 1 {
 14695  							arg := e.Args[0]
 14696  
 14697  							switch js_ast.KnownPrimitiveType(arg.Data) {
 14698  							case js_ast.PrimitiveBigInt:
 14699  								return arg, exprOut{}
 14700  							}
 14701  						}
 14702  					}
 14703  				}
 14704  			}
 14705  
 14706  			// Copy the call side effect flag over if this is a known target
 14707  			if t.CallCanBeUnwrappedIfUnused {
 14708  				e.CanBeUnwrappedIfUnused = true
 14709  			}
 14710  
 14711  			// If this function is inlined, allow it to be tree-shaken
 14712  			if p.options.minifySyntax && !p.isControlFlowDead {
 14713  				p.convertSymbolUseToCall(t.Ref, len(e.Args) == 1 && !hasSpread)
 14714  			}
 14715  
 14716  		case *js_ast.EDot:
 14717  			// Recognize "require.resolve()" calls
 14718  			if couldBeRequireResolve && t.Name == "resolve" {
 14719  				if id, ok := t.Target.Data.(*js_ast.EIdentifier); ok && id.Ref == p.requireRef {
 14720  					p.ignoreUsage(p.requireRef)
 14721  					return p.maybeTransposeIfExprChain(e.Args[0], func(arg js_ast.Expr) js_ast.Expr {
 14722  						if str, ok := e.Args[0].Data.(*js_ast.EString); ok {
 14723  							// Ignore calls to require.resolve() if the control flow is provably
 14724  							// dead here. We don't want to spend time scanning the required files
 14725  							// if they will never be used.
 14726  							if p.isControlFlowDead {
 14727  								return js_ast.Expr{Loc: expr.Loc, Data: js_ast.ENullShared}
 14728  							}
 14729  
 14730  							importRecordIndex := p.addImportRecord(ast.ImportRequireResolve, p.source.RangeOfString(e.Args[0].Loc), helpers.UTF16ToString(str.Value), nil, 0)
 14731  							if p.fnOrArrowDataVisit.tryBodyCount != 0 {
 14732  								record := &p.importRecords[importRecordIndex]
 14733  								record.Flags |= ast.HandlesImportErrors
 14734  								record.ErrorHandlerLoc = p.fnOrArrowDataVisit.tryCatchLoc
 14735  							}
 14736  							p.importRecordsForCurrentPart = append(p.importRecordsForCurrentPart, importRecordIndex)
 14737  
 14738  							// Create a new expression to represent the operation
 14739  							return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ERequireResolveString{
 14740  								ImportRecordIndex: importRecordIndex,
 14741  								CloseParenLoc:     e.CloseParenLoc,
 14742  							}}
 14743  						}
 14744  
 14745  						// Otherwise just return a clone of the "require.resolve()" call
 14746  						return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ECall{
 14747  							Target: js_ast.Expr{Loc: e.Target.Loc, Data: &js_ast.EDot{
 14748  								Target:  p.valueToSubstituteForRequire(t.Target.Loc),
 14749  								Name:    t.Name,
 14750  								NameLoc: t.NameLoc,
 14751  							}},
 14752  							Args:          []js_ast.Expr{arg},
 14753  							Kind:          e.Kind,
 14754  							CloseParenLoc: e.CloseParenLoc,
 14755  						}}
 14756  					}), exprOut{}
 14757  				}
 14758  			}
 14759  
 14760  			// Recognize "Object.create()" calls
 14761  			if couldBeObjectCreate && t.Name == "create" {
 14762  				if id, ok := t.Target.Data.(*js_ast.EIdentifier); ok {
 14763  					if symbol := &p.symbols[id.Ref.InnerIndex]; symbol.Kind == ast.SymbolUnbound && symbol.OriginalName == "Object" {
 14764  						switch e.Args[0].Data.(type) {
 14765  						case *js_ast.ENull, *js_ast.EObject:
 14766  							// Mark "Object.create(null)" and "Object.create({})" as pure
 14767  							e.CanBeUnwrappedIfUnused = true
 14768  						}
 14769  					}
 14770  				}
 14771  			}
 14772  
 14773  			if p.options.minifySyntax {
 14774  				switch t.Name {
 14775  				case "charCodeAt":
 14776  					// Recognize "charCodeAt()" calls
 14777  					if str, ok := t.Target.Data.(*js_ast.EString); ok && len(e.Args) <= 1 {
 14778  						index := 0
 14779  						hasIndex := false
 14780  						if len(e.Args) == 0 {
 14781  							hasIndex = true
 14782  						} else if num, ok := e.Args[0].Data.(*js_ast.ENumber); ok && num.Value == math.Trunc(num.Value) && math.Abs(num.Value) <= 0x7FFF_FFFF {
 14783  							index = int(num.Value)
 14784  							hasIndex = true
 14785  						}
 14786  						if hasIndex {
 14787  							if index >= 0 && index < len(str.Value) {
 14788  								return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ENumber{Value: float64(str.Value[index])}}, exprOut{}
 14789  							} else {
 14790  								return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ENumber{Value: math.NaN()}}, exprOut{}
 14791  							}
 14792  						}
 14793  					}
 14794  
 14795  				case "fromCharCode":
 14796  					// Recognize "fromCharCode()" calls
 14797  					if id, ok := t.Target.Data.(*js_ast.EIdentifier); ok {
 14798  						if symbol := &p.symbols[id.Ref.InnerIndex]; symbol.Kind == ast.SymbolUnbound && symbol.OriginalName == "String" {
 14799  							charCodes := make([]uint16, 0, len(e.Args))
 14800  							for _, arg := range e.Args {
 14801  								arg, ok := js_ast.ToNumberWithoutSideEffects(arg.Data)
 14802  								if !ok {
 14803  									break
 14804  								}
 14805  								charCodes = append(charCodes, uint16(js_ast.ToInt32(arg)))
 14806  							}
 14807  							if len(charCodes) == len(e.Args) {
 14808  								return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EString{Value: charCodes}}, exprOut{}
 14809  							}
 14810  						}
 14811  					}
 14812  
 14813  				case "toString":
 14814  					switch target := t.Target.Data.(type) {
 14815  					case *js_ast.ENumber:
 14816  						radix := 0
 14817  						if len(e.Args) == 0 {
 14818  							radix = 10
 14819  						} else if len(e.Args) == 1 {
 14820  							if num, ok := e.Args[0].Data.(*js_ast.ENumber); ok && num.Value == math.Trunc(num.Value) && num.Value >= 2 && num.Value <= 36 {
 14821  								radix = int(num.Value)
 14822  							}
 14823  						}
 14824  						if radix != 0 {
 14825  							if str, ok := js_ast.TryToStringOnNumberSafely(target.Value, radix); ok {
 14826  								return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(str)}}, exprOut{}
 14827  							}
 14828  						}
 14829  
 14830  					case *js_ast.ERegExp:
 14831  						if len(e.Args) == 0 {
 14832  							return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16(target.Value)}}, exprOut{}
 14833  						}
 14834  
 14835  					case *js_ast.EBoolean:
 14836  						if len(e.Args) == 0 {
 14837  							if target.Value {
 14838  								return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16("true")}}, exprOut{}
 14839  							} else {
 14840  								return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EString{Value: helpers.StringToUTF16("false")}}, exprOut{}
 14841  							}
 14842  						}
 14843  
 14844  					case *js_ast.EString:
 14845  						if len(e.Args) == 0 {
 14846  							return t.Target, exprOut{}
 14847  						}
 14848  					}
 14849  				}
 14850  			}
 14851  
 14852  			// Copy the call side effect flag over if this is a known target
 14853  			if t.CallCanBeUnwrappedIfUnused {
 14854  				e.CanBeUnwrappedIfUnused = true
 14855  			}
 14856  
 14857  		case *js_ast.EIndex:
 14858  			// Copy the call side effect flag over if this is a known target
 14859  			if t.CallCanBeUnwrappedIfUnused {
 14860  				e.CanBeUnwrappedIfUnused = true
 14861  			}
 14862  
 14863  		case *js_ast.ESuper:
 14864  			// If we're shimming "super()" calls, replace this call with "__super()"
 14865  			if p.superCtorRef != ast.InvalidRef {
 14866  				p.recordUsage(p.superCtorRef)
 14867  				target.Data = &js_ast.EIdentifier{Ref: p.superCtorRef}
 14868  				e.Target.Data = target.Data
 14869  			}
 14870  		}
 14871  
 14872  		// Handle parenthesized optional chains
 14873  		if isParenthesizedOptionalChain && out.thisArgFunc != nil && out.thisArgWrapFunc != nil {
 14874  			return p.lowerParenthesizedOptionalChain(expr.Loc, e, out), exprOut{}
 14875  		}
 14876  
 14877  		// Lower optional chaining if we're the top of the chain
 14878  		containsOptionalChain := e.OptionalChain == js_ast.OptionalChainStart ||
 14879  			(e.OptionalChain == js_ast.OptionalChainContinue && out.childContainsOptionalChain)
 14880  		if containsOptionalChain && !in.hasChainParent {
 14881  			return p.lowerOptionalChain(expr, in, out)
 14882  		}
 14883  
 14884  		// If this is a plain call expression (instead of an optional chain), lower
 14885  		// private member access in the call target now if there is one
 14886  		if !containsOptionalChain {
 14887  			if target, loc, private := p.extractPrivateIndex(e.Target); private != nil {
 14888  				// "foo.#bar(123)" => "__privateGet(_a = foo, #bar).call(_a, 123)"
 14889  				targetFunc, targetWrapFunc := p.captureValueWithPossibleSideEffects(target.Loc, 2, target, valueCouldBeMutated)
 14890  				return targetWrapFunc(js_ast.Expr{Loc: target.Loc, Data: &js_ast.ECall{
 14891  					Target: js_ast.Expr{Loc: target.Loc, Data: &js_ast.EDot{
 14892  						Target:  p.lowerPrivateGet(targetFunc(), loc, private),
 14893  						Name:    "call",
 14894  						NameLoc: target.Loc,
 14895  					}},
 14896  					Args:                   append([]js_ast.Expr{targetFunc()}, e.Args...),
 14897  					CanBeUnwrappedIfUnused: e.CanBeUnwrappedIfUnused,
 14898  					Kind:                   js_ast.TargetWasOriginallyPropertyAccess,
 14899  				}}), exprOut{}
 14900  			}
 14901  			p.maybeLowerSuperPropertyGetInsideCall(e)
 14902  		}
 14903  
 14904  		// Track calls to require() so we can use them while bundling
 14905  		if p.options.mode != config.ModePassThrough && e.OptionalChain == js_ast.OptionalChainNone {
 14906  			if id, ok := e.Target.Data.(*js_ast.EIdentifier); ok && id.Ref == p.requireRef {
 14907  				// Heuristic: omit warnings inside try/catch blocks because presumably
 14908  				// the try/catch statement is there to handle the potential run-time
 14909  				// error from the unbundled require() call failing.
 14910  				omitWarnings := p.fnOrArrowDataVisit.tryBodyCount != 0
 14911  
 14912  				if p.options.mode != config.ModePassThrough {
 14913  					// There must be one argument
 14914  					if len(e.Args) == 1 {
 14915  						p.ignoreUsage(p.requireRef)
 14916  						return p.maybeTransposeIfExprChain(e.Args[0], func(arg js_ast.Expr) js_ast.Expr {
 14917  							// The argument must be a string
 14918  							if str, ok := arg.Data.(*js_ast.EString); ok {
 14919  								// Ignore calls to require() if the control flow is provably dead here.
 14920  								// We don't want to spend time scanning the required files if they will
 14921  								// never be used.
 14922  								if p.isControlFlowDead {
 14923  									return js_ast.Expr{Loc: expr.Loc, Data: js_ast.ENullShared}
 14924  								}
 14925  
 14926  								importRecordIndex := p.addImportRecord(ast.ImportRequire, p.source.RangeOfString(arg.Loc), helpers.UTF16ToString(str.Value), nil, 0)
 14927  								if p.fnOrArrowDataVisit.tryBodyCount != 0 {
 14928  									record := &p.importRecords[importRecordIndex]
 14929  									record.Flags |= ast.HandlesImportErrors
 14930  									record.ErrorHandlerLoc = p.fnOrArrowDataVisit.tryCatchLoc
 14931  								}
 14932  								p.importRecordsForCurrentPart = append(p.importRecordsForCurrentPart, importRecordIndex)
 14933  
 14934  								// Currently "require" is not converted into "import" for ESM
 14935  								if p.options.mode != config.ModeBundle && p.options.outputFormat == config.FormatESModule && !omitWarnings {
 14936  									r := js_lexer.RangeOfIdentifier(p.source, e.Target.Loc)
 14937  									p.log.AddID(logger.MsgID_JS_UnsupportedRequireCall, logger.Warning, &p.tracker, r, "Converting \"require\" to \"esm\" is currently not supported")
 14938  								}
 14939  
 14940  								// Create a new expression to represent the operation
 14941  								return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ERequireString{
 14942  									ImportRecordIndex: importRecordIndex,
 14943  									CloseParenLoc:     e.CloseParenLoc,
 14944  								}}
 14945  							}
 14946  
 14947  							// Handle glob patterns
 14948  							if p.options.mode == config.ModeBundle {
 14949  								if value := p.handleGlobPattern(arg, ast.ImportRequire, "globRequire", nil); value.Data != nil {
 14950  									return value
 14951  								}
 14952  							}
 14953  
 14954  							// Use a debug log so people can see this if they want to
 14955  							r := js_lexer.RangeOfIdentifier(p.source, e.Target.Loc)
 14956  							p.log.AddID(logger.MsgID_JS_UnsupportedRequireCall, logger.Debug, &p.tracker, r,
 14957  								"This call to \"require\" will not be bundled because the argument is not a string literal")
 14958  
 14959  							// Otherwise just return a clone of the "require()" call
 14960  							return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ECall{
 14961  								Target:        p.valueToSubstituteForRequire(e.Target.Loc),
 14962  								Args:          []js_ast.Expr{arg},
 14963  								CloseParenLoc: e.CloseParenLoc,
 14964  							}}
 14965  						}), exprOut{}
 14966  					} else {
 14967  						// Use a debug log so people can see this if they want to
 14968  						r := js_lexer.RangeOfIdentifier(p.source, e.Target.Loc)
 14969  						p.log.AddIDWithNotes(logger.MsgID_JS_UnsupportedRequireCall, logger.Debug, &p.tracker, r,
 14970  							fmt.Sprintf("This call to \"require\" will not be bundled because it has %d arguments", len(e.Args)),
 14971  							[]logger.MsgData{{Text: "To be bundled by esbuild, a \"require\" call must have exactly 1 argument."}})
 14972  					}
 14973  
 14974  					return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ECall{
 14975  						Target:        p.valueToSubstituteForRequire(e.Target.Loc),
 14976  						Args:          e.Args,
 14977  						CloseParenLoc: e.CloseParenLoc,
 14978  					}}, exprOut{}
 14979  				}
 14980  			}
 14981  		}
 14982  
 14983  		out = exprOut{
 14984  			childContainsOptionalChain: containsOptionalChain,
 14985  			thisArgFunc:                out.thisArgFunc,
 14986  			thisArgWrapFunc:            out.thisArgWrapFunc,
 14987  		}
 14988  		if !in.hasChainParent {
 14989  			out.thisArgFunc = nil
 14990  			out.thisArgWrapFunc = nil
 14991  		}
 14992  		return expr, out
 14993  
 14994  	case *js_ast.ENew:
 14995  		hasSpread := false
 14996  
 14997  		e.Target = p.visitExpr(e.Target)
 14998  		p.warnAboutImportNamespaceCall(e.Target, exprKindNew)
 14999  
 15000  		for i, arg := range e.Args {
 15001  			arg = p.visitExpr(arg)
 15002  			if _, ok := arg.Data.(*js_ast.ESpread); ok {
 15003  				hasSpread = true
 15004  			}
 15005  			e.Args[i] = arg
 15006  		}
 15007  
 15008  		// "new foo(1, ...[2, 3], 4)" => "new foo(1, 2, 3, 4)"
 15009  		if p.options.minifySyntax && hasSpread {
 15010  			e.Args = js_ast.InlineSpreadsOfArrayLiterals(e.Args)
 15011  		}
 15012  
 15013  		p.maybeMarkKnownGlobalConstructorAsPure(e)
 15014  
 15015  	case *js_ast.EArrow:
 15016  		// Check for a propagated name to keep from the parent context
 15017  		var nameToKeep string
 15018  		if p.nameToKeepIsFor == e {
 15019  			nameToKeep = p.nameToKeep
 15020  		}
 15021  
 15022  		// Prepare for suspicious logical operator checking
 15023  		if e.PreferExpr && len(e.Args) == 1 && e.Args[0].DefaultOrNil.Data == nil && len(e.Body.Block.Stmts) == 1 {
 15024  			if _, ok := e.Args[0].Binding.Data.(*js_ast.BIdentifier); ok {
 15025  				if stmt, ok := e.Body.Block.Stmts[0].Data.(*js_ast.SReturn); ok {
 15026  					if binary, ok := stmt.ValueOrNil.Data.(*js_ast.EBinary); ok && (binary.Op == js_ast.BinOpLogicalAnd || binary.Op == js_ast.BinOpLogicalOr) {
 15027  						p.suspiciousLogicalOperatorInsideArrow = binary
 15028  					}
 15029  				}
 15030  			}
 15031  		}
 15032  
 15033  		asyncArrowNeedsToBeLowered := e.IsAsync && p.options.unsupportedJSFeatures.Has(compat.AsyncAwait)
 15034  		oldFnOrArrowData := p.fnOrArrowDataVisit
 15035  		p.fnOrArrowDataVisit = fnOrArrowDataVisit{
 15036  			isArrow:                        true,
 15037  			isAsync:                        e.IsAsync,
 15038  			shouldLowerSuperPropertyAccess: oldFnOrArrowData.shouldLowerSuperPropertyAccess || asyncArrowNeedsToBeLowered,
 15039  		}
 15040  
 15041  		// Mark if we're inside an async arrow function. This value should be true
 15042  		// even if we're inside multiple arrow functions and the closest inclosing
 15043  		// arrow function isn't async, as long as at least one enclosing arrow
 15044  		// function within the current enclosing function is async.
 15045  		oldInsideAsyncArrowFn := p.fnOnlyDataVisit.isInsideAsyncArrowFn
 15046  		if e.IsAsync {
 15047  			p.fnOnlyDataVisit.isInsideAsyncArrowFn = true
 15048  		}
 15049  
 15050  		p.pushScopeForVisitPass(js_ast.ScopeFunctionArgs, expr.Loc)
 15051  		p.visitArgs(e.Args, visitArgsOpts{
 15052  			hasRestArg:               e.HasRestArg,
 15053  			body:                     e.Body.Block.Stmts,
 15054  			isUniqueFormalParameters: true,
 15055  		})
 15056  		p.pushScopeForVisitPass(js_ast.ScopeFunctionBody, e.Body.Loc)
 15057  		e.Body.Block.Stmts = p.visitStmtsAndPrependTempRefs(e.Body.Block.Stmts, prependTempRefsOpts{kind: stmtsFnBody})
 15058  		p.popScope()
 15059  		p.lowerFunction(&e.IsAsync, nil, &e.Args, e.Body.Loc, &e.Body.Block, &e.PreferExpr, &e.HasRestArg, true /* isArrow */)
 15060  		p.popScope()
 15061  
 15062  		if p.options.minifySyntax && len(e.Body.Block.Stmts) == 1 {
 15063  			if s, ok := e.Body.Block.Stmts[0].Data.(*js_ast.SReturn); ok {
 15064  				if s.ValueOrNil.Data == nil {
 15065  					// "() => { return }" => "() => {}"
 15066  					e.Body.Block.Stmts = []js_ast.Stmt{}
 15067  				} else {
 15068  					// "() => { return x }" => "() => x"
 15069  					e.PreferExpr = true
 15070  				}
 15071  			}
 15072  		}
 15073  
 15074  		p.fnOnlyDataVisit.isInsideAsyncArrowFn = oldInsideAsyncArrowFn
 15075  		p.fnOrArrowDataVisit = oldFnOrArrowData
 15076  
 15077  		// Convert arrow functions to function expressions when lowering
 15078  		if p.options.unsupportedJSFeatures.Has(compat.Arrow) {
 15079  			expr.Data = &js_ast.EFunction{Fn: js_ast.Fn{
 15080  				Args:         e.Args,
 15081  				Body:         e.Body,
 15082  				ArgumentsRef: ast.InvalidRef,
 15083  				IsAsync:      e.IsAsync,
 15084  				HasRestArg:   e.HasRestArg,
 15085  			}}
 15086  		}
 15087  
 15088  		// Optionally preserve the name
 15089  		if p.options.keepNames && nameToKeep != "" {
 15090  			expr = p.keepExprSymbolName(expr, nameToKeep)
 15091  		}
 15092  
 15093  	case *js_ast.EFunction:
 15094  		// Check for a propagated name to keep from the parent context
 15095  		var nameToKeep string
 15096  		if p.nameToKeepIsFor == e {
 15097  			nameToKeep = p.nameToKeep
 15098  		}
 15099  
 15100  		p.visitFn(&e.Fn, expr.Loc, visitFnOpts{
 15101  			isMethod:               in.isMethod,
 15102  			isDerivedClassCtor:     e == p.propDerivedCtorValue,
 15103  			isLoweredPrivateMethod: in.isLoweredPrivateMethod,
 15104  		})
 15105  		name := e.Fn.Name
 15106  
 15107  		// Remove unused function names when minifying
 15108  		if p.options.minifySyntax && !p.currentScope.ContainsDirectEval &&
 15109  			name != nil && p.symbols[name.Ref.InnerIndex].UseCountEstimate == 0 {
 15110  			e.Fn.Name = nil
 15111  		}
 15112  
 15113  		// Optionally preserve the name for functions, but not for methods
 15114  		if p.options.keepNames && (!in.isMethod || in.isLoweredPrivateMethod) {
 15115  			if name != nil {
 15116  				expr = p.keepExprSymbolName(expr, p.symbols[name.Ref.InnerIndex].OriginalName)
 15117  			} else if nameToKeep != "" {
 15118  				expr = p.keepExprSymbolName(expr, nameToKeep)
 15119  			}
 15120  		}
 15121  
 15122  	case *js_ast.EClass:
 15123  		// Check for a propagated name to keep from the parent context
 15124  		var nameToKeep string
 15125  		if p.nameToKeepIsFor == e {
 15126  			nameToKeep = p.nameToKeep
 15127  		}
 15128  
 15129  		result := p.visitClass(expr.Loc, &e.Class, ast.InvalidRef, nameToKeep)
 15130  
 15131  		// Lower class field syntax for browsers that don't support it
 15132  		_, expr = p.lowerClass(js_ast.Stmt{}, expr, result, nameToKeep)
 15133  
 15134  		// We may be able to determine that a class is side-effect before lowering
 15135  		// but not after lowering (e.g. due to "--keep-names" mutating the object).
 15136  		// If that's the case, add a special annotation so this doesn't prevent
 15137  		// tree-shaking from happening.
 15138  		if result.canBeRemovedIfUnused {
 15139  			expr.Data = &js_ast.EAnnotation{
 15140  				Value: expr,
 15141  				Flags: js_ast.CanBeRemovedIfUnusedFlag,
 15142  			}
 15143  		}
 15144  
 15145  	default:
 15146  		// Note: EPrivateIdentifier should have already been handled
 15147  		panic(fmt.Sprintf("Unexpected expression of type %T", expr.Data))
 15148  	}
 15149  
 15150  	return expr, exprOut{}
 15151  }
 15152  
 15153  // This exists to handle very deeply-nested ASTs. For example, the "grapheme-splitter"
 15154  // package contains this monstrosity:
 15155  //
 15156  //	if (
 15157  //	  (0x0300 <= code && code <= 0x036F) ||
 15158  //	  (0x0483 <= code && code <= 0x0487) ||
 15159  //	  (0x0488 <= code && code <= 0x0489) ||
 15160  //	  (0x0591 <= code && code <= 0x05BD) ||
 15161  //	  ... many hundreds of lines later ...
 15162  //	) {
 15163  //	  return;
 15164  //	}
 15165  //
 15166  // If "checkAndPrepare" returns non-nil, then the return value is the final
 15167  // expression. Otherwise, the final expression can be obtained by manually
 15168  // visiting the left child and then calling "visitRightAndFinish":
 15169  //
 15170  //	if result := v.checkAndPrepare(p); result.Data != nil {
 15171  //	  return result
 15172  //	}
 15173  //	v.e.Left, _ = p.visitExprInOut(v.e.Left, v.leftIn)
 15174  //	return v.visitRightAndFinish(p)
 15175  //
 15176  // This code is convoluted this way so that we can use our own stack on the
 15177  // heap instead of the call stack when there are additional levels of nesting.
 15178  // Before this transformation, the code previously looked something like this:
 15179  //
 15180  //	... The code in "checkAndPrepare" ...
 15181  //	e.Left, _ = p.visitExprInOut(e.Left, in)
 15182  //	... The code in "visitRightAndFinish" ...
 15183  //
 15184  // If this code is still confusing, it may be helpful to look back in git
 15185  // history at the commit that introduced this transformation.
 15186  //
 15187  // Go normally has growable call stacks so this code transformation normally
 15188  // doesn't do anything, but WebAssembly doesn't allow stack pointer manipulation
 15189  // so Go's WebAssembly implementation doesn't support growable call stacks and
 15190  // is therefore vulnerable to stack overflow. So this code transformation is
 15191  // only really relevant for esbuild's WebAssembly-based API.
 15192  type binaryExprVisitor struct {
 15193  	// Inputs
 15194  	e   *js_ast.EBinary
 15195  	loc logger.Loc
 15196  	in  exprIn
 15197  
 15198  	// Input for visiting the left child
 15199  	leftIn exprIn
 15200  
 15201  	// "Local variables" passed from "checkAndPrepare" to "visitRightAndFinish"
 15202  	isStmtExpr                               bool
 15203  	oldSilenceWarningAboutThisBeingUndefined bool
 15204  }
 15205  
 15206  func (v *binaryExprVisitor) checkAndPrepare(p *parser) js_ast.Expr {
 15207  	e := v.e
 15208  
 15209  	// Special-case EPrivateIdentifier to allow it here
 15210  	if private, ok := e.Left.Data.(*js_ast.EPrivateIdentifier); ok && e.Op == js_ast.BinOpIn {
 15211  		name := p.loadNameFromRef(private.Ref)
 15212  		result := p.findSymbol(e.Left.Loc, name)
 15213  		private.Ref = result.ref
 15214  
 15215  		// Unlike regular identifiers, there are no unbound private identifiers
 15216  		symbol := &p.symbols[result.ref.InnerIndex]
 15217  		if !symbol.Kind.IsPrivate() {
 15218  			r := logger.Range{Loc: e.Left.Loc, Len: int32(len(name))}
 15219  			p.log.AddError(&p.tracker, r, fmt.Sprintf("Private name %q must be declared in an enclosing class", name))
 15220  		}
 15221  
 15222  		e.Right = p.visitExpr(e.Right)
 15223  
 15224  		if p.privateSymbolNeedsToBeLowered(private) {
 15225  			return p.lowerPrivateBrandCheck(e.Right, v.loc, private)
 15226  		}
 15227  		return js_ast.Expr{Loc: v.loc, Data: e}
 15228  	}
 15229  
 15230  	v.isStmtExpr = e == p.stmtExprValue
 15231  	v.oldSilenceWarningAboutThisBeingUndefined = p.fnOnlyDataVisit.silenceMessageAboutThisBeingUndefined
 15232  
 15233  	if _, ok := e.Left.Data.(*js_ast.EThis); ok && e.Op == js_ast.BinOpLogicalAnd {
 15234  		p.fnOnlyDataVisit.silenceMessageAboutThisBeingUndefined = true
 15235  	}
 15236  	v.leftIn = exprIn{
 15237  		assignTarget:               e.Op.BinaryAssignTarget(),
 15238  		shouldMangleStringsAsProps: e.Op == js_ast.BinOpIn,
 15239  	}
 15240  	return js_ast.Expr{}
 15241  }
 15242  
 15243  func (v *binaryExprVisitor) visitRightAndFinish(p *parser) js_ast.Expr {
 15244  	e := v.e
 15245  
 15246  	// Mark the control flow as dead if the branch is never taken
 15247  	switch e.Op {
 15248  	case js_ast.BinOpLogicalOr:
 15249  		if boolean, _, ok := js_ast.ToBooleanWithSideEffects(e.Left.Data); ok && boolean {
 15250  			// "true || dead"
 15251  			old := p.isControlFlowDead
 15252  			p.isControlFlowDead = true
 15253  			e.Right = p.visitExpr(e.Right)
 15254  			p.isControlFlowDead = old
 15255  		} else {
 15256  			e.Right = p.visitExpr(e.Right)
 15257  		}
 15258  
 15259  	case js_ast.BinOpLogicalAnd:
 15260  		if boolean, _, ok := js_ast.ToBooleanWithSideEffects(e.Left.Data); ok && !boolean {
 15261  			// "false && dead"
 15262  			old := p.isControlFlowDead
 15263  			p.isControlFlowDead = true
 15264  			e.Right = p.visitExpr(e.Right)
 15265  			p.isControlFlowDead = old
 15266  		} else {
 15267  			e.Right = p.visitExpr(e.Right)
 15268  		}
 15269  
 15270  	case js_ast.BinOpNullishCoalescing:
 15271  		if isNullOrUndefined, _, ok := js_ast.ToNullOrUndefinedWithSideEffects(e.Left.Data); ok && !isNullOrUndefined {
 15272  			// "notNullOrUndefined ?? dead"
 15273  			old := p.isControlFlowDead
 15274  			p.isControlFlowDead = true
 15275  			e.Right = p.visitExpr(e.Right)
 15276  			p.isControlFlowDead = old
 15277  		} else {
 15278  			e.Right = p.visitExpr(e.Right)
 15279  		}
 15280  
 15281  	case js_ast.BinOpComma:
 15282  		e.Right, _ = p.visitExprInOut(e.Right, exprIn{
 15283  			shouldMangleStringsAsProps: v.in.shouldMangleStringsAsProps,
 15284  		})
 15285  
 15286  	case js_ast.BinOpAssign, js_ast.BinOpLogicalOrAssign, js_ast.BinOpLogicalAndAssign, js_ast.BinOpNullishCoalescingAssign:
 15287  		// Check for a propagated name to keep from the parent context
 15288  		if id, ok := e.Left.Data.(*js_ast.EIdentifier); ok {
 15289  			p.nameToKeep = p.symbols[id.Ref.InnerIndex].OriginalName
 15290  			p.nameToKeepIsFor = e.Right.Data
 15291  		}
 15292  
 15293  		e.Right = p.visitExpr(e.Right)
 15294  
 15295  	default:
 15296  		e.Right = p.visitExpr(e.Right)
 15297  	}
 15298  	p.fnOnlyDataVisit.silenceMessageAboutThisBeingUndefined = v.oldSilenceWarningAboutThisBeingUndefined
 15299  
 15300  	// Always put constants consistently on the same side for equality
 15301  	// comparisons to help improve compression. In theory, dictionary-based
 15302  	// compression methods may already have a dictionary entry for code that
 15303  	// is similar to previous code. Note that we can only reorder expressions
 15304  	// that do not have any side effects.
 15305  	//
 15306  	// Constants are currently ordered on the right instead of the left because
 15307  	// it results in slightly smalller gzip size on our primary benchmark
 15308  	// (although slightly larger uncompressed size). The size difference is
 15309  	// less than 0.1% so it really isn't that important an optimization.
 15310  	if p.options.minifySyntax {
 15311  		switch e.Op {
 15312  		case js_ast.BinOpLooseEq, js_ast.BinOpLooseNe, js_ast.BinOpStrictEq, js_ast.BinOpStrictNe:
 15313  			// "1 === x" => "x === 1"
 15314  			if js_ast.IsPrimitiveLiteral(e.Left.Data) && !js_ast.IsPrimitiveLiteral(e.Right.Data) {
 15315  				e.Left, e.Right = e.Right, e.Left
 15316  			}
 15317  		}
 15318  	}
 15319  
 15320  	if p.shouldFoldTypeScriptConstantExpressions || (p.options.minifySyntax && js_ast.ShouldFoldBinaryOperatorWhenMinifying(e)) {
 15321  		if result := js_ast.FoldBinaryOperator(v.loc, e); result.Data != nil {
 15322  			return result
 15323  		}
 15324  	}
 15325  
 15326  	// Post-process the binary expression
 15327  	switch e.Op {
 15328  	case js_ast.BinOpComma:
 15329  		// "(1, 2)" => "2"
 15330  		// "(sideEffects(), 2)" => "(sideEffects(), 2)"
 15331  		if p.options.minifySyntax {
 15332  			e.Left = p.astHelpers.SimplifyUnusedExpr(e.Left, p.options.unsupportedJSFeatures)
 15333  			if e.Left.Data == nil {
 15334  				return e.Right
 15335  			}
 15336  		}
 15337  
 15338  	case js_ast.BinOpLooseEq:
 15339  		if result, ok := js_ast.CheckEqualityIfNoSideEffects(e.Left.Data, e.Right.Data, js_ast.LooseEquality); ok {
 15340  			return js_ast.Expr{Loc: v.loc, Data: &js_ast.EBoolean{Value: result}}
 15341  		}
 15342  		afterOpLoc := locAfterOp(e)
 15343  		if !p.warnAboutEqualityCheck("==", e.Left, afterOpLoc) {
 15344  			p.warnAboutEqualityCheck("==", e.Right, afterOpLoc)
 15345  		}
 15346  		p.warnAboutTypeofAndString(e.Left, e.Right, checkBothOrders)
 15347  
 15348  		if p.options.minifySyntax {
 15349  			// "x == void 0" => "x == null"
 15350  			if _, ok := e.Left.Data.(*js_ast.EUndefined); ok {
 15351  				e.Left.Data = js_ast.ENullShared
 15352  			} else if _, ok := e.Right.Data.(*js_ast.EUndefined); ok {
 15353  				e.Right.Data = js_ast.ENullShared
 15354  			}
 15355  
 15356  			if result, ok := js_ast.MaybeSimplifyEqualityComparison(v.loc, e, p.options.unsupportedJSFeatures); ok {
 15357  				return result
 15358  			}
 15359  		}
 15360  
 15361  	case js_ast.BinOpStrictEq:
 15362  		if result, ok := js_ast.CheckEqualityIfNoSideEffects(e.Left.Data, e.Right.Data, js_ast.StrictEquality); ok {
 15363  			return js_ast.Expr{Loc: v.loc, Data: &js_ast.EBoolean{Value: result}}
 15364  		}
 15365  		afterOpLoc := locAfterOp(e)
 15366  		if !p.warnAboutEqualityCheck("===", e.Left, afterOpLoc) {
 15367  			p.warnAboutEqualityCheck("===", e.Right, afterOpLoc)
 15368  		}
 15369  		p.warnAboutTypeofAndString(e.Left, e.Right, checkBothOrders)
 15370  
 15371  		if p.options.minifySyntax {
 15372  			// "typeof x === 'undefined'" => "typeof x == 'undefined'"
 15373  			if js_ast.CanChangeStrictToLoose(e.Left, e.Right) {
 15374  				e.Op = js_ast.BinOpLooseEq
 15375  			}
 15376  
 15377  			if result, ok := js_ast.MaybeSimplifyEqualityComparison(v.loc, e, p.options.unsupportedJSFeatures); ok {
 15378  				return result
 15379  			}
 15380  		}
 15381  
 15382  	case js_ast.BinOpLooseNe:
 15383  		if result, ok := js_ast.CheckEqualityIfNoSideEffects(e.Left.Data, e.Right.Data, js_ast.LooseEquality); ok {
 15384  			return js_ast.Expr{Loc: v.loc, Data: &js_ast.EBoolean{Value: !result}}
 15385  		}
 15386  		afterOpLoc := locAfterOp(e)
 15387  		if !p.warnAboutEqualityCheck("!=", e.Left, afterOpLoc) {
 15388  			p.warnAboutEqualityCheck("!=", e.Right, afterOpLoc)
 15389  		}
 15390  		p.warnAboutTypeofAndString(e.Left, e.Right, checkBothOrders)
 15391  
 15392  		if p.options.minifySyntax {
 15393  			// "x != void 0" => "x != null"
 15394  			if _, ok := e.Left.Data.(*js_ast.EUndefined); ok {
 15395  				e.Left.Data = js_ast.ENullShared
 15396  			} else if _, ok := e.Right.Data.(*js_ast.EUndefined); ok {
 15397  				e.Right.Data = js_ast.ENullShared
 15398  			}
 15399  
 15400  			if result, ok := js_ast.MaybeSimplifyEqualityComparison(v.loc, e, p.options.unsupportedJSFeatures); ok {
 15401  				return result
 15402  			}
 15403  		}
 15404  
 15405  	case js_ast.BinOpStrictNe:
 15406  		if result, ok := js_ast.CheckEqualityIfNoSideEffects(e.Left.Data, e.Right.Data, js_ast.StrictEquality); ok {
 15407  			return js_ast.Expr{Loc: v.loc, Data: &js_ast.EBoolean{Value: !result}}
 15408  		}
 15409  		afterOpLoc := locAfterOp(e)
 15410  		if !p.warnAboutEqualityCheck("!==", e.Left, afterOpLoc) {
 15411  			p.warnAboutEqualityCheck("!==", e.Right, afterOpLoc)
 15412  		}
 15413  		p.warnAboutTypeofAndString(e.Left, e.Right, checkBothOrders)
 15414  
 15415  		if p.options.minifySyntax {
 15416  			// "typeof x !== 'undefined'" => "typeof x != 'undefined'"
 15417  			if js_ast.CanChangeStrictToLoose(e.Left, e.Right) {
 15418  				e.Op = js_ast.BinOpLooseNe
 15419  			}
 15420  
 15421  			if result, ok := js_ast.MaybeSimplifyEqualityComparison(v.loc, e, p.options.unsupportedJSFeatures); ok {
 15422  				return result
 15423  			}
 15424  		}
 15425  
 15426  	case js_ast.BinOpNullishCoalescing:
 15427  		if isNullOrUndefined, sideEffects, ok := js_ast.ToNullOrUndefinedWithSideEffects(e.Left.Data); ok {
 15428  			// Warn about potential bugs
 15429  			if !js_ast.IsPrimitiveLiteral(e.Left.Data) {
 15430  				// "return props.flag === flag ?? true" is "return (props.flag === flag) ?? true" not "return props.flag === (flag ?? true)"
 15431  				var which string
 15432  				var leftIsNullOrUndefined string
 15433  				var leftIsReturned string
 15434  				if !isNullOrUndefined {
 15435  					which = "left"
 15436  					leftIsNullOrUndefined = "never"
 15437  					leftIsReturned = "always"
 15438  				} else {
 15439  					which = "right"
 15440  					leftIsNullOrUndefined = "always"
 15441  					leftIsReturned = "never"
 15442  				}
 15443  				kind := logger.Warning
 15444  				if p.suppressWarningsAboutWeirdCode {
 15445  					kind = logger.Debug
 15446  				}
 15447  				rOp := p.source.RangeOfOperatorBefore(e.Right.Loc, "??")
 15448  				rLeft := logger.Range{Loc: e.Left.Loc, Len: p.source.LocBeforeWhitespace(rOp.Loc).Start - e.Left.Loc.Start}
 15449  				p.log.AddIDWithNotes(logger.MsgID_JS_SuspiciousNullishCoalescing, kind, &p.tracker, rOp,
 15450  					fmt.Sprintf("The \"??\" operator here will always return the %s operand", which), []logger.MsgData{
 15451  						p.tracker.MsgData(rLeft, fmt.Sprintf(
 15452  							"The left operand of the \"??\" operator here will %s be null or undefined, so it will %s be returned. This usually indicates a bug in your code:",
 15453  							leftIsNullOrUndefined, leftIsReturned))})
 15454  			}
 15455  
 15456  			if !isNullOrUndefined {
 15457  				return e.Left
 15458  			} else if sideEffects == js_ast.NoSideEffects {
 15459  				return e.Right
 15460  			}
 15461  		}
 15462  
 15463  		if p.options.minifySyntax {
 15464  			// "a ?? (b ?? c)" => "a ?? b ?? c"
 15465  			if right, ok := e.Right.Data.(*js_ast.EBinary); ok && right.Op == js_ast.BinOpNullishCoalescing {
 15466  				e.Left = js_ast.JoinWithLeftAssociativeOp(js_ast.BinOpNullishCoalescing, e.Left, right.Left)
 15467  				e.Right = right.Right
 15468  			}
 15469  		}
 15470  
 15471  		if p.options.unsupportedJSFeatures.Has(compat.NullishCoalescing) {
 15472  			return p.lowerNullishCoalescing(v.loc, e.Left, e.Right)
 15473  		}
 15474  
 15475  	case js_ast.BinOpLogicalOr:
 15476  		if boolean, sideEffects, ok := js_ast.ToBooleanWithSideEffects(e.Left.Data); ok {
 15477  			// Warn about potential bugs
 15478  			if e == p.suspiciousLogicalOperatorInsideArrow {
 15479  				if arrowLoc := p.source.RangeOfOperatorBefore(v.loc, "=>"); arrowLoc.Loc.Start+2 == p.source.LocBeforeWhitespace(v.loc).Start {
 15480  					// "return foo => 1 || foo <= 0"
 15481  					var which string
 15482  					if boolean {
 15483  						which = "left"
 15484  					} else {
 15485  						which = "right"
 15486  					}
 15487  					kind := logger.Warning
 15488  					if p.suppressWarningsAboutWeirdCode {
 15489  						kind = logger.Debug
 15490  					}
 15491  					note := p.tracker.MsgData(arrowLoc,
 15492  						"The \"=>\" symbol creates an arrow function expression in JavaScript. Did you mean to use the greater-than-or-equal-to operator \">=\" here instead?")
 15493  					note.Location.Suggestion = ">="
 15494  					rOp := p.source.RangeOfOperatorBefore(e.Right.Loc, "||")
 15495  					p.log.AddIDWithNotes(logger.MsgID_JS_SuspiciousLogicalOperator, kind, &p.tracker, rOp,
 15496  						fmt.Sprintf("The \"||\" operator here will always return the %s operand", which), []logger.MsgData{note})
 15497  				}
 15498  			}
 15499  
 15500  			if boolean {
 15501  				return e.Left
 15502  			} else if sideEffects == js_ast.NoSideEffects {
 15503  				return e.Right
 15504  			}
 15505  		}
 15506  
 15507  		if p.options.minifySyntax {
 15508  			// "a || (b || c)" => "a || b || c"
 15509  			if right, ok := e.Right.Data.(*js_ast.EBinary); ok && right.Op == js_ast.BinOpLogicalOr {
 15510  				e.Left = js_ast.JoinWithLeftAssociativeOp(js_ast.BinOpLogicalOr, e.Left, right.Left)
 15511  				e.Right = right.Right
 15512  			}
 15513  
 15514  			// "a === null || a === undefined" => "a == null"
 15515  			if left, right, ok := js_ast.IsBinaryNullAndUndefined(e.Left, e.Right, js_ast.BinOpStrictEq); ok {
 15516  				e.Op = js_ast.BinOpLooseEq
 15517  				e.Left = left
 15518  				e.Right = right
 15519  			}
 15520  		}
 15521  
 15522  	case js_ast.BinOpLogicalAnd:
 15523  		if boolean, sideEffects, ok := js_ast.ToBooleanWithSideEffects(e.Left.Data); ok {
 15524  			// Warn about potential bugs
 15525  			if e == p.suspiciousLogicalOperatorInsideArrow {
 15526  				if arrowLoc := p.source.RangeOfOperatorBefore(v.loc, "=>"); arrowLoc.Loc.Start+2 == p.source.LocBeforeWhitespace(v.loc).Start {
 15527  					// "return foo => 0 && foo <= 1"
 15528  					var which string
 15529  					if !boolean {
 15530  						which = "left"
 15531  					} else {
 15532  						which = "right"
 15533  					}
 15534  					kind := logger.Warning
 15535  					if p.suppressWarningsAboutWeirdCode {
 15536  						kind = logger.Debug
 15537  					}
 15538  					note := p.tracker.MsgData(arrowLoc,
 15539  						"The \"=>\" symbol creates an arrow function expression in JavaScript. Did you mean to use the greater-than-or-equal-to operator \">=\" here instead?")
 15540  					note.Location.Suggestion = ">="
 15541  					rOp := p.source.RangeOfOperatorBefore(e.Right.Loc, "&&")
 15542  					p.log.AddIDWithNotes(logger.MsgID_JS_SuspiciousLogicalOperator, kind, &p.tracker, rOp,
 15543  						fmt.Sprintf("The \"&&\" operator here will always return the %s operand", which), []logger.MsgData{note})
 15544  				}
 15545  			}
 15546  
 15547  			if !boolean {
 15548  				return e.Left
 15549  			} else if sideEffects == js_ast.NoSideEffects {
 15550  				return e.Right
 15551  			}
 15552  		}
 15553  
 15554  		if p.options.minifySyntax {
 15555  			// "a && (b && c)" => "a && b && c"
 15556  			if right, ok := e.Right.Data.(*js_ast.EBinary); ok && right.Op == js_ast.BinOpLogicalAnd {
 15557  				e.Left = js_ast.JoinWithLeftAssociativeOp(js_ast.BinOpLogicalAnd, e.Left, right.Left)
 15558  				e.Right = right.Right
 15559  			}
 15560  
 15561  			// "a !== null && a !== undefined" => "a != null"
 15562  			if left, right, ok := js_ast.IsBinaryNullAndUndefined(e.Left, e.Right, js_ast.BinOpStrictNe); ok {
 15563  				e.Op = js_ast.BinOpLooseNe
 15564  				e.Left = left
 15565  				e.Right = right
 15566  			}
 15567  		}
 15568  
 15569  	case js_ast.BinOpAdd:
 15570  		// "'abc' + 'xyz'" => "'abcxyz'"
 15571  		if result := js_ast.FoldStringAddition(e.Left, e.Right, js_ast.StringAdditionNormal); result.Data != nil {
 15572  			return result
 15573  		}
 15574  
 15575  		if left, ok := e.Left.Data.(*js_ast.EBinary); ok && left.Op == js_ast.BinOpAdd {
 15576  			// "x + 'abc' + 'xyz'" => "x + 'abcxyz'"
 15577  			if result := js_ast.FoldStringAddition(left.Right, e.Right, js_ast.StringAdditionWithNestedLeft); result.Data != nil {
 15578  				return js_ast.Expr{Loc: v.loc, Data: &js_ast.EBinary{Op: left.Op, Left: left.Left, Right: result}}
 15579  			}
 15580  		}
 15581  
 15582  	case js_ast.BinOpPow:
 15583  		// Lower the exponentiation operator for browsers that don't support it
 15584  		if p.options.unsupportedJSFeatures.Has(compat.ExponentOperator) {
 15585  			return p.callRuntime(v.loc, "__pow", []js_ast.Expr{e.Left, e.Right})
 15586  		}
 15587  
 15588  		////////////////////////////////////////////////////////////////////////////////
 15589  		// All assignment operators below here
 15590  
 15591  	case js_ast.BinOpAssign:
 15592  		if target, loc, private := p.extractPrivateIndex(e.Left); private != nil {
 15593  			return p.lowerPrivateSet(target, loc, private, e.Right)
 15594  		}
 15595  
 15596  		if property := p.extractSuperProperty(e.Left); property.Data != nil {
 15597  			return p.lowerSuperPropertySet(e.Left.Loc, property, e.Right)
 15598  		}
 15599  
 15600  		// Lower assignment destructuring patterns for browsers that don't
 15601  		// support them. Note that assignment expressions are used to represent
 15602  		// initializers in binding patterns, so only do this if we're not
 15603  		// ourselves the target of an assignment. Example: "[a = b] = c"
 15604  		if v.in.assignTarget == js_ast.AssignTargetNone {
 15605  			mode := objRestMustReturnInitExpr
 15606  			if v.isStmtExpr {
 15607  				mode = objRestReturnValueIsUnused
 15608  			}
 15609  			if result, ok := p.lowerAssign(e.Left, e.Right, mode); ok {
 15610  				return result
 15611  			}
 15612  
 15613  			// If CommonJS-style exports are disabled, then references to them are
 15614  			// treated as global variable references. This is consistent with how
 15615  			// they work in node and the browser, so it's the correct interpretation.
 15616  			//
 15617  			// However, people sometimes try to use both types of exports within the
 15618  			// same module and expect it to work. We warn about this when module
 15619  			// format conversion is enabled.
 15620  			//
 15621  			// Only warn about this for uses in assignment position since there are
 15622  			// some legitimate other uses. For example, some people do "typeof module"
 15623  			// to check for a CommonJS environment, and we shouldn't warn on that.
 15624  			if p.options.mode != config.ModePassThrough && p.isFileConsideredToHaveESMExports && !p.isControlFlowDead {
 15625  				if dot, ok := e.Left.Data.(*js_ast.EDot); ok {
 15626  					var name string
 15627  					var loc logger.Loc
 15628  
 15629  					switch target := dot.Target.Data.(type) {
 15630  					case *js_ast.EIdentifier:
 15631  						if symbol := &p.symbols[target.Ref.InnerIndex]; symbol.Kind == ast.SymbolUnbound &&
 15632  							((symbol.OriginalName == "module" && dot.Name == "exports") || symbol.OriginalName == "exports") &&
 15633  							!symbol.Flags.Has(ast.DidWarnAboutCommonJSInESM) {
 15634  							// "module.exports = ..."
 15635  							// "exports.something = ..."
 15636  							name = symbol.OriginalName
 15637  							loc = dot.Target.Loc
 15638  							symbol.Flags |= ast.DidWarnAboutCommonJSInESM
 15639  						}
 15640  
 15641  					case *js_ast.EDot:
 15642  						if target.Name == "exports" {
 15643  							if id, ok := target.Target.Data.(*js_ast.EIdentifier); ok {
 15644  								if symbol := &p.symbols[id.Ref.InnerIndex]; symbol.Kind == ast.SymbolUnbound &&
 15645  									symbol.OriginalName == "module" && !symbol.Flags.Has(ast.DidWarnAboutCommonJSInESM) {
 15646  									// "module.exports.foo = ..."
 15647  									name = symbol.OriginalName
 15648  									loc = target.Target.Loc
 15649  									symbol.Flags |= ast.DidWarnAboutCommonJSInESM
 15650  								}
 15651  							}
 15652  						}
 15653  					}
 15654  
 15655  					if name != "" {
 15656  						kind := logger.Warning
 15657  						if p.suppressWarningsAboutWeirdCode {
 15658  							kind = logger.Debug
 15659  						}
 15660  						why, notes := p.whyESModule()
 15661  						if why == whyESMTypeModulePackageJSON {
 15662  							text := "Node's package format requires that CommonJS files in a \"type\": \"module\" package use the \".cjs\" file extension."
 15663  							if p.options.ts.Parse {
 15664  								text += " If you are using TypeScript, you can use the \".cts\" file extension with esbuild instead."
 15665  							}
 15666  							notes = append(notes, logger.MsgData{Text: text})
 15667  						}
 15668  						p.log.AddIDWithNotes(logger.MsgID_JS_CommonJSVariableInESM, kind, &p.tracker, js_lexer.RangeOfIdentifier(p.source, loc),
 15669  							fmt.Sprintf("The CommonJS %q variable is treated as a global variable in an ECMAScript module and may not work as expected", name),
 15670  							notes)
 15671  					}
 15672  				}
 15673  			}
 15674  		}
 15675  
 15676  	case js_ast.BinOpAddAssign:
 15677  		if result := p.maybeLowerSetBinOp(e.Left, js_ast.BinOpAdd, e.Right); result.Data != nil {
 15678  			return result
 15679  		}
 15680  
 15681  	case js_ast.BinOpSubAssign:
 15682  		if result := p.maybeLowerSetBinOp(e.Left, js_ast.BinOpSub, e.Right); result.Data != nil {
 15683  			return result
 15684  		}
 15685  
 15686  	case js_ast.BinOpMulAssign:
 15687  		if result := p.maybeLowerSetBinOp(e.Left, js_ast.BinOpMul, e.Right); result.Data != nil {
 15688  			return result
 15689  		}
 15690  
 15691  	case js_ast.BinOpDivAssign:
 15692  		if result := p.maybeLowerSetBinOp(e.Left, js_ast.BinOpDiv, e.Right); result.Data != nil {
 15693  			return result
 15694  		}
 15695  
 15696  	case js_ast.BinOpRemAssign:
 15697  		if result := p.maybeLowerSetBinOp(e.Left, js_ast.BinOpRem, e.Right); result.Data != nil {
 15698  			return result
 15699  		}
 15700  
 15701  	case js_ast.BinOpPowAssign:
 15702  		// Lower the exponentiation operator for browsers that don't support it
 15703  		if p.options.unsupportedJSFeatures.Has(compat.ExponentOperator) {
 15704  			return p.lowerExponentiationAssignmentOperator(v.loc, e)
 15705  		}
 15706  
 15707  		if result := p.maybeLowerSetBinOp(e.Left, js_ast.BinOpPow, e.Right); result.Data != nil {
 15708  			return result
 15709  		}
 15710  
 15711  	case js_ast.BinOpShlAssign:
 15712  		if result := p.maybeLowerSetBinOp(e.Left, js_ast.BinOpShl, e.Right); result.Data != nil {
 15713  			return result
 15714  		}
 15715  
 15716  	case js_ast.BinOpShrAssign:
 15717  		if result := p.maybeLowerSetBinOp(e.Left, js_ast.BinOpShr, e.Right); result.Data != nil {
 15718  			return result
 15719  		}
 15720  
 15721  	case js_ast.BinOpUShrAssign:
 15722  		if result := p.maybeLowerSetBinOp(e.Left, js_ast.BinOpUShr, e.Right); result.Data != nil {
 15723  			return result
 15724  		}
 15725  
 15726  	case js_ast.BinOpBitwiseOrAssign:
 15727  		if result := p.maybeLowerSetBinOp(e.Left, js_ast.BinOpBitwiseOr, e.Right); result.Data != nil {
 15728  			return result
 15729  		}
 15730  
 15731  	case js_ast.BinOpBitwiseAndAssign:
 15732  		if result := p.maybeLowerSetBinOp(e.Left, js_ast.BinOpBitwiseAnd, e.Right); result.Data != nil {
 15733  			return result
 15734  		}
 15735  
 15736  	case js_ast.BinOpBitwiseXorAssign:
 15737  		if result := p.maybeLowerSetBinOp(e.Left, js_ast.BinOpBitwiseXor, e.Right); result.Data != nil {
 15738  			return result
 15739  		}
 15740  
 15741  	case js_ast.BinOpNullishCoalescingAssign:
 15742  		if value, ok := p.lowerNullishCoalescingAssignmentOperator(v.loc, e); ok {
 15743  			return value
 15744  		}
 15745  
 15746  	case js_ast.BinOpLogicalAndAssign:
 15747  		if value, ok := p.lowerLogicalAssignmentOperator(v.loc, e, js_ast.BinOpLogicalAnd); ok {
 15748  			return value
 15749  		}
 15750  
 15751  	case js_ast.BinOpLogicalOrAssign:
 15752  		if value, ok := p.lowerLogicalAssignmentOperator(v.loc, e, js_ast.BinOpLogicalOr); ok {
 15753  			return value
 15754  		}
 15755  	}
 15756  
 15757  	// "(a, b) + c" => "a, b + c"
 15758  	if p.options.minifySyntax && e.Op != js_ast.BinOpComma {
 15759  		if comma, ok := e.Left.Data.(*js_ast.EBinary); ok && comma.Op == js_ast.BinOpComma {
 15760  			return js_ast.JoinWithComma(comma.Left, js_ast.Expr{
 15761  				Loc: comma.Right.Loc,
 15762  				Data: &js_ast.EBinary{
 15763  					Op:    e.Op,
 15764  					Left:  comma.Right,
 15765  					Right: e.Right,
 15766  				},
 15767  			})
 15768  		}
 15769  	}
 15770  
 15771  	return js_ast.Expr{Loc: v.loc, Data: e}
 15772  }
 15773  
 15774  func remapExprLocsInJSON(expr *js_ast.Expr, table []logger.StringInJSTableEntry) {
 15775  	expr.Loc = logger.RemapStringInJSLoc(table, expr.Loc)
 15776  
 15777  	switch e := expr.Data.(type) {
 15778  	case *js_ast.EArray:
 15779  		e.CloseBracketLoc = logger.RemapStringInJSLoc(table, e.CloseBracketLoc)
 15780  		for i := range e.Items {
 15781  			remapExprLocsInJSON(&e.Items[i], table)
 15782  		}
 15783  
 15784  	case *js_ast.EObject:
 15785  		e.CloseBraceLoc = logger.RemapStringInJSLoc(table, e.CloseBraceLoc)
 15786  		for i := range e.Properties {
 15787  			remapExprLocsInJSON(&e.Properties[i].Key, table)
 15788  			remapExprLocsInJSON(&e.Properties[i].ValueOrNil, table)
 15789  		}
 15790  	}
 15791  }
 15792  
 15793  func (p *parser) handleGlobPattern(expr js_ast.Expr, kind ast.ImportKind, prefix string, assertOrWith *ast.ImportAssertOrWith) js_ast.Expr {
 15794  	pattern, approximateRange := p.globPatternFromExpr(expr)
 15795  	if pattern == nil {
 15796  		return js_ast.Expr{}
 15797  	}
 15798  
 15799  	var last helpers.GlobPart
 15800  	var parts []helpers.GlobPart
 15801  
 15802  	for _, part := range pattern {
 15803  		if part.isWildcard {
 15804  			if last.Wildcard == helpers.GlobNone {
 15805  				if !strings.HasSuffix(last.Prefix, "/") {
 15806  					// "`a${b}c`" => "a*c"
 15807  					last.Wildcard = helpers.GlobAllExceptSlash
 15808  				} else {
 15809  					// "`a/${b}c`" => "a/**/*c"
 15810  					last.Wildcard = helpers.GlobAllIncludingSlash
 15811  					parts = append(parts, last)
 15812  					last = helpers.GlobPart{Prefix: "/", Wildcard: helpers.GlobAllExceptSlash}
 15813  				}
 15814  			}
 15815  		} else if part.text != "" {
 15816  			if last.Wildcard != helpers.GlobNone {
 15817  				parts = append(parts, last)
 15818  				last = helpers.GlobPart{}
 15819  			}
 15820  			last.Prefix += part.text
 15821  		}
 15822  	}
 15823  
 15824  	parts = append(parts, last)
 15825  
 15826  	// Don't handle this if it's a string constant
 15827  	if len(parts) == 1 && parts[0].Wildcard == helpers.GlobNone {
 15828  		return js_ast.Expr{}
 15829  	}
 15830  
 15831  	// We currently only support relative globs
 15832  	if prefix := parts[0].Prefix; !strings.HasPrefix(prefix, "./") && !strings.HasPrefix(prefix, "../") {
 15833  		return js_ast.Expr{}
 15834  	}
 15835  
 15836  	ref := ast.InvalidRef
 15837  
 15838  	// Don't generate duplicate glob imports
 15839  outer:
 15840  	for _, globPattern := range p.globPatternImports {
 15841  		// Check the kind
 15842  		if globPattern.kind != kind {
 15843  			continue
 15844  		}
 15845  
 15846  		// Check the parts
 15847  		if len(globPattern.parts) != len(parts) {
 15848  			continue
 15849  		}
 15850  		for i := range parts {
 15851  			if globPattern.parts[i] != parts[i] {
 15852  				continue outer
 15853  			}
 15854  		}
 15855  
 15856  		// Check the import assertions/attributes
 15857  		if assertOrWith == nil {
 15858  			if globPattern.assertOrWith != nil {
 15859  				continue
 15860  			}
 15861  		} else {
 15862  			if globPattern.assertOrWith == nil {
 15863  				continue
 15864  			}
 15865  			if assertOrWith.Keyword != globPattern.assertOrWith.Keyword {
 15866  				continue
 15867  			}
 15868  			a := assertOrWith.Entries
 15869  			b := globPattern.assertOrWith.Entries
 15870  			if len(a) != len(b) {
 15871  				continue
 15872  			}
 15873  			for i := range a {
 15874  				ai := a[i]
 15875  				bi := b[i]
 15876  				if !helpers.UTF16EqualsUTF16(ai.Key, bi.Key) || !helpers.UTF16EqualsUTF16(ai.Value, bi.Value) {
 15877  					continue outer
 15878  				}
 15879  			}
 15880  		}
 15881  
 15882  		// If we get here, then these are the same glob pattern
 15883  		ref = globPattern.ref
 15884  		break
 15885  	}
 15886  
 15887  	// If there's no duplicate glob import, then generate a new glob import
 15888  	if ref == ast.InvalidRef && prefix != "" {
 15889  		sb := strings.Builder{}
 15890  		sb.WriteString(prefix)
 15891  
 15892  		for _, part := range parts {
 15893  			gap := true
 15894  			for _, c := range part.Prefix {
 15895  				if !js_ast.IsIdentifierContinue(c) {
 15896  					gap = true
 15897  				} else {
 15898  					if gap {
 15899  						sb.WriteByte('_')
 15900  						gap = false
 15901  					}
 15902  					sb.WriteRune(c)
 15903  				}
 15904  			}
 15905  		}
 15906  
 15907  		name := sb.String()
 15908  		ref = p.newSymbol(ast.SymbolOther, name)
 15909  		p.moduleScope.Generated = append(p.moduleScope.Generated, ref)
 15910  
 15911  		p.globPatternImports = append(p.globPatternImports, globPatternImport{
 15912  			assertOrWith:     assertOrWith,
 15913  			parts:            parts,
 15914  			name:             name,
 15915  			approximateRange: approximateRange,
 15916  			ref:              ref,
 15917  			kind:             kind,
 15918  		})
 15919  	}
 15920  
 15921  	p.recordUsage(ref)
 15922  	return js_ast.Expr{Loc: expr.Loc, Data: &js_ast.ECall{
 15923  		Target: js_ast.Expr{Loc: expr.Loc, Data: &js_ast.EIdentifier{Ref: ref}},
 15924  		Args:   []js_ast.Expr{expr},
 15925  	}}
 15926  }
 15927  
 15928  type globPart struct {
 15929  	text       string
 15930  	isWildcard bool
 15931  }
 15932  
 15933  func (p *parser) globPatternFromExpr(expr js_ast.Expr) ([]globPart, logger.Range) {
 15934  	switch e := expr.Data.(type) {
 15935  	case *js_ast.EString:
 15936  		return []globPart{{text: helpers.UTF16ToString(e.Value)}}, p.source.RangeOfString(expr.Loc)
 15937  
 15938  	case *js_ast.ETemplate:
 15939  		if e.TagOrNil.Data != nil {
 15940  			break
 15941  		}
 15942  
 15943  		pattern := make([]globPart, 0, 1+2*len(e.Parts))
 15944  		pattern = append(pattern, globPart{text: helpers.UTF16ToString(e.HeadCooked)})
 15945  
 15946  		for _, part := range e.Parts {
 15947  			if partPattern, _ := p.globPatternFromExpr(part.Value); partPattern != nil {
 15948  				pattern = append(pattern, partPattern...)
 15949  			} else {
 15950  				pattern = append(pattern, globPart{isWildcard: true})
 15951  			}
 15952  			pattern = append(pattern, globPart{text: helpers.UTF16ToString(part.TailCooked)})
 15953  		}
 15954  
 15955  		if len(e.Parts) == 0 {
 15956  			return pattern, p.source.RangeOfString(expr.Loc)
 15957  		}
 15958  
 15959  		text := p.source.Contents
 15960  		templateRange := logger.Range{Loc: e.HeadLoc}
 15961  
 15962  		for i := e.Parts[len(e.Parts)-1].TailLoc.Start; i < int32(len(text)); i++ {
 15963  			c := text[i]
 15964  			if c == '`' {
 15965  				templateRange.Len = i + 1 - templateRange.Loc.Start
 15966  				break
 15967  			} else if c == '\\' {
 15968  				i += 1
 15969  			}
 15970  		}
 15971  
 15972  		return pattern, templateRange
 15973  
 15974  	case *js_ast.EBinary:
 15975  		if e.Op != js_ast.BinOpAdd {
 15976  			break
 15977  		}
 15978  
 15979  		pattern, leftRange := p.globPatternFromExpr(e.Left)
 15980  		if pattern == nil {
 15981  			break
 15982  		}
 15983  
 15984  		if rightPattern, rightRange := p.globPatternFromExpr(e.Right); rightPattern != nil {
 15985  			pattern = append(pattern, rightPattern...)
 15986  			leftRange.Len = rightRange.End() - leftRange.Loc.Start
 15987  			return pattern, leftRange
 15988  		}
 15989  
 15990  		pattern = append(pattern, globPart{isWildcard: true})
 15991  
 15992  		// Try to extend the left range by the right operand in some common cases
 15993  		switch right := e.Right.Data.(type) {
 15994  		case *js_ast.EIdentifier:
 15995  			leftRange.Len = js_lexer.RangeOfIdentifier(p.source, e.Right.Loc).End() - leftRange.Loc.Start
 15996  
 15997  		case *js_ast.ECall:
 15998  			if right.CloseParenLoc.Start > 0 {
 15999  				leftRange.Len = right.CloseParenLoc.Start + 1 - leftRange.Loc.Start
 16000  			}
 16001  		}
 16002  
 16003  		return pattern, leftRange
 16004  	}
 16005  
 16006  	return nil, logger.Range{}
 16007  }
 16008  
 16009  func (p *parser) convertSymbolUseToCall(ref ast.Ref, isSingleNonSpreadArgCall bool) {
 16010  	// Remove the normal symbol use
 16011  	use := p.symbolUses[ref]
 16012  	use.CountEstimate--
 16013  	if use.CountEstimate == 0 {
 16014  		delete(p.symbolUses, ref)
 16015  	} else {
 16016  		p.symbolUses[ref] = use
 16017  	}
 16018  
 16019  	// Add a special symbol use instead
 16020  	if p.symbolCallUses == nil {
 16021  		p.symbolCallUses = make(map[ast.Ref]js_ast.SymbolCallUse)
 16022  	}
 16023  	callUse := p.symbolCallUses[ref]
 16024  	callUse.CallCountEstimate++
 16025  	if isSingleNonSpreadArgCall {
 16026  		callUse.SingleArgNonSpreadCallCountEstimate++
 16027  	}
 16028  	p.symbolCallUses[ref] = callUse
 16029  }
 16030  
 16031  func (p *parser) warnAboutImportNamespaceCall(target js_ast.Expr, kind importNamespaceCallKind) {
 16032  	if p.options.outputFormat != config.FormatPreserve {
 16033  		if id, ok := target.Data.(*js_ast.EIdentifier); ok && p.importItemsForNamespace[id.Ref].entries != nil {
 16034  			key := importNamespaceCall{
 16035  				ref:  id.Ref,
 16036  				kind: kind,
 16037  			}
 16038  			if p.importNamespaceCCMap == nil {
 16039  				p.importNamespaceCCMap = make(map[importNamespaceCall]bool)
 16040  			}
 16041  
 16042  			// Don't log a warning for the same identifier more than once
 16043  			if _, ok := p.importNamespaceCCMap[key]; ok {
 16044  				return
 16045  			}
 16046  
 16047  			p.importNamespaceCCMap[key] = true
 16048  			r := js_lexer.RangeOfIdentifier(p.source, target.Loc)
 16049  
 16050  			var notes []logger.MsgData
 16051  			name := p.symbols[id.Ref.InnerIndex].OriginalName
 16052  			if member, ok := p.moduleScope.Members[name]; ok && member.Ref == id.Ref {
 16053  				if star := p.source.RangeOfOperatorBefore(member.Loc, "*"); star.Len > 0 {
 16054  					if as := p.source.RangeOfOperatorBefore(member.Loc, "as"); as.Len > 0 && as.Loc.Start > star.Loc.Start {
 16055  						note := p.tracker.MsgData(
 16056  							logger.Range{Loc: star.Loc, Len: js_lexer.RangeOfIdentifier(p.source, member.Loc).End() - star.Loc.Start},
 16057  							fmt.Sprintf("Consider changing %q to a default import instead:", name))
 16058  						note.Location.Suggestion = name
 16059  						notes = append(notes, note)
 16060  					}
 16061  				}
 16062  			}
 16063  
 16064  			if p.options.ts.Parse {
 16065  				notes = append(notes, logger.MsgData{
 16066  					Text: "Make sure to enable TypeScript's \"esModuleInterop\" setting so that TypeScript's type checker generates an error when you try to do this. " +
 16067  						"You can read more about this setting here: https://www.typescriptlang.org/tsconfig#esModuleInterop",
 16068  				})
 16069  			}
 16070  
 16071  			var verb string
 16072  			var where string
 16073  			var noun string
 16074  
 16075  			switch kind {
 16076  			case exprKindCall:
 16077  				verb = "Calling"
 16078  				noun = "function"
 16079  
 16080  			case exprKindNew:
 16081  				verb = "Constructing"
 16082  				noun = "constructor"
 16083  
 16084  			case exprKindJSXTag:
 16085  				verb = "Using"
 16086  				where = " in a JSX expression"
 16087  				noun = "component"
 16088  			}
 16089  
 16090  			p.log.AddIDWithNotes(logger.MsgID_JS_CallImportNamespace, logger.Warning, &p.tracker, r, fmt.Sprintf(
 16091  				"%s %q%s will crash at run-time because it's an import namespace object, not a %s",
 16092  				verb,
 16093  				p.symbols[id.Ref.InnerIndex].OriginalName,
 16094  				where,
 16095  				noun,
 16096  			), notes)
 16097  		}
 16098  	}
 16099  }
 16100  
 16101  func (p *parser) maybeMarkKnownGlobalConstructorAsPure(e *js_ast.ENew) {
 16102  	if id, ok := e.Target.Data.(*js_ast.EIdentifier); ok {
 16103  		if symbol := p.symbols[id.Ref.InnerIndex]; symbol.Kind == ast.SymbolUnbound {
 16104  			switch symbol.OriginalName {
 16105  			case "WeakSet", "WeakMap":
 16106  				n := len(e.Args)
 16107  
 16108  				if n == 0 {
 16109  					// "new WeakSet()" is pure
 16110  					e.CanBeUnwrappedIfUnused = true
 16111  					break
 16112  				}
 16113  
 16114  				if n == 1 {
 16115  					switch arg := e.Args[0].Data.(type) {
 16116  					case *js_ast.ENull, *js_ast.EUndefined:
 16117  						// "new WeakSet(null)" is pure
 16118  						// "new WeakSet(void 0)" is pure
 16119  						e.CanBeUnwrappedIfUnused = true
 16120  
 16121  					case *js_ast.EArray:
 16122  						if len(arg.Items) == 0 {
 16123  							// "new WeakSet([])" is pure
 16124  							e.CanBeUnwrappedIfUnused = true
 16125  						} else {
 16126  							// "new WeakSet([x])" is impure because an exception is thrown if "x" is not an object
 16127  						}
 16128  
 16129  					default:
 16130  						// "new WeakSet(x)" is impure because the iterator for "x" could have side effects
 16131  					}
 16132  				}
 16133  
 16134  			case "Date":
 16135  				n := len(e.Args)
 16136  
 16137  				if n == 0 {
 16138  					// "new Date()" is pure
 16139  					e.CanBeUnwrappedIfUnused = true
 16140  					break
 16141  				}
 16142  
 16143  				if n == 1 {
 16144  					switch js_ast.KnownPrimitiveType(e.Args[0].Data) {
 16145  					case js_ast.PrimitiveNull, js_ast.PrimitiveUndefined, js_ast.PrimitiveBoolean, js_ast.PrimitiveNumber, js_ast.PrimitiveString:
 16146  						// "new Date('')" is pure
 16147  						// "new Date(0)" is pure
 16148  						// "new Date(null)" is pure
 16149  						// "new Date(true)" is pure
 16150  						// "new Date(false)" is pure
 16151  						// "new Date(undefined)" is pure
 16152  						e.CanBeUnwrappedIfUnused = true
 16153  
 16154  					default:
 16155  						// "new Date(x)" is impure because converting "x" to a string could have side effects
 16156  					}
 16157  				}
 16158  
 16159  			case "Set":
 16160  				n := len(e.Args)
 16161  
 16162  				if n == 0 {
 16163  					// "new Set()" is pure
 16164  					e.CanBeUnwrappedIfUnused = true
 16165  					break
 16166  				}
 16167  
 16168  				if n == 1 {
 16169  					switch e.Args[0].Data.(type) {
 16170  					case *js_ast.EArray, *js_ast.ENull, *js_ast.EUndefined:
 16171  						// "new Set([a, b, c])" is pure
 16172  						// "new Set(null)" is pure
 16173  						// "new Set(void 0)" is pure
 16174  						e.CanBeUnwrappedIfUnused = true
 16175  
 16176  					default:
 16177  						// "new Set(x)" is impure because the iterator for "x" could have side effects
 16178  					}
 16179  				}
 16180  
 16181  			case "Map":
 16182  				n := len(e.Args)
 16183  
 16184  				if n == 0 {
 16185  					// "new Map()" is pure
 16186  					e.CanBeUnwrappedIfUnused = true
 16187  					break
 16188  				}
 16189  
 16190  				if n == 1 {
 16191  					switch arg := e.Args[0].Data.(type) {
 16192  					case *js_ast.ENull, *js_ast.EUndefined:
 16193  						// "new Map(null)" is pure
 16194  						// "new Map(void 0)" is pure
 16195  						e.CanBeUnwrappedIfUnused = true
 16196  
 16197  					case *js_ast.EArray:
 16198  						allEntriesAreArrays := true
 16199  						for _, item := range arg.Items {
 16200  							if _, ok := item.Data.(*js_ast.EArray); !ok {
 16201  								// "new Map([x])" is impure because "x[0]" could have side effects
 16202  								allEntriesAreArrays = false
 16203  								break
 16204  							}
 16205  						}
 16206  
 16207  						// "new Map([[a, b], [c, d]])" is pure
 16208  						if allEntriesAreArrays {
 16209  							e.CanBeUnwrappedIfUnused = true
 16210  						}
 16211  
 16212  					default:
 16213  						// "new Map(x)" is impure because the iterator for "x" could have side effects
 16214  					}
 16215  				}
 16216  			}
 16217  		}
 16218  	}
 16219  }
 16220  
 16221  type identifierOpts struct {
 16222  	assignTarget            js_ast.AssignTarget
 16223  	isCallTarget            bool
 16224  	isDeleteTarget          bool
 16225  	preferQuotedKey         bool
 16226  	wasOriginallyIdentifier bool
 16227  	matchAgainstDefines     bool
 16228  }
 16229  
 16230  func (p *parser) handleIdentifier(loc logger.Loc, e *js_ast.EIdentifier, opts identifierOpts) js_ast.Expr {
 16231  	ref := e.Ref
 16232  
 16233  	// Substitute inlined constants
 16234  	if p.options.minifySyntax {
 16235  		if value, ok := p.constValues[ref]; ok {
 16236  			p.ignoreUsage(ref)
 16237  			return js_ast.ConstValueToExpr(loc, value)
 16238  		}
 16239  	}
 16240  
 16241  	// Capture the "arguments" variable if necessary
 16242  	if p.fnOnlyDataVisit.argumentsRef != nil && ref == *p.fnOnlyDataVisit.argumentsRef {
 16243  		isInsideUnsupportedArrow := p.fnOrArrowDataVisit.isArrow && p.options.unsupportedJSFeatures.Has(compat.Arrow)
 16244  		isInsideUnsupportedAsyncArrow := p.fnOnlyDataVisit.isInsideAsyncArrowFn && p.options.unsupportedJSFeatures.Has(compat.AsyncAwait)
 16245  		if isInsideUnsupportedArrow || isInsideUnsupportedAsyncArrow {
 16246  			return js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: p.captureArguments()}}
 16247  		}
 16248  	}
 16249  
 16250  	// Create an error for assigning to an import namespace
 16251  	if (opts.assignTarget != js_ast.AssignTargetNone ||
 16252  		(opts.isDeleteTarget && p.symbols[ref.InnerIndex].ImportItemStatus == ast.ImportItemGenerated)) &&
 16253  		p.symbols[ref.InnerIndex].Kind == ast.SymbolImport {
 16254  		r := js_lexer.RangeOfIdentifier(p.source, loc)
 16255  
 16256  		// Try to come up with a setter name to try to make this message more understandable
 16257  		var setterHint string
 16258  		originalName := p.symbols[ref.InnerIndex].OriginalName
 16259  		if js_ast.IsIdentifier(originalName) && originalName != "_" {
 16260  			if len(originalName) == 1 || (len(originalName) > 1 && originalName[0] < utf8.RuneSelf) {
 16261  				setterHint = fmt.Sprintf(" (e.g. \"set%s%s\")", strings.ToUpper(originalName[:1]), originalName[1:])
 16262  			} else {
 16263  				setterHint = fmt.Sprintf(" (e.g. \"set_%s\")", originalName)
 16264  			}
 16265  		}
 16266  
 16267  		notes := []logger.MsgData{{Text: "Imports are immutable in JavaScript. " +
 16268  			fmt.Sprintf("To modify the value of this import, you must export a setter function in the "+
 16269  				"imported file%s and then import and call that function here instead.", setterHint)}}
 16270  
 16271  		if p.options.mode == config.ModeBundle {
 16272  			p.log.AddErrorWithNotes(&p.tracker, r, fmt.Sprintf("Cannot assign to import %q", originalName), notes)
 16273  		} else {
 16274  			kind := logger.Warning
 16275  			if p.suppressWarningsAboutWeirdCode {
 16276  				kind = logger.Debug
 16277  			}
 16278  			p.log.AddIDWithNotes(logger.MsgID_JS_AssignToImport, kind, &p.tracker, r,
 16279  				fmt.Sprintf("This assignment will throw because %q is an import", originalName), notes)
 16280  		}
 16281  	}
 16282  
 16283  	// Substitute an EImportIdentifier now if this has a namespace alias
 16284  	if opts.assignTarget == js_ast.AssignTargetNone && !opts.isDeleteTarget {
 16285  		symbol := &p.symbols[ref.InnerIndex]
 16286  		if nsAlias := symbol.NamespaceAlias; nsAlias != nil {
 16287  			data := p.dotOrMangledPropVisit(
 16288  				js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: nsAlias.NamespaceRef}},
 16289  				symbol.OriginalName, loc)
 16290  
 16291  			// Handle references to namespaces or namespace members
 16292  			if tsMemberData, ok := p.refToTSNamespaceMemberData[nsAlias.NamespaceRef]; ok {
 16293  				if ns, ok := tsMemberData.(*js_ast.TSNamespaceMemberNamespace); ok {
 16294  					if member, ok := ns.ExportedMembers[nsAlias.Alias]; ok {
 16295  						switch m := member.Data.(type) {
 16296  						case *js_ast.TSNamespaceMemberEnumNumber:
 16297  							return p.wrapInlinedEnum(js_ast.Expr{Loc: loc, Data: &js_ast.ENumber{Value: m.Value}}, nsAlias.Alias)
 16298  
 16299  						case *js_ast.TSNamespaceMemberEnumString:
 16300  							return p.wrapInlinedEnum(js_ast.Expr{Loc: loc, Data: &js_ast.EString{Value: m.Value}}, nsAlias.Alias)
 16301  
 16302  						case *js_ast.TSNamespaceMemberNamespace:
 16303  							p.tsNamespaceTarget = data
 16304  							p.tsNamespaceMemberData = member.Data
 16305  						}
 16306  					}
 16307  				}
 16308  			}
 16309  
 16310  			return js_ast.Expr{Loc: loc, Data: data}
 16311  		}
 16312  	}
 16313  
 16314  	// Substitute an EImportIdentifier now if this is an import item
 16315  	if p.isImportItem[ref] {
 16316  		return js_ast.Expr{Loc: loc, Data: &js_ast.EImportIdentifier{
 16317  			Ref:                     ref,
 16318  			PreferQuotedKey:         opts.preferQuotedKey,
 16319  			WasOriginallyIdentifier: opts.wasOriginallyIdentifier,
 16320  		}}
 16321  	}
 16322  
 16323  	// Handle references to namespaces or namespace members
 16324  	if tsMemberData, ok := p.refToTSNamespaceMemberData[ref]; ok {
 16325  		switch m := tsMemberData.(type) {
 16326  		case *js_ast.TSNamespaceMemberEnumNumber:
 16327  			return p.wrapInlinedEnum(js_ast.Expr{Loc: loc, Data: &js_ast.ENumber{Value: m.Value}}, p.symbols[ref.InnerIndex].OriginalName)
 16328  
 16329  		case *js_ast.TSNamespaceMemberEnumString:
 16330  			return p.wrapInlinedEnum(js_ast.Expr{Loc: loc, Data: &js_ast.EString{Value: m.Value}}, p.symbols[ref.InnerIndex].OriginalName)
 16331  
 16332  		case *js_ast.TSNamespaceMemberNamespace:
 16333  			p.tsNamespaceTarget = e
 16334  			p.tsNamespaceMemberData = tsMemberData
 16335  		}
 16336  	}
 16337  
 16338  	// Substitute a namespace export reference now if appropriate
 16339  	if p.options.ts.Parse {
 16340  		if nsRef, ok := p.isExportedInsideNamespace[ref]; ok {
 16341  			name := p.symbols[ref.InnerIndex].OriginalName
 16342  
 16343  			// Otherwise, create a property access on the namespace
 16344  			p.recordUsage(nsRef)
 16345  			propertyAccess := p.dotOrMangledPropVisit(js_ast.Expr{Loc: loc, Data: &js_ast.EIdentifier{Ref: nsRef}}, name, loc)
 16346  			if p.tsNamespaceTarget == e {
 16347  				p.tsNamespaceTarget = propertyAccess
 16348  			}
 16349  			return js_ast.Expr{Loc: loc, Data: propertyAccess}
 16350  		}
 16351  	}
 16352  
 16353  	// Swap references to the global "require" function with our "__require" stub
 16354  	if ref == p.requireRef && !opts.isCallTarget {
 16355  		if p.options.mode == config.ModeBundle && p.source.Index != runtime.SourceIndex && e != p.dotOrIndexTarget {
 16356  			p.log.AddID(logger.MsgID_JS_IndirectRequire, logger.Debug, &p.tracker, js_lexer.RangeOfIdentifier(p.source, loc),
 16357  				"Indirect calls to \"require\" will not be bundled")
 16358  		}
 16359  
 16360  		return p.valueToSubstituteForRequire(loc)
 16361  	}
 16362  
 16363  	// Mark any mutated symbols as mutable
 16364  	if opts.assignTarget != js_ast.AssignTargetNone {
 16365  		p.symbols[e.Ref.InnerIndex].Flags |= ast.CouldPotentiallyBeMutated
 16366  	}
 16367  
 16368  	return js_ast.Expr{Loc: loc, Data: e}
 16369  }
 16370  
 16371  type visitFnOpts struct {
 16372  	isMethod               bool
 16373  	isDerivedClassCtor     bool
 16374  	isLoweredPrivateMethod bool
 16375  }
 16376  
 16377  func (p *parser) visitFn(fn *js_ast.Fn, scopeLoc logger.Loc, opts visitFnOpts) {
 16378  	var decoratorScope *js_ast.Scope
 16379  	oldFnOrArrowData := p.fnOrArrowDataVisit
 16380  	oldFnOnlyData := p.fnOnlyDataVisit
 16381  	p.fnOrArrowDataVisit = fnOrArrowDataVisit{
 16382  		isAsync:                        fn.IsAsync,
 16383  		isGenerator:                    fn.IsGenerator,
 16384  		isDerivedClassCtor:             opts.isDerivedClassCtor,
 16385  		shouldLowerSuperPropertyAccess: (fn.IsAsync && p.options.unsupportedJSFeatures.Has(compat.AsyncAwait)) || opts.isLoweredPrivateMethod,
 16386  	}
 16387  	p.fnOnlyDataVisit = fnOnlyDataVisit{
 16388  		isThisNested:       true,
 16389  		isNewTargetAllowed: true,
 16390  		argumentsRef:       &fn.ArgumentsRef,
 16391  	}
 16392  
 16393  	if opts.isMethod {
 16394  		decoratorScope = p.propMethodDecoratorScope
 16395  		p.fnOnlyDataVisit.innerClassNameRef = oldFnOnlyData.innerClassNameRef
 16396  		p.fnOnlyDataVisit.isInStaticClassContext = oldFnOnlyData.isInStaticClassContext
 16397  	}
 16398  
 16399  	if fn.Name != nil {
 16400  		p.recordDeclaredSymbol(fn.Name.Ref)
 16401  	}
 16402  
 16403  	p.pushScopeForVisitPass(js_ast.ScopeFunctionArgs, scopeLoc)
 16404  	p.visitArgs(fn.Args, visitArgsOpts{
 16405  		hasRestArg:               fn.HasRestArg,
 16406  		body:                     fn.Body.Block.Stmts,
 16407  		isUniqueFormalParameters: fn.IsUniqueFormalParameters,
 16408  		decoratorScope:           decoratorScope,
 16409  	})
 16410  	p.pushScopeForVisitPass(js_ast.ScopeFunctionBody, fn.Body.Loc)
 16411  	if fn.Name != nil {
 16412  		p.validateDeclaredSymbolName(fn.Name.Loc, p.symbols[fn.Name.Ref.InnerIndex].OriginalName)
 16413  	}
 16414  	fn.Body.Block.Stmts = p.visitStmtsAndPrependTempRefs(fn.Body.Block.Stmts, prependTempRefsOpts{fnBodyLoc: &fn.Body.Loc, kind: stmtsFnBody})
 16415  	p.popScope()
 16416  	p.lowerFunction(&fn.IsAsync, &fn.IsGenerator, &fn.Args, fn.Body.Loc, &fn.Body.Block, nil, &fn.HasRestArg, false /* isArrow */)
 16417  	p.popScope()
 16418  
 16419  	p.fnOrArrowDataVisit = oldFnOrArrowData
 16420  	p.fnOnlyDataVisit = oldFnOnlyData
 16421  }
 16422  
 16423  func (p *parser) recordExport(loc logger.Loc, alias string, ref ast.Ref) {
 16424  	if name, ok := p.namedExports[alias]; ok {
 16425  		// Duplicate exports are an error
 16426  		p.log.AddErrorWithNotes(&p.tracker, js_lexer.RangeOfIdentifier(p.source, loc),
 16427  			fmt.Sprintf("Multiple exports with the same name %q", alias),
 16428  			[]logger.MsgData{p.tracker.MsgData(js_lexer.RangeOfIdentifier(p.source, name.AliasLoc),
 16429  				fmt.Sprintf("The name %q was originally exported here:", alias))})
 16430  	} else {
 16431  		p.namedExports[alias] = js_ast.NamedExport{AliasLoc: loc, Ref: ref}
 16432  	}
 16433  }
 16434  
 16435  type importsExportsScanResult struct {
 16436  	stmts               []js_ast.Stmt
 16437  	keptImportEquals    bool
 16438  	removedImportEquals bool
 16439  }
 16440  
 16441  // Returns true if this is an unused TypeScript import-equals statement
 16442  func (p *parser) checkForUnusedTSImportEquals(s *js_ast.SLocal, result *importsExportsScanResult) bool {
 16443  	if s.WasTSImportEquals && !s.IsExport {
 16444  		decl := s.Decls[0]
 16445  
 16446  		// Skip to the underlying reference
 16447  		value := s.Decls[0].ValueOrNil
 16448  		for {
 16449  			if dot, ok := value.Data.(*js_ast.EDot); ok {
 16450  				value = dot.Target
 16451  			} else {
 16452  				break
 16453  			}
 16454  		}
 16455  
 16456  		// Is this an identifier reference and not a require() call?
 16457  		valueRef := ast.InvalidRef
 16458  		switch v := value.Data.(type) {
 16459  		case *js_ast.EIdentifier:
 16460  			valueRef = v.Ref
 16461  		case *js_ast.EImportIdentifier:
 16462  			valueRef = v.Ref
 16463  		}
 16464  		if valueRef != ast.InvalidRef {
 16465  			// Is this import statement unused?
 16466  			if ref := decl.Binding.Data.(*js_ast.BIdentifier).Ref; p.symbols[ref.InnerIndex].UseCountEstimate == 0 {
 16467  				// Also don't count the referenced identifier
 16468  				p.ignoreUsage(valueRef)
 16469  
 16470  				// Import-equals statements can come in any order. Removing one
 16471  				// could potentially cause another one to be removable too.
 16472  				// Continue iterating until a fixed point has been reached to make
 16473  				// sure we get them all.
 16474  				result.removedImportEquals = true
 16475  				return true
 16476  			} else {
 16477  				result.keptImportEquals = true
 16478  			}
 16479  		}
 16480  	}
 16481  
 16482  	return false
 16483  }
 16484  
 16485  func (p *parser) scanForUnusedTSImportEquals(stmts []js_ast.Stmt) (result importsExportsScanResult) {
 16486  	stmtsEnd := 0
 16487  
 16488  	for _, stmt := range stmts {
 16489  		if s, ok := stmt.Data.(*js_ast.SLocal); ok && p.checkForUnusedTSImportEquals(s, &result) {
 16490  			// Remove unused import-equals statements, since those likely
 16491  			// correspond to types instead of values
 16492  			continue
 16493  		}
 16494  
 16495  		// Filter out statements we skipped over
 16496  		stmts[stmtsEnd] = stmt
 16497  		stmtsEnd++
 16498  	}
 16499  
 16500  	result.stmts = stmts[:stmtsEnd]
 16501  	return
 16502  }
 16503  
 16504  func (p *parser) scanForImportsAndExports(stmts []js_ast.Stmt) (result importsExportsScanResult) {
 16505  	unusedImportFlags := p.options.ts.Config.UnusedImportFlags()
 16506  	stmtsEnd := 0
 16507  
 16508  	for _, stmt := range stmts {
 16509  		switch s := stmt.Data.(type) {
 16510  		case *js_ast.SImport:
 16511  			record := &p.importRecords[s.ImportRecordIndex]
 16512  
 16513  			// We implement TypeScript's "preserveValueImports" tsconfig.json setting
 16514  			// to support the use case of compiling partial modules for compile-to-
 16515  			// JavaScript languages such as Svelte. These languages try to reference
 16516  			// imports in ways that are impossible for TypeScript and esbuild to know
 16517  			// about when they are only given a partial module to compile. Here is an
 16518  			// example of some Svelte code that contains a TypeScript snippet:
 16519  			//
 16520  			//   <script lang="ts">
 16521  			//     import Counter from './Counter.svelte';
 16522  			//     export let name: string = 'world';
 16523  			//   </script>
 16524  			//   <main>
 16525  			//     <h1>Hello {name}!</h1>
 16526  			//     <Counter />
 16527  			//   </main>
 16528  			//
 16529  			// Tools that use esbuild to compile TypeScript code inside a Svelte
 16530  			// file like this only give esbuild the contents of the <script> tag.
 16531  			// The "preserveValueImports" setting avoids removing unused import
 16532  			// names, which means additional code appended after the TypeScript-
 16533  			// to-JavaScript conversion can still access those unused imports.
 16534  			//
 16535  			// There are two scenarios where we don't do this:
 16536  			//
 16537  			//   * If we're bundling, then we know we aren't being used to compile
 16538  			//     a partial module. The parser is seeing the entire code for the
 16539  			//     module so it's safe to remove unused imports. And also we don't
 16540  			//     want the linker to generate errors about missing imports if the
 16541  			//     imported file is also in the bundle.
 16542  			//
 16543  			//   * If identifier minification is enabled, then using esbuild as a
 16544  			//     partial-module transform library wouldn't work anyway because
 16545  			//     the names wouldn't match. And that means we're minifying so the
 16546  			//     user is expecting the output to be as small as possible. So we
 16547  			//     should omit unused imports.
 16548  			//
 16549  			keepUnusedImports := p.options.ts.Parse && (unusedImportFlags&config.TSUnusedImport_KeepValues) != 0 &&
 16550  				p.options.mode != config.ModeBundle && !p.options.minifyIdentifiers
 16551  
 16552  			// Forbid non-default imports for JSON import assertions
 16553  			if (record.Flags&ast.AssertTypeJSON) != 0 && p.options.mode == config.ModeBundle && s.Items != nil {
 16554  				for _, item := range *s.Items {
 16555  					if p.options.ts.Parse && p.tsUseCounts[item.Name.Ref.InnerIndex] == 0 && (unusedImportFlags&config.TSUnusedImport_KeepValues) == 0 {
 16556  						// Do not count imports that TypeScript interprets as type annotations
 16557  						continue
 16558  					}
 16559  					if item.Alias != "default" {
 16560  						p.log.AddErrorWithNotes(&p.tracker, js_lexer.RangeOfIdentifier(p.source, item.AliasLoc),
 16561  							fmt.Sprintf("Cannot use non-default import %q with a JSON import assertion", item.Alias),
 16562  							p.notesForAssertTypeJSON(record, item.Alias))
 16563  					}
 16564  				}
 16565  			}
 16566  
 16567  			// TypeScript always trims unused imports. This is important for
 16568  			// correctness since some imports might be fake (only in the type
 16569  			// system and used for type-only imports).
 16570  			if (p.options.minifySyntax || p.options.ts.Parse) && !keepUnusedImports {
 16571  				foundImports := false
 16572  				isUnusedInTypeScript := true
 16573  
 16574  				// Remove the default name if it's unused
 16575  				if s.DefaultName != nil {
 16576  					foundImports = true
 16577  					symbol := p.symbols[s.DefaultName.Ref.InnerIndex]
 16578  
 16579  					// TypeScript has a separate definition of unused
 16580  					if p.options.ts.Parse && (p.tsUseCounts[s.DefaultName.Ref.InnerIndex] != 0 || (p.options.ts.Config.UnusedImportFlags()&config.TSUnusedImport_KeepValues) != 0) {
 16581  						isUnusedInTypeScript = false
 16582  					}
 16583  
 16584  					// Remove the symbol if it's never used outside a dead code region
 16585  					if symbol.UseCountEstimate == 0 && (p.options.ts.Parse || !p.moduleScope.ContainsDirectEval) {
 16586  						s.DefaultName = nil
 16587  					}
 16588  				}
 16589  
 16590  				// Remove the star import if it's unused
 16591  				if s.StarNameLoc != nil {
 16592  					foundImports = true
 16593  					symbol := p.symbols[s.NamespaceRef.InnerIndex]
 16594  
 16595  					// TypeScript has a separate definition of unused
 16596  					if p.options.ts.Parse && (p.tsUseCounts[s.NamespaceRef.InnerIndex] != 0 || (p.options.ts.Config.UnusedImportFlags()&config.TSUnusedImport_KeepValues) != 0) {
 16597  						isUnusedInTypeScript = false
 16598  					}
 16599  
 16600  					// Remove the symbol if it's never used outside a dead code region
 16601  					if symbol.UseCountEstimate == 0 && (p.options.ts.Parse || !p.moduleScope.ContainsDirectEval) {
 16602  						// Make sure we don't remove this if it was used for a property
 16603  						// access while bundling
 16604  						if importItems, ok := p.importItemsForNamespace[s.NamespaceRef]; ok && len(importItems.entries) == 0 {
 16605  							s.StarNameLoc = nil
 16606  						}
 16607  					}
 16608  				}
 16609  
 16610  				// Remove items if they are unused
 16611  				if s.Items != nil {
 16612  					foundImports = true
 16613  					itemsEnd := 0
 16614  
 16615  					for _, item := range *s.Items {
 16616  						symbol := p.symbols[item.Name.Ref.InnerIndex]
 16617  
 16618  						// TypeScript has a separate definition of unused
 16619  						if p.options.ts.Parse && (p.tsUseCounts[item.Name.Ref.InnerIndex] != 0 || (p.options.ts.Config.UnusedImportFlags()&config.TSUnusedImport_KeepValues) != 0) {
 16620  							isUnusedInTypeScript = false
 16621  						}
 16622  
 16623  						// Remove the symbol if it's never used outside a dead code region
 16624  						if symbol.UseCountEstimate != 0 || (!p.options.ts.Parse && p.moduleScope.ContainsDirectEval) {
 16625  							(*s.Items)[itemsEnd] = item
 16626  							itemsEnd++
 16627  						}
 16628  					}
 16629  
 16630  					// Filter the array by taking a slice
 16631  					if itemsEnd == 0 {
 16632  						s.Items = nil
 16633  					} else {
 16634  						*s.Items = (*s.Items)[:itemsEnd]
 16635  					}
 16636  				}
 16637  
 16638  				// Omit this statement if we're parsing TypeScript and all imports are
 16639  				// unused. Note that this is distinct from the case where there were
 16640  				// no imports at all (e.g. "import 'foo'"). In that case we want to keep
 16641  				// the statement because the user is clearly trying to import the module
 16642  				// for side effects.
 16643  				//
 16644  				// This culling is important for correctness when parsing TypeScript
 16645  				// because a) the TypeScript compiler does ths and we want to match it
 16646  				// and b) this may be a fake module that only exists in the type system
 16647  				// and doesn't actually exist in reality.
 16648  				//
 16649  				// We do not want to do this culling in JavaScript though because the
 16650  				// module may have side effects even if all imports are unused.
 16651  				if p.options.ts.Parse && foundImports && isUnusedInTypeScript && (unusedImportFlags&config.TSUnusedImport_KeepStmt) == 0 {
 16652  					// Ignore import records with a pre-filled source index. These are
 16653  					// for injected files and we definitely do not want to trim these.
 16654  					if !record.SourceIndex.IsValid() && !record.CopySourceIndex.IsValid() {
 16655  						record.Flags |= ast.IsUnused
 16656  						continue
 16657  					}
 16658  				}
 16659  			}
 16660  
 16661  			if p.options.mode != config.ModePassThrough {
 16662  				if s.StarNameLoc != nil {
 16663  					// "importItemsForNamespace" has property accesses off the namespace
 16664  					if importItems, ok := p.importItemsForNamespace[s.NamespaceRef]; ok && len(importItems.entries) > 0 {
 16665  						// Sort keys for determinism
 16666  						sorted := make([]string, 0, len(importItems.entries))
 16667  						for alias := range importItems.entries {
 16668  							sorted = append(sorted, alias)
 16669  						}
 16670  						sort.Strings(sorted)
 16671  
 16672  						// Create named imports for these property accesses. This will
 16673  						// cause missing imports to generate useful warnings.
 16674  						//
 16675  						// It will also improve bundling efficiency for internal imports
 16676  						// by still converting property accesses off the namespace into
 16677  						// bare identifiers even if the namespace is still needed.
 16678  						for _, alias := range sorted {
 16679  							name := importItems.entries[alias]
 16680  							p.namedImports[name.Ref] = js_ast.NamedImport{
 16681  								Alias:             alias,
 16682  								AliasLoc:          name.Loc,
 16683  								NamespaceRef:      s.NamespaceRef,
 16684  								ImportRecordIndex: s.ImportRecordIndex,
 16685  							}
 16686  
 16687  							// Make sure the printer prints this as a property access
 16688  							p.symbols[name.Ref.InnerIndex].NamespaceAlias = &ast.NamespaceAlias{
 16689  								NamespaceRef: s.NamespaceRef,
 16690  								Alias:        alias,
 16691  							}
 16692  
 16693  							// Also record these automatically-generated top-level namespace alias symbols
 16694  							p.declaredSymbols = append(p.declaredSymbols, js_ast.DeclaredSymbol{
 16695  								Ref:        name.Ref,
 16696  								IsTopLevel: true,
 16697  							})
 16698  						}
 16699  					}
 16700  				}
 16701  
 16702  				if s.DefaultName != nil {
 16703  					p.namedImports[s.DefaultName.Ref] = js_ast.NamedImport{
 16704  						Alias:             "default",
 16705  						AliasLoc:          s.DefaultName.Loc,
 16706  						NamespaceRef:      s.NamespaceRef,
 16707  						ImportRecordIndex: s.ImportRecordIndex,
 16708  					}
 16709  				}
 16710  
 16711  				if s.StarNameLoc != nil {
 16712  					p.namedImports[s.NamespaceRef] = js_ast.NamedImport{
 16713  						AliasIsStar:       true,
 16714  						AliasLoc:          *s.StarNameLoc,
 16715  						NamespaceRef:      ast.InvalidRef,
 16716  						ImportRecordIndex: s.ImportRecordIndex,
 16717  					}
 16718  				}
 16719  
 16720  				if s.Items != nil {
 16721  					for _, item := range *s.Items {
 16722  						p.namedImports[item.Name.Ref] = js_ast.NamedImport{
 16723  							Alias:             item.Alias,
 16724  							AliasLoc:          item.AliasLoc,
 16725  							NamespaceRef:      s.NamespaceRef,
 16726  							ImportRecordIndex: s.ImportRecordIndex,
 16727  						}
 16728  					}
 16729  				}
 16730  			}
 16731  
 16732  			p.importRecordsForCurrentPart = append(p.importRecordsForCurrentPart, s.ImportRecordIndex)
 16733  
 16734  			if s.StarNameLoc != nil {
 16735  				record.Flags |= ast.ContainsImportStar
 16736  			}
 16737  
 16738  			if s.DefaultName != nil {
 16739  				record.Flags |= ast.ContainsDefaultAlias
 16740  			} else if s.Items != nil {
 16741  				for _, item := range *s.Items {
 16742  					if item.Alias == "default" {
 16743  						record.Flags |= ast.ContainsDefaultAlias
 16744  					} else if item.Alias == "__esModule" {
 16745  						record.Flags |= ast.ContainsESModuleAlias
 16746  					}
 16747  				}
 16748  			}
 16749  
 16750  		case *js_ast.SFunction:
 16751  			if s.IsExport {
 16752  				p.recordExport(s.Fn.Name.Loc, p.symbols[s.Fn.Name.Ref.InnerIndex].OriginalName, s.Fn.Name.Ref)
 16753  			}
 16754  
 16755  		case *js_ast.SClass:
 16756  			if s.IsExport {
 16757  				p.recordExport(s.Class.Name.Loc, p.symbols[s.Class.Name.Ref.InnerIndex].OriginalName, s.Class.Name.Ref)
 16758  			}
 16759  
 16760  		case *js_ast.SLocal:
 16761  			if s.IsExport {
 16762  				js_ast.ForEachIdentifierBindingInDecls(s.Decls, func(loc logger.Loc, b *js_ast.BIdentifier) {
 16763  					p.recordExport(loc, p.symbols[b.Ref.InnerIndex].OriginalName, b.Ref)
 16764  				})
 16765  			}
 16766  
 16767  			// Remove unused import-equals statements, since those likely
 16768  			// correspond to types instead of values
 16769  			if p.checkForUnusedTSImportEquals(s, &result) {
 16770  				continue
 16771  			}
 16772  
 16773  		case *js_ast.SExportDefault:
 16774  			p.recordExport(s.DefaultName.Loc, "default", s.DefaultName.Ref)
 16775  
 16776  		case *js_ast.SExportClause:
 16777  			for _, item := range s.Items {
 16778  				p.recordExport(item.AliasLoc, item.Alias, item.Name.Ref)
 16779  			}
 16780  
 16781  		case *js_ast.SExportStar:
 16782  			record := &p.importRecords[s.ImportRecordIndex]
 16783  			p.importRecordsForCurrentPart = append(p.importRecordsForCurrentPart, s.ImportRecordIndex)
 16784  
 16785  			if s.Alias != nil {
 16786  				// "export * as ns from 'path'"
 16787  				p.namedImports[s.NamespaceRef] = js_ast.NamedImport{
 16788  					AliasIsStar:       true,
 16789  					AliasLoc:          s.Alias.Loc,
 16790  					NamespaceRef:      ast.InvalidRef,
 16791  					ImportRecordIndex: s.ImportRecordIndex,
 16792  					IsExported:        true,
 16793  				}
 16794  				p.recordExport(s.Alias.Loc, s.Alias.OriginalName, s.NamespaceRef)
 16795  
 16796  				record.Flags |= ast.ContainsImportStar
 16797  			} else {
 16798  				// "export * from 'path'"
 16799  				p.exportStarImportRecords = append(p.exportStarImportRecords, s.ImportRecordIndex)
 16800  			}
 16801  
 16802  		case *js_ast.SExportFrom:
 16803  			record := &p.importRecords[s.ImportRecordIndex]
 16804  			p.importRecordsForCurrentPart = append(p.importRecordsForCurrentPart, s.ImportRecordIndex)
 16805  
 16806  			for _, item := range s.Items {
 16807  				// Note that the imported alias is not item.Alias, which is the
 16808  				// exported alias. This is somewhat confusing because each
 16809  				// SExportFrom statement is basically SImport + SExportClause in one.
 16810  				p.namedImports[item.Name.Ref] = js_ast.NamedImport{
 16811  					Alias:             item.OriginalName,
 16812  					AliasLoc:          item.Name.Loc,
 16813  					NamespaceRef:      s.NamespaceRef,
 16814  					ImportRecordIndex: s.ImportRecordIndex,
 16815  					IsExported:        true,
 16816  				}
 16817  				p.recordExport(item.Name.Loc, item.Alias, item.Name.Ref)
 16818  
 16819  				if item.OriginalName == "default" {
 16820  					record.Flags |= ast.ContainsDefaultAlias
 16821  				} else if item.OriginalName == "__esModule" {
 16822  					record.Flags |= ast.ContainsESModuleAlias
 16823  				}
 16824  			}
 16825  
 16826  			// Forbid non-default imports for JSON import assertions
 16827  			if (record.Flags&ast.AssertTypeJSON) != 0 && p.options.mode == config.ModeBundle {
 16828  				for _, item := range s.Items {
 16829  					if item.OriginalName != "default" {
 16830  						p.log.AddErrorWithNotes(&p.tracker, js_lexer.RangeOfIdentifier(p.source, item.Name.Loc),
 16831  							fmt.Sprintf("Cannot use non-default import %q with a JSON import assertion", item.OriginalName),
 16832  							p.notesForAssertTypeJSON(record, item.OriginalName))
 16833  					}
 16834  				}
 16835  			}
 16836  
 16837  			// TypeScript always trims unused re-exports. This is important for
 16838  			// correctness since some re-exports might be fake (only in the type
 16839  			// system and used for type-only stuff).
 16840  			if p.options.ts.Parse && len(s.Items) == 0 && (unusedImportFlags&config.TSUnusedImport_KeepStmt) == 0 {
 16841  				continue
 16842  			}
 16843  		}
 16844  
 16845  		// Filter out statements we skipped over
 16846  		stmts[stmtsEnd] = stmt
 16847  		stmtsEnd++
 16848  	}
 16849  
 16850  	result.stmts = stmts[:stmtsEnd]
 16851  	return
 16852  }
 16853  
 16854  func (p *parser) appendPart(parts []js_ast.Part, stmts []js_ast.Stmt) []js_ast.Part {
 16855  	p.symbolUses = make(map[ast.Ref]js_ast.SymbolUse)
 16856  	p.importSymbolPropertyUses = nil
 16857  	p.symbolCallUses = nil
 16858  	p.declaredSymbols = nil
 16859  	p.importRecordsForCurrentPart = nil
 16860  	p.scopesForCurrentPart = nil
 16861  
 16862  	part := js_ast.Part{
 16863  		Stmts:      p.visitStmtsAndPrependTempRefs(stmts, prependTempRefsOpts{}),
 16864  		SymbolUses: p.symbolUses,
 16865  	}
 16866  
 16867  	// Sanity check
 16868  	if p.currentScope != p.moduleScope {
 16869  		panic("Internal error: Scope stack imbalance")
 16870  	}
 16871  
 16872  	// Insert any relocated variable statements now
 16873  	if len(p.relocatedTopLevelVars) > 0 {
 16874  		alreadyDeclared := make(map[ast.Ref]bool)
 16875  		for _, local := range p.relocatedTopLevelVars {
 16876  			// Follow links because "var" declarations may be merged due to hoisting
 16877  			for {
 16878  				link := p.symbols[local.Ref.InnerIndex].Link
 16879  				if link == ast.InvalidRef {
 16880  					break
 16881  				}
 16882  				local.Ref = link
 16883  			}
 16884  
 16885  			// Only declare a given relocated variable once
 16886  			if !alreadyDeclared[local.Ref] {
 16887  				alreadyDeclared[local.Ref] = true
 16888  				part.Stmts = append(part.Stmts, js_ast.Stmt{Loc: local.Loc, Data: &js_ast.SLocal{
 16889  					Decls: []js_ast.Decl{{
 16890  						Binding: js_ast.Binding{Loc: local.Loc, Data: &js_ast.BIdentifier{Ref: local.Ref}},
 16891  					}},
 16892  				}})
 16893  			}
 16894  		}
 16895  		p.relocatedTopLevelVars = nil
 16896  	}
 16897  
 16898  	if len(part.Stmts) > 0 {
 16899  		var flags js_ast.StmtsCanBeRemovedIfUnusedFlags
 16900  		if p.options.mode == config.ModePassThrough {
 16901  			// Exports are tracked separately, so export clauses can normally always
 16902  			// be removed. Except we should keep them if we're not doing any format
 16903  			// conversion because exports are not re-emitted in that case.
 16904  			flags |= js_ast.KeepExportClauses
 16905  		}
 16906  		part.CanBeRemovedIfUnused = p.astHelpers.StmtsCanBeRemovedIfUnused(part.Stmts, flags)
 16907  		part.DeclaredSymbols = p.declaredSymbols
 16908  		part.ImportRecordIndices = p.importRecordsForCurrentPart
 16909  		part.ImportSymbolPropertyUses = p.importSymbolPropertyUses
 16910  		part.SymbolCallUses = p.symbolCallUses
 16911  		part.Scopes = p.scopesForCurrentPart
 16912  		parts = append(parts, part)
 16913  	}
 16914  	return parts
 16915  }
 16916  
 16917  func newParser(log logger.Log, source logger.Source, lexer js_lexer.Lexer, options *Options) *parser {
 16918  	if options.defines == nil {
 16919  		defaultDefines := config.ProcessDefines(nil)
 16920  		options.defines = &defaultDefines
 16921  	}
 16922  
 16923  	p := &parser{
 16924  		log:                log,
 16925  		source:             source,
 16926  		tracker:            logger.MakeLineColumnTracker(&source),
 16927  		lexer:              lexer,
 16928  		allowIn:            true,
 16929  		options:            *options,
 16930  		runtimeImports:     make(map[string]ast.LocRef),
 16931  		promiseRef:         ast.InvalidRef,
 16932  		regExpRef:          ast.InvalidRef,
 16933  		afterArrowBodyLoc:  logger.Loc{Start: -1},
 16934  		firstJSXElementLoc: logger.Loc{Start: -1},
 16935  		importMetaRef:      ast.InvalidRef,
 16936  		superCtorRef:       ast.InvalidRef,
 16937  
 16938  		// For lowering private methods
 16939  		weakMapRef:     ast.InvalidRef,
 16940  		weakSetRef:     ast.InvalidRef,
 16941  		privateGetters: make(map[ast.Ref]ast.Ref),
 16942  		privateSetters: make(map[ast.Ref]ast.Ref),
 16943  
 16944  		// These are for TypeScript
 16945  		refToTSNamespaceMemberData: make(map[ast.Ref]js_ast.TSNamespaceMemberData),
 16946  		emittedNamespaceVars:       make(map[ast.Ref]bool),
 16947  		isExportedInsideNamespace:  make(map[ast.Ref]ast.Ref),
 16948  		localTypeNames:             make(map[string]bool),
 16949  
 16950  		// These are for handling ES6 imports and exports
 16951  		importItemsForNamespace: make(map[ast.Ref]namespaceImportItems),
 16952  		isImportItem:            make(map[ast.Ref]bool),
 16953  		namedImports:            make(map[ast.Ref]js_ast.NamedImport),
 16954  		namedExports:            make(map[string]js_ast.NamedExport),
 16955  
 16956  		// For JSX runtime imports
 16957  		jsxRuntimeImports: make(map[string]ast.LocRef),
 16958  		jsxLegacyImports:  make(map[string]ast.LocRef),
 16959  
 16960  		suppressWarningsAboutWeirdCode: helpers.IsInsideNodeModules(source.KeyPath.Text),
 16961  	}
 16962  
 16963  	if len(options.dropLabels) > 0 {
 16964  		p.dropLabelsMap = make(map[string]struct{})
 16965  		for _, name := range options.dropLabels {
 16966  			p.dropLabelsMap[name] = struct{}{}
 16967  		}
 16968  	}
 16969  
 16970  	if !options.minifyWhitespace {
 16971  		p.exprComments = make(map[logger.Loc][]string)
 16972  	}
 16973  
 16974  	p.astHelpers = js_ast.MakeHelperContext(func(ref ast.Ref) bool {
 16975  		return p.symbols[ref.InnerIndex].Kind == ast.SymbolUnbound
 16976  	})
 16977  
 16978  	p.pushScopeForParsePass(js_ast.ScopeEntry, logger.Loc{Start: locModuleScope})
 16979  
 16980  	return p
 16981  }
 16982  
 16983  var defaultJSXFactory = []string{"React", "createElement"}
 16984  var defaultJSXFragment = []string{"React", "Fragment"}
 16985  
 16986  const defaultJSXImportSource = "react"
 16987  
 16988  func Parse(log logger.Log, source logger.Source, options Options) (result js_ast.AST, ok bool) {
 16989  	ok = true
 16990  	defer func() {
 16991  		r := recover()
 16992  		if _, isLexerPanic := r.(js_lexer.LexerPanic); isLexerPanic {
 16993  			ok = false
 16994  		} else if r != nil {
 16995  			panic(r)
 16996  		}
 16997  	}()
 16998  
 16999  	// Default options for JSX elements
 17000  	if len(options.jsx.Factory.Parts) == 0 {
 17001  		options.jsx.Factory = config.DefineExpr{Parts: defaultJSXFactory}
 17002  	}
 17003  	if len(options.jsx.Fragment.Parts) == 0 && options.jsx.Fragment.Constant == nil {
 17004  		options.jsx.Fragment = config.DefineExpr{Parts: defaultJSXFragment}
 17005  	}
 17006  	if len(options.jsx.ImportSource) == 0 {
 17007  		options.jsx.ImportSource = defaultJSXImportSource
 17008  	}
 17009  
 17010  	p := newParser(log, source, js_lexer.NewLexer(log, source, options.ts), &options)
 17011  
 17012  	// Consume a leading hashbang comment
 17013  	hashbang := ""
 17014  	if p.lexer.Token == js_lexer.THashbang {
 17015  		hashbang = p.lexer.Identifier.String
 17016  		p.lexer.Next()
 17017  	}
 17018  
 17019  	// Allow top-level await
 17020  	p.fnOrArrowDataParse.await = allowExpr
 17021  	p.fnOrArrowDataParse.isTopLevel = true
 17022  
 17023  	// Parse the file in the first pass, but do not bind symbols
 17024  	stmts := p.parseStmtsUpTo(js_lexer.TEndOfFile, parseStmtOpts{
 17025  		isModuleScope:          true,
 17026  		allowDirectivePrologue: true,
 17027  	})
 17028  	p.prepareForVisitPass()
 17029  
 17030  	// Insert a "use strict" directive if "alwaysStrict" is active
 17031  	var directives []string
 17032  	if tsAlwaysStrict := p.options.tsAlwaysStrict; tsAlwaysStrict != nil && tsAlwaysStrict.Value {
 17033  		directives = append(directives, "use strict")
 17034  	}
 17035  
 17036  	// Strip off all leading directives
 17037  	{
 17038  		totalCount := 0
 17039  		keptCount := 0
 17040  
 17041  		for _, stmt := range stmts {
 17042  			switch s := stmt.Data.(type) {
 17043  			case *js_ast.SComment:
 17044  				stmts[keptCount] = stmt
 17045  				keptCount++
 17046  				totalCount++
 17047  				continue
 17048  
 17049  			case *js_ast.SDirective:
 17050  				if p.isStrictMode() && s.LegacyOctalLoc.Start > 0 {
 17051  					p.markStrictModeFeature(legacyOctalEscape, p.source.RangeOfLegacyOctalEscape(s.LegacyOctalLoc), "")
 17052  				}
 17053  				directive := helpers.UTF16ToString(s.Value)
 17054  
 17055  				// Remove duplicate directives
 17056  				found := false
 17057  				for _, existing := range directives {
 17058  					if existing == directive {
 17059  						found = true
 17060  						break
 17061  					}
 17062  				}
 17063  				if !found {
 17064  					directives = append(directives, directive)
 17065  				}
 17066  
 17067  				// Remove this directive from the statement list
 17068  				totalCount++
 17069  				continue
 17070  			}
 17071  
 17072  			// Stop when the directive prologue ends
 17073  			break
 17074  		}
 17075  
 17076  		if keptCount < totalCount {
 17077  			stmts = append(stmts[:keptCount], stmts[totalCount:]...)
 17078  		}
 17079  	}
 17080  
 17081  	// Add an empty part for the namespace export that we can fill in later
 17082  	nsExportPart := js_ast.Part{
 17083  		SymbolUses:           make(map[ast.Ref]js_ast.SymbolUse),
 17084  		CanBeRemovedIfUnused: true,
 17085  	}
 17086  
 17087  	var before = []js_ast.Part{nsExportPart}
 17088  	var parts []js_ast.Part
 17089  	var after []js_ast.Part
 17090  
 17091  	// Insert any injected import statements now that symbols have been declared
 17092  	for _, file := range p.options.injectedFiles {
 17093  		exportsNoConflict := make([]string, 0, len(file.Exports))
 17094  		symbols := make(map[string]ast.LocRef)
 17095  
 17096  		if file.DefineName != "" {
 17097  			ref := p.newSymbol(ast.SymbolOther, file.DefineName)
 17098  			p.moduleScope.Generated = append(p.moduleScope.Generated, ref)
 17099  			symbols["default"] = ast.LocRef{Ref: ref}
 17100  			exportsNoConflict = append(exportsNoConflict, "default")
 17101  			p.injectedDefineSymbols = append(p.injectedDefineSymbols, ref)
 17102  		} else {
 17103  		nextExport:
 17104  			for _, export := range file.Exports {
 17105  				// Skip injecting this symbol if it's already declared locally (i.e. it's not a reference to a global)
 17106  				if _, ok := p.moduleScope.Members[export.Alias]; ok {
 17107  					continue
 17108  				}
 17109  
 17110  				parts := strings.Split(export.Alias, ".")
 17111  
 17112  				// The key must be a dot-separated identifier list
 17113  				for _, part := range parts {
 17114  					if !js_ast.IsIdentifier(part) {
 17115  						continue nextExport
 17116  					}
 17117  				}
 17118  
 17119  				ref := p.newSymbol(ast.SymbolInjected, export.Alias)
 17120  				symbols[export.Alias] = ast.LocRef{Ref: ref}
 17121  				if len(parts) == 1 {
 17122  					// Handle the identifier case by generating an injected symbol directly
 17123  					p.moduleScope.Members[export.Alias] = js_ast.ScopeMember{Ref: ref}
 17124  				} else {
 17125  					// Handle the dot case using a map. This map is similar to the map
 17126  					// "options.defines.DotDefines" but is kept separate instead of being
 17127  					// implemented using the same mechanism because we allow you to use
 17128  					// "define" to rewrite something to an injected symbol (i.e. we allow
 17129  					// two levels of mappings). This was historically necessary to be able
 17130  					// to map a dot name to an injected symbol because we previously didn't
 17131  					// support dot names as injected symbols. But now dot names as injected
 17132  					// symbols has been implemented, so supporting two levels of mappings
 17133  					// is only for backward-compatibility.
 17134  					if p.injectedDotNames == nil {
 17135  						p.injectedDotNames = make(map[string][]injectedDotName)
 17136  					}
 17137  					tail := parts[len(parts)-1]
 17138  					p.injectedDotNames[tail] = append(p.injectedDotNames[tail], injectedDotName{parts: parts, injectedDefineIndex: uint32(len(p.injectedDefineSymbols))})
 17139  					p.injectedDefineSymbols = append(p.injectedDefineSymbols, ref)
 17140  				}
 17141  				exportsNoConflict = append(exportsNoConflict, export.Alias)
 17142  				if p.injectedSymbolSources == nil {
 17143  					p.injectedSymbolSources = make(map[ast.Ref]injectedSymbolSource)
 17144  				}
 17145  				p.injectedSymbolSources[ref] = injectedSymbolSource{
 17146  					source: file.Source,
 17147  					loc:    export.Loc,
 17148  				}
 17149  			}
 17150  		}
 17151  
 17152  		if file.IsCopyLoader {
 17153  			before, _ = p.generateImportStmt(file.Source.KeyPath.Text, logger.Range{}, exportsNoConflict, before, symbols, nil, &file.Source.Index)
 17154  		} else {
 17155  			before, _ = p.generateImportStmt(file.Source.KeyPath.Text, logger.Range{}, exportsNoConflict, before, symbols, &file.Source.Index, nil)
 17156  		}
 17157  	}
 17158  
 17159  	// When "using" declarations appear at the top level, we change all TDZ
 17160  	// variables in the top-level scope into "var" so that they aren't harmed
 17161  	// when they are moved into the try/catch statement that lowering will
 17162  	// generate.
 17163  	//
 17164  	// This is necessary because exported function declarations must be hoisted
 17165  	// outside of the try/catch statement because they can be evaluated before
 17166  	// this module is evaluated due to ESM cross-file function hoisting. And
 17167  	// these function bodies might reference anything else in this scope, which
 17168  	// must still work when those things are moved inside a try/catch statement.
 17169  	//
 17170  	// Before:
 17171  	//
 17172  	//   using foo = get()
 17173  	//   export function fn() {
 17174  	//     return [foo, new Bar]
 17175  	//   }
 17176  	//   class Bar {}
 17177  	//
 17178  	// After ("fn" is hoisted, "Bar" is converted to "var"):
 17179  	//
 17180  	//   export function fn() {
 17181  	//     return [foo, new Bar]
 17182  	//   }
 17183  	//   try {
 17184  	//     var foo = get();
 17185  	//     var Bar = class {};
 17186  	//   } catch (_) {
 17187  	//     ...
 17188  	//   } finally {
 17189  	//     ...
 17190  	//   }
 17191  	//
 17192  	// This is also necessary because other code might be appended to the code
 17193  	// that we're processing and expect to be able to access top-level variables.
 17194  	p.willWrapModuleInTryCatchForUsing = p.shouldLowerUsingDeclarations(stmts)
 17195  
 17196  	// Bind symbols in a second pass over the AST. I started off doing this in a
 17197  	// single pass, but it turns out it's pretty much impossible to do this
 17198  	// correctly while handling arrow functions because of the grammar
 17199  	// ambiguities.
 17200  	//
 17201  	// Note that top-level lowered "using" declarations disable tree-shaking
 17202  	// because we only do tree-shaking on top-level statements and lowering
 17203  	// a top-level "using" declaration moves all top-level statements into a
 17204  	// nested scope.
 17205  	if !p.options.treeShaking || p.willWrapModuleInTryCatchForUsing {
 17206  		// When tree shaking is disabled, everything comes in a single part
 17207  		parts = p.appendPart(parts, stmts)
 17208  	} else {
 17209  		var preprocessedEnums map[int][]js_ast.Part
 17210  		if p.scopesInOrderForEnum != nil {
 17211  			// Preprocess TypeScript enums to improve code generation. Otherwise
 17212  			// uses of an enum before that enum has been declared won't be inlined:
 17213  			//
 17214  			//   console.log(Foo.FOO) // We want "FOO" to be inlined here
 17215  			//   const enum Foo { FOO = 0 }
 17216  			//
 17217  			// The TypeScript compiler itself contains code with this pattern, so
 17218  			// it's important to implement this optimization.
 17219  			for i, stmt := range stmts {
 17220  				if _, ok := stmt.Data.(*js_ast.SEnum); ok {
 17221  					if preprocessedEnums == nil {
 17222  						preprocessedEnums = make(map[int][]js_ast.Part)
 17223  					}
 17224  					oldScopesInOrder := p.scopesInOrder
 17225  					p.scopesInOrder = p.scopesInOrderForEnum[stmt.Loc]
 17226  					preprocessedEnums[i] = p.appendPart(nil, []js_ast.Stmt{stmt})
 17227  					p.scopesInOrder = oldScopesInOrder
 17228  				}
 17229  			}
 17230  		}
 17231  
 17232  		// When tree shaking is enabled, each top-level statement is potentially a separate part
 17233  		for i, stmt := range stmts {
 17234  			switch s := stmt.Data.(type) {
 17235  			case *js_ast.SLocal:
 17236  				// Split up top-level multi-declaration variable statements
 17237  				for _, decl := range s.Decls {
 17238  					clone := *s
 17239  					clone.Decls = []js_ast.Decl{decl}
 17240  					parts = p.appendPart(parts, []js_ast.Stmt{{Loc: stmt.Loc, Data: &clone}})
 17241  				}
 17242  
 17243  			case *js_ast.SImport, *js_ast.SExportFrom, *js_ast.SExportStar:
 17244  				if p.options.mode != config.ModePassThrough {
 17245  					// Move imports (and import-like exports) to the top of the file to
 17246  					// ensure that if they are converted to a require() call, the effects
 17247  					// will take place before any other statements are evaluated.
 17248  					before = p.appendPart(before, []js_ast.Stmt{stmt})
 17249  				} else {
 17250  					// If we aren't doing any format conversion, just keep these statements
 17251  					// inline where they were. Exports are sorted so order doesn't matter:
 17252  					// https://262.ecma-international.org/6.0/#sec-module-namespace-exotic-objects.
 17253  					// However, this is likely an aesthetic issue that some people will
 17254  					// complain about. In addition, there are code transformation tools
 17255  					// such as TypeScript and Babel with bugs where the order of exports
 17256  					// in the file is incorrectly preserved instead of sorted, so preserving
 17257  					// the order of exports ourselves here may be preferable.
 17258  					parts = p.appendPart(parts, []js_ast.Stmt{stmt})
 17259  				}
 17260  
 17261  			case *js_ast.SExportEquals:
 17262  				// TypeScript "export = value;" becomes "module.exports = value;". This
 17263  				// must happen at the end after everything is parsed because TypeScript
 17264  				// moves this statement to the end when it generates code.
 17265  				after = p.appendPart(after, []js_ast.Stmt{stmt})
 17266  
 17267  			case *js_ast.SEnum:
 17268  				parts = append(parts, preprocessedEnums[i]...)
 17269  				p.scopesInOrder = p.scopesInOrder[len(p.scopesInOrderForEnum[stmt.Loc]):]
 17270  
 17271  			default:
 17272  				parts = p.appendPart(parts, []js_ast.Stmt{stmt})
 17273  			}
 17274  		}
 17275  	}
 17276  
 17277  	// Insert a variable for "import.meta" at the top of the file if it was used.
 17278  	// We don't need to worry about "use strict" directives because this only
 17279  	// happens when bundling, in which case we are flatting the module scopes of
 17280  	// all modules together anyway so such directives are meaningless.
 17281  	if p.importMetaRef != ast.InvalidRef {
 17282  		importMetaStmt := js_ast.Stmt{Data: &js_ast.SLocal{
 17283  			Kind: p.selectLocalKind(js_ast.LocalConst),
 17284  			Decls: []js_ast.Decl{{
 17285  				Binding:    js_ast.Binding{Data: &js_ast.BIdentifier{Ref: p.importMetaRef}},
 17286  				ValueOrNil: js_ast.Expr{Data: &js_ast.EObject{}},
 17287  			}},
 17288  		}}
 17289  		before = append(before, js_ast.Part{
 17290  			Stmts:                []js_ast.Stmt{importMetaStmt},
 17291  			SymbolUses:           make(map[ast.Ref]js_ast.SymbolUse),
 17292  			DeclaredSymbols:      []js_ast.DeclaredSymbol{{Ref: p.importMetaRef, IsTopLevel: true}},
 17293  			CanBeRemovedIfUnused: true,
 17294  		})
 17295  	}
 17296  
 17297  	// Pop the module scope to apply the "ContainsDirectEval" rules
 17298  	p.popScope()
 17299  
 17300  	result = p.toAST(before, parts, after, hashbang, directives)
 17301  	result.SourceMapComment = p.lexer.SourceMappingURL
 17302  	return
 17303  }
 17304  
 17305  func LazyExportAST(log logger.Log, source logger.Source, options Options, expr js_ast.Expr, apiCall string) js_ast.AST {
 17306  	// Don't create a new lexer using js_lexer.NewLexer() here since that will
 17307  	// actually attempt to parse the first token, which might cause a syntax
 17308  	// error.
 17309  	p := newParser(log, source, js_lexer.Lexer{}, &options)
 17310  	p.prepareForVisitPass()
 17311  
 17312  	// Optionally call a runtime API function to transform the expression
 17313  	if apiCall != "" {
 17314  		p.symbolUses = make(map[ast.Ref]js_ast.SymbolUse)
 17315  		expr = p.callRuntime(expr.Loc, apiCall, []js_ast.Expr{expr})
 17316  	}
 17317  
 17318  	// Add an empty part for the namespace export that we can fill in later
 17319  	nsExportPart := js_ast.Part{
 17320  		SymbolUses:           make(map[ast.Ref]js_ast.SymbolUse),
 17321  		CanBeRemovedIfUnused: true,
 17322  	}
 17323  
 17324  	// Defer the actual code generation until linking
 17325  	part := js_ast.Part{
 17326  		Stmts:      []js_ast.Stmt{{Loc: expr.Loc, Data: &js_ast.SLazyExport{Value: expr}}},
 17327  		SymbolUses: p.symbolUses,
 17328  	}
 17329  	p.symbolUses = nil
 17330  
 17331  	ast := p.toAST([]js_ast.Part{nsExportPart}, []js_ast.Part{part}, nil, "", nil)
 17332  	ast.HasLazyExport = true
 17333  	return ast
 17334  }
 17335  
 17336  func GlobResolveAST(log logger.Log, source logger.Source, importRecords []ast.ImportRecord, object *js_ast.EObject, name string) js_ast.AST {
 17337  	// Don't create a new lexer using js_lexer.NewLexer() here since that will
 17338  	// actually attempt to parse the first token, which might cause a syntax
 17339  	// error.
 17340  	p := newParser(log, source, js_lexer.Lexer{}, &Options{})
 17341  	p.prepareForVisitPass()
 17342  
 17343  	// Add an empty part for the namespace export that we can fill in later
 17344  	nsExportPart := js_ast.Part{
 17345  		SymbolUses:           make(map[ast.Ref]js_ast.SymbolUse),
 17346  		CanBeRemovedIfUnused: true,
 17347  	}
 17348  
 17349  	if len(p.importRecords) != 0 {
 17350  		panic("Internal error")
 17351  	}
 17352  	p.importRecords = importRecords
 17353  
 17354  	importRecordIndices := make([]uint32, 0, len(importRecords))
 17355  	for importRecordIndex := range importRecords {
 17356  		importRecordIndices = append(importRecordIndices, uint32(importRecordIndex))
 17357  	}
 17358  
 17359  	p.symbolUses = make(map[ast.Ref]js_ast.SymbolUse)
 17360  	ref := p.newSymbol(ast.SymbolOther, name)
 17361  	p.moduleScope.Generated = append(p.moduleScope.Generated, ref)
 17362  
 17363  	part := js_ast.Part{
 17364  		Stmts: []js_ast.Stmt{{Data: &js_ast.SLocal{
 17365  			IsExport: true,
 17366  			Decls: []js_ast.Decl{{
 17367  				Binding:    js_ast.Binding{Data: &js_ast.BIdentifier{Ref: ref}},
 17368  				ValueOrNil: p.callRuntime(logger.Loc{}, "__glob", []js_ast.Expr{{Data: object}}),
 17369  			}},
 17370  		}}},
 17371  		ImportRecordIndices: importRecordIndices,
 17372  		SymbolUses:          p.symbolUses,
 17373  	}
 17374  	p.symbolUses = nil
 17375  
 17376  	p.esmExportKeyword.Len = 1
 17377  	return p.toAST([]js_ast.Part{nsExportPart}, []js_ast.Part{part}, nil, "", nil)
 17378  }
 17379  
 17380  func ParseDefineExprOrJSON(text string) (config.DefineExpr, js_ast.E) {
 17381  	if text == "" {
 17382  		return config.DefineExpr{}, nil
 17383  	}
 17384  
 17385  	// Try a property chain
 17386  	parts := strings.Split(text, ".")
 17387  	for i, part := range parts {
 17388  		if !js_ast.IsIdentifier(part) {
 17389  			parts = nil
 17390  			break
 17391  		}
 17392  
 17393  		// Don't allow most keywords as the identifier
 17394  		if i == 0 {
 17395  			if token, ok := js_lexer.Keywords[part]; ok && token != js_lexer.TNull && token != js_lexer.TThis &&
 17396  				(token != js_lexer.TImport || len(parts) < 2 || parts[1] != "meta") {
 17397  				parts = nil
 17398  				break
 17399  			}
 17400  		}
 17401  	}
 17402  	if parts != nil {
 17403  		return config.DefineExpr{Parts: parts}, nil
 17404  	}
 17405  
 17406  	// Try parsing a JSON value
 17407  	log := logger.NewDeferLog(logger.DeferLogNoVerboseOrDebug, nil)
 17408  	expr, ok := ParseJSON(log, logger.Source{Contents: text}, JSONOptions{})
 17409  	if !ok {
 17410  		return config.DefineExpr{}, nil
 17411  	}
 17412  
 17413  	// Only primitive literals are inlined directly
 17414  	switch expr.Data.(type) {
 17415  	case *js_ast.ENull, *js_ast.EBoolean, *js_ast.EString, *js_ast.ENumber:
 17416  		return config.DefineExpr{Constant: expr.Data}, nil
 17417  	}
 17418  
 17419  	// If it's not a primitive, return the whole compound JSON value to be injected out-of-line
 17420  	return config.DefineExpr{}, expr.Data
 17421  }
 17422  
 17423  type whyESM uint8
 17424  
 17425  const (
 17426  	whyESMUnknown whyESM = iota
 17427  	whyESMExportKeyword
 17428  	whyESMImportMeta
 17429  	whyESMTopLevelAwait
 17430  	whyESMFileMJS
 17431  	whyESMFileMTS
 17432  	whyESMTypeModulePackageJSON
 17433  	whyESMImportStatement
 17434  )
 17435  
 17436  // Say why this the current file is being considered an ES module
 17437  func (p *parser) whyESModule() (whyESM, []logger.MsgData) {
 17438  	because := "This file is considered to be an ECMAScript module because"
 17439  	switch {
 17440  	case p.esmExportKeyword.Len > 0:
 17441  		return whyESMExportKeyword, []logger.MsgData{p.tracker.MsgData(p.esmExportKeyword,
 17442  			because+" of the \"export\" keyword here:")}
 17443  
 17444  	case p.esmImportMeta.Len > 0:
 17445  		return whyESMImportMeta, []logger.MsgData{p.tracker.MsgData(p.esmImportMeta,
 17446  			because+" of the use of \"import.meta\" here:")}
 17447  
 17448  	case p.topLevelAwaitKeyword.Len > 0:
 17449  		return whyESMTopLevelAwait, []logger.MsgData{p.tracker.MsgData(p.topLevelAwaitKeyword,
 17450  			because+" of the top-level \"await\" keyword here:")}
 17451  
 17452  	case p.options.moduleTypeData.Type == js_ast.ModuleESM_MJS:
 17453  		return whyESMFileMJS, []logger.MsgData{{Text: because + " the file name ends in \".mjs\"."}}
 17454  
 17455  	case p.options.moduleTypeData.Type == js_ast.ModuleESM_MTS:
 17456  		return whyESMFileMTS, []logger.MsgData{{Text: because + " the file name ends in \".mts\"."}}
 17457  
 17458  	case p.options.moduleTypeData.Type == js_ast.ModuleESM_PackageJSON:
 17459  		tracker := logger.MakeLineColumnTracker(p.options.moduleTypeData.Source)
 17460  		return whyESMTypeModulePackageJSON, []logger.MsgData{tracker.MsgData(p.options.moduleTypeData.Range,
 17461  			because+" the enclosing \"package.json\" file sets the type of this file to \"module\":")}
 17462  
 17463  	// This case must come last because some code cares about the "import"
 17464  	// statement keyword and some doesn't, and we don't want to give code
 17465  	// that doesn't care about the "import" statement the wrong error message.
 17466  	case p.esmImportStatementKeyword.Len > 0:
 17467  		return whyESMImportStatement, []logger.MsgData{p.tracker.MsgData(p.esmImportStatementKeyword,
 17468  			because+" of the \"import\" keyword here:")}
 17469  	}
 17470  	return whyESMUnknown, nil
 17471  }
 17472  
 17473  func (p *parser) prepareForVisitPass() {
 17474  	p.pushScopeForVisitPass(js_ast.ScopeEntry, logger.Loc{Start: locModuleScope})
 17475  	p.fnOrArrowDataVisit.isOutsideFnOrArrow = true
 17476  	p.moduleScope = p.currentScope
 17477  
 17478  	// Force-enable strict mode if that's the way TypeScript is configured
 17479  	if tsAlwaysStrict := p.options.tsAlwaysStrict; tsAlwaysStrict != nil && tsAlwaysStrict.Value {
 17480  		p.currentScope.StrictMode = js_ast.ImplicitStrictModeTSAlwaysStrict
 17481  	}
 17482  
 17483  	// Determine whether or not this file is ESM
 17484  	p.isFileConsideredToHaveESMExports =
 17485  		p.esmExportKeyword.Len > 0 ||
 17486  			p.esmImportMeta.Len > 0 ||
 17487  			p.topLevelAwaitKeyword.Len > 0 ||
 17488  			p.options.moduleTypeData.Type.IsESM()
 17489  	p.isFileConsideredESM =
 17490  		p.isFileConsideredToHaveESMExports ||
 17491  			p.esmImportStatementKeyword.Len > 0
 17492  
 17493  	// Legacy HTML comments are not allowed in ESM files
 17494  	if p.isFileConsideredESM && p.lexer.LegacyHTMLCommentRange.Len > 0 {
 17495  		_, notes := p.whyESModule()
 17496  		p.log.AddErrorWithNotes(&p.tracker, p.lexer.LegacyHTMLCommentRange,
 17497  			"Legacy HTML single-line comments are not allowed in ECMAScript modules", notes)
 17498  	}
 17499  
 17500  	// ECMAScript modules are always interpreted as strict mode. This has to be
 17501  	// done before "hoistSymbols" because strict mode can alter hoisting (!).
 17502  	if p.isFileConsideredESM {
 17503  		p.moduleScope.RecursiveSetStrictMode(js_ast.ImplicitStrictModeESM)
 17504  	}
 17505  
 17506  	p.hoistSymbols(p.moduleScope)
 17507  
 17508  	if p.options.mode != config.ModePassThrough {
 17509  		p.requireRef = p.declareCommonJSSymbol(ast.SymbolUnbound, "require")
 17510  	} else {
 17511  		p.requireRef = p.newSymbol(ast.SymbolUnbound, "require")
 17512  	}
 17513  
 17514  	// CommonJS-style exports are only enabled if this isn't using ECMAScript-
 17515  	// style exports. You can still use "require" in ESM, just not "module" or
 17516  	// "exports". You can also still use "import" in CommonJS.
 17517  	if p.options.mode != config.ModePassThrough && !p.isFileConsideredToHaveESMExports {
 17518  		// CommonJS-style exports
 17519  		p.exportsRef = p.declareCommonJSSymbol(ast.SymbolHoisted, "exports")
 17520  		p.moduleRef = p.declareCommonJSSymbol(ast.SymbolHoisted, "module")
 17521  	} else {
 17522  		// ESM-style exports
 17523  		p.exportsRef = p.newSymbol(ast.SymbolHoisted, "exports")
 17524  		p.moduleRef = p.newSymbol(ast.SymbolHoisted, "module")
 17525  	}
 17526  
 17527  	// Handle "@jsx" and "@jsxFrag" pragmas now that lexing is done
 17528  	if p.options.jsx.Parse {
 17529  		if jsxRuntime := p.lexer.JSXRuntimePragmaComment; jsxRuntime.Text != "" {
 17530  			if jsxRuntime.Text == "automatic" {
 17531  				p.options.jsx.AutomaticRuntime = true
 17532  			} else if jsxRuntime.Text == "classic" {
 17533  				p.options.jsx.AutomaticRuntime = false
 17534  			} else {
 17535  				p.log.AddIDWithNotes(logger.MsgID_JS_UnsupportedJSXComment, logger.Warning, &p.tracker, jsxRuntime.Range,
 17536  					fmt.Sprintf("Invalid JSX runtime: %q", jsxRuntime.Text),
 17537  					[]logger.MsgData{{Text: "The JSX runtime can only be set to either \"classic\" or \"automatic\"."}})
 17538  			}
 17539  		}
 17540  
 17541  		if jsxFactory := p.lexer.JSXFactoryPragmaComment; jsxFactory.Text != "" {
 17542  			if p.options.jsx.AutomaticRuntime {
 17543  				p.log.AddID(logger.MsgID_JS_UnsupportedJSXComment, logger.Warning, &p.tracker, jsxFactory.Range,
 17544  					"The JSX factory cannot be set when using React's \"automatic\" JSX transform")
 17545  			} else if expr, _ := ParseDefineExprOrJSON(jsxFactory.Text); len(expr.Parts) > 0 {
 17546  				p.options.jsx.Factory = expr
 17547  			} else {
 17548  				p.log.AddID(logger.MsgID_JS_UnsupportedJSXComment, logger.Warning, &p.tracker, jsxFactory.Range,
 17549  					fmt.Sprintf("Invalid JSX factory: %s", jsxFactory.Text))
 17550  			}
 17551  		}
 17552  
 17553  		if jsxFragment := p.lexer.JSXFragmentPragmaComment; jsxFragment.Text != "" {
 17554  			if p.options.jsx.AutomaticRuntime {
 17555  				p.log.AddID(logger.MsgID_JS_UnsupportedJSXComment, logger.Warning, &p.tracker, jsxFragment.Range,
 17556  					"The JSX fragment cannot be set when using React's \"automatic\" JSX transform")
 17557  			} else if expr, _ := ParseDefineExprOrJSON(jsxFragment.Text); len(expr.Parts) > 0 || expr.Constant != nil {
 17558  				p.options.jsx.Fragment = expr
 17559  			} else {
 17560  				p.log.AddID(logger.MsgID_JS_UnsupportedJSXComment, logger.Warning, &p.tracker, jsxFragment.Range,
 17561  					fmt.Sprintf("Invalid JSX fragment: %s", jsxFragment.Text))
 17562  			}
 17563  		}
 17564  
 17565  		if jsxImportSource := p.lexer.JSXImportSourcePragmaComment; jsxImportSource.Text != "" {
 17566  			if !p.options.jsx.AutomaticRuntime {
 17567  				p.log.AddIDWithNotes(logger.MsgID_JS_UnsupportedJSXComment, logger.Warning, &p.tracker, jsxImportSource.Range,
 17568  					"The JSX import source cannot be set without also enabling React's \"automatic\" JSX transform",
 17569  					[]logger.MsgData{{Text: "You can enable React's \"automatic\" JSX transform for this file by using a \"@jsxRuntime automatic\" comment."}})
 17570  			} else {
 17571  				p.options.jsx.ImportSource = jsxImportSource.Text
 17572  			}
 17573  		}
 17574  	}
 17575  
 17576  	// Force-enable strict mode if the JSX "automatic" runtime is enabled and
 17577  	// there is at least one JSX element. This is because the automatically-
 17578  	// generated import statement turns the file into an ES module. This behavior
 17579  	// matches TypeScript which also does this. See this PR for more information:
 17580  	// https://github.com/microsoft/TypeScript/pull/39199
 17581  	if p.currentScope.StrictMode == js_ast.SloppyMode && p.options.jsx.AutomaticRuntime && p.firstJSXElementLoc.Start != -1 {
 17582  		p.currentScope.StrictMode = js_ast.ImplicitStrictModeJSXAutomaticRuntime
 17583  	}
 17584  }
 17585  
 17586  func (p *parser) declareCommonJSSymbol(kind ast.SymbolKind, name string) ast.Ref {
 17587  	member, ok := p.moduleScope.Members[name]
 17588  
 17589  	// If the code declared this symbol using "var name", then this is actually
 17590  	// not a collision. For example, node will let you do this:
 17591  	//
 17592  	//   var exports;
 17593  	//   module.exports.foo = 123;
 17594  	//   console.log(exports.foo);
 17595  	//
 17596  	// This works because node's implementation of CommonJS wraps the entire
 17597  	// source file like this:
 17598  	//
 17599  	//   (function(require, exports, module, __filename, __dirname) {
 17600  	//     var exports;
 17601  	//     module.exports.foo = 123;
 17602  	//     console.log(exports.foo);
 17603  	//   })
 17604  	//
 17605  	// Both the "exports" argument and "var exports" are hoisted variables, so
 17606  	// they don't collide.
 17607  	if ok && p.symbols[member.Ref.InnerIndex].Kind == ast.SymbolHoisted &&
 17608  		kind == ast.SymbolHoisted && !p.isFileConsideredToHaveESMExports {
 17609  		return member.Ref
 17610  	}
 17611  
 17612  	// Create a new symbol if we didn't merge with an existing one above
 17613  	ref := p.newSymbol(kind, name)
 17614  
 17615  	// If the variable wasn't declared, declare it now. This means any references
 17616  	// to this name will become bound to this symbol after this (since we haven't
 17617  	// run the visit pass yet).
 17618  	if !ok {
 17619  		p.moduleScope.Members[name] = js_ast.ScopeMember{Ref: ref, Loc: logger.Loc{Start: -1}}
 17620  		return ref
 17621  	}
 17622  
 17623  	// If the variable was declared, then it shadows this symbol. The code in
 17624  	// this module will be unable to reference this symbol. However, we must
 17625  	// still add the symbol to the scope so it gets minified (automatically-
 17626  	// generated code may still reference the symbol).
 17627  	p.moduleScope.Generated = append(p.moduleScope.Generated, ref)
 17628  	return ref
 17629  }
 17630  
 17631  // Compute a character frequency histogram for everything that's not a bound
 17632  // symbol. This is used to modify how minified names are generated for slightly
 17633  // better gzip compression. Even though it's a very small win, we still do it
 17634  // because it's simple to do and very cheap to compute.
 17635  func (p *parser) computeCharacterFrequency() *ast.CharFreq {
 17636  	if !p.options.minifyIdentifiers || p.source.Index == runtime.SourceIndex {
 17637  		return nil
 17638  	}
 17639  
 17640  	// Add everything in the file to the histogram
 17641  	charFreq := &ast.CharFreq{}
 17642  	charFreq.Scan(p.source.Contents, 1)
 17643  
 17644  	// Subtract out all comments
 17645  	for _, commentRange := range p.lexer.AllComments {
 17646  		charFreq.Scan(p.source.TextForRange(commentRange), -1)
 17647  	}
 17648  
 17649  	// Subtract out all import paths
 17650  	for _, record := range p.importRecords {
 17651  		if !record.SourceIndex.IsValid() {
 17652  			charFreq.Scan(record.Path.Text, -1)
 17653  		}
 17654  	}
 17655  
 17656  	// Subtract out all symbols that will be minified
 17657  	var visit func(*js_ast.Scope)
 17658  	visit = func(scope *js_ast.Scope) {
 17659  		for _, member := range scope.Members {
 17660  			symbol := &p.symbols[member.Ref.InnerIndex]
 17661  			if symbol.SlotNamespace() != ast.SlotMustNotBeRenamed {
 17662  				charFreq.Scan(symbol.OriginalName, -int32(symbol.UseCountEstimate))
 17663  			}
 17664  		}
 17665  		if scope.Label.Ref != ast.InvalidRef {
 17666  			symbol := &p.symbols[scope.Label.Ref.InnerIndex]
 17667  			if symbol.SlotNamespace() != ast.SlotMustNotBeRenamed {
 17668  				charFreq.Scan(symbol.OriginalName, -int32(symbol.UseCountEstimate)-1)
 17669  			}
 17670  		}
 17671  		for _, child := range scope.Children {
 17672  			visit(child)
 17673  		}
 17674  	}
 17675  	visit(p.moduleScope)
 17676  
 17677  	// Subtract out all properties that will be mangled
 17678  	for _, ref := range p.mangledProps {
 17679  		symbol := &p.symbols[ref.InnerIndex]
 17680  		charFreq.Scan(symbol.OriginalName, -int32(symbol.UseCountEstimate))
 17681  	}
 17682  
 17683  	return charFreq
 17684  }
 17685  
 17686  func (p *parser) generateImportStmt(
 17687  	path string,
 17688  	pathRange logger.Range,
 17689  	imports []string,
 17690  	parts []js_ast.Part,
 17691  	symbols map[string]ast.LocRef,
 17692  	sourceIndex *uint32,
 17693  	copySourceIndex *uint32,
 17694  ) ([]js_ast.Part, uint32) {
 17695  	if pathRange.Len == 0 {
 17696  		isFirst := true
 17697  		for _, it := range symbols {
 17698  			if isFirst || it.Loc.Start < pathRange.Loc.Start {
 17699  				pathRange.Loc = it.Loc
 17700  			}
 17701  			isFirst = false
 17702  		}
 17703  	}
 17704  
 17705  	namespaceRef := p.newSymbol(ast.SymbolOther, "import_"+js_ast.GenerateNonUniqueNameFromPath(path))
 17706  	p.moduleScope.Generated = append(p.moduleScope.Generated, namespaceRef)
 17707  	declaredSymbols := make([]js_ast.DeclaredSymbol, 1+len(imports))
 17708  	clauseItems := make([]js_ast.ClauseItem, len(imports))
 17709  	importRecordIndex := p.addImportRecord(ast.ImportStmt, pathRange, path, nil, 0)
 17710  	if sourceIndex != nil {
 17711  		p.importRecords[importRecordIndex].SourceIndex = ast.MakeIndex32(*sourceIndex)
 17712  	}
 17713  	if copySourceIndex != nil {
 17714  		p.importRecords[importRecordIndex].CopySourceIndex = ast.MakeIndex32(*copySourceIndex)
 17715  	}
 17716  	declaredSymbols[0] = js_ast.DeclaredSymbol{Ref: namespaceRef, IsTopLevel: true}
 17717  
 17718  	// Create per-import information
 17719  	for i, alias := range imports {
 17720  		it := symbols[alias]
 17721  		declaredSymbols[i+1] = js_ast.DeclaredSymbol{Ref: it.Ref, IsTopLevel: true}
 17722  		clauseItems[i] = js_ast.ClauseItem{
 17723  			Alias:    alias,
 17724  			AliasLoc: it.Loc,
 17725  			Name:     ast.LocRef{Loc: it.Loc, Ref: it.Ref},
 17726  		}
 17727  		p.isImportItem[it.Ref] = true
 17728  		p.namedImports[it.Ref] = js_ast.NamedImport{
 17729  			Alias:             alias,
 17730  			AliasLoc:          it.Loc,
 17731  			NamespaceRef:      namespaceRef,
 17732  			ImportRecordIndex: importRecordIndex,
 17733  		}
 17734  	}
 17735  
 17736  	// Append a single import to the end of the file (ES6 imports are hoisted
 17737  	// so we don't need to worry about where the import statement goes)
 17738  	return append(parts, js_ast.Part{
 17739  		DeclaredSymbols:     declaredSymbols,
 17740  		ImportRecordIndices: []uint32{importRecordIndex},
 17741  		Stmts: []js_ast.Stmt{{Loc: pathRange.Loc, Data: &js_ast.SImport{
 17742  			NamespaceRef:      namespaceRef,
 17743  			Items:             &clauseItems,
 17744  			ImportRecordIndex: importRecordIndex,
 17745  			IsSingleLine:      true,
 17746  		}}},
 17747  	}), importRecordIndex
 17748  }
 17749  
 17750  // Sort the keys for determinism
 17751  func sortedKeysOfMapStringLocRef(in map[string]ast.LocRef) []string {
 17752  	keys := make([]string, 0, len(in))
 17753  	for key := range in {
 17754  		keys = append(keys, key)
 17755  	}
 17756  	sort.Strings(keys)
 17757  	return keys
 17758  }
 17759  
 17760  func (p *parser) toAST(before, parts, after []js_ast.Part, hashbang string, directives []string) js_ast.AST {
 17761  	// Insert an import statement for any runtime imports we generated
 17762  	if len(p.runtimeImports) > 0 && !p.options.omitRuntimeForTests {
 17763  		keys := sortedKeysOfMapStringLocRef(p.runtimeImports)
 17764  		sourceIndex := runtime.SourceIndex
 17765  		before, _ = p.generateImportStmt("<runtime>", logger.Range{}, keys, before, p.runtimeImports, &sourceIndex, nil)
 17766  	}
 17767  
 17768  	// Insert an import statement for any jsx runtime imports we generated
 17769  	if len(p.jsxRuntimeImports) > 0 && !p.options.omitJSXRuntimeForTests {
 17770  		keys := sortedKeysOfMapStringLocRef(p.jsxRuntimeImports)
 17771  
 17772  		// Determine the runtime source and whether it's prod or dev
 17773  		path := p.options.jsx.ImportSource
 17774  		if p.options.jsx.Development {
 17775  			path = path + "/jsx-dev-runtime"
 17776  		} else {
 17777  			path = path + "/jsx-runtime"
 17778  		}
 17779  
 17780  		before, _ = p.generateImportStmt(path, logger.Range{}, keys, before, p.jsxRuntimeImports, nil, nil)
 17781  	}
 17782  
 17783  	// Insert an import statement for any legacy jsx imports we generated (i.e., createElement)
 17784  	if len(p.jsxLegacyImports) > 0 && !p.options.omitJSXRuntimeForTests {
 17785  		keys := sortedKeysOfMapStringLocRef(p.jsxLegacyImports)
 17786  		path := p.options.jsx.ImportSource
 17787  		before, _ = p.generateImportStmt(path, logger.Range{}, keys, before, p.jsxLegacyImports, nil, nil)
 17788  	}
 17789  
 17790  	// Insert imports for each glob pattern
 17791  	for _, glob := range p.globPatternImports {
 17792  		symbols := map[string]ast.LocRef{glob.name: {Loc: glob.approximateRange.Loc, Ref: glob.ref}}
 17793  		var importRecordIndex uint32
 17794  		before, importRecordIndex = p.generateImportStmt(helpers.GlobPatternToString(glob.parts), glob.approximateRange, []string{glob.name}, before, symbols, nil, nil)
 17795  		record := &p.importRecords[importRecordIndex]
 17796  		record.AssertOrWith = glob.assertOrWith
 17797  		record.GlobPattern = &ast.GlobPattern{
 17798  			Parts:       glob.parts,
 17799  			ExportAlias: glob.name,
 17800  			Kind:        glob.kind,
 17801  		}
 17802  	}
 17803  
 17804  	// Generated imports are inserted before other code instead of appending them
 17805  	// to the end of the file. Appending them should work fine because JavaScript
 17806  	// import statements are "hoisted" to run before the importing file. However,
 17807  	// some buggy JavaScript toolchains such as the TypeScript compiler convert
 17808  	// ESM into CommonJS by replacing "import" statements inline without doing
 17809  	// any hoisting, which is incorrect. See the following issue for more info:
 17810  	// https://github.com/microsoft/TypeScript/issues/16166. Since JSX-related
 17811  	// imports are present in the generated code when bundling is disabled, and
 17812  	// could therefore be processed by these buggy tools, it's more robust to put
 17813  	// them at the top even though it means potentially reallocating almost the
 17814  	// entire array of parts.
 17815  	if len(before) > 0 {
 17816  		parts = append(before, parts...)
 17817  	}
 17818  	parts = append(parts, after...)
 17819  
 17820  	// Handle import paths after the whole file has been visited because we need
 17821  	// symbol usage counts to be able to remove unused type-only imports in
 17822  	// TypeScript code.
 17823  	keptImportEquals := false
 17824  	removedImportEquals := false
 17825  	partsEnd := 0
 17826  	for partIndex, part := range parts {
 17827  		p.importRecordsForCurrentPart = nil
 17828  		p.declaredSymbols = nil
 17829  
 17830  		result := p.scanForImportsAndExports(part.Stmts)
 17831  		part.Stmts = result.stmts
 17832  		keptImportEquals = keptImportEquals || result.keptImportEquals
 17833  		removedImportEquals = removedImportEquals || result.removedImportEquals
 17834  
 17835  		part.ImportRecordIndices = append(part.ImportRecordIndices, p.importRecordsForCurrentPart...)
 17836  		part.DeclaredSymbols = append(part.DeclaredSymbols, p.declaredSymbols...)
 17837  
 17838  		if len(part.Stmts) > 0 || uint32(partIndex) == js_ast.NSExportPartIndex {
 17839  			if p.moduleScope.ContainsDirectEval && len(part.DeclaredSymbols) > 0 {
 17840  				// If this file contains a direct call to "eval()", all parts that
 17841  				// declare top-level symbols must be kept since the eval'd code may
 17842  				// reference those symbols.
 17843  				part.CanBeRemovedIfUnused = false
 17844  			}
 17845  			parts[partsEnd] = part
 17846  			partsEnd++
 17847  		}
 17848  	}
 17849  	parts = parts[:partsEnd]
 17850  
 17851  	// We need to iterate multiple times if an import-equals statement was
 17852  	// removed and there are more import-equals statements that may be removed.
 17853  	// In the example below, a/b/c should be kept but x/y/z should be removed
 17854  	// (and removal requires multiple passes):
 17855  	//
 17856  	//   import a = foo.a
 17857  	//   import b = a.b
 17858  	//   import c = b.c
 17859  	//
 17860  	//   import x = foo.x
 17861  	//   import y = x.y
 17862  	//   import z = y.z
 17863  	//
 17864  	//   export let bar = c
 17865  	//
 17866  	// This is a smaller version of the general import/export scanning loop above.
 17867  	// We only want to repeat the code that eliminates TypeScript import-equals
 17868  	// statements, not the other code in the loop above.
 17869  	for keptImportEquals && removedImportEquals {
 17870  		keptImportEquals = false
 17871  		removedImportEquals = false
 17872  		partsEnd := 0
 17873  		for partIndex, part := range parts {
 17874  			result := p.scanForUnusedTSImportEquals(part.Stmts)
 17875  			part.Stmts = result.stmts
 17876  			keptImportEquals = keptImportEquals || result.keptImportEquals
 17877  			removedImportEquals = removedImportEquals || result.removedImportEquals
 17878  			if len(part.Stmts) > 0 || uint32(partIndex) == js_ast.NSExportPartIndex {
 17879  				parts[partsEnd] = part
 17880  				partsEnd++
 17881  			}
 17882  		}
 17883  		parts = parts[:partsEnd]
 17884  	}
 17885  
 17886  	// Do a second pass for exported items now that imported items are filled out
 17887  	for _, part := range parts {
 17888  		for _, stmt := range part.Stmts {
 17889  			if s, ok := stmt.Data.(*js_ast.SExportClause); ok {
 17890  				for _, item := range s.Items {
 17891  					// Mark re-exported imports as such
 17892  					if namedImport, ok := p.namedImports[item.Name.Ref]; ok {
 17893  						namedImport.IsExported = true
 17894  						p.namedImports[item.Name.Ref] = namedImport
 17895  					}
 17896  				}
 17897  			}
 17898  		}
 17899  	}
 17900  
 17901  	// Analyze cross-part dependencies for tree shaking and code splitting
 17902  	{
 17903  		// Map locals to parts
 17904  		p.topLevelSymbolToParts = make(map[ast.Ref][]uint32)
 17905  		for partIndex, part := range parts {
 17906  			for _, declared := range part.DeclaredSymbols {
 17907  				if declared.IsTopLevel {
 17908  					// If this symbol was merged, use the symbol at the end of the
 17909  					// linked list in the map. This is the case for multiple "var"
 17910  					// declarations with the same name, for example.
 17911  					ref := declared.Ref
 17912  					for p.symbols[ref.InnerIndex].Link != ast.InvalidRef {
 17913  						ref = p.symbols[ref.InnerIndex].Link
 17914  					}
 17915  					p.topLevelSymbolToParts[ref] = append(
 17916  						p.topLevelSymbolToParts[ref], uint32(partIndex))
 17917  				}
 17918  			}
 17919  		}
 17920  
 17921  		// Pulling in the exports of this module always pulls in the export part
 17922  		p.topLevelSymbolToParts[p.exportsRef] = append(p.topLevelSymbolToParts[p.exportsRef], js_ast.NSExportPartIndex)
 17923  	}
 17924  
 17925  	// Make a wrapper symbol in case we need to be wrapped in a closure
 17926  	wrapperRef := p.newSymbol(ast.SymbolOther, "require_"+p.source.IdentifierName)
 17927  
 17928  	// Assign slots to symbols in nested scopes. This is some precomputation for
 17929  	// the symbol renaming pass that will happen later in the linker. It's done
 17930  	// now in the parser because we want it to be done in parallel per file and
 17931  	// we're already executing code in a dedicated goroutine for this file.
 17932  	var nestedScopeSlotCounts ast.SlotCounts
 17933  	if p.options.minifyIdentifiers {
 17934  		nestedScopeSlotCounts = renamer.AssignNestedScopeSlots(p.moduleScope, p.symbols)
 17935  	}
 17936  
 17937  	exportsKind := js_ast.ExportsNone
 17938  	usesExportsRef := p.symbols[p.exportsRef.InnerIndex].UseCountEstimate > 0
 17939  	usesModuleRef := p.symbols[p.moduleRef.InnerIndex].UseCountEstimate > 0
 17940  
 17941  	if p.esmExportKeyword.Len > 0 || p.esmImportMeta.Len > 0 || p.topLevelAwaitKeyword.Len > 0 {
 17942  		exportsKind = js_ast.ExportsESM
 17943  	} else if usesExportsRef || usesModuleRef || p.hasTopLevelReturn {
 17944  		exportsKind = js_ast.ExportsCommonJS
 17945  	} else {
 17946  		// If this module has no exports, try to determine what kind of module it
 17947  		// is by looking at node's "type" field in "package.json" and/or whether
 17948  		// the file extension is ".mjs"/".mts" or ".cjs"/".cts".
 17949  		switch {
 17950  		case p.options.moduleTypeData.Type.IsCommonJS():
 17951  			// ".cjs" or ".cts" or ("type: commonjs" and (".js" or ".jsx" or ".ts" or ".tsx"))
 17952  			exportsKind = js_ast.ExportsCommonJS
 17953  
 17954  		case p.options.moduleTypeData.Type.IsESM():
 17955  			// ".mjs" or ".mts" or ("type: module" and (".js" or ".jsx" or ".ts" or ".tsx"))
 17956  			exportsKind = js_ast.ExportsESM
 17957  
 17958  		default:
 17959  			// Treat unknown modules containing an import statement as ESM. Otherwise
 17960  			// the bundler will treat this file as CommonJS if it's imported and ESM
 17961  			// if it's not imported.
 17962  			if p.esmImportStatementKeyword.Len > 0 {
 17963  				exportsKind = js_ast.ExportsESM
 17964  			}
 17965  		}
 17966  	}
 17967  
 17968  	return js_ast.AST{
 17969  		Parts:                           parts,
 17970  		ModuleTypeData:                  p.options.moduleTypeData,
 17971  		ModuleScope:                     p.moduleScope,
 17972  		CharFreq:                        p.computeCharacterFrequency(),
 17973  		Symbols:                         p.symbols,
 17974  		ExportsRef:                      p.exportsRef,
 17975  		ModuleRef:                       p.moduleRef,
 17976  		WrapperRef:                      wrapperRef,
 17977  		Hashbang:                        hashbang,
 17978  		Directives:                      directives,
 17979  		NamedImports:                    p.namedImports,
 17980  		NamedExports:                    p.namedExports,
 17981  		TSEnums:                         p.tsEnums,
 17982  		ConstValues:                     p.constValues,
 17983  		ExprComments:                    p.exprComments,
 17984  		NestedScopeSlotCounts:           nestedScopeSlotCounts,
 17985  		TopLevelSymbolToPartsFromParser: p.topLevelSymbolToParts,
 17986  		ExportStarImportRecords:         p.exportStarImportRecords,
 17987  		ImportRecords:                   p.importRecords,
 17988  		ApproximateLineCount:            int32(p.lexer.ApproximateNewlineCount) + 1,
 17989  		MangledProps:                    p.mangledProps,
 17990  		ReservedProps:                   p.reservedProps,
 17991  		ManifestForYarnPnP:              p.manifestForYarnPnP,
 17992  
 17993  		// CommonJS features
 17994  		UsesExportsRef: usesExportsRef,
 17995  		UsesModuleRef:  usesModuleRef,
 17996  		ExportsKind:    exportsKind,
 17997  
 17998  		// ES6 features
 17999  		ExportKeyword:            p.esmExportKeyword,
 18000  		TopLevelAwaitKeyword:     p.topLevelAwaitKeyword,
 18001  		LiveTopLevelAwaitKeyword: p.liveTopLevelAwaitKeyword,
 18002  	}
 18003  }