summaryrefslogtreecommitdiff
path: root/node_modules/webpack/lib/ChunkGraph.js
diff options
context:
space:
mode:
authorlittleblack111 <littleblack11111@gmail.com>2023-11-05 17:16:09 +0800
committerlittleblack111 <littleblack11111@gmail.com>2023-11-05 17:16:09 +0800
commitd1d9f00b1bd660842addf5e6b1d1b64c852a9eea (patch)
tree60fb37ae73a1109d95301de5ec9b61b5726a4b61 /node_modules/webpack/lib/ChunkGraph.js
parent7c85166c4cbdd862fc4252007d2df5befcbc2a58 (diff)
added hover prefixer
Diffstat (limited to 'node_modules/webpack/lib/ChunkGraph.js')
-rw-r--r--node_modules/webpack/lib/ChunkGraph.js1814
1 files changed, 1814 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/ChunkGraph.js b/node_modules/webpack/lib/ChunkGraph.js
new file mode 100644
index 00000000..a1914351
--- /dev/null
+++ b/node_modules/webpack/lib/ChunkGraph.js
@@ -0,0 +1,1814 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Tobias Koppers @sokra
+*/
+
+"use strict";
+
+const util = require("util");
+const Entrypoint = require("./Entrypoint");
+const ModuleGraphConnection = require("./ModuleGraphConnection");
+const { first } = require("./util/SetHelpers");
+const SortableSet = require("./util/SortableSet");
+const {
+ compareModulesById,
+ compareIterables,
+ compareModulesByIdentifier,
+ concatComparators,
+ compareSelect,
+ compareIds
+} = require("./util/comparators");
+const createHash = require("./util/createHash");
+const findGraphRoots = require("./util/findGraphRoots");
+const {
+ RuntimeSpecMap,
+ RuntimeSpecSet,
+ runtimeToString,
+ mergeRuntime,
+ forEachRuntime
+} = require("./util/runtime");
+
+/** @typedef {import("./AsyncDependenciesBlock")} AsyncDependenciesBlock */
+/** @typedef {import("./Chunk")} Chunk */
+/** @typedef {import("./ChunkGroup")} ChunkGroup */
+/** @typedef {import("./Module")} Module */
+/** @typedef {import("./ModuleGraph")} ModuleGraph */
+/** @typedef {import("./RuntimeModule")} RuntimeModule */
+/** @typedef {typeof import("./util/Hash")} Hash */
+/** @typedef {import("./util/runtime").RuntimeSpec} RuntimeSpec */
+
+/** @type {ReadonlySet<string>} */
+const EMPTY_SET = new Set();
+
+const ZERO_BIG_INT = BigInt(0);
+
+const compareModuleIterables = compareIterables(compareModulesByIdentifier);
+
+/** @typedef {(c: Chunk, chunkGraph: ChunkGraph) => boolean} ChunkFilterPredicate */
+/** @typedef {(m: Module) => boolean} ModuleFilterPredicate */
+/** @typedef {[Module, Entrypoint | undefined]} EntryModuleWithChunkGroup */
+
+/**
+ * @typedef {Object} ChunkSizeOptions
+ * @property {number=} chunkOverhead constant overhead for a chunk
+ * @property {number=} entryChunkMultiplicator multiplicator for initial chunks
+ */
+
+class ModuleHashInfo {
+ constructor(hash, renderedHash) {
+ this.hash = hash;
+ this.renderedHash = renderedHash;
+ }
+}
+
+/** @template T @typedef {(set: SortableSet<T>) => T[]} SetToArrayFunction<T> */
+
+/**
+ * @template T
+ * @param {SortableSet<T>} set the set
+ * @returns {T[]} set as array
+ */
+const getArray = set => {
+ return Array.from(set);
+};
+
+/**
+ * @param {SortableSet<Chunk>} chunks the chunks
+ * @returns {RuntimeSpecSet} runtimes
+ */
+const getModuleRuntimes = chunks => {
+ const runtimes = new RuntimeSpecSet();
+ for (const chunk of chunks) {
+ runtimes.add(chunk.runtime);
+ }
+ return runtimes;
+};
+
+/**
+ * @param {WeakMap<Module, Set<string>> | undefined} sourceTypesByModule sourceTypesByModule
+ * @returns {function (SortableSet<Module>): Map<string, SortableSet<Module>>} modules by source type
+ */
+const modulesBySourceType = sourceTypesByModule => set => {
+ /** @type {Map<string, SortableSet<Module>>} */
+ const map = new Map();
+ for (const module of set) {
+ const sourceTypes =
+ (sourceTypesByModule && sourceTypesByModule.get(module)) ||
+ module.getSourceTypes();
+ for (const sourceType of sourceTypes) {
+ let innerSet = map.get(sourceType);
+ if (innerSet === undefined) {
+ innerSet = new SortableSet();
+ map.set(sourceType, innerSet);
+ }
+ innerSet.add(module);
+ }
+ }
+ for (const [key, innerSet] of map) {
+ // When all modules have the source type, we reuse the original SortableSet
+ // to benefit from the shared cache (especially for sorting)
+ if (innerSet.size === set.size) {
+ map.set(key, set);
+ }
+ }
+ return map;
+};
+const defaultModulesBySourceType = modulesBySourceType(undefined);
+
+/** @type {WeakMap<Function, any>} */
+const createOrderedArrayFunctionMap = new WeakMap();
+
+/**
+ * @template T
+ * @param {function(T, T): -1|0|1} comparator comparator function
+ * @returns {SetToArrayFunction<T>} set as ordered array
+ */
+const createOrderedArrayFunction = comparator => {
+ /** @type {SetToArrayFunction<T>} */
+ let fn = createOrderedArrayFunctionMap.get(comparator);
+ if (fn !== undefined) return fn;
+ fn = set => {
+ set.sortWith(comparator);
+ return Array.from(set);
+ };
+ createOrderedArrayFunctionMap.set(comparator, fn);
+ return fn;
+};
+
+/**
+ * @param {Iterable<Module>} modules the modules to get the count/size of
+ * @returns {number} the size of the modules
+ */
+const getModulesSize = modules => {
+ let size = 0;
+ for (const module of modules) {
+ for (const type of module.getSourceTypes()) {
+ size += module.size(type);
+ }
+ }
+ return size;
+};
+
+/**
+ * @param {Iterable<Module>} modules the sortable Set to get the size of
+ * @returns {Record<string, number>} the sizes of the modules
+ */
+const getModulesSizes = modules => {
+ let sizes = Object.create(null);
+ for (const module of modules) {
+ for (const type of module.getSourceTypes()) {
+ sizes[type] = (sizes[type] || 0) + module.size(type);
+ }
+ }
+ return sizes;
+};
+
+/**
+ * @param {Chunk} a chunk
+ * @param {Chunk} b chunk
+ * @returns {boolean} true, if a is always a parent of b
+ */
+const isAvailableChunk = (a, b) => {
+ const queue = new Set(b.groupsIterable);
+ for (const chunkGroup of queue) {
+ if (a.isInGroup(chunkGroup)) continue;
+ if (chunkGroup.isInitial()) return false;
+ for (const parent of chunkGroup.parentsIterable) {
+ queue.add(parent);
+ }
+ }
+ return true;
+};
+
+class ChunkGraphModule {
+ constructor() {
+ /** @type {SortableSet<Chunk>} */
+ this.chunks = new SortableSet();
+ /** @type {Set<Chunk> | undefined} */
+ this.entryInChunks = undefined;
+ /** @type {Set<Chunk> | undefined} */
+ this.runtimeInChunks = undefined;
+ /** @type {RuntimeSpecMap<ModuleHashInfo> | undefined} */
+ this.hashes = undefined;
+ /** @type {string | number} */
+ this.id = null;
+ /** @type {RuntimeSpecMap<Set<string>> | undefined} */
+ this.runtimeRequirements = undefined;
+ /** @type {RuntimeSpecMap<string>} */
+ this.graphHashes = undefined;
+ /** @type {RuntimeSpecMap<string>} */
+ this.graphHashesWithConnections = undefined;
+ }
+}
+
+class ChunkGraphChunk {
+ constructor() {
+ /** @type {SortableSet<Module>} */
+ this.modules = new SortableSet();
+ /** @type {WeakMap<Module, Set<string>> | undefined} */
+ this.sourceTypesByModule = undefined;
+ /** @type {Map<Module, Entrypoint>} */
+ this.entryModules = new Map();
+ /** @type {SortableSet<RuntimeModule>} */
+ this.runtimeModules = new SortableSet();
+ /** @type {Set<RuntimeModule> | undefined} */
+ this.fullHashModules = undefined;
+ /** @type {Set<RuntimeModule> | undefined} */
+ this.dependentHashModules = undefined;
+ /** @type {Set<string> | undefined} */
+ this.runtimeRequirements = undefined;
+ /** @type {Set<string>} */
+ this.runtimeRequirementsInTree = new Set();
+
+ this._modulesBySourceType = defaultModulesBySourceType;
+ }
+}
+
+class ChunkGraph {
+ /**
+ * @param {ModuleGraph} moduleGraph the module graph
+ * @param {string | Hash} hashFunction the hash function to use
+ */
+ constructor(moduleGraph, hashFunction = "md4") {
+ /** @private @type {WeakMap<Module, ChunkGraphModule>} */
+ this._modules = new WeakMap();
+ /** @private @type {WeakMap<Chunk, ChunkGraphChunk>} */
+ this._chunks = new WeakMap();
+ /** @private @type {WeakMap<AsyncDependenciesBlock, ChunkGroup>} */
+ this._blockChunkGroups = new WeakMap();
+ /** @private @type {Map<string, string | number>} */
+ this._runtimeIds = new Map();
+ /** @type {ModuleGraph} */
+ this.moduleGraph = moduleGraph;
+
+ this._hashFunction = hashFunction;
+
+ this._getGraphRoots = this._getGraphRoots.bind(this);
+ }
+
+ /**
+ * @private
+ * @param {Module} module the module
+ * @returns {ChunkGraphModule} internal module
+ */
+ _getChunkGraphModule(module) {
+ let cgm = this._modules.get(module);
+ if (cgm === undefined) {
+ cgm = new ChunkGraphModule();
+ this._modules.set(module, cgm);
+ }
+ return cgm;
+ }
+
+ /**
+ * @private
+ * @param {Chunk} chunk the chunk
+ * @returns {ChunkGraphChunk} internal chunk
+ */
+ _getChunkGraphChunk(chunk) {
+ let cgc = this._chunks.get(chunk);
+ if (cgc === undefined) {
+ cgc = new ChunkGraphChunk();
+ this._chunks.set(chunk, cgc);
+ }
+ return cgc;
+ }
+
+ /**
+ * @param {SortableSet<Module>} set the sortable Set to get the roots of
+ * @returns {Module[]} the graph roots
+ */
+ _getGraphRoots(set) {
+ const { moduleGraph } = this;
+ return Array.from(
+ findGraphRoots(set, module => {
+ /** @type {Set<Module>} */
+ const set = new Set();
+ const addDependencies = module => {
+ for (const connection of moduleGraph.getOutgoingConnections(module)) {
+ if (!connection.module) continue;
+ const activeState = connection.getActiveState(undefined);
+ if (activeState === false) continue;
+ if (activeState === ModuleGraphConnection.TRANSITIVE_ONLY) {
+ addDependencies(connection.module);
+ continue;
+ }
+ set.add(connection.module);
+ }
+ };
+ addDependencies(module);
+ return set;
+ })
+ ).sort(compareModulesByIdentifier);
+ }
+
+ /**
+ * @param {Chunk} chunk the new chunk
+ * @param {Module} module the module
+ * @returns {void}
+ */
+ connectChunkAndModule(chunk, module) {
+ const cgm = this._getChunkGraphModule(module);
+ const cgc = this._getChunkGraphChunk(chunk);
+ cgm.chunks.add(chunk);
+ cgc.modules.add(module);
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {Module} module the module
+ * @returns {void}
+ */
+ disconnectChunkAndModule(chunk, module) {
+ const cgm = this._getChunkGraphModule(module);
+ const cgc = this._getChunkGraphChunk(chunk);
+ cgc.modules.delete(module);
+ // No need to invalidate cgc._modulesBySourceType because we modified cgc.modules anyway
+ if (cgc.sourceTypesByModule) cgc.sourceTypesByModule.delete(module);
+ cgm.chunks.delete(chunk);
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk which will be disconnected
+ * @returns {void}
+ */
+ disconnectChunk(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ for (const module of cgc.modules) {
+ const cgm = this._getChunkGraphModule(module);
+ cgm.chunks.delete(chunk);
+ }
+ cgc.modules.clear();
+ chunk.disconnectFromGroups();
+ ChunkGraph.clearChunkGraphForChunk(chunk);
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {Iterable<Module>} modules the modules
+ * @returns {void}
+ */
+ attachModules(chunk, modules) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ for (const module of modules) {
+ cgc.modules.add(module);
+ }
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {Iterable<RuntimeModule>} modules the runtime modules
+ * @returns {void}
+ */
+ attachRuntimeModules(chunk, modules) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ for (const module of modules) {
+ cgc.runtimeModules.add(module);
+ }
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {Iterable<RuntimeModule>} modules the modules that require a full hash
+ * @returns {void}
+ */
+ attachFullHashModules(chunk, modules) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ if (cgc.fullHashModules === undefined) cgc.fullHashModules = new Set();
+ for (const module of modules) {
+ cgc.fullHashModules.add(module);
+ }
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {Iterable<RuntimeModule>} modules the modules that require a full hash
+ * @returns {void}
+ */
+ attachDependentHashModules(chunk, modules) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ if (cgc.dependentHashModules === undefined)
+ cgc.dependentHashModules = new Set();
+ for (const module of modules) {
+ cgc.dependentHashModules.add(module);
+ }
+ }
+
+ /**
+ * @param {Module} oldModule the replaced module
+ * @param {Module} newModule the replacing module
+ * @returns {void}
+ */
+ replaceModule(oldModule, newModule) {
+ const oldCgm = this._getChunkGraphModule(oldModule);
+ const newCgm = this._getChunkGraphModule(newModule);
+
+ for (const chunk of oldCgm.chunks) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ cgc.modules.delete(oldModule);
+ cgc.modules.add(newModule);
+ newCgm.chunks.add(chunk);
+ }
+ oldCgm.chunks.clear();
+
+ if (oldCgm.entryInChunks !== undefined) {
+ if (newCgm.entryInChunks === undefined) {
+ newCgm.entryInChunks = new Set();
+ }
+ for (const chunk of oldCgm.entryInChunks) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ const old = cgc.entryModules.get(oldModule);
+ /** @type {Map<Module, Entrypoint>} */
+ const newEntryModules = new Map();
+ for (const [m, cg] of cgc.entryModules) {
+ if (m === oldModule) {
+ newEntryModules.set(newModule, old);
+ } else {
+ newEntryModules.set(m, cg);
+ }
+ }
+ cgc.entryModules = newEntryModules;
+ newCgm.entryInChunks.add(chunk);
+ }
+ oldCgm.entryInChunks = undefined;
+ }
+
+ if (oldCgm.runtimeInChunks !== undefined) {
+ if (newCgm.runtimeInChunks === undefined) {
+ newCgm.runtimeInChunks = new Set();
+ }
+ for (const chunk of oldCgm.runtimeInChunks) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ cgc.runtimeModules.delete(/** @type {RuntimeModule} */ (oldModule));
+ cgc.runtimeModules.add(/** @type {RuntimeModule} */ (newModule));
+ newCgm.runtimeInChunks.add(chunk);
+ if (
+ cgc.fullHashModules !== undefined &&
+ cgc.fullHashModules.has(/** @type {RuntimeModule} */ (oldModule))
+ ) {
+ cgc.fullHashModules.delete(/** @type {RuntimeModule} */ (oldModule));
+ cgc.fullHashModules.add(/** @type {RuntimeModule} */ (newModule));
+ }
+ if (
+ cgc.dependentHashModules !== undefined &&
+ cgc.dependentHashModules.has(/** @type {RuntimeModule} */ (oldModule))
+ ) {
+ cgc.dependentHashModules.delete(
+ /** @type {RuntimeModule} */ (oldModule)
+ );
+ cgc.dependentHashModules.add(
+ /** @type {RuntimeModule} */ (newModule)
+ );
+ }
+ }
+ oldCgm.runtimeInChunks = undefined;
+ }
+ }
+
+ /**
+ * @param {Module} module the checked module
+ * @param {Chunk} chunk the checked chunk
+ * @returns {boolean} true, if the chunk contains the module
+ */
+ isModuleInChunk(module, chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.modules.has(module);
+ }
+
+ /**
+ * @param {Module} module the checked module
+ * @param {ChunkGroup} chunkGroup the checked chunk group
+ * @returns {boolean} true, if the chunk contains the module
+ */
+ isModuleInChunkGroup(module, chunkGroup) {
+ for (const chunk of chunkGroup.chunks) {
+ if (this.isModuleInChunk(module, chunk)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param {Module} module the checked module
+ * @returns {boolean} true, if the module is entry of any chunk
+ */
+ isEntryModule(module) {
+ const cgm = this._getChunkGraphModule(module);
+ return cgm.entryInChunks !== undefined;
+ }
+
+ /**
+ * @param {Module} module the module
+ * @returns {Iterable<Chunk>} iterable of chunks (do not modify)
+ */
+ getModuleChunksIterable(module) {
+ const cgm = this._getChunkGraphModule(module);
+ return cgm.chunks;
+ }
+
+ /**
+ * @param {Module} module the module
+ * @param {function(Chunk, Chunk): -1|0|1} sortFn sort function
+ * @returns {Iterable<Chunk>} iterable of chunks (do not modify)
+ */
+ getOrderedModuleChunksIterable(module, sortFn) {
+ const cgm = this._getChunkGraphModule(module);
+ cgm.chunks.sortWith(sortFn);
+ return cgm.chunks;
+ }
+
+ /**
+ * @param {Module} module the module
+ * @returns {Chunk[]} array of chunks (cached, do not modify)
+ */
+ getModuleChunks(module) {
+ const cgm = this._getChunkGraphModule(module);
+ return cgm.chunks.getFromCache(getArray);
+ }
+
+ /**
+ * @param {Module} module the module
+ * @returns {number} the number of chunk which contain the module
+ */
+ getNumberOfModuleChunks(module) {
+ const cgm = this._getChunkGraphModule(module);
+ return cgm.chunks.size;
+ }
+
+ /**
+ * @param {Module} module the module
+ * @returns {RuntimeSpecSet} runtimes
+ */
+ getModuleRuntimes(module) {
+ const cgm = this._getChunkGraphModule(module);
+ return cgm.chunks.getFromUnorderedCache(getModuleRuntimes);
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {number} the number of modules which are contained in this chunk
+ */
+ getNumberOfChunkModules(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.modules.size;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {number} the number of full hash modules which are contained in this chunk
+ */
+ getNumberOfChunkFullHashModules(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.fullHashModules === undefined ? 0 : cgc.fullHashModules.size;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {Iterable<Module>} return the modules for this chunk
+ */
+ getChunkModulesIterable(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.modules;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {string} sourceType source type
+ * @returns {Iterable<Module> | undefined} return the modules for this chunk
+ */
+ getChunkModulesIterableBySourceType(chunk, sourceType) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ const modulesWithSourceType = cgc.modules
+ .getFromUnorderedCache(cgc._modulesBySourceType)
+ .get(sourceType);
+ return modulesWithSourceType;
+ }
+
+ /**
+ * @param {Chunk} chunk chunk
+ * @param {Module} module chunk module
+ * @param {Set<string>} sourceTypes source types
+ */
+ setChunkModuleSourceTypes(chunk, module, sourceTypes) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ if (cgc.sourceTypesByModule === undefined) {
+ cgc.sourceTypesByModule = new WeakMap();
+ }
+ cgc.sourceTypesByModule.set(module, sourceTypes);
+ // Update cgc._modulesBySourceType to invalidate the cache
+ cgc._modulesBySourceType = modulesBySourceType(cgc.sourceTypesByModule);
+ }
+
+ /**
+ * @param {Chunk} chunk chunk
+ * @param {Module} module chunk module
+ * @returns {Set<string>} source types
+ */
+ getChunkModuleSourceTypes(chunk, module) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ if (cgc.sourceTypesByModule === undefined) {
+ return module.getSourceTypes();
+ }
+ return cgc.sourceTypesByModule.get(module) || module.getSourceTypes();
+ }
+
+ /**
+ * @param {Module} module module
+ * @returns {Set<string>} source types
+ */
+ getModuleSourceTypes(module) {
+ return (
+ this._getOverwrittenModuleSourceTypes(module) || module.getSourceTypes()
+ );
+ }
+
+ /**
+ * @param {Module} module module
+ * @returns {Set<string> | undefined} source types
+ */
+ _getOverwrittenModuleSourceTypes(module) {
+ let newSet = false;
+ let sourceTypes;
+ for (const chunk of this.getModuleChunksIterable(module)) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ if (cgc.sourceTypesByModule === undefined) return;
+ const st = cgc.sourceTypesByModule.get(module);
+ if (st === undefined) return;
+ if (!sourceTypes) {
+ sourceTypes = st;
+ continue;
+ } else if (!newSet) {
+ for (const type of st) {
+ if (!newSet) {
+ if (!sourceTypes.has(type)) {
+ newSet = true;
+ sourceTypes = new Set(sourceTypes);
+ sourceTypes.add(type);
+ }
+ } else {
+ sourceTypes.add(type);
+ }
+ }
+ } else {
+ for (const type of st) sourceTypes.add(type);
+ }
+ }
+
+ return sourceTypes;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {function(Module, Module): -1|0|1} comparator comparator function
+ * @returns {Iterable<Module>} return the modules for this chunk
+ */
+ getOrderedChunkModulesIterable(chunk, comparator) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ cgc.modules.sortWith(comparator);
+ return cgc.modules;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {string} sourceType source type
+ * @param {function(Module, Module): -1|0|1} comparator comparator function
+ * @returns {Iterable<Module> | undefined} return the modules for this chunk
+ */
+ getOrderedChunkModulesIterableBySourceType(chunk, sourceType, comparator) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ const modulesWithSourceType = cgc.modules
+ .getFromUnorderedCache(cgc._modulesBySourceType)
+ .get(sourceType);
+ if (modulesWithSourceType === undefined) return undefined;
+ modulesWithSourceType.sortWith(comparator);
+ return modulesWithSourceType;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {Module[]} return the modules for this chunk (cached, do not modify)
+ */
+ getChunkModules(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.modules.getFromUnorderedCache(getArray);
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {function(Module, Module): -1|0|1} comparator comparator function
+ * @returns {Module[]} return the modules for this chunk (cached, do not modify)
+ */
+ getOrderedChunkModules(chunk, comparator) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ const arrayFunction = createOrderedArrayFunction(comparator);
+ return cgc.modules.getFromUnorderedCache(arrayFunction);
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {ModuleFilterPredicate} filterFn function used to filter modules
+ * @param {boolean} includeAllChunks all chunks or only async chunks
+ * @returns {Record<string|number, (string|number)[]>} chunk to module ids object
+ */
+ getChunkModuleIdMap(chunk, filterFn, includeAllChunks = false) {
+ /** @type {Record<string|number, (string|number)[]>} */
+ const chunkModuleIdMap = Object.create(null);
+
+ for (const asyncChunk of includeAllChunks
+ ? chunk.getAllReferencedChunks()
+ : chunk.getAllAsyncChunks()) {
+ /** @type {(string|number)[]} */
+ let array;
+ for (const module of this.getOrderedChunkModulesIterable(
+ asyncChunk,
+ compareModulesById(this)
+ )) {
+ if (filterFn(module)) {
+ if (array === undefined) {
+ array = [];
+ chunkModuleIdMap[asyncChunk.id] = array;
+ }
+ const moduleId = this.getModuleId(module);
+ array.push(moduleId);
+ }
+ }
+ }
+
+ return chunkModuleIdMap;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {ModuleFilterPredicate} filterFn function used to filter modules
+ * @param {number} hashLength length of the hash
+ * @param {boolean} includeAllChunks all chunks or only async chunks
+ * @returns {Record<string|number, Record<string|number, string>>} chunk to module id to module hash object
+ */
+ getChunkModuleRenderedHashMap(
+ chunk,
+ filterFn,
+ hashLength = 0,
+ includeAllChunks = false
+ ) {
+ /** @type {Record<string|number, Record<string|number, string>>} */
+ const chunkModuleHashMap = Object.create(null);
+
+ for (const asyncChunk of includeAllChunks
+ ? chunk.getAllReferencedChunks()
+ : chunk.getAllAsyncChunks()) {
+ /** @type {Record<string|number, string>} */
+ let idToHashMap;
+ for (const module of this.getOrderedChunkModulesIterable(
+ asyncChunk,
+ compareModulesById(this)
+ )) {
+ if (filterFn(module)) {
+ if (idToHashMap === undefined) {
+ idToHashMap = Object.create(null);
+ chunkModuleHashMap[asyncChunk.id] = idToHashMap;
+ }
+ const moduleId = this.getModuleId(module);
+ const hash = this.getRenderedModuleHash(module, asyncChunk.runtime);
+ idToHashMap[moduleId] = hashLength ? hash.slice(0, hashLength) : hash;
+ }
+ }
+ }
+
+ return chunkModuleHashMap;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {ChunkFilterPredicate} filterFn function used to filter chunks
+ * @returns {Record<string|number, boolean>} chunk map
+ */
+ getChunkConditionMap(chunk, filterFn) {
+ const map = Object.create(null);
+ for (const c of chunk.getAllReferencedChunks()) {
+ map[c.id] = filterFn(c, this);
+ }
+ return map;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {ModuleFilterPredicate} filterFn predicate function used to filter modules
+ * @param {ChunkFilterPredicate=} filterChunkFn predicate function used to filter chunks
+ * @returns {boolean} return true if module exists in graph
+ */
+ hasModuleInGraph(chunk, filterFn, filterChunkFn) {
+ const queue = new Set(chunk.groupsIterable);
+ const chunksProcessed = new Set();
+
+ for (const chunkGroup of queue) {
+ for (const innerChunk of chunkGroup.chunks) {
+ if (!chunksProcessed.has(innerChunk)) {
+ chunksProcessed.add(innerChunk);
+ if (!filterChunkFn || filterChunkFn(innerChunk, this)) {
+ for (const module of this.getChunkModulesIterable(innerChunk)) {
+ if (filterFn(module)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ for (const child of chunkGroup.childrenIterable) {
+ queue.add(child);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param {Chunk} chunkA first chunk
+ * @param {Chunk} chunkB second chunk
+ * @returns {-1|0|1} this is a comparator function like sort and returns -1, 0, or 1 based on sort order
+ */
+ compareChunks(chunkA, chunkB) {
+ const cgcA = this._getChunkGraphChunk(chunkA);
+ const cgcB = this._getChunkGraphChunk(chunkB);
+ if (cgcA.modules.size > cgcB.modules.size) return -1;
+ if (cgcA.modules.size < cgcB.modules.size) return 1;
+ cgcA.modules.sortWith(compareModulesByIdentifier);
+ cgcB.modules.sortWith(compareModulesByIdentifier);
+ return compareModuleIterables(cgcA.modules, cgcB.modules);
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {number} total size of all modules in the chunk
+ */
+ getChunkModulesSize(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.modules.getFromUnorderedCache(getModulesSize);
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {Record<string, number>} total sizes of all modules in the chunk by source type
+ */
+ getChunkModulesSizes(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.modules.getFromUnorderedCache(getModulesSizes);
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {Module[]} root modules of the chunks (ordered by identifier)
+ */
+ getChunkRootModules(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.modules.getFromUnorderedCache(this._getGraphRoots);
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {ChunkSizeOptions} options options object
+ * @returns {number} total size of the chunk
+ */
+ getChunkSize(chunk, options = {}) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ const modulesSize = cgc.modules.getFromUnorderedCache(getModulesSize);
+ const chunkOverhead =
+ typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
+ const entryChunkMultiplicator =
+ typeof options.entryChunkMultiplicator === "number"
+ ? options.entryChunkMultiplicator
+ : 10;
+ return (
+ chunkOverhead +
+ modulesSize * (chunk.canBeInitial() ? entryChunkMultiplicator : 1)
+ );
+ }
+
+ /**
+ * @param {Chunk} chunkA chunk
+ * @param {Chunk} chunkB chunk
+ * @param {ChunkSizeOptions} options options object
+ * @returns {number} total size of the chunk or false if chunks can't be integrated
+ */
+ getIntegratedChunksSize(chunkA, chunkB, options = {}) {
+ const cgcA = this._getChunkGraphChunk(chunkA);
+ const cgcB = this._getChunkGraphChunk(chunkB);
+ const allModules = new Set(cgcA.modules);
+ for (const m of cgcB.modules) allModules.add(m);
+ let modulesSize = getModulesSize(allModules);
+ const chunkOverhead =
+ typeof options.chunkOverhead === "number" ? options.chunkOverhead : 10000;
+ const entryChunkMultiplicator =
+ typeof options.entryChunkMultiplicator === "number"
+ ? options.entryChunkMultiplicator
+ : 10;
+ return (
+ chunkOverhead +
+ modulesSize *
+ (chunkA.canBeInitial() || chunkB.canBeInitial()
+ ? entryChunkMultiplicator
+ : 1)
+ );
+ }
+
+ /**
+ * @param {Chunk} chunkA chunk
+ * @param {Chunk} chunkB chunk
+ * @returns {boolean} true, if chunks could be integrated
+ */
+ canChunksBeIntegrated(chunkA, chunkB) {
+ if (chunkA.preventIntegration || chunkB.preventIntegration) {
+ return false;
+ }
+
+ const hasRuntimeA = chunkA.hasRuntime();
+ const hasRuntimeB = chunkB.hasRuntime();
+
+ if (hasRuntimeA !== hasRuntimeB) {
+ if (hasRuntimeA) {
+ return isAvailableChunk(chunkA, chunkB);
+ } else if (hasRuntimeB) {
+ return isAvailableChunk(chunkB, chunkA);
+ } else {
+ return false;
+ }
+ }
+
+ if (
+ this.getNumberOfEntryModules(chunkA) > 0 ||
+ this.getNumberOfEntryModules(chunkB) > 0
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @param {Chunk} chunkA the target chunk
+ * @param {Chunk} chunkB the chunk to integrate
+ * @returns {void}
+ */
+ integrateChunks(chunkA, chunkB) {
+ // Decide for one name (deterministic)
+ if (chunkA.name && chunkB.name) {
+ if (
+ this.getNumberOfEntryModules(chunkA) > 0 ===
+ this.getNumberOfEntryModules(chunkB) > 0
+ ) {
+ // When both chunks have entry modules or none have one, use
+ // shortest name
+ if (chunkA.name.length !== chunkB.name.length) {
+ chunkA.name =
+ chunkA.name.length < chunkB.name.length ? chunkA.name : chunkB.name;
+ } else {
+ chunkA.name = chunkA.name < chunkB.name ? chunkA.name : chunkB.name;
+ }
+ } else if (this.getNumberOfEntryModules(chunkB) > 0) {
+ // Pick the name of the chunk with the entry module
+ chunkA.name = chunkB.name;
+ }
+ } else if (chunkB.name) {
+ chunkA.name = chunkB.name;
+ }
+
+ // Merge id name hints
+ for (const hint of chunkB.idNameHints) {
+ chunkA.idNameHints.add(hint);
+ }
+
+ // Merge runtime
+ chunkA.runtime = mergeRuntime(chunkA.runtime, chunkB.runtime);
+
+ // getChunkModules is used here to create a clone, because disconnectChunkAndModule modifies
+ for (const module of this.getChunkModules(chunkB)) {
+ this.disconnectChunkAndModule(chunkB, module);
+ this.connectChunkAndModule(chunkA, module);
+ }
+
+ for (const [module, chunkGroup] of Array.from(
+ this.getChunkEntryModulesWithChunkGroupIterable(chunkB)
+ )) {
+ this.disconnectChunkAndEntryModule(chunkB, module);
+ this.connectChunkAndEntryModule(chunkA, module, chunkGroup);
+ }
+
+ for (const chunkGroup of chunkB.groupsIterable) {
+ chunkGroup.replaceChunk(chunkB, chunkA);
+ chunkA.addGroup(chunkGroup);
+ chunkB.removeGroup(chunkGroup);
+ }
+ ChunkGraph.clearChunkGraphForChunk(chunkB);
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk to upgrade
+ * @returns {void}
+ */
+ upgradeDependentToFullHashModules(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ if (cgc.dependentHashModules === undefined) return;
+ if (cgc.fullHashModules === undefined) {
+ cgc.fullHashModules = cgc.dependentHashModules;
+ } else {
+ for (const m of cgc.dependentHashModules) {
+ cgc.fullHashModules.add(m);
+ }
+ cgc.dependentHashModules = undefined;
+ }
+ }
+
+ /**
+ * @param {Module} module the checked module
+ * @param {Chunk} chunk the checked chunk
+ * @returns {boolean} true, if the chunk contains the module as entry
+ */
+ isEntryModuleInChunk(module, chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.entryModules.has(module);
+ }
+
+ /**
+ * @param {Chunk} chunk the new chunk
+ * @param {Module} module the entry module
+ * @param {Entrypoint=} entrypoint the chunk group which must be loaded before the module is executed
+ * @returns {void}
+ */
+ connectChunkAndEntryModule(chunk, module, entrypoint) {
+ const cgm = this._getChunkGraphModule(module);
+ const cgc = this._getChunkGraphChunk(chunk);
+ if (cgm.entryInChunks === undefined) {
+ cgm.entryInChunks = new Set();
+ }
+ cgm.entryInChunks.add(chunk);
+ cgc.entryModules.set(module, entrypoint);
+ }
+
+ /**
+ * @param {Chunk} chunk the new chunk
+ * @param {RuntimeModule} module the runtime module
+ * @returns {void}
+ */
+ connectChunkAndRuntimeModule(chunk, module) {
+ const cgm = this._getChunkGraphModule(module);
+ const cgc = this._getChunkGraphChunk(chunk);
+ if (cgm.runtimeInChunks === undefined) {
+ cgm.runtimeInChunks = new Set();
+ }
+ cgm.runtimeInChunks.add(chunk);
+ cgc.runtimeModules.add(module);
+ }
+
+ /**
+ * @param {Chunk} chunk the new chunk
+ * @param {RuntimeModule} module the module that require a full hash
+ * @returns {void}
+ */
+ addFullHashModuleToChunk(chunk, module) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ if (cgc.fullHashModules === undefined) cgc.fullHashModules = new Set();
+ cgc.fullHashModules.add(module);
+ }
+
+ /**
+ * @param {Chunk} chunk the new chunk
+ * @param {RuntimeModule} module the module that require a full hash
+ * @returns {void}
+ */
+ addDependentHashModuleToChunk(chunk, module) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ if (cgc.dependentHashModules === undefined)
+ cgc.dependentHashModules = new Set();
+ cgc.dependentHashModules.add(module);
+ }
+
+ /**
+ * @param {Chunk} chunk the new chunk
+ * @param {Module} module the entry module
+ * @returns {void}
+ */
+ disconnectChunkAndEntryModule(chunk, module) {
+ const cgm = this._getChunkGraphModule(module);
+ const cgc = this._getChunkGraphChunk(chunk);
+ cgm.entryInChunks.delete(chunk);
+ if (cgm.entryInChunks.size === 0) {
+ cgm.entryInChunks = undefined;
+ }
+ cgc.entryModules.delete(module);
+ }
+
+ /**
+ * @param {Chunk} chunk the new chunk
+ * @param {RuntimeModule} module the runtime module
+ * @returns {void}
+ */
+ disconnectChunkAndRuntimeModule(chunk, module) {
+ const cgm = this._getChunkGraphModule(module);
+ const cgc = this._getChunkGraphChunk(chunk);
+ cgm.runtimeInChunks.delete(chunk);
+ if (cgm.runtimeInChunks.size === 0) {
+ cgm.runtimeInChunks = undefined;
+ }
+ cgc.runtimeModules.delete(module);
+ }
+
+ /**
+ * @param {Module} module the entry module, it will no longer be entry
+ * @returns {void}
+ */
+ disconnectEntryModule(module) {
+ const cgm = this._getChunkGraphModule(module);
+ for (const chunk of cgm.entryInChunks) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ cgc.entryModules.delete(module);
+ }
+ cgm.entryInChunks = undefined;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk, for which all entries will be removed
+ * @returns {void}
+ */
+ disconnectEntries(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ for (const module of cgc.entryModules.keys()) {
+ const cgm = this._getChunkGraphModule(module);
+ cgm.entryInChunks.delete(chunk);
+ if (cgm.entryInChunks.size === 0) {
+ cgm.entryInChunks = undefined;
+ }
+ }
+ cgc.entryModules.clear();
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {number} the amount of entry modules in chunk
+ */
+ getNumberOfEntryModules(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.entryModules.size;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {number} the amount of entry modules in chunk
+ */
+ getNumberOfRuntimeModules(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.runtimeModules.size;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {Iterable<Module>} iterable of modules (do not modify)
+ */
+ getChunkEntryModulesIterable(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.entryModules.keys();
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {Iterable<Chunk>} iterable of chunks
+ */
+ getChunkEntryDependentChunksIterable(chunk) {
+ /** @type {Set<Chunk>} */
+ const set = new Set();
+ for (const chunkGroup of chunk.groupsIterable) {
+ if (chunkGroup instanceof Entrypoint) {
+ const entrypointChunk = chunkGroup.getEntrypointChunk();
+ const cgc = this._getChunkGraphChunk(entrypointChunk);
+ for (const chunkGroup of cgc.entryModules.values()) {
+ for (const c of chunkGroup.chunks) {
+ if (c !== chunk && c !== entrypointChunk && !c.hasRuntime()) {
+ set.add(c);
+ }
+ }
+ }
+ }
+ }
+
+ return set;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {boolean} true, when it has dependent chunks
+ */
+ hasChunkEntryDependentChunks(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ for (const chunkGroup of cgc.entryModules.values()) {
+ for (const c of chunkGroup.chunks) {
+ if (c !== chunk) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {Iterable<RuntimeModule>} iterable of modules (do not modify)
+ */
+ getChunkRuntimeModulesIterable(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.runtimeModules;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {RuntimeModule[]} array of modules in order of execution
+ */
+ getChunkRuntimeModulesInOrder(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ const array = Array.from(cgc.runtimeModules);
+ array.sort(
+ concatComparators(
+ compareSelect(
+ /**
+ * @param {RuntimeModule} r runtime module
+ * @returns {number=} stage
+ */
+ r => r.stage,
+ compareIds
+ ),
+ compareModulesByIdentifier
+ )
+ );
+ return array;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {Iterable<RuntimeModule> | undefined} iterable of modules (do not modify)
+ */
+ getChunkFullHashModulesIterable(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.fullHashModules;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {ReadonlySet<RuntimeModule> | undefined} set of modules (do not modify)
+ */
+ getChunkFullHashModulesSet(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.fullHashModules;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {Iterable<RuntimeModule> | undefined} iterable of modules (do not modify)
+ */
+ getChunkDependentHashModulesIterable(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.dependentHashModules;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {Iterable<EntryModuleWithChunkGroup>} iterable of modules (do not modify)
+ */
+ getChunkEntryModulesWithChunkGroupIterable(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.entryModules;
+ }
+
+ /**
+ * @param {AsyncDependenciesBlock} depBlock the async block
+ * @returns {ChunkGroup} the chunk group
+ */
+ getBlockChunkGroup(depBlock) {
+ return this._blockChunkGroups.get(depBlock);
+ }
+
+ /**
+ * @param {AsyncDependenciesBlock} depBlock the async block
+ * @param {ChunkGroup} chunkGroup the chunk group
+ * @returns {void}
+ */
+ connectBlockAndChunkGroup(depBlock, chunkGroup) {
+ this._blockChunkGroups.set(depBlock, chunkGroup);
+ chunkGroup.addBlock(depBlock);
+ }
+
+ /**
+ * @param {ChunkGroup} chunkGroup the chunk group
+ * @returns {void}
+ */
+ disconnectChunkGroup(chunkGroup) {
+ for (const block of chunkGroup.blocksIterable) {
+ this._blockChunkGroups.delete(block);
+ }
+ // TODO refactor by moving blocks list into ChunkGraph
+ chunkGroup._blocks.clear();
+ }
+
+ /**
+ * @param {Module} module the module
+ * @returns {string | number} the id of the module
+ */
+ getModuleId(module) {
+ const cgm = this._getChunkGraphModule(module);
+ return cgm.id;
+ }
+
+ /**
+ * @param {Module} module the module
+ * @param {string | number} id the id of the module
+ * @returns {void}
+ */
+ setModuleId(module, id) {
+ const cgm = this._getChunkGraphModule(module);
+ cgm.id = id;
+ }
+
+ /**
+ * @param {string} runtime runtime
+ * @returns {string | number} the id of the runtime
+ */
+ getRuntimeId(runtime) {
+ return this._runtimeIds.get(runtime);
+ }
+
+ /**
+ * @param {string} runtime runtime
+ * @param {string | number} id the id of the runtime
+ * @returns {void}
+ */
+ setRuntimeId(runtime, id) {
+ this._runtimeIds.set(runtime, id);
+ }
+
+ /**
+ * @template T
+ * @param {Module} module the module
+ * @param {RuntimeSpecMap<T>} hashes hashes data
+ * @param {RuntimeSpec} runtime the runtime
+ * @returns {T} hash
+ */
+ _getModuleHashInfo(module, hashes, runtime) {
+ if (!hashes) {
+ throw new Error(
+ `Module ${module.identifier()} has no hash info for runtime ${runtimeToString(
+ runtime
+ )} (hashes not set at all)`
+ );
+ } else if (runtime === undefined) {
+ const hashInfoItems = new Set(hashes.values());
+ if (hashInfoItems.size !== 1) {
+ throw new Error(
+ `No unique hash info entry for unspecified runtime for ${module.identifier()} (existing runtimes: ${Array.from(
+ hashes.keys(),
+ r => runtimeToString(r)
+ ).join(", ")}).
+Caller might not support runtime-dependent code generation (opt-out via optimization.usedExports: "global").`
+ );
+ }
+ return first(hashInfoItems);
+ } else {
+ const hashInfo = hashes.get(runtime);
+ if (!hashInfo) {
+ throw new Error(
+ `Module ${module.identifier()} has no hash info for runtime ${runtimeToString(
+ runtime
+ )} (available runtimes ${Array.from(
+ hashes.keys(),
+ runtimeToString
+ ).join(", ")})`
+ );
+ }
+ return hashInfo;
+ }
+ }
+
+ /**
+ * @param {Module} module the module
+ * @param {RuntimeSpec} runtime the runtime
+ * @returns {boolean} true, if the module has hashes for this runtime
+ */
+ hasModuleHashes(module, runtime) {
+ const cgm = this._getChunkGraphModule(module);
+ const hashes = /** @type {RuntimeSpecMap<ModuleHashInfo>} */ (cgm.hashes);
+ return hashes && hashes.has(runtime);
+ }
+
+ /**
+ * @param {Module} module the module
+ * @param {RuntimeSpec} runtime the runtime
+ * @returns {string} hash
+ */
+ getModuleHash(module, runtime) {
+ const cgm = this._getChunkGraphModule(module);
+ const hashes = /** @type {RuntimeSpecMap<ModuleHashInfo>} */ (cgm.hashes);
+ return this._getModuleHashInfo(module, hashes, runtime).hash;
+ }
+
+ /**
+ * @param {Module} module the module
+ * @param {RuntimeSpec} runtime the runtime
+ * @returns {string} hash
+ */
+ getRenderedModuleHash(module, runtime) {
+ const cgm = this._getChunkGraphModule(module);
+ const hashes = /** @type {RuntimeSpecMap<ModuleHashInfo>} */ (cgm.hashes);
+ return this._getModuleHashInfo(module, hashes, runtime).renderedHash;
+ }
+
+ /**
+ * @param {Module} module the module
+ * @param {RuntimeSpec} runtime the runtime
+ * @param {string} hash the full hash
+ * @param {string} renderedHash the shortened hash for rendering
+ * @returns {void}
+ */
+ setModuleHashes(module, runtime, hash, renderedHash) {
+ const cgm = this._getChunkGraphModule(module);
+ if (cgm.hashes === undefined) {
+ cgm.hashes = new RuntimeSpecMap();
+ }
+ cgm.hashes.set(runtime, new ModuleHashInfo(hash, renderedHash));
+ }
+
+ /**
+ * @param {Module} module the module
+ * @param {RuntimeSpec} runtime the runtime
+ * @param {Set<string>} items runtime requirements to be added (ownership of this Set is given to ChunkGraph when transferOwnership not false)
+ * @param {boolean} transferOwnership true: transfer ownership of the items object, false: items is immutable and shared and won't be modified
+ * @returns {void}
+ */
+ addModuleRuntimeRequirements(
+ module,
+ runtime,
+ items,
+ transferOwnership = true
+ ) {
+ const cgm = this._getChunkGraphModule(module);
+ const runtimeRequirementsMap = cgm.runtimeRequirements;
+ if (runtimeRequirementsMap === undefined) {
+ const map = new RuntimeSpecMap();
+ // TODO avoid cloning item and track ownership instead
+ map.set(runtime, transferOwnership ? items : new Set(items));
+ cgm.runtimeRequirements = map;
+ return;
+ }
+ runtimeRequirementsMap.update(runtime, runtimeRequirements => {
+ if (runtimeRequirements === undefined) {
+ return transferOwnership ? items : new Set(items);
+ } else if (!transferOwnership || runtimeRequirements.size >= items.size) {
+ for (const item of items) runtimeRequirements.add(item);
+ return runtimeRequirements;
+ } else {
+ for (const item of runtimeRequirements) items.add(item);
+ return items;
+ }
+ });
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {Set<string>} items runtime requirements to be added (ownership of this Set is given to ChunkGraph)
+ * @returns {void}
+ */
+ addChunkRuntimeRequirements(chunk, items) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ const runtimeRequirements = cgc.runtimeRequirements;
+ if (runtimeRequirements === undefined) {
+ cgc.runtimeRequirements = items;
+ } else if (runtimeRequirements.size >= items.size) {
+ for (const item of items) runtimeRequirements.add(item);
+ } else {
+ for (const item of runtimeRequirements) items.add(item);
+ cgc.runtimeRequirements = items;
+ }
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {Iterable<string>} items runtime requirements to be added
+ * @returns {void}
+ */
+ addTreeRuntimeRequirements(chunk, items) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ const runtimeRequirements = cgc.runtimeRequirementsInTree;
+ for (const item of items) runtimeRequirements.add(item);
+ }
+
+ /**
+ * @param {Module} module the module
+ * @param {RuntimeSpec} runtime the runtime
+ * @returns {ReadonlySet<string>} runtime requirements
+ */
+ getModuleRuntimeRequirements(module, runtime) {
+ const cgm = this._getChunkGraphModule(module);
+ const runtimeRequirements =
+ cgm.runtimeRequirements && cgm.runtimeRequirements.get(runtime);
+ return runtimeRequirements === undefined ? EMPTY_SET : runtimeRequirements;
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {ReadonlySet<string>} runtime requirements
+ */
+ getChunkRuntimeRequirements(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ const runtimeRequirements = cgc.runtimeRequirements;
+ return runtimeRequirements === undefined ? EMPTY_SET : runtimeRequirements;
+ }
+
+ /**
+ * @param {Module} module the module
+ * @param {RuntimeSpec} runtime the runtime
+ * @param {boolean} withConnections include connections
+ * @returns {string} hash
+ */
+ getModuleGraphHash(module, runtime, withConnections = true) {
+ const cgm = this._getChunkGraphModule(module);
+ return withConnections
+ ? this._getModuleGraphHashWithConnections(cgm, module, runtime)
+ : this._getModuleGraphHashBigInt(cgm, module, runtime).toString(16);
+ }
+
+ /**
+ * @param {Module} module the module
+ * @param {RuntimeSpec} runtime the runtime
+ * @param {boolean} withConnections include connections
+ * @returns {bigint} hash
+ */
+ getModuleGraphHashBigInt(module, runtime, withConnections = true) {
+ const cgm = this._getChunkGraphModule(module);
+ return withConnections
+ ? BigInt(
+ `0x${this._getModuleGraphHashWithConnections(cgm, module, runtime)}`
+ )
+ : this._getModuleGraphHashBigInt(cgm, module, runtime);
+ }
+
+ /**
+ * @param {ChunkGraphModule} cgm the ChunkGraphModule
+ * @param {Module} module the module
+ * @param {RuntimeSpec} runtime the runtime
+ * @returns {bigint} hash as big int
+ */
+ _getModuleGraphHashBigInt(cgm, module, runtime) {
+ if (cgm.graphHashes === undefined) {
+ cgm.graphHashes = new RuntimeSpecMap();
+ }
+ const graphHash = cgm.graphHashes.provide(runtime, () => {
+ const hash = createHash(this._hashFunction);
+ hash.update(`${cgm.id}${this.moduleGraph.isAsync(module)}`);
+ const sourceTypes = this._getOverwrittenModuleSourceTypes(module);
+ if (sourceTypes !== undefined) {
+ for (const type of sourceTypes) hash.update(type);
+ }
+ this.moduleGraph.getExportsInfo(module).updateHash(hash, runtime);
+ return BigInt(`0x${/** @type {string} */ (hash.digest("hex"))}`);
+ });
+ return graphHash;
+ }
+
+ /**
+ * @param {ChunkGraphModule} cgm the ChunkGraphModule
+ * @param {Module} module the module
+ * @param {RuntimeSpec} runtime the runtime
+ * @returns {string} hash
+ */
+ _getModuleGraphHashWithConnections(cgm, module, runtime) {
+ if (cgm.graphHashesWithConnections === undefined) {
+ cgm.graphHashesWithConnections = new RuntimeSpecMap();
+ }
+ const activeStateToString = state => {
+ if (state === false) return "F";
+ if (state === true) return "T";
+ if (state === ModuleGraphConnection.TRANSITIVE_ONLY) return "O";
+ throw new Error("Not implemented active state");
+ };
+ const strict = module.buildMeta && module.buildMeta.strictHarmonyModule;
+ return cgm.graphHashesWithConnections.provide(runtime, () => {
+ const graphHash = this._getModuleGraphHashBigInt(
+ cgm,
+ module,
+ runtime
+ ).toString(16);
+ const connections = this.moduleGraph.getOutgoingConnections(module);
+ /** @type {Set<Module>} */
+ const activeNamespaceModules = new Set();
+ /** @type {Map<string, Module | Set<Module>>} */
+ const connectedModules = new Map();
+ const processConnection = (connection, stateInfo) => {
+ const module = connection.module;
+ stateInfo += module.getExportsType(this.moduleGraph, strict);
+ // cspell:word Tnamespace
+ if (stateInfo === "Tnamespace") activeNamespaceModules.add(module);
+ else {
+ const oldModule = connectedModules.get(stateInfo);
+ if (oldModule === undefined) {
+ connectedModules.set(stateInfo, module);
+ } else if (oldModule instanceof Set) {
+ oldModule.add(module);
+ } else if (oldModule !== module) {
+ connectedModules.set(stateInfo, new Set([oldModule, module]));
+ }
+ }
+ };
+ if (runtime === undefined || typeof runtime === "string") {
+ for (const connection of connections) {
+ const state = connection.getActiveState(runtime);
+ if (state === false) continue;
+ processConnection(connection, state === true ? "T" : "O");
+ }
+ } else {
+ // cspell:word Tnamespace
+ for (const connection of connections) {
+ const states = new Set();
+ let stateInfo = "";
+ forEachRuntime(
+ runtime,
+ runtime => {
+ const state = connection.getActiveState(runtime);
+ states.add(state);
+ stateInfo += activeStateToString(state) + runtime;
+ },
+ true
+ );
+ if (states.size === 1) {
+ const state = first(states);
+ if (state === false) continue;
+ stateInfo = activeStateToString(state);
+ }
+ processConnection(connection, stateInfo);
+ }
+ }
+ // cspell:word Tnamespace
+ if (activeNamespaceModules.size === 0 && connectedModules.size === 0)
+ return graphHash;
+ const connectedModulesInOrder =
+ connectedModules.size > 1
+ ? Array.from(connectedModules).sort(([a], [b]) => (a < b ? -1 : 1))
+ : connectedModules;
+ const hash = createHash(this._hashFunction);
+ const addModuleToHash = module => {
+ hash.update(
+ this._getModuleGraphHashBigInt(
+ this._getChunkGraphModule(module),
+ module,
+ runtime
+ ).toString(16)
+ );
+ };
+ const addModulesToHash = modules => {
+ let xor = ZERO_BIG_INT;
+ for (const m of modules) {
+ xor =
+ xor ^
+ this._getModuleGraphHashBigInt(
+ this._getChunkGraphModule(m),
+ m,
+ runtime
+ );
+ }
+ hash.update(xor.toString(16));
+ };
+ if (activeNamespaceModules.size === 1)
+ addModuleToHash(activeNamespaceModules.values().next().value);
+ else if (activeNamespaceModules.size > 1)
+ addModulesToHash(activeNamespaceModules);
+ for (const [stateInfo, modules] of connectedModulesInOrder) {
+ hash.update(stateInfo);
+ if (modules instanceof Set) {
+ addModulesToHash(modules);
+ } else {
+ addModuleToHash(modules);
+ }
+ }
+ hash.update(graphHash);
+ return /** @type {string} */ (hash.digest("hex"));
+ });
+ }
+
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {ReadonlySet<string>} runtime requirements
+ */
+ getTreeRuntimeRequirements(chunk) {
+ const cgc = this._getChunkGraphChunk(chunk);
+ return cgc.runtimeRequirementsInTree;
+ }
+
+ // TODO remove in webpack 6
+ /**
+ * @param {Module} module the module
+ * @param {string} deprecateMessage message for the deprecation message
+ * @param {string} deprecationCode code for the deprecation
+ * @returns {ChunkGraph} the chunk graph
+ */
+ static getChunkGraphForModule(module, deprecateMessage, deprecationCode) {
+ const fn = deprecateGetChunkGraphForModuleMap.get(deprecateMessage);
+ if (fn) return fn(module);
+ const newFn = util.deprecate(
+ /**
+ * @param {Module} module the module
+ * @returns {ChunkGraph} the chunk graph
+ */
+ module => {
+ const chunkGraph = chunkGraphForModuleMap.get(module);
+ if (!chunkGraph)
+ throw new Error(
+ deprecateMessage +
+ ": There was no ChunkGraph assigned to the Module for backward-compat (Use the new API)"
+ );
+ return chunkGraph;
+ },
+ deprecateMessage + ": Use new ChunkGraph API",
+ deprecationCode
+ );
+ deprecateGetChunkGraphForModuleMap.set(deprecateMessage, newFn);
+ return newFn(module);
+ }
+
+ // TODO remove in webpack 6
+ /**
+ * @param {Module} module the module
+ * @param {ChunkGraph} chunkGraph the chunk graph
+ * @returns {void}
+ */
+ static setChunkGraphForModule(module, chunkGraph) {
+ chunkGraphForModuleMap.set(module, chunkGraph);
+ }
+
+ // TODO remove in webpack 6
+ /**
+ * @param {Module} module the module
+ * @returns {void}
+ */
+ static clearChunkGraphForModule(module) {
+ chunkGraphForModuleMap.delete(module);
+ }
+
+ // TODO remove in webpack 6
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {string} deprecateMessage message for the deprecation message
+ * @param {string} deprecationCode code for the deprecation
+ * @returns {ChunkGraph} the chunk graph
+ */
+ static getChunkGraphForChunk(chunk, deprecateMessage, deprecationCode) {
+ const fn = deprecateGetChunkGraphForChunkMap.get(deprecateMessage);
+ if (fn) return fn(chunk);
+ const newFn = util.deprecate(
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {ChunkGraph} the chunk graph
+ */
+ chunk => {
+ const chunkGraph = chunkGraphForChunkMap.get(chunk);
+ if (!chunkGraph)
+ throw new Error(
+ deprecateMessage +
+ "There was no ChunkGraph assigned to the Chunk for backward-compat (Use the new API)"
+ );
+ return chunkGraph;
+ },
+ deprecateMessage + ": Use new ChunkGraph API",
+ deprecationCode
+ );
+ deprecateGetChunkGraphForChunkMap.set(deprecateMessage, newFn);
+ return newFn(chunk);
+ }
+
+ // TODO remove in webpack 6
+ /**
+ * @param {Chunk} chunk the chunk
+ * @param {ChunkGraph} chunkGraph the chunk graph
+ * @returns {void}
+ */
+ static setChunkGraphForChunk(chunk, chunkGraph) {
+ chunkGraphForChunkMap.set(chunk, chunkGraph);
+ }
+
+ // TODO remove in webpack 6
+ /**
+ * @param {Chunk} chunk the chunk
+ * @returns {void}
+ */
+ static clearChunkGraphForChunk(chunk) {
+ chunkGraphForChunkMap.delete(chunk);
+ }
+}
+
+// TODO remove in webpack 6
+/** @type {WeakMap<Module, ChunkGraph>} */
+const chunkGraphForModuleMap = new WeakMap();
+
+// TODO remove in webpack 6
+/** @type {WeakMap<Chunk, ChunkGraph>} */
+const chunkGraphForChunkMap = new WeakMap();
+
+// TODO remove in webpack 6
+/** @type {Map<string, (module: Module) => ChunkGraph>} */
+const deprecateGetChunkGraphForModuleMap = new Map();
+
+// TODO remove in webpack 6
+/** @type {Map<string, (chunk: Chunk) => ChunkGraph>} */
+const deprecateGetChunkGraphForChunkMap = new Map();
+
+module.exports = ChunkGraph;