package js_ast

import (
	
	

	
	
	
)
Every module (i.e. file) is parsed into a separate AST data structure. For efficiency, the parser also resolves all scopes and binds all symbols in the tree. Identifiers in the tree are referenced by a Ref, which is a pointer into the symbol table for the file. The symbol table is stored as a top-level field in the AST so it can be accessed without traversing the tree. For example, a renaming pass can iterate over the symbol table without touching the tree. Parse trees are intended to be immutable. That makes it easy to build an incremental compiler with a "watch" mode that can avoid re-parsing files that have already been parsed. Any passes that operate on an AST after it has been parsed should create a copy of the mutated parts of the tree instead of mutating the original tree.

type L int
If you add a new token, remember to add it to "OpTable" too
Prefix update
Postfix update
Non-associative
Prefix
	{"+", LPrefix, false},
	{"-", LPrefix, false},
	{"~", LPrefix, false},
	{"!", LPrefix, false},
	{"void", LPrefix, true},
	{"typeof", LPrefix, true},
	{"delete", LPrefix, true},
Prefix update
	{"--", LPrefix, false},
	{"++", LPrefix, false},
Postfix update
	{"--", LPostfix, false},
	{"++", LPostfix, false},
Left-associative
	{"+", LAdd, false},
	{"-", LAdd, false},
	{"*", LMultiply, false},
	{"/", LMultiply, false},
	{"%", LMultiply, false},
	{"**", LExponentiation, false}, // Right-associative
	{"<", LCompare, false},
	{"<=", LCompare, false},
	{">", LCompare, false},
	{">=", LCompare, false},
	{"in", LCompare, true},
	{"instanceof", LCompare, true},
	{"<<", LShift, false},
	{">>", LShift, false},
	{">>>", LShift, false},
	{"==", LEquals, false},
	{"!=", LEquals, false},
	{"===", LEquals, false},
	{"!==", LEquals, false},
	{"??", LNullishCoalescing, false},
	{"||", LLogicalOr, false},
	{"&&", LLogicalAnd, false},
	{"|", LBitwiseOr, false},
	{"&", LBitwiseAnd, false},
	{"^", LBitwiseXor, false},
Non-associative
	{",", LComma, false},
Right-associative
	{"=", LAssign, false},
	{"+=", LAssign, false},
	{"-=", LAssign, false},
	{"*=", LAssign, false},
	{"/=", LAssign, false},
	{"%=", LAssign, false},
	{"**=", LAssign, false},
	{"<<=", LAssign, false},
	{">>=", LAssign, false},
	{">>>=", LAssign, false},
	{"|=", LAssign, false},
	{"&=", LAssign, false},
	{"^=", LAssign, false},
	{"??=", LAssign, false},
	{"||=", LAssign, false},
	{"&&=", LAssign, false},
}

type LocRef struct {
	Loc logger.Loc
	Ref Ref
}

type Comment struct {
	Loc  logger.Loc
	Text string
}

type Span struct {
	Text  string
	Range logger.Range
}

type PropertyKind int

const (
	PropertyNormal PropertyKind = iota
	PropertyGet
	PropertySet
	PropertySpread
)

type Property struct {
	TSDecorators []Expr
	Key          Expr
This is omitted for class fields
This is used when parsing a pattern that uses default values: [a = 1] = []; ({a = 1} = {}); It's also used for class fields: class Foo { a = 1 }
This is true if the function is a method
This interface is never called. Its purpose is to encode a variant type in Go's type system.
type B interface{ isBinding() }

type BMissing struct{}

type BIdentifier struct{ Ref Ref }

type BArray struct {
	Items        []ArrayBinding
	HasSpread    bool
	IsSingleLine bool
}

type BObject struct {
	Properties   []PropertyBinding
	IsSingleLine bool
}

func (*BMissing) ()    {}
func (*BIdentifier) () {}
func (*BArray) ()      {}
func (*BObject) ()     {}

type Expr struct {
	Loc  logger.Loc
	Data E
}
This interface is never called. Its purpose is to encode a variant type in Go's type system.
type E interface{ isExpr() }

type EArray struct {
	Items            []Expr
	CommaAfterSpread logger.Loc
	IsSingleLine     bool
	IsParenthesized  bool
}

type EUnary struct {
	Op    OpCode
	Value Expr
}

type EBinary struct {
	Left  Expr
	Right Expr
	Op    OpCode
}

type EBoolean struct{ Value bool }

type ESuper struct{}

type ENull struct{}

type EUndefined struct{}

type EThis struct{}

type ENew struct {
	Target Expr
	Args   []Expr
True if there is a comment containing "@__PURE__" or "#__PURE__" preceding this call expression. See the comment inside ECall for more details.
"a?.b.c" => ".c" is OptionalChainContinue "(a?.b).c" => ".c" is OptionalChainNone
True if there is a comment containing "@__PURE__" or "#__PURE__" preceding this call expression. This is an annotation used for tree shaking, and means that the call can be removed if it's unused. It does not mean the call is pure (e.g. it may still return something different if called twice). Note that the arguments are not considered to be part of the call. If the call itself is removed due to this annotation, the arguments must remain if they have side effects.
If true, this property access is known to be free of side-effects. That means it can be removed if the resulting value isn't used.
If true, this property access is a function that, when called, can be unwrapped if the resulting value is unused. Unwrapping means discarding the call target but keeping any arguments with side effects.
	CallCanBeUnwrappedIfUnused bool
}

func ( *EDot) ( *EDot) bool {
	return .OptionalChain == .OptionalChain &&
		.CanBeRemovedIfUnused == .CanBeRemovedIfUnused &&
		.CallCanBeUnwrappedIfUnused == .CallCanBeUnwrappedIfUnused
}

type EIndex struct {
	Target        Expr
	Index         Expr
	OptionalChain OptionalChain
}

func ( *EIndex) ( *EIndex) bool {
	return .OptionalChain == .OptionalChain
}

type EArrow struct {
	Args []Arg
	Body FnBody

	IsAsync    bool
	HasRestArg bool
	PreferExpr bool // Use shorthand if true and "Body" is a single return statement
}

type EFunction struct{ Fn Fn }

type EClass struct{ Class Class }

type EIdentifier struct {
	Ref Ref
If we're inside a "with" statement, this identifier may be a property access. In that case it would be incorrect to remove this identifier since the property access may be a getter or setter with side effects.
If true, this identifier is known to not have a side effect (i.e. to not throw an exception) when referenced. If false, this identifier may or may not have side effects when referenced. This is used to allow the removal of known globals such as "Object" if they aren't used.
If true, this identifier represents a function that, when called, can be unwrapped if the resulting value is unused. Unwrapping means discarding the call target but keeping any arguments with side effects.
This is similar to an EIdentifier but it represents a reference to an ES6 import item. Depending on how the code is linked, the file containing this EImportIdentifier may or may not be in the same module group as the file it was imported from. If it's the same module group than we can just merge the import item symbol with the corresponding symbol that was imported, effectively renaming them to be the same thing and statically binding them together. But if it's a different module group, then the import must be dynamically evaluated using a property access off the corresponding namespace symbol, which represents the result of a require() call. It's stored as a separate type so it's not easy to confuse with a plain identifier. For example, it'd be bad if code trying to convert "{x: x}" into "{x}" shorthand syntax wasn't aware that the "x" in this case is actually "{x: importedNamespace.x}". This separate type forces code to opt-in to doing this instead of opt-out.
type EImportIdentifier struct {
	Ref Ref
If true, this was originally an identifier expression such as "foo". If false, this could potentially have been a member access expression such as "ns.foo" off of an imported namespace object.
This is similar to EIdentifier but it represents class-private fields and methods. It can be used where computed properties can be used, such as EIndex and Property.
This is used for both strings and no-substitution template literals to reduce the number of cases that need to be checked for string optimization code
type EString struct {
	Value          []uint16
	LegacyOctalLoc logger.Loc
	PreferTemplate bool
}

type TemplatePart struct {
	Value   Expr
	TailLoc logger.Loc
	Tail    []uint16
	TailRaw string // This is only filled out for tagged template literals
}

type ETemplate struct {
	Tag            *Expr
	Head           []uint16
	HeadRaw        string // This is only filled out for tagged template literals
	Parts          []TemplatePart
	LegacyOctalLoc logger.Loc
}

type ERegExp struct{ Value string }

type EAwait struct {
	Value Expr
}

type EYield struct {
	Value  *Expr
	IsStar bool
}

type EIf struct {
	Test Expr
	Yes  Expr
	No   Expr
}

type ERequire struct {
	ImportRecordIndex uint32
}

type ERequireResolve struct {
	ImportRecordIndex uint32
}

type EImport struct {
	Expr              Expr
	ImportRecordIndex ast.Index32
Comments inside "import()" expressions have special meaning for Webpack. Preserving comments inside these expressions makes it possible to use esbuild as a TypeScript-to-JavaScript frontend for Webpack to improve performance. We intentionally do not interpret these comments in esbuild because esbuild is not Webpack. But we do preserve them since doing so is harmless, easy to maintain, and useful to people. See the Webpack docs for more info: https://webpack.js.org/api/module-methods/#magic-comments.
	LeadingInteriorComments []Comment
}

func (*EArray) ()             {}
func (*EUnary) ()             {}
func (*EBinary) ()            {}
func (*EBoolean) ()           {}
func (*ESuper) ()             {}
func (*ENull) ()              {}
func (*EUndefined) ()         {}
func (*EThis) ()              {}
func (*ENew) ()               {}
func (*ENewTarget) ()         {}
func (*EImportMeta) ()        {}
func (*ECall) ()              {}
func (*EDot) ()               {}
func (*EIndex) ()             {}
func (*EArrow) ()             {}
func (*EFunction) ()          {}
func (*EClass) ()             {}
func (*EIdentifier) ()        {}
func (*EImportIdentifier) ()  {}
func (*EPrivateIdentifier) () {}
func (*EJSXElement) ()        {}
func (*EMissing) ()           {}
func (*ENumber) ()            {}
func (*EBigInt) ()            {}
func (*EObject) ()            {}
func (*ESpread) ()            {}
func (*EString) ()            {}
func (*ETemplate) ()          {}
func (*ERegExp) ()            {}
func (*EAwait) ()             {}
func (*EYield) ()             {}
func (*EIf) ()                {}
func (*ERequire) ()           {}
func (*ERequireResolve) ()    {}
func (*EImport) ()            {}

func ( Expr) bool {
	switch e := .Data.(type) {
	case *EDot:
		return .OptionalChain != OptionalChainNone
	case *EIndex:
		return .OptionalChain != OptionalChainNone
	case *ECall:
		return .OptionalChain != OptionalChainNone
	}
	return false
}

func ( Expr,  Expr) Expr {
	return Expr{Loc: .Loc, Data: &EBinary{Op: BinOpAssign, Left: , Right: }}
}

func ( Expr,  Expr) Stmt {
	return Stmt{Loc: .Loc, Data: &SExpr{Value: Assign(, )}}
}
Wraps the provided expression in the "!" prefix operator. The expression will potentially be simplified to avoid generating unnecessary extra "!" operators. For example, calling this with "!!x" will return "!x" instead of returning "!!!x".
func ( Expr) Expr {
	if ,  := MaybeSimplifyNot();  {
		return 
	}
	return Expr{Loc: .Loc, Data: &EUnary{Op: UnOpNot, Value: }}
}
The given "expr" argument should be the operand of a "!" prefix operator (i.e. the "x" in "!x"). This returns a simplified expression for the whole operator (i.e. the "!x") if it can be simplified, or false if not. It's separate from "Not()" above to avoid allocation on failure in case that is undesired.
func ( Expr) (Expr, bool) {
	switch e := .Data.(type) {
	case *ENull, *EUndefined:
		return Expr{Loc: .Loc, Data: &EBoolean{Value: true}}, true

	case *EBoolean:
		return Expr{Loc: .Loc, Data: &EBoolean{Value: !.Value}}, true

	case *ENumber:
		return Expr{Loc: .Loc, Data: &EBoolean{Value: .Value == 0 || math.IsNaN(.Value)}}, true

	case *EBigInt:
		return Expr{Loc: .Loc, Data: &EBoolean{Value: .Value == "0"}}, true

	case *EString:
		return Expr{Loc: .Loc, Data: &EBoolean{Value: len(.Value) == 0}}, true

	case *EFunction, *EArrow, *ERegExp:
		return Expr{Loc: .Loc, Data: &EBoolean{Value: false}}, true

"!!!a" => "!a"
		if .Op == UnOpNot && IsBooleanValue(.Value) {
			return .Value, true
		}

Make sure that these transformations are all safe for special values. For example, "!(a < b)" is not the same as "a >= b" if a and/or b are NaN (or undefined, or null, or possibly other problem cases too).
		switch .Op {
"!(a == b)" => "a != b"
			.Op = BinOpLooseNe
			return , true

"!(a != b)" => "a == b"
			.Op = BinOpLooseEq
			return , true

"!(a === b)" => "a !== b"
			.Op = BinOpStrictNe
			return , true

"!(a !== b)" => "a === b"
			.Op = BinOpStrictEq
			return , true

"!(a, b)" => "a, !b"
			.Right = Not(.Right)
			return , true
		}
	}

	return Expr{}, false
}

func ( Expr) bool {
	switch e := .Data.(type) {
	case *EBoolean:
		return true

	case *EIf:
		return (.Yes) && (.No)

	case *EUnary:
		return .Op == UnOpNot || .Op == UnOpDelete

	case *EBinary:
		switch .Op {
		case BinOpStrictEq, BinOpStrictNe, BinOpLooseEq, BinOpLooseNe,
			BinOpLt, BinOpGt, BinOpLe, BinOpGe,
			BinOpInstanceof, BinOpIn:
			return true

		case BinOpLogicalOr, BinOpLogicalAnd:
			return (.Left) && (.Right)

		case BinOpNullishCoalescing:
			return (.Left)
		}
	}

	return false
}

func ( Expr) bool {
	switch e := .Data.(type) {
	case *ENumber:
		return true

	case *EIf:
		return (.Yes) && (.No)

	case *EUnary:
		switch .Op {
		case UnOpPos, UnOpNeg, UnOpCpl, UnOpPreDec, UnOpPreInc, UnOpPostDec, UnOpPostInc:
			return true
		}

	case *EBinary:
		switch .Op {
		case BinOpAdd:
			return (.Left) && (.Right)

		case BinOpSub, BinOpMul, BinOpDiv, BinOpRem,
			BinOpBitwiseAnd, BinOpBitwiseOr, BinOpBitwiseXor,
			BinOpShl, BinOpShr, BinOpUShr:
			return true

		case BinOpSubAssign, BinOpMulAssign, BinOpDivAssign, BinOpRemAssign,
			BinOpBitwiseAndAssign, BinOpBitwiseOrAssign, BinOpBitwiseXorAssign,
			BinOpShlAssign, BinOpShrAssign, BinOpUShrAssign:

		case BinOpAssign, BinOpComma:
			return (.Right)
		}
	}

	return false
}

func ( Expr) bool {
	switch e := .Data.(type) {
	case *EString:
		return true

	case *ETemplate:
		return .Tag == nil

	case *EIf:
		return (.Yes) && (.No)

	case *EUnary:
		return .Op == UnOpTypeof

	case *EBinary:
		switch .Op {
		case BinOpAdd:
			return (.Left) || (.Right)

		case BinOpAssign, BinOpAddAssign, BinOpComma:
			return IsNumericValue(.Right)
		}
	}

	return false
}
The goal of this function is to "rotate" the AST if it's possible to use the left-associative property of the operator to avoid unnecessary parentheses. When using this, make absolutely sure that the operator is actually associative. For example, the "-" operator is not associative for floating-point numbers.
"(a, b) op c" => "a, b op c"
	if ,  := .Data.(*EBinary);  && .Op == BinOpComma {
		.Right = (, .Right, )
		return 
	}
"a op (b op c)" => "(a op b) op c" "a op (b op (c op d))" => "((a op b) op c) op d"
	if ,  := .Data.(*EBinary);  && .Op ==  {
		return (
			,
			(, , .Left),
			.Right,
		)
	}
"a op b" => "a op b" "(a op b) op c" => "(a op b) op c"
	return Expr{Loc: .Loc, Data: &EBinary{Op: , Left: , Right: }}
}

func ( Expr,  Expr) Expr {
	return Expr{Loc: .Loc, Data: &EBinary{Op: BinOpComma, Left: , Right: }}
}

func ( []Expr) Expr {
	 := [0]
	for ,  := range [1:] {
		 = JoinWithComma(, )
	}
	return 
}

type ExprOrStmt struct {
	Expr *Expr
	Stmt *Stmt
}

type Stmt struct {
	Loc  logger.Loc
	Data S
}
This interface is never called. Its purpose is to encode a variant type in Go's type system.
type S interface{ isStmt() }

type SBlock struct {
	Stmts []Stmt
}

type SEmpty struct{}
This is a stand-in for a TypeScript type declaration
type STypeScript struct{}

type SComment struct {
	Text string
}

type SDebugger struct{}

type SDirective struct {
	Value          []uint16
	LegacyOctalLoc logger.Loc
}

type SExportClause struct {
	Items        []ClauseItem
	IsSingleLine bool
}

type SExportFrom struct {
	Items             []ClauseItem
	NamespaceRef      Ref
	ImportRecordIndex uint32
	IsSingleLine      bool
}

type SExportDefault struct {
	DefaultName LocRef
	Value       ExprOrStmt // May be a SFunction or SClass
}

type ExportStarAlias struct {
	Loc logger.Loc
Although this alias name starts off as being the same as the statement's namespace symbol, it may diverge if the namespace symbol name is minified. The original alias name is preserved here to avoid this scenario.
This is an "export = value;" statement in TypeScript
type SExportEquals struct {
	Value Expr
}
The decision of whether to export an expression using "module.exports" or "export default" is deferred until linking using this statement kind
type SLazyExport struct {
	Value Expr
}

type SExpr struct {
	Value Expr
This is set to true for automatically-generated expressions that should not affect tree shaking. For example, calling a function from the runtime that doesn't have externally-visible side effects.
	DoesNotAffectTreeShaking bool
}

type EnumValue struct {
	Loc   logger.Loc
	Ref   Ref
	Name  []uint16
	Value *Expr
}

type SEnum struct {
	Name     LocRef
	Arg      Ref
	Values   []EnumValue
	IsExport bool
}

type SNamespace struct {
	Name     LocRef
	Arg      Ref
	Stmts    []Stmt
	IsExport bool
}

type SFunction struct {
	Fn       Fn
	IsExport bool
}

type SClass struct {
	Class    Class
	IsExport bool
}

type SLabel struct {
	Name LocRef
	Stmt Stmt
}

type SIf struct {
	Test Expr
	Yes  Stmt
	No   *Stmt
}

type SFor struct {
	Init   *Stmt // May be a SConst, SLet, SVar, or SExpr
	Test   *Expr
	Update *Expr
	Body   Stmt
}

type SForIn struct {
	Init  Stmt // May be a SConst, SLet, SVar, or SExpr
	Value Expr
	Body  Stmt
}

type SForOf struct {
	IsAwait bool
	Init    Stmt // May be a SConst, SLet, SVar, or SExpr
	Value   Expr
	Body    Stmt
}

type SDoWhile struct {
	Body Stmt
	Test Expr
}

type SWhile struct {
	Test Expr
	Body Stmt
}

type SWith struct {
	Value   Expr
	BodyLoc logger.Loc
	Body    Stmt
}

type Catch struct {
	Loc     logger.Loc
	Binding *Binding
	Body    []Stmt
}

type Finally struct {
	Loc   logger.Loc
	Stmts []Stmt
}

type STry struct {
	BodyLoc logger.Loc
	Body    []Stmt
	Catch   *Catch
	Finally *Finally
}

type Case struct {
	Value *Expr
	Body  []Stmt
}

type SSwitch struct {
	Test    Expr
	BodyLoc logger.Loc
	Cases   []Case
}
This object represents all of these types of import statements: import 'path' import {item1, item2} from 'path' import * as ns from 'path' import defaultItem, {item1, item2} from 'path' import defaultItem, * as ns from 'path' Many parts are optional and can be combined in different ways. The only restriction is that you cannot have both a clause and a star namespace.
If this is a star import: This is a Ref for the namespace symbol. The Loc for the symbol is StarLoc. Otherwise: This is an auto-generated Ref for the namespace representing the imported file. In this case StarLoc is nil. The NamespaceRef is used when converting this module to a CommonJS module.
The TypeScript compiler doesn't generate code for "import foo = bar" statements where the import is never used.
	WasTSImportEquals bool
}

type SBreak struct {
	Label *LocRef
}

type SContinue struct {
	Label *LocRef
}

func (*SBlock) ()         {}
func (*SComment) ()       {}
func (*SDebugger) ()      {}
func (*SDirective) ()     {}
func (*SEmpty) ()         {}
func (*STypeScript) ()    {}
func (*SExportClause) ()  {}
func (*SExportFrom) ()    {}
func (*SExportDefault) () {}
func (*SExportStar) ()    {}
func (*SExportEquals) ()  {}
func (*SLazyExport) ()    {}
func (*SExpr) ()          {}
func (*SEnum) ()          {}
func (*SNamespace) ()     {}
func (*SFunction) ()      {}
func (*SClass) ()         {}
func (*SLabel) ()         {}
func (*SIf) ()            {}
func (*SFor) ()           {}
func (*SForIn) ()         {}
func (*SForOf) ()         {}
func (*SDoWhile) ()       {}
func (*SWhile) ()         {}
func (*SWith) ()          {}
func (*STry) ()           {}
func (*SSwitch) ()        {}
func (*SImport) ()        {}
func (*SReturn) ()        {}
func (*SThrow) ()         {}
func (*SLocal) ()         {}
func (*SBreak) ()         {}
func (*SContinue) ()      {}

func ( Stmt) bool {
	if ,  := .Data.(*SExpr);  {
		if ,  := .Value.Data.(*ECall);  {
			if ,  := .Target.Data.(*ESuper);  {
				return true
			}
		}
	}
	return false
}

type ClauseItem struct {
	Alias    string
	AliasLoc logger.Loc
	Name     LocRef
This is the original name of the symbol stored in "Name". It's needed for "SExportClause" statements such as this: export {foo as bar} from 'path' In this case both "foo" and "bar" are aliases because it's a re-export. We need to preserve both aliases in case the symbol is renamed. In this example, "foo" is "OriginalName" and "bar" is "Alias".
An unbound symbol is one that isn't declared in the file it's referenced in. For example, using "window" without declaring it will be unbound.
This has special merging behavior. You're allowed to re-declare these symbols more than once in the same scope. These symbols are also hoisted out of the scope they are declared in to the closest containing function or module scope. These are the symbols with this kind: - Function arguments - Function statements - Variables declared using "var"
There's a weird special case where catch variables declared using a simple identifier (i.e. not a binding pattern) block hoisted variables instead of becoming an error: var e = 0; try { throw 1 } catch (e) { print(e) // 1 var e = 2 print(e) // 2 } print(e) // 0 (since the hoisting stops at the catch block boundary) However, other forms are still a syntax error: try {} catch (e) { let e } try {} catch ({e}) { var e } This symbol is for handling this weird special case.
Generator and async functions are not hoisted, but still have special properties such as being able to overwrite previous functions with the same name
This is the special "arguments" variable inside functions
Classes can merge with TypeScript namespaces.
Labels are in their own namespace
TypeScript enums can merge with TypeScript namespaces and other TypeScript enums.
TypeScript namespaces can merge with classes, functions, TypeScript enums, and other TypeScript namespaces.
In TypeScript, imports are allowed to silently collide with symbols within the module. Presumably this is because the imports may be type-only.
Assigning to a "const" symbol will throw a TypeError at runtime
Files are parsed in parallel for speed. We want to allow each parser to generate symbol IDs that won't conflict with each other. We also want to be able to quickly merge symbol tables from all files into one giant symbol table. We can accomplish both goals by giving each symbol ID two parts: an outer index that is unique to the parser goroutine, and an inner index that increments as the parser generates new symbol IDs. Then a symbol map can be an array of arrays indexed first by outer index, then by inner index. The maps can be merged quickly by creating a single outer array containing all inner arrays from all parsed files.
The linker doesn't report import/export mismatch errors
The printer will replace this import with "undefined"
Note: the order of values in this struct matters to reduce struct size.
This is the name that came from the parser. Printed names may be renamed during minification or to avoid name collisions. Do not use the original name during printing.
This is used for symbols that represent items in the import clause of an ES6 import statement. These should always be referenced by EImportIdentifier instead of an EIdentifier. When this is present, the expression should be printed as a property access off the namespace instead of as a bare identifier. For correctness, this must be stored on the symbol instead of indirectly associated with the Ref for the symbol somehow. In ES6 "flat bundling" mode, re-exported symbols are collapsed using MergeSymbols() and renamed symbols from other files that end up at this symbol must be able to tell if it has a namespace alias.
Used by the parser for single pass parsing. Symbols that have been merged form a linked-list where the last link is the symbol to use. This link is an invalid ref if it's the last link. If this isn't invalid, you need to FollowSymbols to get the real one.
An estimate of the number of uses of this symbol. This is used to detect whether a symbol is used or not. For example, TypeScript imports that are unused must be removed because they are probably type-only imports. This is an estimate and may not be completely accurate due to oversights in the code. But it should always be non-zero when the symbol is used.
This is for generating cross-chunk imports and exports for code splitting.
This is used for minification. Symbols that are declared in sibling scopes can share a name. A good heuristic (from Google Closure Compiler) is to assign names to symbols from sibling scopes in declaration order. That way local variable names are reused in each global function like this, which improves gzip compression: function x(a, b) { ... } function y(a, b, c) { ... } The parser fills this in for symbols inside nested scopes. There are three slot namespaces: regular symbols, label symbols, and private symbols.
Certain symbols must not be renamed or minified. For example, the "arguments" variable is declared by the runtime for every function. Renaming can also break any identifier used inside a "with" statement.
We automatically generate import items for property accesses off of namespace imports. This lets us remove the expensive namespace imports while bundling in many cases, replacing them with a cheap import item instead: import * as ns from 'path' ns.foo() That can often be replaced by this, which avoids needing the namespace: import {foo} from 'path' foo() However, if the import is actually missing then we don't want to report a compile-time error like we do for real import items. This status lets us avoid this. We also need to be able to replace such import items with undefined, which this status is also used for.
The scopes below stop hoisted variables from extending into parent scopes
	ScopeEntry // This is a module, TypeScript enum, or TypeScript namespace
	ScopeFunctionArgs
	ScopeFunctionBody
)

func ( ScopeKind) () bool {
	return  >= ScopeEntry
}

type ScopeMember struct {
	Ref Ref
	Loc logger.Loc
}

type Scope struct {
	Kind      ScopeKind
	Parent    *Scope
	Children  []*Scope
	Members   map[string]ScopeMember
	Generated []Ref
This is used to store the ref of the label symbol for ScopeLabel scopes.
If a scope contains a direct eval() expression, then none of the symbols inside that scope can be renamed. We conservatively assume that the evaluated code might reference anything that it has access to.
This is to help forbid "arguments" inside class body scopes
This could be represented as a "map[Ref]Symbol" but a two-level array was more efficient in profiles. This appears to be because it doesn't involve a hash. This representation also makes it trivial to quickly merge symbol maps from multiple files together. Each file only generates symbols in a single inner array, so you can join the maps together by just make a single outer array containing all of the inner arrays. See the comment on "Ref" for more detail.
	Outer [][]Symbol
}

func ( int) SymbolMap {
	return SymbolMap{make([][]Symbol, )}
}

func ( SymbolMap) ( Ref) *Symbol {
	return &.Outer[.OuterIndex][.InnerIndex]
}

type AST struct {
	ApproximateLineCount  int32
	NestedScopeSlotCounts SlotCounts
	HasLazyExport         bool
This is a list of CommonJS features. When a file uses CommonJS features, it's not a candidate for "flat bundling" and must be wrapped in its own closure.
This is a list of ES6 features. They are ranges instead of booleans so that they can be used in log messages. Check to see if "Len > 0".
	ImportKeyword        logger.Range // Does not include TypeScript-specific syntax or "import()"
	ExportKeyword        logger.Range // Does not include TypeScript-specific syntax
	TopLevelAwaitKeyword logger.Range

	Hashbang    string
	Directive   string
	URLForCSS   string
	Parts       []Part
	Symbols     []Symbol
	ModuleScope *Scope
	CharFreq    *CharFreq
	ExportsRef  Ref
	ModuleRef   Ref
	WrapperRef  Ref
These are stored at the AST level instead of on individual AST nodes so they can be manipulated efficiently without a full AST traversal
These are used when bundling. They are filled in during the parser pass since we already have to traverse the AST then anyway and the parser pass is conveniently fully parallelized.
This is a histogram of character frequencies for minification
type CharFreq [64]int32

func ( *CharFreq) ( string,  int32) {
	if  == 0 {
		return
	}
This matches the order in "DefaultNameMinifier"
	for ,  := 0, len();  < ; ++ {
		 := []
		switch {
		case  >= 'a' &&  <= 'z':
			(*)[-'a'] += 
		case  >= 'A' &&  <= 'Z':
			(*)[-('A'-26)] += 
		case  >= '0' &&  <= '9':
			(*)[+(52-'0')] += 
		case  == '_':
			(*)[62] += 
		case  == '$':
			(*)[63] += 
		}
	}
}

func ( *CharFreq) ( *CharFreq) {
	for  := 0;  < 64; ++ {
		(*)[] += (*)[]
	}
}

type NameMinifier struct {
	head string
	tail string
}

var DefaultNameMinifier = NameMinifier{
	head: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$",
	tail: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_$",
}

type charAndCount struct {
	index byte
	count int32
	char  string
}
This type is just so we can use Go's native sort function
type charAndCountArray []charAndCount

func ( charAndCountArray) () int          { return len() }
func ( charAndCountArray) ( int,  int) { [], [] = [], [] }

func ( charAndCountArray) ( int,  int) bool {
	 := []
	 := []
	return .count > .count || (.count == .count && .index < .index)
}

Sort the histogram in descending order by count
	 := make(charAndCountArray, 64)
	for  := 0;  < len(DefaultNameMinifier.tail); ++ {
		[] = charAndCount{
			char:  DefaultNameMinifier.tail[ : +1],
			index: byte(),
			count: [],
		}
	}
	sort.Sort()
Compute the identifier start and identifier continue sequences
	 := NameMinifier{}
	for ,  := range  {
		if .char < "0" || .char > "9" {
			.head += .char
		}
		.tail += .char
	}
	return 
}

func ( *NameMinifier) ( int) string {
	 :=  % 54
	 := .head[ : +1]
	 =  / 54

	for  > 0 {
		--
		 :=  % 64
		 += .tail[ : +1]
		 =  / 64
	}

	return 
}

func ( *AST) () bool {
	return .UsesCommonJSExports() || .HasTopLevelReturn
}

func ( *AST) () bool {
	return .UsesExportsRef || .UsesModuleRef
}

func ( *AST) () bool {
	return .ImportKeyword.Len > 0 || .ExportKeyword.Len > 0 || .TopLevelAwaitKeyword.Len > 0
}

It's useful to flag exported imports because if they are in a TypeScript file, we can't tell if they are a type or a value.
Each file is made up of multiple parts, and each part consists of one or more top-level statements. Parts are used for tree shaking and code splitting analysis. Individual parts of a file can be discarded by tree shaking and can be assigned to separate chunks (i.e. output files) by code splitting.
type Part struct {
	Stmts  []Stmt
	Scopes []*Scope
Each is an index into the file-level import record list
All symbols that are declared in this part. Note that a given symbol may have multiple declarations, and so may end up being declared in multiple parts (e.g. multiple "var" declarations with the same name). Also note that this list isn't deduplicated and may contain duplicates.
An estimate of the number of uses of all symbols used within this part.
The indices of the other parts in this file that are needed if this part is needed.
If true, this part can be removed if none of the declared symbols are used. If the file containing this part is imported, then all parts that don't have this flag enabled must be included.
If true, this is the automatically-generated part for this file's ES6 exports. It may hold the "var exports = {};" statement and also the "__export(exports, { ... })" call to initialize the getters.
This is used for generated parts that we don't want to be present if they aren't needed. This enables tree shaking for these parts even if global tree shaking isn't enabled.
Returns the canonical ref that represents the ref for the provided symbol. This may not be the provided ref if the symbol has been merged with another symbol.
func ( SymbolMap,  Ref) Ref {
	 := .Get()
	if .Link == InvalidRef {
		return 
	}

	 := (, .Link)
Only write if needed to avoid concurrent map update hazards
	if .Link !=  {
		.Link = 
	}

	return 
}
Use this before calling "FollowSymbols" from separate threads to avoid concurrent map update hazards. In Go, mutating a map is not threadsafe but reading from a map is. Calling "FollowAllSymbols" first ensures that all mutation is done up front.
func ( SymbolMap) {
	for ,  := range .Outer {
		for  := range  {
			FollowSymbols(, Ref{uint32(), uint32()})
		}
	}
}
Makes "old" point to "new" by joining the linked lists for the two symbols together. That way "FollowSymbols" on both "old" and "new" will result in the same ref.
func ( SymbolMap,  Ref,  Ref) Ref {
	if  ==  {
		return 
	}

	 := .Get()
	if .Link != InvalidRef {
		.Link = (, .Link, )
		return .Link
	}

	 := .Get()
	if .Link != InvalidRef {
		.Link = (, , .Link)
		return .Link
	}

	.Link = 
	.UseCountEstimate += .UseCountEstimate
	if .MustNotBeRenamed {
		.OriginalName = .OriginalName
		.MustNotBeRenamed = true
	}
	return 
}
For readability, the names of certain automatically-generated symbols are derived from the file name. For example, instead of the CommonJS wrapper for a file being called something like "require273" it can be called something like "require_react" instead. This function generates the part of these identifiers that's specific to the file path. It can take both an absolute path (OS-specific) and a path in the source code (OS-independent). Note that these generated names do not at all relate to the correctness of the code as far as avoiding symbol name collisions. These names still go through the renaming logic that all other symbols go through to avoid name collisions.
Get the file name without the extension
If the name is "index", use the directory name instead. This is because many packages in npm use the file name "index.js" because it triggers node's implicit module resolution rules that allows you to import it by just naming the directory.
	if  == "index" {
		, ,  := logger.PlatformIndependentPathDirBaseExt()
		if  != "" {
			 = 
		}
	}

	return EnsureValidIdentifier()
}

Convert it to an ASCII identifier. Note: If you change this to a non-ASCII identifier, you're going to potentially cause trouble with non-BMP code points in target environments that don't support bracketed Unicode escapes.
	 := []byte{}
	 := false
	for ,  := range  {
		if ( >= 'a' &&  <= 'z') || ( >= 'A' &&  <= 'Z') || (len() > 0 &&  >= '0' &&  <= '9') {
			if  {
				 = append(, '_')
				 = false
			}
			 = append(, byte())
		} else if len() > 0 {
			 = true
		}
	}
Make sure the name isn't empty
	if len() == 0 {
		return "_"
	}
	return string()