github.com/evanw/esbuild@v0.21.4/internal/js_ast/js_ast.go (about) 1 package js_ast 2 3 import ( 4 "strconv" 5 6 "github.com/evanw/esbuild/internal/ast" 7 "github.com/evanw/esbuild/internal/logger" 8 ) 9 10 // Every module (i.e. file) is parsed into a separate AST data structure. For 11 // efficiency, the parser also resolves all scopes and binds all symbols in the 12 // tree. 13 // 14 // Identifiers in the tree are referenced by a Ref, which is a pointer into the 15 // symbol table for the file. The symbol table is stored as a top-level field 16 // in the AST so it can be accessed without traversing the tree. For example, 17 // a renaming pass can iterate over the symbol table without touching the tree. 18 // 19 // Parse trees are intended to be immutable. That makes it easy to build an 20 // incremental compiler with a "watch" mode that can avoid re-parsing files 21 // that have already been parsed. Any passes that operate on an AST after it 22 // has been parsed should create a copy of the mutated parts of the tree 23 // instead of mutating the original tree. 24 25 type L uint8 26 27 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence 28 const ( 29 LLowest L = iota 30 LComma 31 LSpread 32 LYield 33 LAssign 34 LConditional 35 LNullishCoalescing 36 LLogicalOr 37 LLogicalAnd 38 LBitwiseOr 39 LBitwiseXor 40 LBitwiseAnd 41 LEquals 42 LCompare 43 LShift 44 LAdd 45 LMultiply 46 LExponentiation 47 LPrefix 48 LPostfix 49 LNew 50 LCall 51 LMember 52 ) 53 54 type OpCode uint8 55 56 func (op OpCode) IsPrefix() bool { 57 return op < UnOpPostDec 58 } 59 60 func (op OpCode) UnaryAssignTarget() AssignTarget { 61 if op >= UnOpPreDec && op <= UnOpPostInc { 62 return AssignTargetUpdate 63 } 64 return AssignTargetNone 65 } 66 67 func (op OpCode) IsLeftAssociative() bool { 68 return op >= BinOpAdd && op < BinOpComma && op != BinOpPow 69 } 70 71 func (op OpCode) IsRightAssociative() bool { 72 return op >= BinOpAssign || op == BinOpPow 73 } 74 75 func (op OpCode) BinaryAssignTarget() AssignTarget { 76 if op == BinOpAssign { 77 return AssignTargetReplace 78 } 79 if op > BinOpAssign { 80 return AssignTargetUpdate 81 } 82 return AssignTargetNone 83 } 84 85 func (op OpCode) IsShortCircuit() bool { 86 switch op { 87 case BinOpLogicalOr, BinOpLogicalOrAssign, 88 BinOpLogicalAnd, BinOpLogicalAndAssign, 89 BinOpNullishCoalescing, BinOpNullishCoalescingAssign: 90 return true 91 } 92 return false 93 } 94 95 type AssignTarget uint8 96 97 const ( 98 AssignTargetNone AssignTarget = iota 99 AssignTargetReplace // "a = b" 100 AssignTargetUpdate // "a += b" 101 ) 102 103 // If you add a new token, remember to add it to "OpTable" too 104 const ( 105 // Prefix 106 UnOpPos OpCode = iota 107 UnOpNeg 108 UnOpCpl 109 UnOpNot 110 UnOpVoid 111 UnOpTypeof 112 UnOpDelete 113 114 // Prefix update 115 UnOpPreDec 116 UnOpPreInc 117 118 // Postfix update 119 UnOpPostDec 120 UnOpPostInc 121 122 // Left-associative 123 BinOpAdd 124 BinOpSub 125 BinOpMul 126 BinOpDiv 127 BinOpRem 128 BinOpPow 129 BinOpLt 130 BinOpLe 131 BinOpGt 132 BinOpGe 133 BinOpIn 134 BinOpInstanceof 135 BinOpShl 136 BinOpShr 137 BinOpUShr 138 BinOpLooseEq 139 BinOpLooseNe 140 BinOpStrictEq 141 BinOpStrictNe 142 BinOpNullishCoalescing 143 BinOpLogicalOr 144 BinOpLogicalAnd 145 BinOpBitwiseOr 146 BinOpBitwiseAnd 147 BinOpBitwiseXor 148 149 // Non-associative 150 BinOpComma 151 152 // Right-associative 153 BinOpAssign 154 BinOpAddAssign 155 BinOpSubAssign 156 BinOpMulAssign 157 BinOpDivAssign 158 BinOpRemAssign 159 BinOpPowAssign 160 BinOpShlAssign 161 BinOpShrAssign 162 BinOpUShrAssign 163 BinOpBitwiseOrAssign 164 BinOpBitwiseAndAssign 165 BinOpBitwiseXorAssign 166 BinOpNullishCoalescingAssign 167 BinOpLogicalOrAssign 168 BinOpLogicalAndAssign 169 ) 170 171 type OpTableEntry struct { 172 Text string 173 Level L 174 IsKeyword bool 175 } 176 177 var OpTable = []OpTableEntry{ 178 // Prefix 179 {"+", LPrefix, false}, 180 {"-", LPrefix, false}, 181 {"~", LPrefix, false}, 182 {"!", LPrefix, false}, 183 {"void", LPrefix, true}, 184 {"typeof", LPrefix, true}, 185 {"delete", LPrefix, true}, 186 187 // Prefix update 188 {"--", LPrefix, false}, 189 {"++", LPrefix, false}, 190 191 // Postfix update 192 {"--", LPostfix, false}, 193 {"++", LPostfix, false}, 194 195 // Left-associative 196 {"+", LAdd, false}, 197 {"-", LAdd, false}, 198 {"*", LMultiply, false}, 199 {"/", LMultiply, false}, 200 {"%", LMultiply, false}, 201 {"**", LExponentiation, false}, // Right-associative 202 {"<", LCompare, false}, 203 {"<=", LCompare, false}, 204 {">", LCompare, false}, 205 {">=", LCompare, false}, 206 {"in", LCompare, true}, 207 {"instanceof", LCompare, true}, 208 {"<<", LShift, false}, 209 {">>", LShift, false}, 210 {">>>", LShift, false}, 211 {"==", LEquals, false}, 212 {"!=", LEquals, false}, 213 {"===", LEquals, false}, 214 {"!==", LEquals, false}, 215 {"??", LNullishCoalescing, false}, 216 {"||", LLogicalOr, false}, 217 {"&&", LLogicalAnd, false}, 218 {"|", LBitwiseOr, false}, 219 {"&", LBitwiseAnd, false}, 220 {"^", LBitwiseXor, false}, 221 222 // Non-associative 223 {",", LComma, false}, 224 225 // Right-associative 226 {"=", LAssign, false}, 227 {"+=", LAssign, false}, 228 {"-=", LAssign, false}, 229 {"*=", LAssign, false}, 230 {"/=", LAssign, false}, 231 {"%=", LAssign, false}, 232 {"**=", LAssign, false}, 233 {"<<=", LAssign, false}, 234 {">>=", LAssign, false}, 235 {">>>=", LAssign, false}, 236 {"|=", LAssign, false}, 237 {"&=", LAssign, false}, 238 {"^=", LAssign, false}, 239 {"??=", LAssign, false}, 240 {"||=", LAssign, false}, 241 {"&&=", LAssign, false}, 242 } 243 244 type Decorator struct { 245 Value Expr 246 AtLoc logger.Loc 247 OmitNewlineAfter bool 248 } 249 250 type PropertyKind uint8 251 252 const ( 253 PropertyField PropertyKind = iota 254 PropertyMethod 255 PropertyGetter 256 PropertySetter 257 PropertyAutoAccessor 258 PropertySpread 259 PropertyDeclareOrAbstract 260 PropertyClassStaticBlock 261 ) 262 263 // This returns true if and only if this property matches the "MethodDefinition" 264 // grammar from the specification. That means it's one of the following forms: 265 // 266 // foo() {} 267 // *foo() {} 268 // async foo() {} 269 // async *foo() {} 270 // get foo() {} 271 // set foo(_) {} 272 // 273 // If this returns true, the "ValueOrNil" field of the property is always an 274 // "EFunction" expression and it is always printed as a method. 275 func (kind PropertyKind) IsMethodDefinition() bool { 276 return kind == PropertyMethod || kind == PropertyGetter || kind == PropertySetter 277 } 278 279 type ClassStaticBlock struct { 280 Block SBlock 281 Loc logger.Loc 282 } 283 284 type PropertyFlags uint8 285 286 const ( 287 PropertyIsComputed PropertyFlags = 1 << iota 288 PropertyIsStatic 289 PropertyWasShorthand 290 PropertyPreferQuotedKey 291 ) 292 293 func (flags PropertyFlags) Has(flag PropertyFlags) bool { 294 return (flags & flag) != 0 295 } 296 297 type Property struct { 298 ClassStaticBlock *ClassStaticBlock 299 300 Key Expr 301 302 // This is omitted for class fields 303 ValueOrNil Expr 304 305 // This is used when parsing a pattern that uses default values: 306 // 307 // [a = 1] = []; 308 // ({a = 1} = {}); 309 // 310 // It's also used for class fields: 311 // 312 // class Foo { a = 1 } 313 // 314 InitializerOrNil Expr 315 316 Decorators []Decorator 317 318 Loc logger.Loc 319 CloseBracketLoc logger.Loc 320 Kind PropertyKind 321 Flags PropertyFlags 322 } 323 324 type PropertyBinding struct { 325 Key Expr 326 Value Binding 327 DefaultValueOrNil Expr 328 Loc logger.Loc 329 CloseBracketLoc logger.Loc 330 IsComputed bool 331 IsSpread bool 332 PreferQuotedKey bool 333 } 334 335 type Arg struct { 336 Binding Binding 337 DefaultOrNil Expr 338 Decorators []Decorator 339 340 // "constructor(public x: boolean) {}" 341 IsTypeScriptCtorField bool 342 } 343 344 type Fn struct { 345 Name *ast.LocRef 346 Args []Arg 347 Body FnBody 348 ArgumentsRef ast.Ref 349 OpenParenLoc logger.Loc 350 351 IsAsync bool 352 IsGenerator bool 353 HasRestArg bool 354 HasIfScope bool 355 356 // See: https://github.com/rollup/rollup/pull/5024 357 HasNoSideEffectsComment bool 358 359 // This is true if the function is a method 360 IsUniqueFormalParameters bool 361 } 362 363 type FnBody struct { 364 Block SBlock 365 Loc logger.Loc 366 } 367 368 type Class struct { 369 Decorators []Decorator 370 Name *ast.LocRef 371 ExtendsOrNil Expr 372 Properties []Property 373 ClassKeyword logger.Range 374 BodyLoc logger.Loc 375 CloseBraceLoc logger.Loc 376 377 // If true, property field initializers cannot be assumed to have no side 378 // effects. For example: 379 // 380 // class Foo { 381 // static set foo(x) { importantSideEffect(x) } 382 // } 383 // class Bar extends Foo { 384 // foo = 1 385 // } 386 // 387 // This happens in TypeScript when "useDefineForClassFields" is disabled 388 // because TypeScript (and esbuild) transforms the above class into this: 389 // 390 // class Foo { 391 // static set foo(x) { importantSideEffect(x); } 392 // } 393 // class Bar extends Foo { 394 // } 395 // Bar.foo = 1; 396 // 397 UseDefineForClassFields bool 398 } 399 400 type ArrayBinding struct { 401 Binding Binding 402 DefaultValueOrNil Expr 403 Loc logger.Loc 404 } 405 406 type Binding struct { 407 Data B 408 Loc logger.Loc 409 } 410 411 // This interface is never called. Its purpose is to encode a variant type in 412 // Go's type system. 413 type B interface{ isBinding() } 414 415 func (*BMissing) isBinding() {} 416 func (*BIdentifier) isBinding() {} 417 func (*BArray) isBinding() {} 418 func (*BObject) isBinding() {} 419 420 type BMissing struct{} 421 422 type BIdentifier struct{ Ref ast.Ref } 423 424 type BArray struct { 425 Items []ArrayBinding 426 CloseBracketLoc logger.Loc 427 HasSpread bool 428 IsSingleLine bool 429 } 430 431 type BObject struct { 432 Properties []PropertyBinding 433 CloseBraceLoc logger.Loc 434 IsSingleLine bool 435 } 436 437 type Expr struct { 438 Data E 439 Loc logger.Loc 440 } 441 442 // This interface is never called. Its purpose is to encode a variant type in 443 // Go's type system. 444 type E interface{ isExpr() } 445 446 func (*EArray) isExpr() {} 447 func (*EUnary) isExpr() {} 448 func (*EBinary) isExpr() {} 449 func (*EBoolean) isExpr() {} 450 func (*ESuper) isExpr() {} 451 func (*ENull) isExpr() {} 452 func (*EUndefined) isExpr() {} 453 func (*EThis) isExpr() {} 454 func (*ENew) isExpr() {} 455 func (*ENewTarget) isExpr() {} 456 func (*EImportMeta) isExpr() {} 457 func (*ECall) isExpr() {} 458 func (*EDot) isExpr() {} 459 func (*EIndex) isExpr() {} 460 func (*EArrow) isExpr() {} 461 func (*EFunction) isExpr() {} 462 func (*EClass) isExpr() {} 463 func (*EIdentifier) isExpr() {} 464 func (*EImportIdentifier) isExpr() {} 465 func (*EPrivateIdentifier) isExpr() {} 466 func (*ENameOfSymbol) isExpr() {} 467 func (*EJSXElement) isExpr() {} 468 func (*EJSXText) isExpr() {} 469 func (*EMissing) isExpr() {} 470 func (*ENumber) isExpr() {} 471 func (*EBigInt) isExpr() {} 472 func (*EObject) isExpr() {} 473 func (*ESpread) isExpr() {} 474 func (*EString) isExpr() {} 475 func (*ETemplate) isExpr() {} 476 func (*ERegExp) isExpr() {} 477 func (*EInlinedEnum) isExpr() {} 478 func (*EAnnotation) isExpr() {} 479 func (*EAwait) isExpr() {} 480 func (*EYield) isExpr() {} 481 func (*EIf) isExpr() {} 482 func (*ERequireString) isExpr() {} 483 func (*ERequireResolveString) isExpr() {} 484 func (*EImportString) isExpr() {} 485 func (*EImportCall) isExpr() {} 486 487 type EArray struct { 488 Items []Expr 489 CommaAfterSpread logger.Loc 490 CloseBracketLoc logger.Loc 491 IsSingleLine bool 492 IsParenthesized bool 493 } 494 495 type EUnary struct { 496 Value Expr 497 Op OpCode 498 499 // The expression "typeof (0, x)" must not become "typeof x" if "x" 500 // is unbound because that could suppress a ReferenceError from "x". 501 // 502 // Also if we know a typeof operator was originally an identifier, then 503 // we know that this typeof operator always has no side effects (even if 504 // we consider the identifier by itself to have a side effect). 505 // 506 // Note that there *is* actually a case where "typeof x" can throw an error: 507 // when "x" is being referenced inside of its TDZ (temporal dead zone). TDZ 508 // checks are not yet handled correctly by esbuild, so this possibility is 509 // currently ignored. 510 WasOriginallyTypeofIdentifier bool 511 512 // Similarly the expression "delete (0, x)" must not become "delete x" 513 // because that syntax is invalid in strict mode. We also need to make sure 514 // we don't accidentally change the return value: 515 // 516 // Returns false: 517 // "var a; delete (a)" 518 // "var a = Object.freeze({b: 1}); delete (a.b)" 519 // "var a = Object.freeze({b: 1}); delete (a?.b)" 520 // "var a = Object.freeze({b: 1}); delete (a['b'])" 521 // "var a = Object.freeze({b: 1}); delete (a?.['b'])" 522 // 523 // Returns true: 524 // "var a; delete (0, a)" 525 // "var a = Object.freeze({b: 1}); delete (true && a.b)" 526 // "var a = Object.freeze({b: 1}); delete (false || a?.b)" 527 // "var a = Object.freeze({b: 1}); delete (null ?? a?.['b'])" 528 // "var a = Object.freeze({b: 1}); delete (true ? a['b'] : a['b'])" 529 // 530 WasOriginallyDeleteOfIdentifierOrPropertyAccess bool 531 } 532 533 type EBinary struct { 534 Left Expr 535 Right Expr 536 Op OpCode 537 } 538 539 type EBoolean struct{ Value bool } 540 541 type EMissing struct{} 542 543 type ESuper struct{} 544 545 type ENull struct{} 546 547 type EUndefined struct{} 548 549 type EThis struct{} 550 551 type ENewTarget struct { 552 Range logger.Range 553 } 554 555 type EImportMeta struct { 556 RangeLen int32 557 } 558 559 // These help reduce unnecessary memory allocations 560 var BMissingShared = &BMissing{} 561 var EMissingShared = &EMissing{} 562 var ENullShared = &ENull{} 563 var ESuperShared = &ESuper{} 564 var EThisShared = &EThis{} 565 var EUndefinedShared = &EUndefined{} 566 var SDebuggerShared = &SDebugger{} 567 var SEmptyShared = &SEmpty{} 568 var STypeScriptShared = &STypeScript{} 569 var STypeScriptSharedWasDeclareClass = &STypeScript{WasDeclareClass: true} 570 571 type ENew struct { 572 Target Expr 573 Args []Expr 574 575 CloseParenLoc logger.Loc 576 IsMultiLine bool 577 578 // True if there is a comment containing "@__PURE__" or "#__PURE__" preceding 579 // this call expression. See the comment inside ECall for more details. 580 CanBeUnwrappedIfUnused bool 581 } 582 583 type CallKind uint8 584 585 const ( 586 NormalCall CallKind = iota 587 DirectEval 588 TargetWasOriginallyPropertyAccess 589 ) 590 591 type OptionalChain uint8 592 593 const ( 594 // "a.b" 595 OptionalChainNone OptionalChain = iota 596 597 // "a?.b" 598 OptionalChainStart 599 600 // "a?.b.c" => ".c" is OptionalChainContinue 601 // "(a?.b).c" => ".c" is OptionalChainNone 602 OptionalChainContinue 603 ) 604 605 type ECall struct { 606 Target Expr 607 Args []Expr 608 CloseParenLoc logger.Loc 609 OptionalChain OptionalChain 610 Kind CallKind 611 IsMultiLine bool 612 613 // True if there is a comment containing "@__PURE__" or "#__PURE__" preceding 614 // this call expression. This is an annotation used for tree shaking, and 615 // means that the call can be removed if it's unused. It does not mean the 616 // call is pure (e.g. it may still return something different if called twice). 617 // 618 // Note that the arguments are not considered to be part of the call. If the 619 // call itself is removed due to this annotation, the arguments must remain 620 // if they have side effects. 621 CanBeUnwrappedIfUnused bool 622 } 623 624 func (a *ECall) HasSameFlagsAs(b *ECall) bool { 625 return a.OptionalChain == b.OptionalChain && 626 a.Kind == b.Kind && 627 a.CanBeUnwrappedIfUnused == b.CanBeUnwrappedIfUnused 628 } 629 630 type EDot struct { 631 Target Expr 632 Name string 633 NameLoc logger.Loc 634 OptionalChain OptionalChain 635 636 // If true, this property access is known to be free of side-effects. That 637 // means it can be removed if the resulting value isn't used. 638 CanBeRemovedIfUnused bool 639 640 // If true, this property access is a function that, when called, can be 641 // unwrapped if the resulting value is unused. Unwrapping means discarding 642 // the call target but keeping any arguments with side effects. 643 CallCanBeUnwrappedIfUnused bool 644 645 // Symbol values are known to not have side effects when used as property 646 // names in class declarations and object literals. 647 IsSymbolInstance bool 648 } 649 650 func (a *EDot) HasSameFlagsAs(b *EDot) bool { 651 return a.OptionalChain == b.OptionalChain && 652 a.CanBeRemovedIfUnused == b.CanBeRemovedIfUnused && 653 a.CallCanBeUnwrappedIfUnused == b.CallCanBeUnwrappedIfUnused && 654 a.IsSymbolInstance == b.IsSymbolInstance 655 } 656 657 type EIndex struct { 658 Target Expr 659 Index Expr 660 CloseBracketLoc logger.Loc 661 OptionalChain OptionalChain 662 663 // If true, this property access is known to be free of side-effects. That 664 // means it can be removed if the resulting value isn't used. 665 CanBeRemovedIfUnused bool 666 667 // If true, this property access is a function that, when called, can be 668 // unwrapped if the resulting value is unused. Unwrapping means discarding 669 // the call target but keeping any arguments with side effects. 670 CallCanBeUnwrappedIfUnused bool 671 672 // Symbol values are known to not have side effects when used as property 673 // names in class declarations and object literals. 674 IsSymbolInstance bool 675 } 676 677 func (a *EIndex) HasSameFlagsAs(b *EIndex) bool { 678 return a.OptionalChain == b.OptionalChain && 679 a.CanBeRemovedIfUnused == b.CanBeRemovedIfUnused && 680 a.CallCanBeUnwrappedIfUnused == b.CallCanBeUnwrappedIfUnused && 681 a.IsSymbolInstance == b.IsSymbolInstance 682 } 683 684 type EArrow struct { 685 Args []Arg 686 Body FnBody 687 688 IsAsync bool 689 HasRestArg bool 690 PreferExpr bool // Use shorthand if true and "Body" is a single return statement 691 692 // See: https://github.com/rollup/rollup/pull/5024 693 HasNoSideEffectsComment bool 694 } 695 696 type EFunction struct{ Fn Fn } 697 698 type EClass struct{ Class Class } 699 700 type EIdentifier struct { 701 Ref ast.Ref 702 703 // If we're inside a "with" statement, this identifier may be a property 704 // access. In that case it would be incorrect to remove this identifier since 705 // the property access may be a getter or setter with side effects. 706 MustKeepDueToWithStmt bool 707 708 // If true, this identifier is known to not have a side effect (i.e. to not 709 // throw an exception) when referenced. If false, this identifier may or may 710 // not have side effects when referenced. This is used to allow the removal 711 // of known globals such as "Object" if they aren't used. 712 CanBeRemovedIfUnused bool 713 714 // If true, this identifier represents a function that, when called, can be 715 // unwrapped if the resulting value is unused. Unwrapping means discarding 716 // the call target but keeping any arguments with side effects. 717 CallCanBeUnwrappedIfUnused bool 718 } 719 720 // This is similar to an EIdentifier but it represents a reference to an ES6 721 // import item. 722 // 723 // Depending on how the code is linked, the file containing this EImportIdentifier 724 // may or may not be in the same module group as the file it was imported from. 725 // 726 // If it's the same module group than we can just merge the import item symbol 727 // with the corresponding symbol that was imported, effectively renaming them 728 // to be the same thing and statically binding them together. 729 // 730 // But if it's a different module group, then the import must be dynamically 731 // evaluated using a property access off the corresponding namespace symbol, 732 // which represents the result of a require() call. 733 // 734 // It's stored as a separate type so it's not easy to confuse with a plain 735 // identifier. For example, it'd be bad if code trying to convert "{x: x}" into 736 // "{x}" shorthand syntax wasn't aware that the "x" in this case is actually 737 // "{x: importedNamespace.x}". This separate type forces code to opt-in to 738 // doing this instead of opt-out. 739 type EImportIdentifier struct { 740 Ref ast.Ref 741 PreferQuotedKey bool 742 743 // If true, this was originally an identifier expression such as "foo". If 744 // false, this could potentially have been a member access expression such 745 // as "ns.foo" off of an imported namespace object. 746 WasOriginallyIdentifier bool 747 } 748 749 // This is similar to EIdentifier but it represents class-private fields and 750 // methods. It can be used where computed properties can be used, such as 751 // EIndex and Property. 752 type EPrivateIdentifier struct { 753 Ref ast.Ref 754 } 755 756 // This represents an internal property name that can be mangled. The symbol 757 // referenced by this expression should be a "SymbolMangledProp" symbol. 758 type ENameOfSymbol struct { 759 Ref ast.Ref 760 HasPropertyKeyComment bool // If true, a preceding comment contains "@__KEY__" 761 } 762 763 type EJSXElement struct { 764 TagOrNil Expr 765 Properties []Property 766 767 // Note: This array may contain nil entries. Be careful about nil entries 768 // when iterating over this array. 769 // 770 // Each nil entry corresponds to the "JSXChildExpression_opt" part of the 771 // grammar (https://facebook.github.io/jsx/#prod-JSXChild): 772 // 773 // JSXChild : 774 // JSXText 775 // JSXElement 776 // JSXFragment 777 // { JSXChildExpression_opt } 778 // 779 // This is the "{}" part in "<a>{}</a>". We allow this because some people 780 // put comments there and then expect to be able to process them from 781 // esbuild's output. These absent AST nodes are completely omitted when 782 // JSX is transformed to JS. They are only present when JSX preservation is 783 // enabled. 784 NullableChildren []Expr 785 786 CloseLoc logger.Loc 787 IsTagSingleLine bool 788 } 789 790 // The JSX specification doesn't say how JSX text is supposed to be interpreted 791 // so our "preserve" JSX transform should reproduce the original source code 792 // verbatim. One reason why this matters is because there is no canonical way 793 // to interpret JSX text (Babel and TypeScript differ in what newlines mean). 794 // Another reason is that some people want to do custom things such as this: 795 // https://github.com/evanw/esbuild/issues/3605 796 type EJSXText struct { 797 Raw string 798 } 799 800 type ENumber struct{ Value float64 } 801 802 type EBigInt struct{ Value string } 803 804 type EObject struct { 805 Properties []Property 806 CommaAfterSpread logger.Loc 807 CloseBraceLoc logger.Loc 808 IsSingleLine bool 809 IsParenthesized bool 810 } 811 812 type ESpread struct{ Value Expr } 813 814 // This is used for both strings and no-substitution template literals to reduce 815 // the number of cases that need to be checked for string optimization code 816 type EString struct { 817 Value []uint16 818 LegacyOctalLoc logger.Loc 819 PreferTemplate bool 820 HasPropertyKeyComment bool // If true, a preceding comment contains "@__KEY__" 821 ContainsUniqueKey bool // If true, this string must not be wrapped 822 } 823 824 type TemplatePart struct { 825 Value Expr 826 TailRaw string // Only use when "TagOrNil" is not nil 827 TailCooked []uint16 // Only use when "TagOrNil" is nil 828 TailLoc logger.Loc 829 } 830 831 type ETemplate struct { 832 TagOrNil Expr 833 HeadRaw string // Only use when "TagOrNil" is not nil 834 HeadCooked []uint16 // Only use when "TagOrNil" is nil 835 Parts []TemplatePart 836 HeadLoc logger.Loc 837 LegacyOctalLoc logger.Loc 838 839 // True if this is a tagged template literal with a comment that indicates 840 // this function call can be removed if the result is unused. Note that the 841 // arguments are not considered to be part of the call. If the call itself 842 // is removed due to this annotation, the arguments must remain if they have 843 // side effects (including the string conversions). 844 CanBeUnwrappedIfUnused bool 845 846 // If the tag is present, it is expected to be a function and is called. If 847 // the tag is a syntactic property access, then the value for "this" in the 848 // function call is the object whose property was accessed (e.g. in "a.b``" 849 // the value for "this" in "a.b" is "a"). We need to ensure that if "a``" 850 // ever becomes "b.c``" later on due to optimizations, it is written as 851 // "(0, b.c)``" to avoid a behavior change. 852 TagWasOriginallyPropertyAccess bool 853 } 854 855 type ERegExp struct{ Value string } 856 857 type EInlinedEnum struct { 858 Value Expr 859 Comment string 860 } 861 862 type AnnotationFlags uint8 863 864 const ( 865 // This is sort of like an IIFE with a "/* @__PURE__ */" comment except it's an 866 // inline annotation on an expression itself without the nested scope. Sometimes 867 // we can't easily introduce a new scope (e.g. if the expression uses "await"). 868 CanBeRemovedIfUnusedFlag AnnotationFlags = 1 << iota 869 ) 870 871 func (flags AnnotationFlags) Has(flag AnnotationFlags) bool { 872 return (flags & flag) != 0 873 } 874 875 type EAnnotation struct { 876 Value Expr 877 Flags AnnotationFlags 878 } 879 880 type EAwait struct { 881 Value Expr 882 } 883 884 type EYield struct { 885 ValueOrNil Expr 886 IsStar bool 887 } 888 889 type EIf struct { 890 Test Expr 891 Yes Expr 892 No Expr 893 } 894 895 type ERequireString struct { 896 ImportRecordIndex uint32 897 CloseParenLoc logger.Loc 898 } 899 900 type ERequireResolveString struct { 901 ImportRecordIndex uint32 902 CloseParenLoc logger.Loc 903 } 904 905 type EImportString struct { 906 ImportRecordIndex uint32 907 CloseParenLoc logger.Loc 908 } 909 910 type EImportCall struct { 911 Expr Expr 912 OptionsOrNil Expr 913 CloseParenLoc logger.Loc 914 } 915 916 type Stmt struct { 917 Data S 918 Loc logger.Loc 919 } 920 921 // This interface is never called. Its purpose is to encode a variant type in 922 // Go's type system. 923 type S interface{ isStmt() } 924 925 func (*SBlock) isStmt() {} 926 func (*SComment) isStmt() {} 927 func (*SDebugger) isStmt() {} 928 func (*SDirective) isStmt() {} 929 func (*SEmpty) isStmt() {} 930 func (*STypeScript) isStmt() {} 931 func (*SExportClause) isStmt() {} 932 func (*SExportFrom) isStmt() {} 933 func (*SExportDefault) isStmt() {} 934 func (*SExportStar) isStmt() {} 935 func (*SExportEquals) isStmt() {} 936 func (*SLazyExport) isStmt() {} 937 func (*SExpr) isStmt() {} 938 func (*SEnum) isStmt() {} 939 func (*SNamespace) isStmt() {} 940 func (*SFunction) isStmt() {} 941 func (*SClass) isStmt() {} 942 func (*SLabel) isStmt() {} 943 func (*SIf) isStmt() {} 944 func (*SFor) isStmt() {} 945 func (*SForIn) isStmt() {} 946 func (*SForOf) isStmt() {} 947 func (*SDoWhile) isStmt() {} 948 func (*SWhile) isStmt() {} 949 func (*SWith) isStmt() {} 950 func (*STry) isStmt() {} 951 func (*SSwitch) isStmt() {} 952 func (*SImport) isStmt() {} 953 func (*SReturn) isStmt() {} 954 func (*SThrow) isStmt() {} 955 func (*SLocal) isStmt() {} 956 func (*SBreak) isStmt() {} 957 func (*SContinue) isStmt() {} 958 959 type SBlock struct { 960 Stmts []Stmt 961 CloseBraceLoc logger.Loc 962 } 963 964 type SEmpty struct{} 965 966 // This is a stand-in for a TypeScript type declaration 967 type STypeScript struct { 968 WasDeclareClass bool 969 } 970 971 type SComment struct { 972 Text string 973 IsLegalComment bool 974 } 975 976 type SDebugger struct{} 977 978 type SDirective struct { 979 Value []uint16 980 LegacyOctalLoc logger.Loc 981 } 982 983 type SExportClause struct { 984 Items []ClauseItem 985 IsSingleLine bool 986 } 987 988 type SExportFrom struct { 989 Items []ClauseItem 990 NamespaceRef ast.Ref 991 ImportRecordIndex uint32 992 IsSingleLine bool 993 } 994 995 type SExportDefault struct { 996 Value Stmt // May be a SExpr or SFunction or SClass 997 DefaultName ast.LocRef 998 } 999 1000 type ExportStarAlias struct { 1001 // Although this alias name starts off as being the same as the statement's 1002 // namespace symbol, it may diverge if the namespace symbol name is minified. 1003 // The original alias name is preserved here to avoid this scenario. 1004 OriginalName string 1005 1006 Loc logger.Loc 1007 } 1008 1009 type SExportStar struct { 1010 Alias *ExportStarAlias 1011 NamespaceRef ast.Ref 1012 ImportRecordIndex uint32 1013 } 1014 1015 // This is an "export = value;" statement in TypeScript 1016 type SExportEquals struct { 1017 Value Expr 1018 } 1019 1020 // The decision of whether to export an expression using "module.exports" or 1021 // "export default" is deferred until linking using this statement kind 1022 type SLazyExport struct { 1023 Value Expr 1024 } 1025 1026 type SExpr struct { 1027 Value Expr 1028 1029 // This is set to true for automatically-generated expressions that are part 1030 // of class syntax lowering. A single class declaration may end up with many 1031 // generated expressions after it (e.g. class field initializations, a call 1032 // to keep the original value of the "name" property). When this happens we 1033 // can't tell that the class is side-effect free anymore because all of these 1034 // methods mutate the class. We use this annotation for that instead. 1035 IsFromClassOrFnThatCanBeRemovedIfUnused bool 1036 } 1037 1038 type EnumValue struct { 1039 ValueOrNil Expr 1040 Name []uint16 1041 Ref ast.Ref 1042 Loc logger.Loc 1043 } 1044 1045 type SEnum struct { 1046 Values []EnumValue 1047 Name ast.LocRef 1048 Arg ast.Ref 1049 IsExport bool 1050 } 1051 1052 type SNamespace struct { 1053 Stmts []Stmt 1054 Name ast.LocRef 1055 Arg ast.Ref 1056 IsExport bool 1057 } 1058 1059 type SFunction struct { 1060 Fn Fn 1061 IsExport bool 1062 } 1063 1064 type SClass struct { 1065 Class Class 1066 IsExport bool 1067 } 1068 1069 type SLabel struct { 1070 Stmt Stmt 1071 Name ast.LocRef 1072 IsSingleLineStmt bool 1073 } 1074 1075 type SIf struct { 1076 Test Expr 1077 Yes Stmt 1078 NoOrNil Stmt 1079 IsSingleLineYes bool 1080 IsSingleLineNo bool 1081 } 1082 1083 type SFor struct { 1084 InitOrNil Stmt // May be a SConst, SLet, SVar, or SExpr 1085 TestOrNil Expr 1086 UpdateOrNil Expr 1087 Body Stmt 1088 IsSingleLineBody bool 1089 } 1090 1091 type SForIn struct { 1092 Init Stmt // May be a SConst, SLet, SVar, or SExpr 1093 Value Expr 1094 Body Stmt 1095 IsSingleLineBody bool 1096 } 1097 1098 type SForOf struct { 1099 Init Stmt // May be a SConst, SLet, SVar, or SExpr 1100 Value Expr 1101 Body Stmt 1102 Await logger.Range 1103 IsSingleLineBody bool 1104 } 1105 1106 type SDoWhile struct { 1107 Body Stmt 1108 Test Expr 1109 } 1110 1111 type SWhile struct { 1112 Test Expr 1113 Body Stmt 1114 IsSingleLineBody bool 1115 } 1116 1117 type SWith struct { 1118 Value Expr 1119 Body Stmt 1120 BodyLoc logger.Loc 1121 IsSingleLineBody bool 1122 } 1123 1124 type Catch struct { 1125 BindingOrNil Binding 1126 Block SBlock 1127 Loc logger.Loc 1128 BlockLoc logger.Loc 1129 } 1130 1131 type Finally struct { 1132 Block SBlock 1133 Loc logger.Loc 1134 } 1135 1136 type STry struct { 1137 Catch *Catch 1138 Finally *Finally 1139 Block SBlock 1140 BlockLoc logger.Loc 1141 } 1142 1143 type Case struct { 1144 ValueOrNil Expr // If this is nil, this is "default" instead of "case" 1145 Body []Stmt 1146 Loc logger.Loc 1147 } 1148 1149 type SSwitch struct { 1150 Test Expr 1151 Cases []Case 1152 BodyLoc logger.Loc 1153 CloseBraceLoc logger.Loc 1154 } 1155 1156 // This object represents all of these types of import statements: 1157 // 1158 // import 'path' 1159 // import {item1, item2} from 'path' 1160 // import * as ns from 'path' 1161 // import defaultItem, {item1, item2} from 'path' 1162 // import defaultItem, * as ns from 'path' 1163 // 1164 // Many parts are optional and can be combined in different ways. The only 1165 // restriction is that you cannot have both a clause and a star namespace. 1166 type SImport struct { 1167 DefaultName *ast.LocRef 1168 Items *[]ClauseItem 1169 StarNameLoc *logger.Loc 1170 1171 // If this is a star import: This is a Ref for the namespace symbol. The Loc 1172 // for the symbol is StarLoc. 1173 // 1174 // Otherwise: This is an auto-generated Ref for the namespace representing 1175 // the imported file. In this case StarLoc is nil. The NamespaceRef is used 1176 // when converting this module to a CommonJS module. 1177 NamespaceRef ast.Ref 1178 1179 ImportRecordIndex uint32 1180 IsSingleLine bool 1181 } 1182 1183 type SReturn struct { 1184 ValueOrNil Expr 1185 } 1186 1187 type SThrow struct { 1188 Value Expr 1189 } 1190 1191 type LocalKind uint8 1192 1193 const ( 1194 LocalVar LocalKind = iota 1195 LocalLet 1196 LocalConst 1197 LocalUsing 1198 LocalAwaitUsing 1199 ) 1200 1201 func (kind LocalKind) IsUsing() bool { 1202 return kind >= LocalUsing 1203 } 1204 1205 type SLocal struct { 1206 Decls []Decl 1207 Kind LocalKind 1208 IsExport bool 1209 1210 // The TypeScript compiler doesn't generate code for "import foo = bar" 1211 // statements where the import is never used. 1212 WasTSImportEquals bool 1213 } 1214 1215 type SBreak struct { 1216 Label *ast.LocRef 1217 } 1218 1219 type SContinue struct { 1220 Label *ast.LocRef 1221 } 1222 1223 type ClauseItem struct { 1224 Alias string 1225 1226 // This is the original name of the symbol stored in "Name". It's needed for 1227 // "SExportClause" statements such as this: 1228 // 1229 // export {foo as bar} from 'path' 1230 // 1231 // In this case both "foo" and "bar" are aliases because it's a re-export. 1232 // We need to preserve both aliases in case the symbol is renamed. In this 1233 // example, "foo" is "OriginalName" and "bar" is "Alias". 1234 OriginalName string 1235 1236 AliasLoc logger.Loc 1237 Name ast.LocRef 1238 } 1239 1240 type Decl struct { 1241 Binding Binding 1242 ValueOrNil Expr 1243 } 1244 1245 type ScopeKind uint8 1246 1247 const ( 1248 ScopeBlock ScopeKind = iota 1249 ScopeWith 1250 ScopeLabel 1251 ScopeClassName 1252 ScopeClassBody 1253 ScopeCatchBinding 1254 1255 // The scopes below stop hoisted variables from extending into parent scopes 1256 ScopeEntry // This is a module, TypeScript enum, or TypeScript namespace 1257 ScopeFunctionArgs 1258 ScopeFunctionBody 1259 ScopeClassStaticInit 1260 ) 1261 1262 func (kind ScopeKind) StopsHoisting() bool { 1263 return kind >= ScopeEntry 1264 } 1265 1266 type ScopeMember struct { 1267 Ref ast.Ref 1268 Loc logger.Loc 1269 } 1270 1271 type Scope struct { 1272 // This will be non-nil if this is a TypeScript "namespace" or "enum" 1273 TSNamespace *TSNamespaceScope 1274 1275 Parent *Scope 1276 Children []*Scope 1277 Members map[string]ScopeMember 1278 Replaced []ScopeMember 1279 Generated []ast.Ref 1280 1281 // The location of the "use strict" directive for ExplicitStrictMode 1282 UseStrictLoc logger.Loc 1283 1284 // This is used to store the ref of the label symbol for ScopeLabel scopes. 1285 Label ast.LocRef 1286 LabelStmtIsLoop bool 1287 1288 // If a scope contains a direct eval() expression, then none of the symbols 1289 // inside that scope can be renamed. We conservatively assume that the 1290 // evaluated code might reference anything that it has access to. 1291 ContainsDirectEval bool 1292 1293 // This is to help forbid "arguments" inside class body scopes 1294 ForbidArguments bool 1295 1296 // As a special case, we enable constant propagation for any chain of "const" 1297 // declarations at the start of a statement list. This special case doesn't 1298 // have any TDZ considerations because no other statements come before it. 1299 IsAfterConstLocalPrefix bool 1300 1301 StrictMode StrictModeKind 1302 Kind ScopeKind 1303 } 1304 1305 type StrictModeKind uint8 1306 1307 const ( 1308 SloppyMode StrictModeKind = iota 1309 ExplicitStrictMode 1310 ImplicitStrictModeClass 1311 ImplicitStrictModeESM 1312 ImplicitStrictModeTSAlwaysStrict 1313 ImplicitStrictModeJSXAutomaticRuntime 1314 ) 1315 1316 func (s *Scope) RecursiveSetStrictMode(kind StrictModeKind) { 1317 if s.StrictMode == SloppyMode { 1318 s.StrictMode = kind 1319 for _, child := range s.Children { 1320 child.RecursiveSetStrictMode(kind) 1321 } 1322 } 1323 } 1324 1325 // This is for TypeScript "enum" and "namespace" blocks. Each block can 1326 // potentially be instantiated multiple times. The exported members of each 1327 // block are merged into a single namespace while the non-exported code is 1328 // still scoped to just within that block: 1329 // 1330 // let x = 1; 1331 // namespace Foo { 1332 // let x = 2; 1333 // export let y = 3; 1334 // } 1335 // namespace Foo { 1336 // console.log(x); // 1 1337 // console.log(y); // 3 1338 // } 1339 // 1340 // Doing this also works inside an enum: 1341 // 1342 // enum Foo { 1343 // A = 3, 1344 // B = A + 1, 1345 // } 1346 // enum Foo { 1347 // C = A + 2, 1348 // } 1349 // console.log(Foo.B) // 4 1350 // console.log(Foo.C) // 5 1351 // 1352 // This is a form of identifier lookup that works differently than the 1353 // hierarchical scope-based identifier lookup in JavaScript. Lookup now needs 1354 // to search sibling scopes in addition to parent scopes. This is accomplished 1355 // by sharing the map of exported members between all matching sibling scopes. 1356 type TSNamespaceScope struct { 1357 // This is shared between all sibling namespace blocks 1358 ExportedMembers TSNamespaceMembers 1359 1360 // This is a lazily-generated map of identifiers that actually represent 1361 // property accesses to this namespace's properties. For example: 1362 // 1363 // namespace x { 1364 // export let y = 123 1365 // } 1366 // namespace x { 1367 // export let z = y 1368 // } 1369 // 1370 // This should be compiled into the following code: 1371 // 1372 // var x; 1373 // (function(x2) { 1374 // x2.y = 123; 1375 // })(x || (x = {})); 1376 // (function(x3) { 1377 // x3.z = x3.y; 1378 // })(x || (x = {})); 1379 // 1380 // When we try to find the symbol "y", we instead return one of these lazily 1381 // generated proxy symbols that represent the property access "x3.y". This 1382 // map is unique per namespace block because "x3" is the argument symbol that 1383 // is specific to that particular namespace block. 1384 LazilyGeneratedProperyAccesses map[string]ast.Ref 1385 1386 // This is specific to this namespace block. It's the argument of the 1387 // immediately-invoked function expression that the namespace block is 1388 // compiled into: 1389 // 1390 // var ns; 1391 // (function (ns2) { 1392 // ns2.x = 123; 1393 // })(ns || (ns = {})); 1394 // 1395 // This variable is "ns2" in the above example. It's the symbol to use when 1396 // generating property accesses off of this namespace when it's in scope. 1397 ArgRef ast.Ref 1398 1399 // Even though enums are like namespaces and both enums and namespaces allow 1400 // implicit references to properties of sibling scopes, they behave like 1401 // separate, er, namespaces. Implicit references only work namespace-to- 1402 // namespace and enum-to-enum. They do not work enum-to-namespace. And I'm 1403 // not sure what's supposed to happen for the namespace-to-enum case because 1404 // the compiler crashes: https://github.com/microsoft/TypeScript/issues/46891. 1405 // So basically these both work: 1406 // 1407 // enum a { b = 1 } 1408 // enum a { c = b } 1409 // 1410 // namespace x { export let y = 1 } 1411 // namespace x { export let z = y } 1412 // 1413 // This doesn't work: 1414 // 1415 // enum a { b = 1 } 1416 // namespace a { export let c = b } 1417 // 1418 // And this crashes the TypeScript compiler: 1419 // 1420 // namespace a { export let b = 1 } 1421 // enum a { c = b } 1422 // 1423 // Therefore we only allow enum/enum and namespace/namespace interactions. 1424 IsEnumScope bool 1425 } 1426 1427 type TSNamespaceMembers map[string]TSNamespaceMember 1428 1429 type TSNamespaceMember struct { 1430 Data TSNamespaceMemberData 1431 Loc logger.Loc 1432 IsEnumValue bool 1433 } 1434 1435 type TSNamespaceMemberData interface { 1436 isTSNamespaceMember() 1437 } 1438 1439 func (TSNamespaceMemberProperty) isTSNamespaceMember() {} 1440 func (TSNamespaceMemberNamespace) isTSNamespaceMember() {} 1441 func (TSNamespaceMemberEnumNumber) isTSNamespaceMember() {} 1442 func (TSNamespaceMemberEnumString) isTSNamespaceMember() {} 1443 1444 // "namespace ns { export let it }" 1445 type TSNamespaceMemberProperty struct{} 1446 1447 // "namespace ns { export namespace it {} }" 1448 type TSNamespaceMemberNamespace struct { 1449 ExportedMembers TSNamespaceMembers 1450 } 1451 1452 // "enum ns { it }" 1453 type TSNamespaceMemberEnumNumber struct { 1454 Value float64 1455 } 1456 1457 // "enum ns { it = 'it' }" 1458 type TSNamespaceMemberEnumString struct { 1459 Value []uint16 1460 } 1461 1462 type ExportsKind uint8 1463 1464 const ( 1465 // This file doesn't have any kind of export, so it's impossible to say what 1466 // kind of file this is. An empty file is in this category, for example. 1467 ExportsNone ExportsKind = iota 1468 1469 // The exports are stored on "module" and/or "exports". Calling "require()" 1470 // on this module returns "module.exports". All imports to this module are 1471 // allowed but may return undefined. 1472 ExportsCommonJS 1473 1474 // All export names are known explicitly. Calling "require()" on this module 1475 // generates an exports object (stored in "exports") with getters for the 1476 // export names. Named imports to this module are only allowed if they are 1477 // in the set of export names. 1478 ExportsESM 1479 1480 // Some export names are known explicitly, but others fall back to a dynamic 1481 // run-time object. This is necessary when using the "export * from" syntax 1482 // with either a CommonJS module or an external module (i.e. a module whose 1483 // export names are not known at compile-time). 1484 // 1485 // Calling "require()" on this module generates an exports object (stored in 1486 // "exports") with getters for the export names. All named imports to this 1487 // module are allowed. Direct named imports reference the corresponding export 1488 // directly. Other imports go through property accesses on "exports". 1489 ExportsESMWithDynamicFallback 1490 ) 1491 1492 func (kind ExportsKind) IsDynamic() bool { 1493 return kind == ExportsCommonJS || kind == ExportsESMWithDynamicFallback 1494 } 1495 1496 type ModuleType uint8 1497 1498 const ( 1499 ModuleUnknown ModuleType = iota 1500 1501 // ".cjs" or ".cts" or "type: commonjs" in package.json 1502 ModuleCommonJS_CJS 1503 ModuleCommonJS_CTS 1504 ModuleCommonJS_PackageJSON 1505 1506 // ".mjs" or ".mts" or "type: module" in package.json 1507 ModuleESM_MJS 1508 ModuleESM_MTS 1509 ModuleESM_PackageJSON 1510 ) 1511 1512 func (mt ModuleType) IsCommonJS() bool { 1513 return mt >= ModuleCommonJS_CJS && mt <= ModuleCommonJS_PackageJSON 1514 } 1515 1516 func (mt ModuleType) IsESM() bool { 1517 return mt >= ModuleESM_MJS && mt <= ModuleESM_PackageJSON 1518 } 1519 1520 type ModuleTypeData struct { 1521 Source *logger.Source 1522 Range logger.Range 1523 Type ModuleType 1524 } 1525 1526 // This is the index to the automatically-generated part containing code that 1527 // calls "__export(exports, { ... getters ... })". This is used to generate 1528 // getters on an exports object for ES6 export statements, and is both for 1529 // ES6 star imports and CommonJS-style modules. All files have one of these, 1530 // although it may contain no statements if there is nothing to export. 1531 const NSExportPartIndex = uint32(0) 1532 1533 type AST struct { 1534 ModuleTypeData ModuleTypeData 1535 Parts []Part 1536 Symbols []ast.Symbol 1537 ExprComments map[logger.Loc][]string 1538 ModuleScope *Scope 1539 CharFreq *ast.CharFreq 1540 1541 // This is internal-only data used for the implementation of Yarn PnP 1542 ManifestForYarnPnP Expr 1543 1544 Hashbang string 1545 Directives []string 1546 URLForCSS string 1547 1548 // Note: If you're in the linker, do not use this map directly. This map is 1549 // filled in by the parser and is considered immutable. For performance reasons, 1550 // the linker doesn't mutate this map (cloning a map is slow in Go). Instead the 1551 // linker super-imposes relevant information on top in a method call. You should 1552 // call "TopLevelSymbolToParts" instead. 1553 TopLevelSymbolToPartsFromParser map[ast.Ref][]uint32 1554 1555 // This contains all top-level exported TypeScript enum constants. It exists 1556 // to enable cross-module inlining of constant enums. 1557 TSEnums map[ast.Ref]map[string]TSEnumValue 1558 1559 // This contains the values of all detected inlinable constants. It exists 1560 // to enable cross-module inlining of these constants. 1561 ConstValues map[ast.Ref]ConstValue 1562 1563 // Properties in here are represented as symbols instead of strings, which 1564 // allows them to be renamed to smaller names. 1565 MangledProps map[string]ast.Ref 1566 1567 // Properties in here are existing non-mangled properties in the source code 1568 // and must not be used when generating mangled names to avoid a collision. 1569 ReservedProps map[string]bool 1570 1571 // These are stored at the AST level instead of on individual AST nodes so 1572 // they can be manipulated efficiently without a full AST traversal 1573 ImportRecords []ast.ImportRecord 1574 1575 // These are used when bundling. They are filled in during the parser pass 1576 // since we already have to traverse the AST then anyway and the parser pass 1577 // is conveniently fully parallelized. 1578 NamedImports map[ast.Ref]NamedImport 1579 NamedExports map[string]NamedExport 1580 ExportStarImportRecords []uint32 1581 1582 SourceMapComment logger.Span 1583 1584 // This is a list of ES6 features. They are ranges instead of booleans so 1585 // that they can be used in log messages. Check to see if "Len > 0". 1586 ExportKeyword logger.Range // Does not include TypeScript-specific syntax 1587 TopLevelAwaitKeyword logger.Range 1588 LiveTopLevelAwaitKeyword logger.Range // Excludes top-level await in dead branches 1589 1590 ExportsRef ast.Ref 1591 ModuleRef ast.Ref 1592 WrapperRef ast.Ref 1593 1594 ApproximateLineCount int32 1595 NestedScopeSlotCounts ast.SlotCounts 1596 HasLazyExport bool 1597 1598 // This is a list of CommonJS features. When a file uses CommonJS features, 1599 // it's not a candidate for "flat bundling" and must be wrapped in its own 1600 // closure. Note that this also includes top-level "return" but these aren't 1601 // here because only the parser checks those. 1602 UsesExportsRef bool 1603 UsesModuleRef bool 1604 ExportsKind ExportsKind 1605 } 1606 1607 type TSEnumValue struct { 1608 String []uint16 // Use this if it's not nil 1609 Number float64 // Use this if "String" is nil 1610 } 1611 1612 type ConstValueKind uint8 1613 1614 const ( 1615 ConstValueNone ConstValueKind = iota 1616 ConstValueNull 1617 ConstValueUndefined 1618 ConstValueTrue 1619 ConstValueFalse 1620 ConstValueNumber 1621 ) 1622 1623 type ConstValue struct { 1624 Number float64 // Use this for "ConstValueNumber" 1625 Kind ConstValueKind 1626 } 1627 1628 func ExprToConstValue(expr Expr) ConstValue { 1629 switch v := expr.Data.(type) { 1630 case *ENull: 1631 return ConstValue{Kind: ConstValueNull} 1632 1633 case *EUndefined: 1634 return ConstValue{Kind: ConstValueUndefined} 1635 1636 case *EBoolean: 1637 if v.Value { 1638 return ConstValue{Kind: ConstValueTrue} 1639 } else { 1640 return ConstValue{Kind: ConstValueFalse} 1641 } 1642 1643 case *ENumber: 1644 // Inline integers and other small numbers. Don't inline large 1645 // real numbers because people may not want them to be inlined 1646 // as it will increase the minified code size by too much. 1647 if asInt := int64(v.Value); v.Value == float64(asInt) || len(strconv.FormatFloat(v.Value, 'g', -1, 64)) <= 8 { 1648 return ConstValue{Kind: ConstValueNumber, Number: v.Value} 1649 } 1650 1651 case *EString: 1652 // I'm deliberately not inlining strings here. It seems more likely that 1653 // people won't want them to be inlined since they can be arbitrarily long. 1654 1655 case *EBigInt: 1656 // I'm deliberately not inlining bigints here for the same reason (they can 1657 // be arbitrarily long). 1658 } 1659 1660 return ConstValue{} 1661 } 1662 1663 func ConstValueToExpr(loc logger.Loc, value ConstValue) Expr { 1664 switch value.Kind { 1665 case ConstValueNull: 1666 return Expr{Loc: loc, Data: ENullShared} 1667 1668 case ConstValueUndefined: 1669 return Expr{Loc: loc, Data: EUndefinedShared} 1670 1671 case ConstValueTrue: 1672 return Expr{Loc: loc, Data: &EBoolean{Value: true}} 1673 1674 case ConstValueFalse: 1675 return Expr{Loc: loc, Data: &EBoolean{Value: false}} 1676 1677 case ConstValueNumber: 1678 return Expr{Loc: loc, Data: &ENumber{Value: value.Number}} 1679 } 1680 1681 panic("Internal error: invalid constant value") 1682 } 1683 1684 type NamedImport struct { 1685 Alias string 1686 1687 // Parts within this file that use this import 1688 LocalPartsWithUses []uint32 1689 1690 AliasLoc logger.Loc 1691 NamespaceRef ast.Ref 1692 ImportRecordIndex uint32 1693 1694 // If true, the alias refers to the entire export namespace object of a 1695 // module. This is no longer represented as an alias called "*" because of 1696 // the upcoming "Arbitrary module namespace identifier names" feature: 1697 // https://github.com/tc39/ecma262/pull/2154 1698 AliasIsStar bool 1699 1700 // It's useful to flag exported imports because if they are in a TypeScript 1701 // file, we can't tell if they are a type or a value. 1702 IsExported bool 1703 } 1704 1705 type NamedExport struct { 1706 Ref ast.Ref 1707 AliasLoc logger.Loc 1708 } 1709 1710 // Each file is made up of multiple parts, and each part consists of one or 1711 // more top-level statements. Parts are used for tree shaking and code 1712 // splitting analysis. Individual parts of a file can be discarded by tree 1713 // shaking and can be assigned to separate chunks (i.e. output files) by code 1714 // splitting. 1715 type Part struct { 1716 Stmts []Stmt 1717 Scopes []*Scope 1718 1719 // Each is an index into the file-level import record list 1720 ImportRecordIndices []uint32 1721 1722 // All symbols that are declared in this part. Note that a given symbol may 1723 // have multiple declarations, and so may end up being declared in multiple 1724 // parts (e.g. multiple "var" declarations with the same name). Also note 1725 // that this list isn't deduplicated and may contain duplicates. 1726 DeclaredSymbols []DeclaredSymbol 1727 1728 // An estimate of the number of uses of all symbols used within this part. 1729 SymbolUses map[ast.Ref]SymbolUse 1730 1731 // An estimate of the number of uses of all symbols used as the target of 1732 // function calls within this part. 1733 SymbolCallUses map[ast.Ref]SymbolCallUse 1734 1735 // This tracks property accesses off of imported symbols. We don't know 1736 // during parsing if an imported symbol is going to be an inlined enum 1737 // value or not. This is only known during linking. So we defer adding 1738 // a dependency on these imported symbols until we know whether the 1739 // property access is an inlined enum value or not. 1740 ImportSymbolPropertyUses map[ast.Ref]map[string]SymbolUse 1741 1742 // The indices of the other parts in this file that are needed if this part 1743 // is needed. 1744 Dependencies []Dependency 1745 1746 // If true, this part can be removed if none of the declared symbols are 1747 // used. If the file containing this part is imported, then all parts that 1748 // don't have this flag enabled must be included. 1749 CanBeRemovedIfUnused bool 1750 1751 // This is used for generated parts that we don't want to be present if they 1752 // aren't needed. This enables tree shaking for these parts even if global 1753 // tree shaking isn't enabled. 1754 ForceTreeShaking bool 1755 1756 // This is true if this file has been marked as live by the tree shaking 1757 // algorithm. 1758 IsLive bool 1759 } 1760 1761 type Dependency struct { 1762 SourceIndex uint32 1763 PartIndex uint32 1764 } 1765 1766 type DeclaredSymbol struct { 1767 Ref ast.Ref 1768 IsTopLevel bool 1769 } 1770 1771 type SymbolUse struct { 1772 CountEstimate uint32 1773 } 1774 1775 type SymbolCallUse struct { 1776 CallCountEstimate uint32 1777 SingleArgNonSpreadCallCountEstimate uint32 1778 } 1779 1780 // For readability, the names of certain automatically-generated symbols are 1781 // derived from the file name. For example, instead of the CommonJS wrapper for 1782 // a file being called something like "require273" it can be called something 1783 // like "require_react" instead. This function generates the part of these 1784 // identifiers that's specific to the file path. It can take both an absolute 1785 // path (OS-specific) and a path in the source code (OS-independent). 1786 // 1787 // Note that these generated names do not at all relate to the correctness of 1788 // the code as far as avoiding symbol name collisions. These names still go 1789 // through the renaming logic that all other symbols go through to avoid name 1790 // collisions. 1791 func GenerateNonUniqueNameFromPath(path string) string { 1792 // Get the file name without the extension 1793 dir, base, _ := logger.PlatformIndependentPathDirBaseExt(path) 1794 1795 // If the name is "index", use the directory name instead. This is because 1796 // many packages in npm use the file name "index.js" because it triggers 1797 // node's implicit module resolution rules that allows you to import it by 1798 // just naming the directory. 1799 if base == "index" { 1800 _, dirBase, _ := logger.PlatformIndependentPathDirBaseExt(dir) 1801 if dirBase != "" { 1802 base = dirBase 1803 } 1804 } 1805 1806 return EnsureValidIdentifier(base) 1807 } 1808 1809 func EnsureValidIdentifier(base string) string { 1810 // Convert it to an ASCII identifier. Note: If you change this to a non-ASCII 1811 // identifier, you're going to potentially cause trouble with non-BMP code 1812 // points in target environments that don't support bracketed Unicode escapes. 1813 bytes := []byte{} 1814 needsGap := false 1815 for _, c := range base { 1816 if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (len(bytes) > 0 && c >= '0' && c <= '9') { 1817 if needsGap { 1818 bytes = append(bytes, '_') 1819 needsGap = false 1820 } 1821 bytes = append(bytes, byte(c)) 1822 } else if len(bytes) > 0 { 1823 needsGap = true 1824 } 1825 } 1826 1827 // Make sure the name isn't empty 1828 if len(bytes) == 0 { 1829 return "_" 1830 } 1831 return string(bytes) 1832 }