summaryrefslogtreecommitdiff
path: root/node_modules/webpack/lib/optimize/ConcatenatedModule.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/webpack/lib/optimize/ConcatenatedModule.js')
-rw-r--r--node_modules/webpack/lib/optimize/ConcatenatedModule.js1905
1 files changed, 1905 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/optimize/ConcatenatedModule.js b/node_modules/webpack/lib/optimize/ConcatenatedModule.js
new file mode 100644
index 00000000..f889b5e2
--- /dev/null
+++ b/node_modules/webpack/lib/optimize/ConcatenatedModule.js
@@ -0,0 +1,1905 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const eslintScope = require("eslint-scope");
+const Referencer = require("eslint-scope/lib/referencer");
+const {
+ CachedSource,
+ ConcatSource,
+ ReplaceSource
+} = require("webpack-sources");
+const ConcatenationScope = require("../ConcatenationScope");
+const { UsageState } = require("../ExportsInfo");
+const Module = require("../Module");
+const { JAVASCRIPT_MODULE_TYPE_ESM } = require("../ModuleTypeConstants");
+const RuntimeGlobals = require("../RuntimeGlobals");
+const Template = require("../Template");
+const HarmonyImportDependency = require("../dependencies/HarmonyImportDependency");
+const JavascriptParser = require("../javascript/JavascriptParser");
+const { equals } = require("../util/ArrayHelpers");
+const LazySet = require("../util/LazySet");
+const { concatComparators } = require("../util/comparators");
+const createHash = require("../util/createHash");
+const { makePathsRelative } = require("../util/identifier");
+const makeSerializable = require("../util/makeSerializable");
+const propertyAccess = require("../util/propertyAccess");
+const { propertyName } = require("../util/propertyName");
+const {
+ filterRuntime,
+ intersectRuntime,
+ mergeRuntimeCondition,
+ mergeRuntimeConditionNonFalse,
+ runtimeConditionToString,
+ subtractRuntimeCondition
+} = require("../util/runtime");
+
+/** @typedef {import("eslint-scope").Scope} Scope */
+/** @typedef {import("webpack-sources").Source} Source */
+/** @typedef {import("../../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptions */
+/** @typedef {import("../ChunkGraph")} ChunkGraph */
+/** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */
+/** @typedef {import("../Compilation")} Compilation */
+/** @typedef {import("../Dependency")} Dependency */
+/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
+/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
+/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
+/** @typedef {import("../ExportsInfo").ExportInfo} ExportInfo */
+/** @template T @typedef {import("../InitFragment")<T>} InitFragment */
+/** @typedef {import("../Module").CodeGenerationContext} CodeGenerationContext */
+/** @typedef {import("../Module").CodeGenerationResult} CodeGenerationResult */
+/** @typedef {import("../Module").LibIdentOptions} LibIdentOptions */
+/** @typedef {import("../ModuleGraph")} ModuleGraph */
+/** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */
+/** @typedef {import("../ModuleGraphConnection").ConnectionState} ConnectionState */
+/** @typedef {import("../RequestShortener")} RequestShortener */
+/** @typedef {import("../ResolverFactory").ResolverWithOptions} ResolverWithOptions */
+/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
+/** @typedef {import("../WebpackError")} WebpackError */
+/** @typedef {import("../javascript/JavascriptModulesPlugin").ChunkRenderContext} ChunkRenderContext */
+/** @typedef {import("../util/Hash")} Hash */
+/** @typedef {typeof import("../util/Hash")} HashConstructor */
+/** @typedef {import("../util/fs").InputFileSystem} InputFileSystem */
+/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
+
+// fix eslint-scope to support class properties correctly
+// cspell:word Referencer
+const ReferencerClass = Referencer;
+if (!ReferencerClass.prototype.PropertyDefinition) {
+ ReferencerClass.prototype.PropertyDefinition =
+ ReferencerClass.prototype.Property;
+}
+
+/**
+ * @typedef {Object} ReexportInfo
+ * @property {Module} module
+ * @property {string[]} export
+ */
+
+/** @typedef {RawBinding | SymbolBinding} Binding */
+
+/**
+ * @typedef {Object} RawBinding
+ * @property {ModuleInfo} info
+ * @property {string} rawName
+ * @property {string=} comment
+ * @property {string[]} ids
+ * @property {string[]} exportName
+ */
+
+/**
+ * @typedef {Object} SymbolBinding
+ * @property {ConcatenatedModuleInfo} info
+ * @property {string} name
+ * @property {string=} comment
+ * @property {string[]} ids
+ * @property {string[]} exportName
+ */
+
+/** @typedef {ConcatenatedModuleInfo | ExternalModuleInfo } ModuleInfo */
+/** @typedef {ConcatenatedModuleInfo | ExternalModuleInfo | ReferenceToModuleInfo } ModuleInfoOrReference */
+
+/**
+ * @typedef {Object} ConcatenatedModuleInfo
+ * @property {"concatenated"} type
+ * @property {Module} module
+ * @property {number} index
+ * @property {Object} ast
+ * @property {Source} internalSource
+ * @property {ReplaceSource} source
+ * @property {InitFragment<ChunkRenderContext>[]=} chunkInitFragments
+ * @property {Iterable<string>} runtimeRequirements
+ * @property {Scope} globalScope
+ * @property {Scope} moduleScope
+ * @property {Map<string, string>} internalNames
+ * @property {Map<string, string>} exportMap
+ * @property {Map<string, string>} rawExportMap
+ * @property {string=} namespaceExportSymbol
+ * @property {string} namespaceObjectName
+ * @property {boolean} interopNamespaceObjectUsed
+ * @property {string} interopNamespaceObjectName
+ * @property {boolean} interopNamespaceObject2Used
+ * @property {string} interopNamespaceObject2Name
+ * @property {boolean} interopDefaultAccessUsed
+ * @property {string} interopDefaultAccessName
+ */
+
+/**
+ * @typedef {Object} ExternalModuleInfo
+ * @property {"external"} type
+ * @property {Module} module
+ * @property {RuntimeSpec | boolean} runtimeCondition
+ * @property {number} index
+ * @property {string} name
+ * @property {boolean} interopNamespaceObjectUsed
+ * @property {string} interopNamespaceObjectName
+ * @property {boolean} interopNamespaceObject2Used
+ * @property {string} interopNamespaceObject2Name
+ * @property {boolean} interopDefaultAccessUsed
+ * @property {string} interopDefaultAccessName
+ */
+
+/**
+ * @typedef {Object} ReferenceToModuleInfo
+ * @property {"reference"} type
+ * @property {RuntimeSpec | boolean} runtimeCondition
+ * @property {ConcatenatedModuleInfo | ExternalModuleInfo} target
+ */
+
+const RESERVED_NAMES = new Set(
+ [
+ // internal names (should always be renamed)
+ ConcatenationScope.DEFAULT_EXPORT,
+ ConcatenationScope.NAMESPACE_OBJECT_EXPORT,
+
+ // keywords
+ "abstract,arguments,async,await,boolean,break,byte,case,catch,char,class,const,continue",
+ "debugger,default,delete,do,double,else,enum,eval,export,extends,false,final,finally,float",
+ "for,function,goto,if,implements,import,in,instanceof,int,interface,let,long,native,new,null",
+ "package,private,protected,public,return,short,static,super,switch,synchronized,this,throw",
+ "throws,transient,true,try,typeof,var,void,volatile,while,with,yield",
+
+ // commonjs/amd
+ "module,__dirname,__filename,exports,require,define",
+
+ // js globals
+ "Array,Date,eval,function,hasOwnProperty,Infinity,isFinite,isNaN,isPrototypeOf,length,Math",
+ "NaN,name,Number,Object,prototype,String,toString,undefined,valueOf",
+
+ // browser globals
+ "alert,all,anchor,anchors,area,assign,blur,button,checkbox,clearInterval,clearTimeout",
+ "clientInformation,close,closed,confirm,constructor,crypto,decodeURI,decodeURIComponent",
+ "defaultStatus,document,element,elements,embed,embeds,encodeURI,encodeURIComponent,escape",
+ "event,fileUpload,focus,form,forms,frame,innerHeight,innerWidth,layer,layers,link,location",
+ "mimeTypes,navigate,navigator,frames,frameRate,hidden,history,image,images,offscreenBuffering",
+ "open,opener,option,outerHeight,outerWidth,packages,pageXOffset,pageYOffset,parent,parseFloat",
+ "parseInt,password,pkcs11,plugin,prompt,propertyIsEnum,radio,reset,screenX,screenY,scroll",
+ "secure,select,self,setInterval,setTimeout,status,submit,taint,text,textarea,top,unescape",
+ "untaint,window",
+
+ // window events
+ "onblur,onclick,onerror,onfocus,onkeydown,onkeypress,onkeyup,onmouseover,onload,onmouseup,onmousedown,onsubmit"
+ ]
+ .join(",")
+ .split(",")
+);
+
+const createComparator = (property, comparator) => (a, b) =>
+ comparator(a[property], b[property]);
+const compareNumbers = (a, b) => {
+ if (isNaN(a)) {
+ if (!isNaN(b)) {
+ return 1;
+ }
+ } else {
+ if (isNaN(b)) {
+ return -1;
+ }
+ if (a !== b) {
+ return a < b ? -1 : 1;
+ }
+ }
+ return 0;
+};
+const bySourceOrder = createComparator("sourceOrder", compareNumbers);
+const byRangeStart = createComparator("rangeStart", compareNumbers);
+
+const joinIterableWithComma = iterable => {
+ // This is more performant than Array.from().join(", ")
+ // as it doesn't create an array
+ let str = "";
+ let first = true;
+ for (const item of iterable) {
+ if (first) {
+ first = false;
+ } else {
+ str += ", ";
+ }
+ str += item;
+ }
+ return str;
+};
+
+/**
+ * @typedef {Object} ConcatenationEntry
+ * @property {"concatenated" | "external"} type
+ * @property {Module} module
+ * @property {RuntimeSpec | boolean} runtimeCondition
+ */
+
+/**
+ * @param {ModuleGraph} moduleGraph the module graph
+ * @param {ModuleInfo} info module info
+ * @param {string[]} exportName exportName
+ * @param {Map<Module, ModuleInfo>} moduleToInfoMap moduleToInfoMap
+ * @param {RuntimeSpec} runtime for which runtime
+ * @param {RequestShortener} requestShortener the request shortener
+ * @param {RuntimeTemplate} runtimeTemplate the runtime template
+ * @param {Set<ConcatenatedModuleInfo>} neededNamespaceObjects modules for which a namespace object should be generated
+ * @param {boolean} asCall asCall
+ * @param {boolean} strictHarmonyModule strictHarmonyModule
+ * @param {boolean | undefined} asiSafe asiSafe
+ * @param {Set<ExportInfo>} alreadyVisited alreadyVisited
+ * @returns {Binding} the final variable
+ */
+const getFinalBinding = (
+ moduleGraph,
+ info,
+ exportName,
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ asCall,
+ strictHarmonyModule,
+ asiSafe,
+ alreadyVisited = new Set()
+) => {
+ const exportsType = info.module.getExportsType(
+ moduleGraph,
+ strictHarmonyModule
+ );
+ if (exportName.length === 0) {
+ switch (exportsType) {
+ case "default-only":
+ info.interopNamespaceObject2Used = true;
+ return {
+ info,
+ rawName: info.interopNamespaceObject2Name,
+ ids: exportName,
+ exportName
+ };
+ case "default-with-named":
+ info.interopNamespaceObjectUsed = true;
+ return {
+ info,
+ rawName: info.interopNamespaceObjectName,
+ ids: exportName,
+ exportName
+ };
+ case "namespace":
+ case "dynamic":
+ break;
+ default:
+ throw new Error(`Unexpected exportsType ${exportsType}`);
+ }
+ } else {
+ switch (exportsType) {
+ case "namespace":
+ break;
+ case "default-with-named":
+ switch (exportName[0]) {
+ case "default":
+ exportName = exportName.slice(1);
+ break;
+ case "__esModule":
+ return {
+ info,
+ rawName: "/* __esModule */true",
+ ids: exportName.slice(1),
+ exportName
+ };
+ }
+ break;
+ case "default-only": {
+ const exportId = exportName[0];
+ if (exportId === "__esModule") {
+ return {
+ info,
+ rawName: "/* __esModule */true",
+ ids: exportName.slice(1),
+ exportName
+ };
+ }
+ exportName = exportName.slice(1);
+ if (exportId !== "default") {
+ return {
+ info,
+ rawName:
+ "/* non-default import from default-exporting module */undefined",
+ ids: exportName,
+ exportName
+ };
+ }
+ break;
+ }
+ case "dynamic":
+ switch (exportName[0]) {
+ case "default": {
+ exportName = exportName.slice(1);
+ info.interopDefaultAccessUsed = true;
+ const defaultExport = asCall
+ ? `${info.interopDefaultAccessName}()`
+ : asiSafe
+ ? `(${info.interopDefaultAccessName}())`
+ : asiSafe === false
+ ? `;(${info.interopDefaultAccessName}())`
+ : `${info.interopDefaultAccessName}.a`;
+ return {
+ info,
+ rawName: defaultExport,
+ ids: exportName,
+ exportName
+ };
+ }
+ case "__esModule":
+ return {
+ info,
+ rawName: "/* __esModule */true",
+ ids: exportName.slice(1),
+ exportName
+ };
+ }
+ break;
+ default:
+ throw new Error(`Unexpected exportsType ${exportsType}`);
+ }
+ }
+ if (exportName.length === 0) {
+ switch (info.type) {
+ case "concatenated":
+ neededNamespaceObjects.add(info);
+ return {
+ info,
+ rawName: info.namespaceObjectName,
+ ids: exportName,
+ exportName
+ };
+ case "external":
+ return { info, rawName: info.name, ids: exportName, exportName };
+ }
+ }
+ const exportsInfo = moduleGraph.getExportsInfo(info.module);
+ const exportInfo = exportsInfo.getExportInfo(exportName[0]);
+ if (alreadyVisited.has(exportInfo)) {
+ return {
+ info,
+ rawName: "/* circular reexport */ Object(function x() { x() }())",
+ ids: [],
+ exportName
+ };
+ }
+ alreadyVisited.add(exportInfo);
+ switch (info.type) {
+ case "concatenated": {
+ const exportId = exportName[0];
+ if (exportInfo.provided === false) {
+ // It's not provided, but it could be on the prototype
+ neededNamespaceObjects.add(info);
+ return {
+ info,
+ rawName: info.namespaceObjectName,
+ ids: exportName,
+ exportName
+ };
+ }
+ const directExport = info.exportMap && info.exportMap.get(exportId);
+ if (directExport) {
+ const usedName = /** @type {string[]} */ (
+ exportsInfo.getUsedName(exportName, runtime)
+ );
+ if (!usedName) {
+ return {
+ info,
+ rawName: "/* unused export */ undefined",
+ ids: exportName.slice(1),
+ exportName
+ };
+ }
+ return {
+ info,
+ name: directExport,
+ ids: usedName.slice(1),
+ exportName
+ };
+ }
+ const rawExport = info.rawExportMap && info.rawExportMap.get(exportId);
+ if (rawExport) {
+ return {
+ info,
+ rawName: rawExport,
+ ids: exportName.slice(1),
+ exportName
+ };
+ }
+ const reexport = exportInfo.findTarget(moduleGraph, module =>
+ moduleToInfoMap.has(module)
+ );
+ if (reexport === false) {
+ throw new Error(
+ `Target module of reexport from '${info.module.readableIdentifier(
+ requestShortener
+ )}' is not part of the concatenation (export '${exportId}')\nModules in the concatenation:\n${Array.from(
+ moduleToInfoMap,
+ ([m, info]) =>
+ ` * ${info.type} ${m.readableIdentifier(requestShortener)}`
+ ).join("\n")}`
+ );
+ }
+ if (reexport) {
+ const refInfo = moduleToInfoMap.get(reexport.module);
+ return getFinalBinding(
+ moduleGraph,
+ refInfo,
+ reexport.export
+ ? [...reexport.export, ...exportName.slice(1)]
+ : exportName.slice(1),
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ asCall,
+ info.module.buildMeta.strictHarmonyModule,
+ asiSafe,
+ alreadyVisited
+ );
+ }
+ if (info.namespaceExportSymbol) {
+ const usedName = /** @type {string[]} */ (
+ exportsInfo.getUsedName(exportName, runtime)
+ );
+ return {
+ info,
+ rawName: info.namespaceObjectName,
+ ids: usedName,
+ exportName
+ };
+ }
+ throw new Error(
+ `Cannot get final name for export '${exportName.join(
+ "."
+ )}' of ${info.module.readableIdentifier(requestShortener)}`
+ );
+ }
+
+ case "external": {
+ const used = /** @type {string[]} */ (
+ exportsInfo.getUsedName(exportName, runtime)
+ );
+ if (!used) {
+ return {
+ info,
+ rawName: "/* unused export */ undefined",
+ ids: exportName.slice(1),
+ exportName
+ };
+ }
+ const comment = equals(used, exportName)
+ ? ""
+ : Template.toNormalComment(`${exportName.join(".")}`);
+ return { info, rawName: info.name + comment, ids: used, exportName };
+ }
+ }
+};
+
+/**
+ * @param {ModuleGraph} moduleGraph the module graph
+ * @param {ModuleInfo} info module info
+ * @param {string[]} exportName exportName
+ * @param {Map<Module, ModuleInfo>} moduleToInfoMap moduleToInfoMap
+ * @param {RuntimeSpec} runtime for which runtime
+ * @param {RequestShortener} requestShortener the request shortener
+ * @param {RuntimeTemplate} runtimeTemplate the runtime template
+ * @param {Set<ConcatenatedModuleInfo>} neededNamespaceObjects modules for which a namespace object should be generated
+ * @param {boolean} asCall asCall
+ * @param {boolean} callContext callContext
+ * @param {boolean} strictHarmonyModule strictHarmonyModule
+ * @param {boolean | undefined} asiSafe asiSafe
+ * @returns {string} the final name
+ */
+const getFinalName = (
+ moduleGraph,
+ info,
+ exportName,
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ asCall,
+ callContext,
+ strictHarmonyModule,
+ asiSafe
+) => {
+ const binding = getFinalBinding(
+ moduleGraph,
+ info,
+ exportName,
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ asCall,
+ strictHarmonyModule,
+ asiSafe
+ );
+ {
+ const { ids, comment } = binding;
+ let reference;
+ let isPropertyAccess;
+ if ("rawName" in binding) {
+ reference = `${binding.rawName}${comment || ""}${propertyAccess(ids)}`;
+ isPropertyAccess = ids.length > 0;
+ } else {
+ const { info, name: exportId } = binding;
+ const name = info.internalNames.get(exportId);
+ if (!name) {
+ throw new Error(
+ `The export "${exportId}" in "${info.module.readableIdentifier(
+ requestShortener
+ )}" has no internal name (existing names: ${
+ Array.from(
+ info.internalNames,
+ ([name, symbol]) => `${name}: ${symbol}`
+ ).join(", ") || "none"
+ })`
+ );
+ }
+ reference = `${name}${comment || ""}${propertyAccess(ids)}`;
+ isPropertyAccess = ids.length > 1;
+ }
+ if (isPropertyAccess && asCall && callContext === false) {
+ return asiSafe
+ ? `(0,${reference})`
+ : asiSafe === false
+ ? `;(0,${reference})`
+ : `/*#__PURE__*/Object(${reference})`;
+ }
+ return reference;
+ }
+};
+
+const addScopeSymbols = (s, nameSet, scopeSet1, scopeSet2) => {
+ let scope = s;
+ while (scope) {
+ if (scopeSet1.has(scope)) break;
+ if (scopeSet2.has(scope)) break;
+ scopeSet1.add(scope);
+ for (const variable of scope.variables) {
+ nameSet.add(variable.name);
+ }
+ scope = scope.upper;
+ }
+};
+
+const getAllReferences = variable => {
+ let set = variable.references;
+ // Look for inner scope variables too (like in class Foo { t() { Foo } })
+ const identifiers = new Set(variable.identifiers);
+ for (const scope of variable.scope.childScopes) {
+ for (const innerVar of scope.variables) {
+ if (innerVar.identifiers.some(id => identifiers.has(id))) {
+ set = set.concat(innerVar.references);
+ break;
+ }
+ }
+ }
+ return set;
+};
+
+const getPathInAst = (ast, node) => {
+ if (ast === node) {
+ return [];
+ }
+
+ const nr = node.range;
+
+ const enterNode = n => {
+ if (!n) return undefined;
+ const r = n.range;
+ if (r) {
+ if (r[0] <= nr[0] && r[1] >= nr[1]) {
+ const path = getPathInAst(n, node);
+ if (path) {
+ path.push(n);
+ return path;
+ }
+ }
+ }
+ return undefined;
+ };
+
+ if (Array.isArray(ast)) {
+ for (let i = 0; i < ast.length; i++) {
+ const enterResult = enterNode(ast[i]);
+ if (enterResult !== undefined) return enterResult;
+ }
+ } else if (ast && typeof ast === "object") {
+ const keys = Object.keys(ast);
+ for (let i = 0; i < keys.length; i++) {
+ const value = ast[keys[i]];
+ if (Array.isArray(value)) {
+ const pathResult = getPathInAst(value, node);
+ if (pathResult !== undefined) return pathResult;
+ } else if (value && typeof value === "object") {
+ const enterResult = enterNode(value);
+ if (enterResult !== undefined) return enterResult;
+ }
+ }
+ }
+};
+
+const TYPES = new Set(["javascript"]);
+
+class ConcatenatedModule extends Module {
+ /**
+ * @param {Module} rootModule the root module of the concatenation
+ * @param {Set<Module>} modules all modules in the concatenation (including the root module)
+ * @param {RuntimeSpec} runtime the runtime
+ * @param {Object=} associatedObjectForCache object for caching
+ * @param {string | HashConstructor=} hashFunction hash function to use
+ * @returns {ConcatenatedModule} the module
+ */
+ static create(
+ rootModule,
+ modules,
+ runtime,
+ associatedObjectForCache,
+ hashFunction = "md4"
+ ) {
+ const identifier = ConcatenatedModule._createIdentifier(
+ rootModule,
+ modules,
+ associatedObjectForCache,
+ hashFunction
+ );
+ return new ConcatenatedModule({
+ identifier,
+ rootModule,
+ modules,
+ runtime
+ });
+ }
+
+ /**
+ * @param {Object} options options
+ * @param {string} options.identifier the identifier of the module
+ * @param {Module=} options.rootModule the root module of the concatenation
+ * @param {RuntimeSpec} options.runtime the selected runtime
+ * @param {Set<Module>=} options.modules all concatenated modules
+ */
+ constructor({ identifier, rootModule, modules, runtime }) {
+ super(JAVASCRIPT_MODULE_TYPE_ESM, null, rootModule && rootModule.layer);
+
+ // Info from Factory
+ /** @type {string} */
+ this._identifier = identifier;
+ /** @type {Module} */
+ this.rootModule = rootModule;
+ /** @type {Set<Module>} */
+ this._modules = modules;
+ this._runtime = runtime;
+ this.factoryMeta = rootModule && rootModule.factoryMeta;
+ }
+
+ /**
+ * Assuming this module is in the cache. Update the (cached) module with
+ * the fresh module from the factory. Usually updates internal references
+ * and properties.
+ * @param {Module} module fresh module
+ * @returns {void}
+ */
+ updateCacheModule(module) {
+ throw new Error("Must not be called");
+ }
+
+ /**
+ * @returns {Set<string>} types available (do not mutate)
+ */
+ getSourceTypes() {
+ return TYPES;
+ }
+
+ get modules() {
+ return Array.from(this._modules);
+ }
+
+ /**
+ * @returns {string} a unique identifier of the module
+ */
+ identifier() {
+ return this._identifier;
+ }
+
+ /**
+ * @param {RequestShortener} requestShortener the request shortener
+ * @returns {string} a user readable identifier of the module
+ */
+ readableIdentifier(requestShortener) {
+ return (
+ this.rootModule.readableIdentifier(requestShortener) +
+ ` + ${this._modules.size - 1} modules`
+ );
+ }
+
+ /**
+ * @param {LibIdentOptions} options options
+ * @returns {string | null} an identifier for library inclusion
+ */
+ libIdent(options) {
+ return this.rootModule.libIdent(options);
+ }
+
+ /**
+ * @returns {string | null} absolute path which should be used for condition matching (usually the resource path)
+ */
+ nameForCondition() {
+ return this.rootModule.nameForCondition();
+ }
+
+ /**
+ * @param {ModuleGraph} moduleGraph the module graph
+ * @returns {ConnectionState} how this module should be connected to referencing modules when consumed for side-effects only
+ */
+ getSideEffectsConnectionState(moduleGraph) {
+ return this.rootModule.getSideEffectsConnectionState(moduleGraph);
+ }
+
+ /**
+ * @param {WebpackOptions} options webpack options
+ * @param {Compilation} compilation the compilation
+ * @param {ResolverWithOptions} resolver the resolver
+ * @param {InputFileSystem} fs the file system
+ * @param {function(WebpackError=): void} callback callback function
+ * @returns {void}
+ */
+ build(options, compilation, resolver, fs, callback) {
+ const { rootModule } = this;
+ this.buildInfo = {
+ strict: true,
+ cacheable: true,
+ moduleArgument: rootModule.buildInfo.moduleArgument,
+ exportsArgument: rootModule.buildInfo.exportsArgument,
+ fileDependencies: new LazySet(),
+ contextDependencies: new LazySet(),
+ missingDependencies: new LazySet(),
+ topLevelDeclarations: new Set(),
+ assets: undefined
+ };
+ this.buildMeta = rootModule.buildMeta;
+ this.clearDependenciesAndBlocks();
+ this.clearWarningsAndErrors();
+
+ for (const m of this._modules) {
+ // populate cacheable
+ if (!m.buildInfo.cacheable) {
+ this.buildInfo.cacheable = false;
+ }
+
+ // populate dependencies
+ for (const d of m.dependencies.filter(
+ dep =>
+ !(dep instanceof HarmonyImportDependency) ||
+ !this._modules.has(compilation.moduleGraph.getModule(dep))
+ )) {
+ this.dependencies.push(d);
+ }
+ // populate blocks
+ for (const d of m.blocks) {
+ this.blocks.push(d);
+ }
+
+ // populate warnings
+ const warnings = m.getWarnings();
+ if (warnings !== undefined) {
+ for (const warning of warnings) {
+ this.addWarning(warning);
+ }
+ }
+
+ // populate errors
+ const errors = m.getErrors();
+ if (errors !== undefined) {
+ for (const error of errors) {
+ this.addError(error);
+ }
+ }
+
+ // populate topLevelDeclarations
+ if (m.buildInfo.topLevelDeclarations) {
+ const topLevelDeclarations = this.buildInfo.topLevelDeclarations;
+ if (topLevelDeclarations !== undefined) {
+ for (const decl of m.buildInfo.topLevelDeclarations) {
+ topLevelDeclarations.add(decl);
+ }
+ }
+ } else {
+ this.buildInfo.topLevelDeclarations = undefined;
+ }
+
+ // populate assets
+ if (m.buildInfo.assets) {
+ if (this.buildInfo.assets === undefined) {
+ this.buildInfo.assets = Object.create(null);
+ }
+ Object.assign(this.buildInfo.assets, m.buildInfo.assets);
+ }
+ if (m.buildInfo.assetsInfo) {
+ if (this.buildInfo.assetsInfo === undefined) {
+ this.buildInfo.assetsInfo = new Map();
+ }
+ for (const [key, value] of m.buildInfo.assetsInfo) {
+ this.buildInfo.assetsInfo.set(key, value);
+ }
+ }
+ }
+ callback();
+ }
+
+ /**
+ * @param {string=} type the source type for which the size should be estimated
+ * @returns {number} the estimated size of the module (must be non-zero)
+ */
+ size(type) {
+ // Guess size from embedded modules
+ let size = 0;
+ for (const module of this._modules) {
+ size += module.size(type);
+ }
+ return size;
+ }
+
+ /**
+ * @private
+ * @param {Module} rootModule the root of the concatenation
+ * @param {Set<Module>} modulesSet a set of modules which should be concatenated
+ * @param {RuntimeSpec} runtime for this runtime
+ * @param {ModuleGraph} moduleGraph the module graph
+ * @returns {ConcatenationEntry[]} concatenation list
+ */
+ _createConcatenationList(rootModule, modulesSet, runtime, moduleGraph) {
+ /** @type {ConcatenationEntry[]} */
+ const list = [];
+ /** @type {Map<Module, RuntimeSpec | true>} */
+ const existingEntries = new Map();
+
+ /**
+ * @param {Module} module a module
+ * @returns {Iterable<{ connection: ModuleGraphConnection, runtimeCondition: RuntimeSpec | true }>} imported modules in order
+ */
+ const getConcatenatedImports = module => {
+ let connections = Array.from(moduleGraph.getOutgoingConnections(module));
+ if (module === rootModule) {
+ for (const c of moduleGraph.getOutgoingConnections(this))
+ connections.push(c);
+ }
+ /**
+ * @type {Array<{ connection: ModuleGraphConnection, sourceOrder: number, rangeStart: number }>}
+ */
+ const references = connections
+ .filter(connection => {
+ if (!(connection.dependency instanceof HarmonyImportDependency))
+ return false;
+ return (
+ connection &&
+ connection.resolvedOriginModule === module &&
+ connection.module &&
+ connection.isTargetActive(runtime)
+ );
+ })
+ .map(connection => {
+ const dep = /** @type {HarmonyImportDependency} */ (
+ connection.dependency
+ );
+ return {
+ connection,
+ sourceOrder: dep.sourceOrder,
+ rangeStart: dep.range && dep.range[0]
+ };
+ });
+ /**
+ * bySourceOrder
+ * @example
+ * import a from "a"; // sourceOrder=1
+ * import b from "b"; // sourceOrder=2
+ *
+ * byRangeStart
+ * @example
+ * import {a, b} from "a"; // sourceOrder=1
+ * a.a(); // first range
+ * b.b(); // second range
+ *
+ * If there is no reexport, we have the same source.
+ * If there is reexport, but module has side effects, this will lead to reexport module only.
+ * If there is side-effects-free reexport, we can get simple deterministic result with range start comparison.
+ */
+ references.sort(concatComparators(bySourceOrder, byRangeStart));
+ /** @type {Map<Module, { connection: ModuleGraphConnection, runtimeCondition: RuntimeSpec | true }>} */
+ const referencesMap = new Map();
+ for (const { connection } of references) {
+ const runtimeCondition = filterRuntime(runtime, r =>
+ connection.isTargetActive(r)
+ );
+ if (runtimeCondition === false) continue;
+ const module = connection.module;
+ const entry = referencesMap.get(module);
+ if (entry === undefined) {
+ referencesMap.set(module, { connection, runtimeCondition });
+ continue;
+ }
+ entry.runtimeCondition = mergeRuntimeConditionNonFalse(
+ entry.runtimeCondition,
+ runtimeCondition,
+ runtime
+ );
+ }
+ return referencesMap.values();
+ };
+
+ /**
+ * @param {ModuleGraphConnection} connection graph connection
+ * @param {RuntimeSpec | true} runtimeCondition runtime condition
+ * @returns {void}
+ */
+ const enterModule = (connection, runtimeCondition) => {
+ const module = connection.module;
+ if (!module) return;
+ const existingEntry = existingEntries.get(module);
+ if (existingEntry === true) {
+ return;
+ }
+ if (modulesSet.has(module)) {
+ existingEntries.set(module, true);
+ if (runtimeCondition !== true) {
+ throw new Error(
+ `Cannot runtime-conditional concatenate a module (${module.identifier()} in ${this.rootModule.identifier()}, ${runtimeConditionToString(
+ runtimeCondition
+ )}). This should not happen.`
+ );
+ }
+ const imports = getConcatenatedImports(module);
+ for (const { connection, runtimeCondition } of imports)
+ enterModule(connection, runtimeCondition);
+ list.push({
+ type: "concatenated",
+ module: connection.module,
+ runtimeCondition
+ });
+ } else {
+ if (existingEntry !== undefined) {
+ const reducedRuntimeCondition = subtractRuntimeCondition(
+ runtimeCondition,
+ existingEntry,
+ runtime
+ );
+ if (reducedRuntimeCondition === false) return;
+ runtimeCondition = reducedRuntimeCondition;
+ existingEntries.set(
+ connection.module,
+ mergeRuntimeConditionNonFalse(
+ existingEntry,
+ runtimeCondition,
+ runtime
+ )
+ );
+ } else {
+ existingEntries.set(connection.module, runtimeCondition);
+ }
+ if (list.length > 0) {
+ const lastItem = list[list.length - 1];
+ if (
+ lastItem.type === "external" &&
+ lastItem.module === connection.module
+ ) {
+ lastItem.runtimeCondition = mergeRuntimeCondition(
+ lastItem.runtimeCondition,
+ runtimeCondition,
+ runtime
+ );
+ return;
+ }
+ }
+ list.push({
+ type: "external",
+ get module() {
+ // We need to use a getter here, because the module in the dependency
+ // could be replaced by some other process (i. e. also replaced with a
+ // concatenated module)
+ return connection.module;
+ },
+ runtimeCondition
+ });
+ }
+ };
+
+ existingEntries.set(rootModule, true);
+ const imports = getConcatenatedImports(rootModule);
+ for (const { connection, runtimeCondition } of imports)
+ enterModule(connection, runtimeCondition);
+ list.push({
+ type: "concatenated",
+ module: rootModule,
+ runtimeCondition: true
+ });
+
+ return list;
+ }
+
+ /**
+ * @param {Module} rootModule the root module of the concatenation
+ * @param {Set<Module>} modules all modules in the concatenation (including the root module)
+ * @param {Object=} associatedObjectForCache object for caching
+ * @param {string | HashConstructor=} hashFunction hash function to use
+ * @returns {string} the identifier
+ */
+ static _createIdentifier(
+ rootModule,
+ modules,
+ associatedObjectForCache,
+ hashFunction = "md4"
+ ) {
+ const cachedMakePathsRelative = makePathsRelative.bindContextCache(
+ rootModule.context,
+ associatedObjectForCache
+ );
+ let identifiers = [];
+ for (const module of modules) {
+ identifiers.push(cachedMakePathsRelative(module.identifier()));
+ }
+ identifiers.sort();
+ const hash = createHash(hashFunction);
+ hash.update(identifiers.join(" "));
+ return rootModule.identifier() + "|" + hash.digest("hex");
+ }
+
+ /**
+ * @param {LazySet<string>} fileDependencies set where file dependencies are added to
+ * @param {LazySet<string>} contextDependencies set where context dependencies are added to
+ * @param {LazySet<string>} missingDependencies set where missing dependencies are added to
+ * @param {LazySet<string>} buildDependencies set where build dependencies are added to
+ */
+ addCacheDependencies(
+ fileDependencies,
+ contextDependencies,
+ missingDependencies,
+ buildDependencies
+ ) {
+ for (const module of this._modules) {
+ module.addCacheDependencies(
+ fileDependencies,
+ contextDependencies,
+ missingDependencies,
+ buildDependencies
+ );
+ }
+ }
+
+ /**
+ * @param {CodeGenerationContext} context context for code generation
+ * @returns {CodeGenerationResult} result
+ */
+ codeGeneration({
+ dependencyTemplates,
+ runtimeTemplate,
+ moduleGraph,
+ chunkGraph,
+ runtime: generationRuntime,
+ codeGenerationResults
+ }) {
+ /** @type {Set<string>} */
+ const runtimeRequirements = new Set();
+ const runtime = intersectRuntime(generationRuntime, this._runtime);
+
+ const requestShortener = runtimeTemplate.requestShortener;
+ // Meta info for each module
+ const [modulesWithInfo, moduleToInfoMap] = this._getModulesWithInfo(
+ moduleGraph,
+ runtime
+ );
+
+ // Set with modules that need a generated namespace object
+ /** @type {Set<ConcatenatedModuleInfo>} */
+ const neededNamespaceObjects = new Set();
+
+ // Generate source code and analyse scopes
+ // Prepare a ReplaceSource for the final source
+ for (const info of moduleToInfoMap.values()) {
+ this._analyseModule(
+ moduleToInfoMap,
+ info,
+ dependencyTemplates,
+ runtimeTemplate,
+ moduleGraph,
+ chunkGraph,
+ runtime,
+ codeGenerationResults
+ );
+ }
+
+ // List of all used names to avoid conflicts
+ const allUsedNames = new Set(RESERVED_NAMES);
+ // Updated Top level declarations are created by renaming
+ const topLevelDeclarations = new Set();
+
+ // List of additional names in scope for module references
+ /** @type {Map<string, { usedNames: Set<string>, alreadyCheckedScopes: Set<TODO> }>} */
+ const usedNamesInScopeInfo = new Map();
+ /**
+ * @param {string} module module identifier
+ * @param {string} id export id
+ * @returns {{ usedNames: Set<string>, alreadyCheckedScopes: Set<TODO> }} info
+ */
+ const getUsedNamesInScopeInfo = (module, id) => {
+ const key = `${module}-${id}`;
+ let info = usedNamesInScopeInfo.get(key);
+ if (info === undefined) {
+ info = {
+ usedNames: new Set(),
+ alreadyCheckedScopes: new Set()
+ };
+ usedNamesInScopeInfo.set(key, info);
+ }
+ return info;
+ };
+
+ // Set of already checked scopes
+ const ignoredScopes = new Set();
+
+ // get all global names
+ for (const info of modulesWithInfo) {
+ if (info.type === "concatenated") {
+ // ignore symbols from moduleScope
+ if (info.moduleScope) {
+ ignoredScopes.add(info.moduleScope);
+ }
+
+ // The super class expression in class scopes behaves weird
+ // We get ranges of all super class expressions to make
+ // renaming to work correctly
+ const superClassCache = new WeakMap();
+ const getSuperClassExpressions = scope => {
+ const cacheEntry = superClassCache.get(scope);
+ if (cacheEntry !== undefined) return cacheEntry;
+ const superClassExpressions = [];
+ for (const childScope of scope.childScopes) {
+ if (childScope.type !== "class") continue;
+ const block = childScope.block;
+ if (
+ (block.type === "ClassDeclaration" ||
+ block.type === "ClassExpression") &&
+ block.superClass
+ ) {
+ superClassExpressions.push({
+ range: block.superClass.range,
+ variables: childScope.variables
+ });
+ }
+ }
+ superClassCache.set(scope, superClassExpressions);
+ return superClassExpressions;
+ };
+
+ // add global symbols
+ if (info.globalScope) {
+ for (const reference of info.globalScope.through) {
+ const name = reference.identifier.name;
+ if (ConcatenationScope.isModuleReference(name)) {
+ const match = ConcatenationScope.matchModuleReference(name);
+ if (!match) continue;
+ const referencedInfo = modulesWithInfo[match.index];
+ if (referencedInfo.type === "reference")
+ throw new Error("Module reference can't point to a reference");
+ const binding = getFinalBinding(
+ moduleGraph,
+ referencedInfo,
+ match.ids,
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ false,
+ info.module.buildMeta.strictHarmonyModule,
+ true
+ );
+ if (!binding.ids) continue;
+ const { usedNames, alreadyCheckedScopes } =
+ getUsedNamesInScopeInfo(
+ binding.info.module.identifier(),
+ "name" in binding ? binding.name : ""
+ );
+ for (const expr of getSuperClassExpressions(reference.from)) {
+ if (
+ expr.range[0] <= reference.identifier.range[0] &&
+ expr.range[1] >= reference.identifier.range[1]
+ ) {
+ for (const variable of expr.variables) {
+ usedNames.add(variable.name);
+ }
+ }
+ }
+ addScopeSymbols(
+ reference.from,
+ usedNames,
+ alreadyCheckedScopes,
+ ignoredScopes
+ );
+ } else {
+ allUsedNames.add(name);
+ }
+ }
+ }
+ }
+ }
+
+ // generate names for symbols
+ for (const info of moduleToInfoMap.values()) {
+ const { usedNames: namespaceObjectUsedNames } = getUsedNamesInScopeInfo(
+ info.module.identifier(),
+ ""
+ );
+ switch (info.type) {
+ case "concatenated": {
+ for (const variable of info.moduleScope.variables) {
+ const name = variable.name;
+ const { usedNames, alreadyCheckedScopes } = getUsedNamesInScopeInfo(
+ info.module.identifier(),
+ name
+ );
+ if (allUsedNames.has(name) || usedNames.has(name)) {
+ const references = getAllReferences(variable);
+ for (const ref of references) {
+ addScopeSymbols(
+ ref.from,
+ usedNames,
+ alreadyCheckedScopes,
+ ignoredScopes
+ );
+ }
+ const newName = this.findNewName(
+ name,
+ allUsedNames,
+ usedNames,
+ info.module.readableIdentifier(requestShortener)
+ );
+ allUsedNames.add(newName);
+ info.internalNames.set(name, newName);
+ topLevelDeclarations.add(newName);
+ const source = info.source;
+ const allIdentifiers = new Set(
+ references.map(r => r.identifier).concat(variable.identifiers)
+ );
+ for (const identifier of allIdentifiers) {
+ const r = identifier.range;
+ const path = getPathInAst(info.ast, identifier);
+ if (path && path.length > 1) {
+ const maybeProperty =
+ path[1].type === "AssignmentPattern" &&
+ path[1].left === path[0]
+ ? path[2]
+ : path[1];
+ if (
+ maybeProperty.type === "Property" &&
+ maybeProperty.shorthand
+ ) {
+ source.insert(r[1], `: ${newName}`);
+ continue;
+ }
+ }
+ source.replace(r[0], r[1] - 1, newName);
+ }
+ } else {
+ allUsedNames.add(name);
+ info.internalNames.set(name, name);
+ topLevelDeclarations.add(name);
+ }
+ }
+ let namespaceObjectName;
+ if (info.namespaceExportSymbol) {
+ namespaceObjectName = info.internalNames.get(
+ info.namespaceExportSymbol
+ );
+ } else {
+ namespaceObjectName = this.findNewName(
+ "namespaceObject",
+ allUsedNames,
+ namespaceObjectUsedNames,
+ info.module.readableIdentifier(requestShortener)
+ );
+ allUsedNames.add(namespaceObjectName);
+ }
+ info.namespaceObjectName = namespaceObjectName;
+ topLevelDeclarations.add(namespaceObjectName);
+ break;
+ }
+ case "external": {
+ const externalName = this.findNewName(
+ "",
+ allUsedNames,
+ namespaceObjectUsedNames,
+ info.module.readableIdentifier(requestShortener)
+ );
+ allUsedNames.add(externalName);
+ info.name = externalName;
+ topLevelDeclarations.add(externalName);
+ break;
+ }
+ }
+ if (info.module.buildMeta.exportsType !== "namespace") {
+ const externalNameInterop = this.findNewName(
+ "namespaceObject",
+ allUsedNames,
+ namespaceObjectUsedNames,
+ info.module.readableIdentifier(requestShortener)
+ );
+ allUsedNames.add(externalNameInterop);
+ info.interopNamespaceObjectName = externalNameInterop;
+ topLevelDeclarations.add(externalNameInterop);
+ }
+ if (
+ info.module.buildMeta.exportsType === "default" &&
+ info.module.buildMeta.defaultObject !== "redirect"
+ ) {
+ const externalNameInterop = this.findNewName(
+ "namespaceObject2",
+ allUsedNames,
+ namespaceObjectUsedNames,
+ info.module.readableIdentifier(requestShortener)
+ );
+ allUsedNames.add(externalNameInterop);
+ info.interopNamespaceObject2Name = externalNameInterop;
+ topLevelDeclarations.add(externalNameInterop);
+ }
+ if (
+ info.module.buildMeta.exportsType === "dynamic" ||
+ !info.module.buildMeta.exportsType
+ ) {
+ const externalNameInterop = this.findNewName(
+ "default",
+ allUsedNames,
+ namespaceObjectUsedNames,
+ info.module.readableIdentifier(requestShortener)
+ );
+ allUsedNames.add(externalNameInterop);
+ info.interopDefaultAccessName = externalNameInterop;
+ topLevelDeclarations.add(externalNameInterop);
+ }
+ }
+
+ // Find and replace references to modules
+ for (const info of moduleToInfoMap.values()) {
+ if (info.type === "concatenated") {
+ for (const reference of info.globalScope.through) {
+ const name = reference.identifier.name;
+ const match = ConcatenationScope.matchModuleReference(name);
+ if (match) {
+ const referencedInfo = modulesWithInfo[match.index];
+ if (referencedInfo.type === "reference")
+ throw new Error("Module reference can't point to a reference");
+ const finalName = getFinalName(
+ moduleGraph,
+ referencedInfo,
+ match.ids,
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ match.call,
+ !match.directImport,
+ info.module.buildMeta.strictHarmonyModule,
+ match.asiSafe
+ );
+ const r = reference.identifier.range;
+ const source = info.source;
+ // range is extended by 2 chars to cover the appended "._"
+ source.replace(r[0], r[1] + 1, finalName);
+ }
+ }
+ }
+ }
+
+ // Map with all root exposed used exports
+ /** @type {Map<string, function(RequestShortener): string>} */
+ const exportsMap = new Map();
+
+ // Set with all root exposed unused exports
+ /** @type {Set<string>} */
+ const unusedExports = new Set();
+
+ const rootInfo = /** @type {ConcatenatedModuleInfo} */ (
+ moduleToInfoMap.get(this.rootModule)
+ );
+ const strictHarmonyModule = rootInfo.module.buildMeta.strictHarmonyModule;
+ const exportsInfo = moduleGraph.getExportsInfo(rootInfo.module);
+ for (const exportInfo of exportsInfo.orderedExports) {
+ const name = exportInfo.name;
+ if (exportInfo.provided === false) continue;
+ const used = exportInfo.getUsedName(undefined, runtime);
+ if (!used) {
+ unusedExports.add(name);
+ continue;
+ }
+ exportsMap.set(used, requestShortener => {
+ try {
+ const finalName = getFinalName(
+ moduleGraph,
+ rootInfo,
+ [name],
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ false,
+ false,
+ strictHarmonyModule,
+ true
+ );
+ return `/* ${
+ exportInfo.isReexport() ? "reexport" : "binding"
+ } */ ${finalName}`;
+ } catch (e) {
+ e.message += `\nwhile generating the root export '${name}' (used name: '${used}')`;
+ throw e;
+ }
+ });
+ }
+
+ const result = new ConcatSource();
+
+ // add harmony compatibility flag (must be first because of possible circular dependencies)
+ if (
+ moduleGraph.getExportsInfo(this).otherExportsInfo.getUsed(runtime) !==
+ UsageState.Unused
+ ) {
+ result.add(`// ESM COMPAT FLAG\n`);
+ result.add(
+ runtimeTemplate.defineEsModuleFlagStatement({
+ exportsArgument: this.exportsArgument,
+ runtimeRequirements
+ })
+ );
+ }
+
+ // define exports
+ if (exportsMap.size > 0) {
+ runtimeRequirements.add(RuntimeGlobals.exports);
+ runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
+ const definitions = [];
+ for (const [key, value] of exportsMap) {
+ definitions.push(
+ `\n ${propertyName(key)}: ${runtimeTemplate.returningFunction(
+ value(requestShortener)
+ )}`
+ );
+ }
+ result.add(`\n// EXPORTS\n`);
+ result.add(
+ `${RuntimeGlobals.definePropertyGetters}(${
+ this.exportsArgument
+ }, {${definitions.join(",")}\n});\n`
+ );
+ }
+
+ // list unused exports
+ if (unusedExports.size > 0) {
+ result.add(
+ `\n// UNUSED EXPORTS: ${joinIterableWithComma(unusedExports)}\n`
+ );
+ }
+
+ // generate namespace objects
+ const namespaceObjectSources = new Map();
+ for (const info of neededNamespaceObjects) {
+ if (info.namespaceExportSymbol) continue;
+ const nsObj = [];
+ const exportsInfo = moduleGraph.getExportsInfo(info.module);
+ for (const exportInfo of exportsInfo.orderedExports) {
+ if (exportInfo.provided === false) continue;
+ const usedName = exportInfo.getUsedName(undefined, runtime);
+ if (usedName) {
+ const finalName = getFinalName(
+ moduleGraph,
+ info,
+ [exportInfo.name],
+ moduleToInfoMap,
+ runtime,
+ requestShortener,
+ runtimeTemplate,
+ neededNamespaceObjects,
+ false,
+ undefined,
+ info.module.buildMeta.strictHarmonyModule,
+ true
+ );
+ nsObj.push(
+ `\n ${propertyName(usedName)}: ${runtimeTemplate.returningFunction(
+ finalName
+ )}`
+ );
+ }
+ }
+ const name = info.namespaceObjectName;
+ const defineGetters =
+ nsObj.length > 0
+ ? `${RuntimeGlobals.definePropertyGetters}(${name}, {${nsObj.join(
+ ","
+ )}\n});\n`
+ : "";
+ if (nsObj.length > 0)
+ runtimeRequirements.add(RuntimeGlobals.definePropertyGetters);
+ namespaceObjectSources.set(
+ info,
+ `
+// NAMESPACE OBJECT: ${info.module.readableIdentifier(requestShortener)}
+var ${name} = {};
+${RuntimeGlobals.makeNamespaceObject}(${name});
+${defineGetters}`
+ );
+ runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject);
+ }
+
+ // define required namespace objects (must be before evaluation modules)
+ for (const info of modulesWithInfo) {
+ if (info.type === "concatenated") {
+ const source = namespaceObjectSources.get(info);
+ if (!source) continue;
+ result.add(source);
+ }
+ }
+
+ const chunkInitFragments = [];
+
+ // evaluate modules in order
+ for (const rawInfo of modulesWithInfo) {
+ let name;
+ let isConditional = false;
+ const info = rawInfo.type === "reference" ? rawInfo.target : rawInfo;
+ switch (info.type) {
+ case "concatenated": {
+ result.add(
+ `\n;// CONCATENATED MODULE: ${info.module.readableIdentifier(
+ requestShortener
+ )}\n`
+ );
+ result.add(info.source);
+ if (info.chunkInitFragments) {
+ for (const f of info.chunkInitFragments) chunkInitFragments.push(f);
+ }
+ if (info.runtimeRequirements) {
+ for (const r of info.runtimeRequirements) {
+ runtimeRequirements.add(r);
+ }
+ }
+ name = info.namespaceObjectName;
+ break;
+ }
+ case "external": {
+ result.add(
+ `\n// EXTERNAL MODULE: ${info.module.readableIdentifier(
+ requestShortener
+ )}\n`
+ );
+ runtimeRequirements.add(RuntimeGlobals.require);
+ const { runtimeCondition } =
+ /** @type {ExternalModuleInfo | ReferenceToModuleInfo} */ (rawInfo);
+ const condition = runtimeTemplate.runtimeConditionExpression({
+ chunkGraph,
+ runtimeCondition,
+ runtime,
+ runtimeRequirements
+ });
+ if (condition !== "true") {
+ isConditional = true;
+ result.add(`if (${condition}) {\n`);
+ }
+ result.add(
+ `var ${info.name} = ${RuntimeGlobals.require}(${JSON.stringify(
+ chunkGraph.getModuleId(info.module)
+ )});`
+ );
+ name = info.name;
+ break;
+ }
+ default:
+ // @ts-expect-error never is expected here
+ throw new Error(`Unsupported concatenation entry type ${info.type}`);
+ }
+ if (info.interopNamespaceObjectUsed) {
+ runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
+ result.add(
+ `\nvar ${info.interopNamespaceObjectName} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${name}, 2);`
+ );
+ }
+ if (info.interopNamespaceObject2Used) {
+ runtimeRequirements.add(RuntimeGlobals.createFakeNamespaceObject);
+ result.add(
+ `\nvar ${info.interopNamespaceObject2Name} = /*#__PURE__*/${RuntimeGlobals.createFakeNamespaceObject}(${name});`
+ );
+ }
+ if (info.interopDefaultAccessUsed) {
+ runtimeRequirements.add(RuntimeGlobals.compatGetDefaultExport);
+ result.add(
+ `\nvar ${info.interopDefaultAccessName} = /*#__PURE__*/${RuntimeGlobals.compatGetDefaultExport}(${name});`
+ );
+ }
+ if (isConditional) {
+ result.add("\n}");
+ }
+ }
+
+ const data = new Map();
+ if (chunkInitFragments.length > 0)
+ data.set("chunkInitFragments", chunkInitFragments);
+ data.set("topLevelDeclarations", topLevelDeclarations);
+
+ /** @type {CodeGenerationResult} */
+ const resultEntry = {
+ sources: new Map([["javascript", new CachedSource(result)]]),
+ data,
+ runtimeRequirements
+ };
+
+ return resultEntry;
+ }
+
+ /**
+ * @param {Map<Module, ModuleInfo>} modulesMap modulesMap
+ * @param {ModuleInfo} info info
+ * @param {DependencyTemplates} dependencyTemplates dependencyTemplates
+ * @param {RuntimeTemplate} runtimeTemplate runtimeTemplate
+ * @param {ModuleGraph} moduleGraph moduleGraph
+ * @param {ChunkGraph} chunkGraph chunkGraph
+ * @param {RuntimeSpec} runtime runtime
+ * @param {CodeGenerationResults} codeGenerationResults codeGenerationResults
+ */
+ _analyseModule(
+ modulesMap,
+ info,
+ dependencyTemplates,
+ runtimeTemplate,
+ moduleGraph,
+ chunkGraph,
+ runtime,
+ codeGenerationResults
+ ) {
+ if (info.type === "concatenated") {
+ const m = info.module;
+ try {
+ // Create a concatenation scope to track and capture information
+ const concatenationScope = new ConcatenationScope(modulesMap, info);
+
+ // TODO cache codeGeneration results
+ const codeGenResult = m.codeGeneration({
+ dependencyTemplates,
+ runtimeTemplate,
+ moduleGraph,
+ chunkGraph,
+ runtime,
+ concatenationScope,
+ codeGenerationResults,
+ sourceTypes: TYPES
+ });
+ const source = codeGenResult.sources.get("javascript");
+ const data = codeGenResult.data;
+ const chunkInitFragments = data && data.get("chunkInitFragments");
+ const code = source.source().toString();
+ let ast;
+ try {
+ ast = JavascriptParser._parse(code, {
+ sourceType: "module"
+ });
+ } catch (err) {
+ if (
+ err.loc &&
+ typeof err.loc === "object" &&
+ typeof err.loc.line === "number"
+ ) {
+ const lineNumber = err.loc.line;
+ const lines = code.split("\n");
+ err.message +=
+ "\n| " +
+ lines
+ .slice(Math.max(0, lineNumber - 3), lineNumber + 2)
+ .join("\n| ");
+ }
+ throw err;
+ }
+ const scopeManager = eslintScope.analyze(ast, {
+ ecmaVersion: 6,
+ sourceType: "module",
+ optimistic: true,
+ ignoreEval: true,
+ impliedStrict: true
+ });
+ const globalScope = scopeManager.acquire(ast);
+ const moduleScope = globalScope.childScopes[0];
+ const resultSource = new ReplaceSource(source);
+ info.runtimeRequirements = codeGenResult.runtimeRequirements;
+ info.ast = ast;
+ info.internalSource = source;
+ info.source = resultSource;
+ info.chunkInitFragments = chunkInitFragments;
+ info.globalScope = globalScope;
+ info.moduleScope = moduleScope;
+ } catch (err) {
+ err.message += `\nwhile analyzing module ${m.identifier()} for concatenation`;
+ throw err;
+ }
+ }
+ }
+
+ /**
+ * @param {ModuleGraph} moduleGraph the module graph
+ * @param {RuntimeSpec} runtime the runtime
+ * @returns {[ModuleInfoOrReference[], Map<Module, ModuleInfo>]} module info items
+ */
+ _getModulesWithInfo(moduleGraph, runtime) {
+ const orderedConcatenationList = this._createConcatenationList(
+ this.rootModule,
+ this._modules,
+ runtime,
+ moduleGraph
+ );
+ /** @type {Map<Module, ModuleInfo>} */
+ const map = new Map();
+ const list = orderedConcatenationList.map((info, index) => {
+ let item = map.get(info.module);
+ if (item === undefined) {
+ switch (info.type) {
+ case "concatenated":
+ item = {
+ type: "concatenated",
+ module: info.module,
+ index,
+ ast: undefined,
+ internalSource: undefined,
+ runtimeRequirements: undefined,
+ source: undefined,
+ globalScope: undefined,
+ moduleScope: undefined,
+ internalNames: new Map(),
+ exportMap: undefined,
+ rawExportMap: undefined,
+ namespaceExportSymbol: undefined,
+ namespaceObjectName: undefined,
+ interopNamespaceObjectUsed: false,
+ interopNamespaceObjectName: undefined,
+ interopNamespaceObject2Used: false,
+ interopNamespaceObject2Name: undefined,
+ interopDefaultAccessUsed: false,
+ interopDefaultAccessName: undefined
+ };
+ break;
+ case "external":
+ item = {
+ type: "external",
+ module: info.module,
+ runtimeCondition: info.runtimeCondition,
+ index,
+ name: undefined,
+ interopNamespaceObjectUsed: false,
+ interopNamespaceObjectName: undefined,
+ interopNamespaceObject2Used: false,
+ interopNamespaceObject2Name: undefined,
+ interopDefaultAccessUsed: false,
+ interopDefaultAccessName: undefined
+ };
+ break;
+ default:
+ throw new Error(
+ `Unsupported concatenation entry type ${info.type}`
+ );
+ }
+ map.set(item.module, item);
+ return item;
+ } else {
+ /** @type {ReferenceToModuleInfo} */
+ const ref = {
+ type: "reference",
+ runtimeCondition: info.runtimeCondition,
+ target: item
+ };
+ return ref;
+ }
+ });
+ return [list, map];
+ }
+
+ findNewName(oldName, usedNamed1, usedNamed2, extraInfo) {
+ let name = oldName;
+
+ if (name === ConcatenationScope.DEFAULT_EXPORT) {
+ name = "";
+ }
+ if (name === ConcatenationScope.NAMESPACE_OBJECT_EXPORT) {
+ name = "namespaceObject";
+ }
+
+ // Remove uncool stuff
+ extraInfo = extraInfo.replace(
+ /\.+\/|(\/index)?\.([a-zA-Z0-9]{1,4})($|\s|\?)|\s*\+\s*\d+\s*modules/g,
+ ""
+ );
+
+ const splittedInfo = extraInfo.split("/");
+ while (splittedInfo.length) {
+ name = splittedInfo.pop() + (name ? "_" + name : "");
+ const nameIdent = Template.toIdentifier(name);
+ if (
+ !usedNamed1.has(nameIdent) &&
+ (!usedNamed2 || !usedNamed2.has(nameIdent))
+ )
+ return nameIdent;
+ }
+
+ let i = 0;
+ let nameWithNumber = Template.toIdentifier(`${name}_${i}`);
+ while (
+ usedNamed1.has(nameWithNumber) ||
+ (usedNamed2 && usedNamed2.has(nameWithNumber))
+ ) {
+ i++;
+ nameWithNumber = Template.toIdentifier(`${name}_${i}`);
+ }
+ return nameWithNumber;
+ }
+
+ /**
+ * @param {Hash} hash the hash used to track dependencies
+ * @param {UpdateHashContext} context context
+ * @returns {void}
+ */
+ updateHash(hash, context) {
+ const { chunkGraph, runtime } = context;
+ for (const info of this._createConcatenationList(
+ this.rootModule,
+ this._modules,
+ intersectRuntime(runtime, this._runtime),
+ chunkGraph.moduleGraph
+ )) {
+ switch (info.type) {
+ case "concatenated":
+ info.module.updateHash(hash, context);
+ break;
+ case "external":
+ hash.update(`${chunkGraph.getModuleId(info.module)}`);
+ // TODO runtimeCondition
+ break;
+ }
+ }
+ super.updateHash(hash, context);
+ }
+
+ static deserialize(context) {
+ const obj = new ConcatenatedModule({
+ identifier: undefined,
+ rootModule: undefined,
+ modules: undefined,
+ runtime: undefined
+ });
+ obj.deserialize(context);
+ return obj;
+ }
+}
+
+makeSerializable(ConcatenatedModule, "webpack/lib/optimize/ConcatenatedModule");
+
+module.exports = ConcatenatedModule;