package graph // The code in this file represents data that is required by the compile phase // of the bundler but that is not required by the scan phase. import ( "github.com/evanw/esbuild/internal/ast" "github.com/evanw/esbuild/internal/js_ast" "github.com/evanw/esbuild/internal/logger" ) type WrapKind uint8 const ( WrapNone WrapKind = iota // The module will be bundled CommonJS-style like this: // // // foo.ts // let require_foo = __commonJS((exports, module) => { // exports.foo = 123; // }); // // // bar.ts // let foo = flag ? require_foo() : null; // WrapCJS // The module will be bundled ESM-style like this: // // // foo.ts // var foo, foo_exports = {}; // __export(foo_exports, { // foo: () => foo // }); // let init_foo = __esm(() => { // foo = 123; // }); // // // bar.ts // let foo = flag ? (init_foo(), foo_exports) : null; // WrapESM ) // This contains linker-specific metadata corresponding to a "file" struct // from the initial scan phase of the bundler. It's separated out because it's // conceptually only used for a single linking operation and because multiple // linking operations may be happening in parallel with different metadata for // the same file. type JSReprMeta struct { // This is only for TypeScript files. If an import symbol is in this map, it // means the import couldn't be found and doesn't actually exist. This is not // an error in TypeScript because the import is probably just a type. // // Normally we remove all unused imports for TypeScript files during parsing, // which automatically removes type-only imports. But there are certain re- // export situations where it's impossible to tell if an import is a type or // not: // // import {typeOrNotTypeWhoKnows} from 'path'; // export {typeOrNotTypeWhoKnows}; // // Really people should be using the TypeScript "isolatedModules" flag with // bundlers like this one that compile TypeScript files independently without // type checking. That causes the TypeScript type checker to emit the error // "Re-exporting a type when the '--isolatedModules' flag is provided requires // using 'export type'." But we try to be robust to such code anyway. IsProbablyTypeScriptType map[js_ast.Ref]bool // Imports are matched with exports in a separate pass from when the matched // exports are actually bound to the imports. Here "binding" means adding non- // local dependencies on the parts in the exporting file that declare the // exported symbol to all parts in the importing file that use the imported // symbol. // // This must be a separate pass because of the "probably TypeScript type" // check above. We can't generate the part for the export namespace until // we've matched imports with exports because the generated code must omit // type-only imports in the export namespace code. And we can't bind exports // to imports until the part for the export namespace is generated since that // part needs to participate in the binding. // // This array holds the deferred imports to bind so the pass can be split // into two separate passes. ImportsToBind map[js_ast.Ref]ImportData // This includes both named exports and re-exports. // // Named exports come from explicit export statements in the original file, // and are copied from the "NamedExports" field in the AST. // // Re-exports come from other files and are the result of resolving export // star statements (i.e. "export * from 'foo'"). ResolvedExports map[string]ExportData ResolvedExportStar *ExportData // Never iterate over "resolvedExports" directly. Instead, iterate over this // array. Some exports in that map aren't meant to end up in generated code. // This array excludes these exports and is also sorted, which avoids non- // determinism due to random map iteration order. SortedAndFilteredExportAliases []string // If this is an entry point, this array holds a reference to one free // temporary symbol for each entry in "sortedAndFilteredExportAliases". // These may be needed to store copies of CommonJS re-exports in ESM. CJSExportCopies []js_ast.Ref // This is merged on top of the corresponding map from the parser in the AST. // You should call "TopLevelSymbolToParts" to access this instead of accessing // it directly. TopLevelSymbolToPartsOverlay map[js_ast.Ref][]uint32 // The index of the automatically-generated part used to represent the // CommonJS or ESM wrapper. This part is empty and is only useful for tree // shaking and code splitting. The wrapper can't be inserted into the part // because the wrapper contains other parts, which can't be represented by // the current part system. Only wrapped files have one of these. WrapperPartIndex ast.Index32 // The index of the automatically-generated part used to handle entry point // specific stuff. If a certain part is needed by the entry point, it's added // as a dependency of this part. This is important for parts that are marked // as removable when unused and that are not used by anything else. Only // entry point files have one of these. EntryPointPartIndex ast.Index32 // This is true if this file is affected by top-level await, either by having // a top-level await inside this file or by having an import/export statement // that transitively imports such a file. It is forbidden to call "require()" // on these files since they are evaluated asynchronously. IsAsyncOrHasAsyncDependency bool Wrap WrapKind // If true, the "__export(exports, { ... })" call will be force-included even // if there are no parts that reference "exports". Otherwise this call will // be removed due to the tree shaking pass. This is used when for entry point // files when code related to the current output format needs to reference // the "exports" variable. ForceIncludeExportsForEntryPoint bool // This is set when we need to pull in the "__export" symbol in to the part // at "nsExportPartIndex". This can't be done in "createExportsForFile" // because of concurrent map hazards. Instead, it must be done later. NeedsExportSymbolFromRuntime bool NeedsMarkAsModuleSymbolFromRuntime bool // Wrapped files must also ensure that their dependencies are wrapped. This // flag is used during the traversal that enforces this invariant, and is used // to detect when the fixed point has been reached. DidWrapDependencies bool } type ImportData struct { // This is an array of intermediate statements that re-exported this symbol // in a chain before getting to the final symbol. This can be done either with // "export * from" or "export {} from". If this is done with "export * from" // then this may not be the result of a single chain but may instead form // a diamond shape if this same symbol was re-exported multiple times from // different files. ReExports []js_ast.Dependency NameLoc logger.Loc // Optional, goes with sourceIndex, ignore if zero Ref js_ast.Ref SourceIndex uint32 } type ExportData struct { Ref js_ast.Ref // Export star resolution happens first before import resolution. That means // it cannot yet determine if duplicate names from export star resolution are // ambiguous (point to different symbols) or not (point to the same symbol). // This issue can happen in the following scenario: // // // entry.js // export * from './a' // export * from './b' // // // a.js // export * from './c' // // // b.js // export {x} from './c' // // // c.js // export let x = 1, y = 2 // // In this case "entry.js" should have two exports "x" and "y", neither of // which are ambiguous. To handle this case, ambiguity resolution must be // deferred until import resolution time. That is done using this array. PotentiallyAmbiguousExportStarRefs []ImportData // This is the file that the named export above came from. This will be // different from the file that contains this object if this is a re-export. NameLoc logger.Loc // Optional, goes with sourceIndex, ignore if zero SourceIndex uint32 }