code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

/** @typedef {import("http").ServerOptions} HttpServerOptions */
/** @typedef {import("https").ServerOptions} HttpsServerOptions */
/** @typedef {import("../../declarations/WebpackOptions").LazyCompilationDefaultBackendOptions} LazyCompilationDefaultBackendOptions */
/** @typedef {import("../Compiler")} Compiler */

/**
 * @callback BackendHandler
 * @param {Compiler} compiler compiler
 * @param {function((Error | null)=, any=): void} callback callback
 * @returns {void}
 */

/**
 * @param {Omit<LazyCompilationDefaultBackendOptions, "client"> & { client: NonNullable<LazyCompilationDefaultBackendOptions["client"]>}} options additional options for the backend
 * @returns {BackendHandler} backend
 */
module.exports = options => (compiler, callback) => {
	const logger = compiler.getInfrastructureLogger("LazyCompilationBackend");
	const activeModules = new Map();
	const prefix = "/lazy-compilation-using-";

	const isHttps =
		options.protocol === "https" ||
		(typeof options.server === "object" &&
			("key" in options.server || "pfx" in options.server));

	const createServer =
		typeof options.server === "function"
			? options.server
			: (() => {
					const http = isHttps ? require("https") : require("http");
					return http.createServer.bind(http, options.server);
				})();
	const listen =
		typeof options.listen === "function"
			? options.listen
			: server => {
					let listen = options.listen;
					if (typeof listen === "object" && !("port" in listen))
						listen = { ...listen, port: undefined };
					server.listen(listen);
				};

	const protocol = options.protocol || (isHttps ? "https" : "http");

	const requestListener = (req, res) => {
		const keys = req.url.slice(prefix.length).split("@");
		req.socket.on("close", () => {
			setTimeout(() => {
				for (const key of keys) {
					const oldValue = activeModules.get(key) || 0;
					activeModules.set(key, oldValue - 1);
					if (oldValue === 1) {
						logger.log(
							`${key} is no longer in use. Next compilation will skip this module.`
						);
					}
				}
			}, 120000);
		});
		req.socket.setNoDelay(true);
		res.writeHead(200, {
			"content-type": "text/event-stream",
			"Access-Control-Allow-Origin": "*",
			"Access-Control-Allow-Methods": "*",
			"Access-Control-Allow-Headers": "*"
		});
		res.write("\n");
		let moduleActivated = false;
		for (const key of keys) {
			const oldValue = activeModules.get(key) || 0;
			activeModules.set(key, oldValue + 1);
			if (oldValue === 0) {
				logger.log(`${key} is now in use and will be compiled.`);
				moduleActivated = true;
			}
		}
		if (moduleActivated && compiler.watching) compiler.watching.invalidate();
	};

	const server = /** @type {import("net").Server} */ (createServer());
	server.on("request", requestListener);

	let isClosing = false;
	/** @type {Set<import("net").Socket>} */
	const sockets = new Set();
	server.on("connection", socket => {
		sockets.add(socket);
		socket.on("close", () => {
			sockets.delete(socket);
		});
		if (isClosing) socket.destroy();
	});
	server.on("clientError", e => {
		if (e.message !== "Server is disposing") logger.warn(e);
	});
	server.on("listening", err => {
		if (err) return callback(err);
		const addr = server.address();
		if (typeof addr === "string") throw new Error("addr must not be a string");
		const urlBase =
			addr.address === "::" || addr.address === "0.0.0.0"
				? `${protocol}://localhost:${addr.port}`
				: addr.family === "IPv6"
					? `${protocol}://[${addr.address}]:${addr.port}`
					: `${protocol}://${addr.address}:${addr.port}`;
		logger.log(
			`Server-Sent-Events server for lazy compilation open at ${urlBase}.`
		);
		callback(null, {
			dispose(callback) {
				isClosing = true;
				// Removing the listener is a workaround for a memory leak in node.js
				server.off("request", requestListener);
				server.close(err => {
					callback(err);
				});
				for (const socket of sockets) {
					socket.destroy(new Error("Server is disposing"));
				}
			},
			module(originalModule) {
				const key = `${encodeURIComponent(
					originalModule.identifier().replace(/\\/g, "/").replace(/@/g, "_")
				).replace(/%(2F|3A|24|26|2B|2C|3B|3D|3A)/g, decodeURIComponent)}`;
				const active = activeModules.get(key) > 0;
				return {
					client: `${options.client}?${encodeURIComponent(urlBase + prefix)}`,
					data: key,
					active
				};
			}
		});
	});
	listen(server);
};


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { find } = require("../util/SetHelpers");
const {
	compareModulesByPreOrderIndexOrIdentifier,
	compareModulesByPostOrderIndexOrIdentifier
} = require("../util/comparators");

/** @typedef {import("../Compiler")} Compiler */

/**
 * @typedef {object} ChunkModuleIdRangePluginOptions
 * @property {string} name the chunk name
 * @property {("index" | "index2" | "preOrderIndex" | "postOrderIndex")=} order order
 * @property {number=} start start id
 * @property {number=} end end id
 */

class ChunkModuleIdRangePlugin {
	/**
	 * @param {ChunkModuleIdRangePluginOptions} options options object
	 */
	constructor(options) {
		this.options = options;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		const options = this.options;
		compiler.hooks.compilation.tap("ChunkModuleIdRangePlugin", compilation => {
			const moduleGraph = compilation.moduleGraph;
			compilation.hooks.moduleIds.tap("ChunkModuleIdRangePlugin", modules => {
				const chunkGraph = compilation.chunkGraph;
				const chunk = find(
					compilation.chunks,
					chunk => chunk.name === options.name
				);
				if (!chunk) {
					throw new Error(
						`ChunkModuleIdRangePlugin: Chunk with name '${options.name}"' was not found`
					);
				}

				let chunkModules;
				if (options.order) {
					let cmpFn;
					switch (options.order) {
						case "index":
						case "preOrderIndex":
							cmpFn = compareModulesByPreOrderIndexOrIdentifier(moduleGraph);
							break;
						case "index2":
						case "postOrderIndex":
							cmpFn = compareModulesByPostOrderIndexOrIdentifier(moduleGraph);
							break;
						default:
							throw new Error(
								"ChunkModuleIdRangePlugin: unexpected value of order"
							);
					}
					chunkModules = chunkGraph.getOrderedChunkModules(chunk, cmpFn);
				} else {
					chunkModules = Array.from(modules)
						.filter(m => {
							return chunkGraph.isModuleInChunk(m, chunk);
						})
						.sort(compareModulesByPreOrderIndexOrIdentifier(moduleGraph));
				}

				let currentId = options.start || 0;
				for (let i = 0; i < chunkModules.length; i++) {
					const m = chunkModules[i];
					if (m.needId && chunkGraph.getModuleId(m) === null) {
						chunkGraph.setModuleId(m, currentId++);
					}
					if (options.end && currentId > options.end) break;
				}
			});
		});
	}
}
module.exports = ChunkModuleIdRangePlugin;

license: mit


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Florent Cailhol @ooflorent
*/

"use strict";

const { compareChunksNatural } = require("../util/comparators");
const {
	getFullChunkName,
	getUsedChunkIds,
	assignDeterministicIds
} = require("./IdHelpers");

/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */

/**
 * @typedef {object} DeterministicChunkIdsPluginOptions
 * @property {string=} context context for ids
 * @property {number=} maxLength maximum length of ids
 */

class DeterministicChunkIdsPlugin {
	/**
	 * @param {DeterministicChunkIdsPluginOptions} [options] options
	 */
	constructor(options = {}) {
		this.options = options;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.compilation.tap(
			"DeterministicChunkIdsPlugin",
			compilation => {
				compilation.hooks.chunkIds.tap(
					"DeterministicChunkIdsPlugin",
					chunks => {
						const chunkGraph = compilation.chunkGraph;
						const context = this.options.context
							? this.options.context
							: compiler.context;
						const maxLength = this.options.maxLength || 3;

						const compareNatural = compareChunksNatural(chunkGraph);

						const usedIds = getUsedChunkIds(compilation);
						assignDeterministicIds(
							Array.from(chunks).filter(chunk => {
								return chunk.id === null;
							}),
							chunk =>
								getFullChunkName(chunk, chunkGraph, context, compiler.root),
							compareNatural,
							(chunk, id) => {
								const size = usedIds.size;
								usedIds.add(`${id}`);
								if (size === usedIds.size) return false;
								chunk.id = id;
								chunk.ids = [id];
								return true;
							},
							[Math.pow(10, maxLength)],
							10,
							usedIds.size
						);
					}
				);
			}
		);
	}
}

module.exports = DeterministicChunkIdsPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Florent Cailhol @ooflorent
*/

"use strict";

const {
	compareModulesByPreOrderIndexOrIdentifier
} = require("../util/comparators");
const {
	getUsedModuleIdsAndModules,
	getFullModuleName,
	assignDeterministicIds
} = require("./IdHelpers");

/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */

/**
 * @typedef {object} DeterministicModuleIdsPluginOptions
 * @property {string=} context context relative to which module identifiers are computed
 * @property {function(Module): boolean=} test selector function for modules
 * @property {number=} maxLength maximum id length in digits (used as starting point)
 * @property {number=} salt hash salt for ids
 * @property {boolean=} fixedLength do not increase the maxLength to find an optimal id space size
 * @property {boolean=} failOnConflict throw an error when id conflicts occur (instead of rehashing)
 */

class DeterministicModuleIdsPlugin {
	/**
	 * @param {DeterministicModuleIdsPluginOptions} [options] options
	 */
	constructor(options = {}) {
		this.options = options;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.compilation.tap(
			"DeterministicModuleIdsPlugin",
			compilation => {
				compilation.hooks.moduleIds.tap("DeterministicModuleIdsPlugin", () => {
					const chunkGraph = compilation.chunkGraph;
					const context = this.options.context
						? this.options.context
						: compiler.context;
					const maxLength = this.options.maxLength || 3;
					const failOnConflict = this.options.failOnConflict || false;
					const fixedLength = this.options.fixedLength || false;
					const salt = this.options.salt || 0;
					let conflicts = 0;

					const [usedIds, modules] = getUsedModuleIdsAndModules(
						compilation,
						this.options.test
					);
					assignDeterministicIds(
						modules,
						module => getFullModuleName(module, context, compiler.root),
						failOnConflict
							? () => 0
							: compareModulesByPreOrderIndexOrIdentifier(
									compilation.moduleGraph
								),
						(module, id) => {
							const size = usedIds.size;
							usedIds.add(`${id}`);
							if (size === usedIds.size) {
								conflicts++;
								return false;
							}
							chunkGraph.setModuleId(module, id);
							return true;
						},
						[Math.pow(10, maxLength)],
						fixedLength ? 0 : 10,
						usedIds.size,
						salt
					);
					if (failOnConflict && conflicts)
						throw new Error(
							`Assigning deterministic module ids has lead to ${conflicts} conflict${
								conflicts > 1 ? "s" : ""
							}.\nIncrease the 'maxLength' to increase the id space and make conflicts less likely (recommended when there are many conflicts or application is expected to grow), or add an 'salt' number to try another hash starting value in the same id space (recommended when there is only a single conflict).`
						);
				});
			}
		);
	}
}

module.exports = DeterministicModuleIdsPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const {
	compareModulesByPreOrderIndexOrIdentifier
} = require("../util/comparators");
const createSchemaValidation = require("../util/create-schema-validation");
const createHash = require("../util/createHash");
const {
	getUsedModuleIdsAndModules,
	getFullModuleName
} = require("./IdHelpers");

/** @typedef {import("../../declarations/plugins/HashedModuleIdsPlugin").HashedModuleIdsPluginOptions} HashedModuleIdsPluginOptions */
/** @typedef {import("../Compiler")} Compiler */

const validate = createSchemaValidation(
	require("../../schemas/plugins/HashedModuleIdsPlugin.check.js"),
	() => require("../../schemas/plugins/HashedModuleIdsPlugin.json"),
	{
		name: "Hashed Module Ids Plugin",
		baseDataPath: "options"
	}
);

class HashedModuleIdsPlugin {
	/**
	 * @param {HashedModuleIdsPluginOptions=} options options object
	 */
	constructor(options = {}) {
		validate(options);

		/** @type {HashedModuleIdsPluginOptions} */
		this.options = {
			context: undefined,
			hashFunction: "md4",
			hashDigest: "base64",
			hashDigestLength: 4,
			...options
		};
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		const options = this.options;
		compiler.hooks.compilation.tap("HashedModuleIdsPlugin", compilation => {
			compilation.hooks.moduleIds.tap("HashedModuleIdsPlugin", () => {
				const chunkGraph = compilation.chunkGraph;
				const context = this.options.context
					? this.options.context
					: compiler.context;

				const [usedIds, modules] = getUsedModuleIdsAndModules(compilation);
				const modulesInNaturalOrder = modules.sort(
					compareModulesByPreOrderIndexOrIdentifier(compilation.moduleGraph)
				);
				for (const module of modulesInNaturalOrder) {
					const ident = getFullModuleName(module, context, compiler.root);
					const hash = createHash(options.hashFunction);
					hash.update(ident || "");
					const hashId = /** @type {string} */ (
						hash.digest(options.hashDigest)
					);
					let len = options.hashDigestLength;
					while (usedIds.has(hashId.slice(0, len)))
						/** @type {number} */ (len)++;
					const moduleId = hashId.slice(0, len);
					chunkGraph.setModuleId(module, moduleId);
					usedIds.add(moduleId);
				}
			});
		});
	}
}

module.exports = HashedModuleIdsPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const createHash = require("../util/createHash");
const { makePathsRelative } = require("../util/identifier");
const numberHash = require("../util/numberHash");

/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Module")} Module */
/** @typedef {typeof import("../util/Hash")} Hash */

/**
 * @param {string} str string to hash
 * @param {number} len max length of the hash
 * @param {string | Hash} hashFunction hash function to use
 * @returns {string} hash
 */
const getHash = (str, len, hashFunction) => {
	const hash = createHash(hashFunction);
	hash.update(str);
	const digest = /** @type {string} */ (hash.digest("hex"));
	return digest.slice(0, len);
};

/**
 * @param {string} str the string
 * @returns {string} string prefixed by an underscore if it is a number
 */
const avoidNumber = str => {
	// max length of a number is 21 chars, bigger numbers a written as "...e+xx"
	if (str.length > 21) return str;
	const firstChar = str.charCodeAt(0);
	// skip everything that doesn't look like a number
	// charCodes: "-": 45, "1": 49, "9": 57
	if (firstChar < 49) {
		if (firstChar !== 45) return str;
	} else if (firstChar > 57) {
		return str;
	}
	if (str === +str + "") {
		return `_${str}`;
	}
	return str;
};

/**
 * @param {string} request the request
 * @returns {string} id representation
 */
const requestToId = request => {
	return request
		.replace(/^(\.\.?\/)+/, "")
		.replace(/(^[.-]|[^a-zA-Z0-9_-])+/g, "_");
};
exports.requestToId = requestToId;

/**
 * @param {string} string the string
 * @param {string} delimiter separator for string and hash
 * @param {string | Hash} hashFunction hash function to use
 * @returns {string} string with limited max length to 100 chars
 */
const shortenLongString = (string, delimiter, hashFunction) => {
	if (string.length < 100) return string;
	return (
		string.slice(0, 100 - 6 - delimiter.length) +
		delimiter +
		getHash(string, 6, hashFunction)
	);
};

/**
 * @param {Module} module the module
 * @param {string} context context directory
 * @param {object=} associatedObjectForCache an object to which the cache will be attached
 * @returns {string} short module name
 */
const getShortModuleName = (module, context, associatedObjectForCache) => {
	const libIdent = module.libIdent({ context, associatedObjectForCache });
	if (libIdent) return avoidNumber(libIdent);
	const nameForCondition = module.nameForCondition();
	if (nameForCondition)
		return avoidNumber(
			makePathsRelative(context, nameForCondition, associatedObjectForCache)
		);
	return "";
};
exports.getShortModuleName = getShortModuleName;

/**
 * @param {string} shortName the short name
 * @param {Module} module the module
 * @param {string} context context directory
 * @param {string | Hash} hashFunction hash function to use
 * @param {object=} associatedObjectForCache an object to which the cache will be attached
 * @returns {string} long module name
 */
const getLongModuleName = (
	shortName,
	module,
	context,
	hashFunction,
	associatedObjectForCache
) => {
	const fullName = getFullModuleName(module, context, associatedObjectForCache);
	return `${shortName}?${getHash(fullName, 4, hashFunction)}`;
};
exports.getLongModuleName = getLongModuleName;

/**
 * @param {Module} module the module
 * @param {string} context context directory
 * @param {object=} associatedObjectForCache an object to which the cache will be attached
 * @returns {string} full module name
 */
const getFullModuleName = (module, context, associatedObjectForCache) => {
	return makePathsRelative(
		context,
		module.identifier(),
		associatedObjectForCache
	);
};
exports.getFullModuleName = getFullModuleName;

/**
 * @param {Chunk} chunk the chunk
 * @param {ChunkGraph} chunkGraph the chunk graph
 * @param {string} context context directory
 * @param {string} delimiter delimiter for names
 * @param {string | Hash} hashFunction hash function to use
 * @param {object=} associatedObjectForCache an object to which the cache will be attached
 * @returns {string} short chunk name
 */
const getShortChunkName = (
	chunk,
	chunkGraph,
	context,
	delimiter,
	hashFunction,
	associatedObjectForCache
) => {
	const modules = chunkGraph.getChunkRootModules(chunk);
	const shortModuleNames = modules.map(m =>
		requestToId(getShortModuleName(m, context, associatedObjectForCache))
	);
	chunk.idNameHints.sort();
	const chunkName = Array.from(chunk.idNameHints)
		.concat(shortModuleNames)
		.filter(Boolean)
		.join(delimiter);
	return shortenLongString(chunkName, delimiter, hashFunction);
};
exports.getShortChunkName = getShortChunkName;

/**
 * @param {Chunk} chunk the chunk
 * @param {ChunkGraph} chunkGraph the chunk graph
 * @param {string} context context directory
 * @param {string} delimiter delimiter for names
 * @param {string | Hash} hashFunction hash function to use
 * @param {object=} associatedObjectForCache an object to which the cache will be attached
 * @returns {string} short chunk name
 */
const getLongChunkName = (
	chunk,
	chunkGraph,
	context,
	delimiter,
	hashFunction,
	associatedObjectForCache
) => {
	const modules = chunkGraph.getChunkRootModules(chunk);
	const shortModuleNames = modules.map(m =>
		requestToId(getShortModuleName(m, context, associatedObjectForCache))
	);
	const longModuleNames = modules.map(m =>
		requestToId(
			getLongModuleName("", m, context, hashFunction, associatedObjectForCache)
		)
	);
	chunk.idNameHints.sort();
	const chunkName = Array.from(chunk.idNameHints)
		.concat(shortModuleNames, longModuleNames)
		.filter(Boolean)
		.join(delimiter);
	return shortenLongString(chunkName, delimiter, hashFunction);
};
exports.getLongChunkName = getLongChunkName;

/**
 * @param {Chunk} chunk the chunk
 * @param {ChunkGraph} chunkGraph the chunk graph
 * @param {string} context context directory
 * @param {object=} associatedObjectForCache an object to which the cache will be attached
 * @returns {string} full chunk name
 */
const getFullChunkName = (
	chunk,
	chunkGraph,
	context,
	associatedObjectForCache
) => {
	if (chunk.name) return chunk.name;
	const modules = chunkGraph.getChunkRootModules(chunk);
	const fullModuleNames = modules.map(m =>
		makePathsRelative(context, m.identifier(), associatedObjectForCache)
	);
	return fullModuleNames.join();
};
exports.getFullChunkName = getFullChunkName;

/**
 * @template K
 * @template V
 * @param {Map<K, V[]>} map a map from key to values
 * @param {K} key key
 * @param {V} value value
 * @returns {void}
 */
const addToMapOfItems = (map, key, value) => {
	let array = map.get(key);
	if (array === undefined) {
		array = [];
		map.set(key, array);
	}
	array.push(value);
};

/**
 * @param {Compilation} compilation the compilation
 * @param {function(Module): boolean=} filter filter modules
 * @returns {[Set<string>, Module[]]} used module ids as strings and modules without id matching the filter
 */
const getUsedModuleIdsAndModules = (compilation, filter) => {
	const chunkGraph = compilation.chunkGraph;

	const modules = [];

	/** @type {Set<string>} */
	const usedIds = new Set();
	if (compilation.usedModuleIds) {
		for (const id of compilation.usedModuleIds) {
			usedIds.add(id + "");
		}
	}

	for (const module of compilation.modules) {
		if (!module.needId) continue;
		const moduleId = chunkGraph.getModuleId(module);
		if (moduleId !== null) {
			usedIds.add(moduleId + "");
		} else {
			if (
				(!filter || filter(module)) &&
				chunkGraph.getNumberOfModuleChunks(module) !== 0
			) {
				modules.push(module);
			}
		}
	}

	return [usedIds, modules];
};
exports.getUsedModuleIdsAndModules = getUsedModuleIdsAndModules;

/**
 * @param {Compilation} compilation the compilation
 * @returns {Set<string>} used chunk ids as strings
 */
const getUsedChunkIds = compilation => {
	/** @type {Set<string>} */
	const usedIds = new Set();
	if (compilation.usedChunkIds) {
		for (const id of compilation.usedChunkIds) {
			usedIds.add(id + "");
		}
	}

	for (const chunk of compilation.chunks) {
		const chunkId = chunk.id;
		if (chunkId !== null) {
			usedIds.add(chunkId + "");
		}
	}

	return usedIds;
};
exports.getUsedChunkIds = getUsedChunkIds;

/**
 * @template T
 * @param {Iterable<T>} items list of items to be named
 * @param {function(T): string} getShortName get a short name for an item
 * @param {function(T, string): string} getLongName get a long name for an item
 * @param {function(T, T): -1|0|1} comparator order of items
 * @param {Set<string>} usedIds already used ids, will not be assigned
 * @param {function(T, string): void} assignName assign a name to an item
 * @returns {T[]} list of items without a name
 */
const assignNames = (
	items,
	getShortName,
	getLongName,
	comparator,
	usedIds,
	assignName
) => {
	/** @type {Map<string, T[]>} */
	const nameToItems = new Map();

	for (const item of items) {
		const name = getShortName(item);
		addToMapOfItems(nameToItems, name, item);
	}

	/** @type {Map<string, T[]>} */
	const nameToItems2 = new Map();

	for (const [name, items] of nameToItems) {
		if (items.length > 1 || !name) {
			for (const item of items) {
				const longName = getLongName(item, name);
				addToMapOfItems(nameToItems2, longName, item);
			}
		} else {
			addToMapOfItems(nameToItems2, name, items[0]);
		}
	}

	/** @type {T[]} */
	const unnamedItems = [];

	for (const [name, items] of nameToItems2) {
		if (!name) {
			for (const item of items) {
				unnamedItems.push(item);
			}
		} else if (items.length === 1 && !usedIds.has(name)) {
			assignName(items[0], name);
			usedIds.add(name);
		} else {
			items.sort(comparator);
			let i = 0;
			for (const item of items) {
				while (nameToItems2.has(name + i) && usedIds.has(name + i)) i++;
				assignName(item, name + i);
				usedIds.add(name + i);
				i++;
			}
		}
	}

	unnamedItems.sort(comparator);
	return unnamedItems;
};
exports.assignNames = assignNames;

/**
 * @template T
 * @param {T[]} items list of items to be named
 * @param {function(T): string} getName get a name for an item
 * @param {function(T, T): -1|0|1} comparator order of items
 * @param {function(T, number): boolean} assignId assign an id to an item
 * @param {number[]} ranges usable ranges for ids
 * @param {number} expandFactor factor to create more ranges
 * @param {number} extraSpace extra space to allocate, i. e. when some ids are already used
 * @param {number} salt salting number to initialize hashing
 * @returns {void}
 */
const assignDeterministicIds = (
	items,
	getName,
	comparator,
	assignId,
	ranges = [10],
	expandFactor = 10,
	extraSpace = 0,
	salt = 0
) => {
	items.sort(comparator);

	// max 5% fill rate
	const optimalRange = Math.min(
		items.length * 20 + extraSpace,
		Number.MAX_SAFE_INTEGER
	);

	let i = 0;
	let range = ranges[i];
	while (range < optimalRange) {
		i++;
		if (i < ranges.length) {
			range = Math.min(ranges[i], Number.MAX_SAFE_INTEGER);
		} else if (expandFactor) {
			range = Math.min(range * expandFactor, Number.MAX_SAFE_INTEGER);
		} else {
			break;
		}
	}

	for (const item of items) {
		const ident = getName(item);
		let id;
		let i = salt;
		do {
			id = numberHash(ident + i++, range);
		} while (!assignId(item, id));
	}
};
exports.assignDeterministicIds = assignDeterministicIds;

/**
 * @param {Set<string>} usedIds used ids
 * @param {Iterable<Module>} modules the modules
 * @param {Compilation} compilation the compilation
 * @returns {void}
 */
const assignAscendingModuleIds = (usedIds, modules, compilation) => {
	const chunkGraph = compilation.chunkGraph;

	let nextId = 0;
	let assignId;
	if (usedIds.size > 0) {
		/**
		 * @param {Module} module the module
		 */
		assignId = module => {
			if (chunkGraph.getModuleId(module) === null) {
				while (usedIds.has(nextId + "")) nextId++;
				chunkGraph.setModuleId(module, nextId++);
			}
		};
	} else {
		/**
		 * @param {Module} module the module
		 */
		assignId = module => {
			if (chunkGraph.getModuleId(module) === null) {
				chunkGraph.setModuleId(module, nextId++);
			}
		};
	}
	for (const module of modules) {
		assignId(module);
	}
};
exports.assignAscendingModuleIds = assignAscendingModuleIds;

/**
 * @param {Iterable<Chunk>} chunks the chunks
 * @param {Compilation} compilation the compilation
 * @returns {void}
 */
const assignAscendingChunkIds = (chunks, compilation) => {
	const usedIds = getUsedChunkIds(compilation);

	let nextId = 0;
	if (usedIds.size > 0) {
		for (const chunk of chunks) {
			if (chunk.id === null) {
				while (usedIds.has(nextId + "")) nextId++;
				chunk.id = nextId;
				chunk.ids = [nextId];
				nextId++;
			}
		}
	} else {
		for (const chunk of chunks) {
			if (chunk.id === null) {
				chunk.id = nextId;
				chunk.ids = [nextId];
				nextId++;
			}
		}
	}
};
exports.assignAscendingChunkIds = assignAscendingChunkIds;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { compareChunksNatural } = require("../util/comparators");
const {
	getShortChunkName,
	getLongChunkName,
	assignNames,
	getUsedChunkIds,
	assignAscendingChunkIds
} = require("./IdHelpers");

/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} Output */
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */

/**
 * @typedef {object} NamedChunkIdsPluginOptions
 * @property {string} [context] context
 * @property {string} [delimiter] delimiter
 */

class NamedChunkIdsPlugin {
	/**
	 * @param {NamedChunkIdsPluginOptions=} options options
	 */
	constructor(options) {
		this.delimiter = (options && options.delimiter) || "-";
		this.context = options && options.context;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.compilation.tap("NamedChunkIdsPlugin", compilation => {
			const hashFunction =
				/** @type {NonNullable<Output["hashFunction"]>} */
				(compilation.outputOptions.hashFunction);
			compilation.hooks.chunkIds.tap("NamedChunkIdsPlugin", chunks => {
				const chunkGraph = compilation.chunkGraph;
				const context = this.context ? this.context : compiler.context;
				const delimiter = this.delimiter;

				const unnamedChunks = assignNames(
					Array.from(chunks).filter(chunk => {
						if (chunk.name) {
							chunk.id = chunk.name;
							chunk.ids = [chunk.name];
						}
						return chunk.id === null;
					}),
					chunk =>
						getShortChunkName(
							chunk,
							chunkGraph,
							context,
							delimiter,
							hashFunction,
							compiler.root
						),
					chunk =>
						getLongChunkName(
							chunk,
							chunkGraph,
							context,
							delimiter,
							hashFunction,
							compiler.root
						),
					compareChunksNatural(chunkGraph),
					getUsedChunkIds(compilation),
					(chunk, name) => {
						chunk.id = name;
						chunk.ids = [name];
					}
				);
				if (unnamedChunks.length > 0) {
					assignAscendingChunkIds(unnamedChunks, compilation);
				}
			});
		});
	}
}

module.exports = NamedChunkIdsPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { compareModulesByIdentifier } = require("../util/comparators");
const {
	getShortModuleName,
	getLongModuleName,
	assignNames,
	getUsedModuleIdsAndModules,
	assignAscendingModuleIds
} = require("./IdHelpers");

/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} Output */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */

/**
 * @typedef {object} NamedModuleIdsPluginOptions
 * @property {string} [context] context
 */

class NamedModuleIdsPlugin {
	/**
	 * @param {NamedModuleIdsPluginOptions} [options] options
	 */
	constructor(options = {}) {
		this.options = options;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		const { root } = compiler;
		compiler.hooks.compilation.tap("NamedModuleIdsPlugin", compilation => {
			const hashFunction =
				/** @type {NonNullable<Output["hashFunction"]>} */
				(compilation.outputOptions.hashFunction);
			compilation.hooks.moduleIds.tap("NamedModuleIdsPlugin", () => {
				const chunkGraph = compilation.chunkGraph;
				const context = this.options.context
					? this.options.context
					: compiler.context;

				const [usedIds, modules] = getUsedModuleIdsAndModules(compilation);
				const unnamedModules = assignNames(
					modules,
					m => getShortModuleName(m, context, root),
					(m, shortName) =>
						getLongModuleName(shortName, m, context, hashFunction, root),
					compareModulesByIdentifier,
					usedIds,
					(m, name) => chunkGraph.setModuleId(m, name)
				);
				if (unnamedModules.length > 0) {
					assignAscendingModuleIds(usedIds, unnamedModules, compilation);
				}
			});
		});
	}
}

module.exports = NamedModuleIdsPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { compareChunksNatural } = require("../util/comparators");
const { assignAscendingChunkIds } = require("./IdHelpers");

/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */

class NaturalChunkIdsPlugin {
	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.compilation.tap("NaturalChunkIdsPlugin", compilation => {
			compilation.hooks.chunkIds.tap("NaturalChunkIdsPlugin", chunks => {
				const chunkGraph = compilation.chunkGraph;
				const compareNatural = compareChunksNatural(chunkGraph);
				const chunksInNaturalOrder = Array.from(chunks).sort(compareNatural);
				assignAscendingChunkIds(chunksInNaturalOrder, compilation);
			});
		});
	}
}

module.exports = NaturalChunkIdsPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Florent Cailhol @ooflorent
*/

"use strict";

const {
	compareModulesByPreOrderIndexOrIdentifier
} = require("../util/comparators");
const {
	assignAscendingModuleIds,
	getUsedModuleIdsAndModules
} = require("./IdHelpers");

/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */

class NaturalModuleIdsPlugin {
	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.compilation.tap("NaturalModuleIdsPlugin", compilation => {
			compilation.hooks.moduleIds.tap("NaturalModuleIdsPlugin", modules => {
				const [usedIds, modulesInNaturalOrder] =
					getUsedModuleIdsAndModules(compilation);
				modulesInNaturalOrder.sort(
					compareModulesByPreOrderIndexOrIdentifier(compilation.moduleGraph)
				);
				assignAscendingModuleIds(usedIds, modulesInNaturalOrder, compilation);
			});
		});
	}
}

module.exports = NaturalModuleIdsPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { compareChunksNatural } = require("../util/comparators");
const createSchemaValidation = require("../util/create-schema-validation");
const { assignAscendingChunkIds } = require("./IdHelpers");

/** @typedef {import("../../declarations/plugins/ids/OccurrenceChunkIdsPlugin").OccurrenceChunkIdsPluginOptions} OccurrenceChunkIdsPluginOptions */
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */

const validate = createSchemaValidation(
	require("../../schemas/plugins/ids/OccurrenceChunkIdsPlugin.check.js"),
	() => require("../../schemas/plugins/ids/OccurrenceChunkIdsPlugin.json"),
	{
		name: "Occurrence Order Chunk Ids Plugin",
		baseDataPath: "options"
	}
);

class OccurrenceChunkIdsPlugin {
	/**
	 * @param {OccurrenceChunkIdsPluginOptions=} options options object
	 */
	constructor(options = {}) {
		validate(options);
		this.options = options;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		const prioritiseInitial = this.options.prioritiseInitial;
		compiler.hooks.compilation.tap("OccurrenceChunkIdsPlugin", compilation => {
			compilation.hooks.chunkIds.tap("OccurrenceChunkIdsPlugin", chunks => {
				const chunkGraph = compilation.chunkGraph;

				/** @type {Map<Chunk, number>} */
				const occursInInitialChunksMap = new Map();

				const compareNatural = compareChunksNatural(chunkGraph);

				for (const c of chunks) {
					let occurs = 0;
					for (const chunkGroup of c.groupsIterable) {
						for (const parent of chunkGroup.parentsIterable) {
							if (parent.isInitial()) occurs++;
						}
					}
					occursInInitialChunksMap.set(c, occurs);
				}

				const chunksInOccurrenceOrder = Array.from(chunks).sort((a, b) => {
					if (prioritiseInitial) {
						const aEntryOccurs =
							/** @type {number} */
							(occursInInitialChunksMap.get(a));
						const bEntryOccurs =
							/** @type {number} */
							(occursInInitialChunksMap.get(b));
						if (aEntryOccurs > bEntryOccurs) return -1;
						if (aEntryOccurs < bEntryOccurs) return 1;
					}
					const aOccurs = a.getNumberOfGroups();
					const bOccurs = b.getNumberOfGroups();
					if (aOccurs > bOccurs) return -1;
					if (aOccurs < bOccurs) return 1;
					return compareNatural(a, b);
				});
				assignAscendingChunkIds(chunksInOccurrenceOrder, compilation);
			});
		});
	}
}

module.exports = OccurrenceChunkIdsPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const {
	compareModulesByPreOrderIndexOrIdentifier
} = require("../util/comparators");
const createSchemaValidation = require("../util/create-schema-validation");
const {
	assignAscendingModuleIds,
	getUsedModuleIdsAndModules
} = require("./IdHelpers");

/** @typedef {import("../../declarations/plugins/ids/OccurrenceModuleIdsPlugin").OccurrenceModuleIdsPluginOptions} OccurrenceModuleIdsPluginOptions */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../ModuleGraphConnection")} ModuleGraphConnection */

const validate = createSchemaValidation(
	require("../../schemas/plugins/ids/OccurrenceModuleIdsPlugin.check.js"),
	() => require("../../schemas/plugins/ids/OccurrenceModuleIdsPlugin.json"),
	{
		name: "Occurrence Order Module Ids Plugin",
		baseDataPath: "options"
	}
);

class OccurrenceModuleIdsPlugin {
	/**
	 * @param {OccurrenceModuleIdsPluginOptions=} options options object
	 */
	constructor(options = {}) {
		validate(options);
		this.options = options;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		const prioritiseInitial = this.options.prioritiseInitial;
		compiler.hooks.compilation.tap("OccurrenceModuleIdsPlugin", compilation => {
			const moduleGraph = compilation.moduleGraph;

			compilation.hooks.moduleIds.tap("OccurrenceModuleIdsPlugin", () => {
				const chunkGraph = compilation.chunkGraph;

				const [usedIds, modulesInOccurrenceOrder] =
					getUsedModuleIdsAndModules(compilation);

				const occursInInitialChunksMap = new Map();
				const occursInAllChunksMap = new Map();

				const initialChunkChunkMap = new Map();
				const entryCountMap = new Map();
				for (const m of modulesInOccurrenceOrder) {
					let initial = 0;
					let entry = 0;
					for (const c of chunkGraph.getModuleChunksIterable(m)) {
						if (c.canBeInitial()) initial++;
						if (chunkGraph.isEntryModuleInChunk(m, c)) entry++;
					}
					initialChunkChunkMap.set(m, initial);
					entryCountMap.set(m, entry);
				}

				/**
				 * @param {Module} module module
				 * @returns {number} count of occurs
				 */
				const countOccursInEntry = module => {
					let sum = 0;
					for (const [
						originModule,
						connections
					] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
						if (!originModule) continue;
						if (!connections.some(c => c.isTargetActive(undefined))) continue;
						sum += initialChunkChunkMap.get(originModule) || 0;
					}
					return sum;
				};

				/**
				 * @param {Module} module module
				 * @returns {number} count of occurs
				 */
				const countOccurs = module => {
					let sum = 0;
					for (const [
						originModule,
						connections
					] of moduleGraph.getIncomingConnectionsByOriginModule(module)) {
						if (!originModule) continue;
						const chunkModules =
							chunkGraph.getNumberOfModuleChunks(originModule);
						for (const c of connections) {
							if (!c.isTargetActive(undefined)) continue;
							if (!c.dependency) continue;
							const factor = c.dependency.getNumberOfIdOccurrences();
							if (factor === 0) continue;
							sum += factor * chunkModules;
						}
					}
					return sum;
				};

				if (prioritiseInitial) {
					for (const m of modulesInOccurrenceOrder) {
						const result =
							countOccursInEntry(m) +
							initialChunkChunkMap.get(m) +
							entryCountMap.get(m);
						occursInInitialChunksMap.set(m, result);
					}
				}

				for (const m of modulesInOccurrenceOrder) {
					const result =
						countOccurs(m) +
						chunkGraph.getNumberOfModuleChunks(m) +
						entryCountMap.get(m);
					occursInAllChunksMap.set(m, result);
				}

				const naturalCompare = compareModulesByPreOrderIndexOrIdentifier(
					compilation.moduleGraph
				);

				modulesInOccurrenceOrder.sort((a, b) => {
					if (prioritiseInitial) {
						const aEntryOccurs = occursInInitialChunksMap.get(a);
						const bEntryOccurs = occursInInitialChunksMap.get(b);
						if (aEntryOccurs > bEntryOccurs) return -1;
						if (aEntryOccurs < bEntryOccurs) return 1;
					}
					const aOccurs = occursInAllChunksMap.get(a);
					const bOccurs = occursInAllChunksMap.get(b);
					if (aOccurs > bOccurs) return -1;
					if (aOccurs < bOccurs) return 1;
					return naturalCompare(a, b);
				});

				assignAscendingModuleIds(
					usedIds,
					modulesInOccurrenceOrder,
					compilation
				);
			});
		});
	}
}

module.exports = OccurrenceModuleIdsPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { WebpackError } = require("..");
const { getUsedModuleIdsAndModules } = require("./IdHelpers");

/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */

const plugin = "SyncModuleIdsPlugin";

class SyncModuleIdsPlugin {
	/**
	 * @param {object} options options
	 * @param {string} options.path path to file
	 * @param {string=} options.context context for module names
	 * @param {function(Module): boolean} options.test selector for modules
	 * @param {"read" | "create" | "merge" | "update"=} options.mode operation mode (defaults to merge)
	 */
	constructor({ path, context, test, mode }) {
		this._path = path;
		this._context = context;
		this._test = test || (() => true);
		const readAndWrite = !mode || mode === "merge" || mode === "update";
		this._read = readAndWrite || mode === "read";
		this._write = readAndWrite || mode === "create";
		this._prune = mode === "update";
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		/** @type {Map<string, string | number>} */
		let data;
		let dataChanged = false;
		if (this._read) {
			compiler.hooks.readRecords.tapAsync(plugin, callback => {
				const fs = compiler.intermediateFileSystem;
				fs.readFile(this._path, (err, buffer) => {
					if (err) {
						if (err.code !== "ENOENT") {
							return callback(err);
						}
						return callback();
					}
					const json = JSON.parse(/** @type {Buffer} */ (buffer).toString());
					data = new Map();
					for (const key of Object.keys(json)) {
						data.set(key, json[key]);
					}
					dataChanged = false;
					return callback();
				});
			});
		}
		if (this._write) {
			compiler.hooks.emitRecords.tapAsync(plugin, callback => {
				if (!data || !dataChanged) return callback();
				/** @type {{[key: string]: string | number}} */
				const json = {};
				const sorted = Array.from(data).sort(([a], [b]) => (a < b ? -1 : 1));
				for (const [key, value] of sorted) {
					json[key] = value;
				}
				const fs = compiler.intermediateFileSystem;
				fs.writeFile(this._path, JSON.stringify(json), callback);
			});
		}
		compiler.hooks.thisCompilation.tap(plugin, compilation => {
			const associatedObjectForCache = compiler.root;
			const context = this._context || compiler.context;
			if (this._read) {
				compilation.hooks.reviveModules.tap(plugin, (_1, _2) => {
					if (!data) return;
					const { chunkGraph } = compilation;
					const [usedIds, modules] = getUsedModuleIdsAndModules(
						compilation,
						this._test
					);
					for (const module of modules) {
						const name = module.libIdent({
							context,
							associatedObjectForCache
						});
						if (!name) continue;
						const id = data.get(name);
						const idAsString = `${id}`;
						if (usedIds.has(idAsString)) {
							const err = new WebpackError(
								`SyncModuleIdsPlugin: Unable to restore id '${id}' from '${this._path}' as it's already used.`
							);
							err.module = module;
							compilation.errors.push(err);
						}
						chunkGraph.setModuleId(module, /** @type {string | number} */ (id));
						usedIds.add(idAsString);
					}
				});
			}
			if (this._write) {
				compilation.hooks.recordModules.tap(plugin, modules => {
					const { chunkGraph } = compilation;
					let oldData = data;
					if (!oldData) {
						oldData = data = new Map();
					} else if (this._prune) {
						data = new Map();
					}
					for (const module of modules) {
						if (this._test(module)) {
							const name = module.libIdent({
								context,
								associatedObjectForCache
							});
							if (!name) continue;
							const id = chunkGraph.getModuleId(module);
							if (id === null) continue;
							const oldId = oldData.get(name);
							if (oldId !== id) {
								dataChanged = true;
							} else if (data === oldData) {
								continue;
							}
							data.set(name, id);
						}
					}
					if (data.size !== oldData.size) dataChanged = true;
				});
			}
		});
	}
}

module.exports = SyncModuleIdsPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const util = require("util");
const memoize = require("./util/memoize");

/** @typedef {import("../declarations/WebpackOptions").Entry} Entry */
/** @typedef {import("../declarations/WebpackOptions").EntryNormalized} EntryNormalized */
/** @typedef {import("../declarations/WebpackOptions").EntryObject} EntryObject */
/** @typedef {import("../declarations/WebpackOptions").ExternalItemFunctionData} ExternalItemFunctionData */
/** @typedef {import("../declarations/WebpackOptions").ExternalItemObjectKnown} ExternalItemObjectKnown */
/** @typedef {import("../declarations/WebpackOptions").ExternalItemObjectUnknown} ExternalItemObjectUnknown */
/** @typedef {import("../declarations/WebpackOptions").ExternalItemValue} ExternalItemValue */
/** @typedef {import("../declarations/WebpackOptions").Externals} Externals */
/** @typedef {import("../declarations/WebpackOptions").FileCacheOptions} FileCacheOptions */
/** @typedef {import("../declarations/WebpackOptions").LibraryOptions} LibraryOptions */
/** @typedef {import("../declarations/WebpackOptions").MemoryCacheOptions} MemoryCacheOptions */
/** @typedef {import("../declarations/WebpackOptions").ModuleOptions} ModuleOptions */
/** @typedef {import("../declarations/WebpackOptions").ResolveOptions} ResolveOptions */
/** @typedef {import("../declarations/WebpackOptions").RuleSetCondition} RuleSetCondition */
/** @typedef {import("../declarations/WebpackOptions").RuleSetConditionAbsolute} RuleSetConditionAbsolute */
/** @typedef {import("../declarations/WebpackOptions").RuleSetRule} RuleSetRule */
/** @typedef {import("../declarations/WebpackOptions").RuleSetUse} RuleSetUse */
/** @typedef {import("../declarations/WebpackOptions").RuleSetUseItem} RuleSetUseItem */
/** @typedef {import("../declarations/WebpackOptions").StatsOptions} StatsOptions */
/** @typedef {import("../declarations/WebpackOptions").WebpackOptions} Configuration */
/** @typedef {import("../declarations/WebpackOptions").WebpackOptionsNormalized} WebpackOptionsNormalized */
/** @typedef {import("../declarations/WebpackOptions").WebpackPluginFunction} WebpackPluginFunction */
/** @typedef {import("../declarations/WebpackOptions").WebpackPluginInstance} WebpackPluginInstance */
/** @typedef {import("./ChunkGroup")} ChunkGroup */
/** @typedef {import("./Compilation").Asset} Asset */
/** @typedef {import("./Compilation").AssetInfo} AssetInfo */
/** @typedef {import("./Compilation").EntryOptions} EntryOptions */
/** @typedef {import("./Compilation").PathData} PathData */
/** @typedef {import("./Compiler").AssetEmittedInfo} AssetEmittedInfo */
/** @typedef {import("./MultiCompiler").MultiCompilerOptions} MultiCompilerOptions */
/** @typedef {import("./MultiStats")} MultiStats */
/** @typedef {import("./NormalModuleFactory").ResolveData} ResolveData */
/** @typedef {import("./Parser").ParserState} ParserState */
/** @typedef {import("./ResolverFactory").ResolvePluginInstance} ResolvePluginInstance */
/** @typedef {import("./ResolverFactory").Resolver} Resolver */
/** @typedef {import("./Watching")} Watching */
/** @typedef {import("./cli").Argument} Argument */
/** @typedef {import("./cli").Problem} Problem */
/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsAsset} StatsAsset */
/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsChunk} StatsChunk */
/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsChunkGroup} StatsChunkGroup */
/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsChunkOrigin} StatsChunkOrigin */
/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsCompilation} StatsCompilation */
/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsError} StatsError */
/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsLogging} StatsLogging */
/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsLoggingEntry} StatsLoggingEntry */
/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsModule} StatsModule */
/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsModuleIssuer} StatsModuleIssuer */
/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsModuleReason} StatsModuleReason */
/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsModuleTraceDependency} StatsModuleTraceDependency */
/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsModuleTraceItem} StatsModuleTraceItem */
/** @typedef {import("./stats/DefaultStatsFactoryPlugin").StatsProfile} StatsProfile */
/** @typedef {import("./util/fs").InputFileSystem} InputFileSystem */
/** @typedef {import("./util/fs").OutputFileSystem} OutputFileSystem */

/**
 * @template {Function} T
 * @param {function(): T} factory factory function
 * @returns {T} function
 */
const lazyFunction = factory => {
	const fac = memoize(factory);
	const f = /** @type {any} */ (
		(...args) => {
			return fac()(...args);
		}
	);
	return /** @type {T} */ (f);
};

/**
 * @template A
 * @template B
 * @param {A} obj input a
 * @param {B} exports input b
 * @returns {A & B} merged
 */
const mergeExports = (obj, exports) => {
	const descriptors = Object.getOwnPropertyDescriptors(exports);
	for (const name of Object.keys(descriptors)) {
		const descriptor = descriptors[name];
		if (descriptor.get) {
			const fn = descriptor.get;
			Object.defineProperty(obj, name, {
				configurable: false,
				enumerable: true,
				get: memoize(fn)
			});
		} else if (typeof descriptor.value === "object") {
			Object.defineProperty(obj, name, {
				configurable: false,
				enumerable: true,
				writable: false,
				value: mergeExports({}, descriptor.value)
			});
		} else {
			throw new Error(
				"Exposed values must be either a getter or an nested object"
			);
		}
	}
	return /** @type {A & B} */ (Object.freeze(obj));
};

const fn = lazyFunction(() => require("./webpack"));
module.exports = mergeExports(fn, {
	get webpack() {
		return require("./webpack");
	},
	get validate() {
		const webpackOptionsSchemaCheck = require("../schemas/WebpackOptions.check.js");
		const getRealValidate = memoize(() => {
			const validateSchema = require("./validateSchema");
			const webpackOptionsSchema = require("../schemas/WebpackOptions.json");
			return options => validateSchema(webpackOptionsSchema, options);
		});
		return options => {
			if (!webpackOptionsSchemaCheck(options)) getRealValidate()(options);
		};
	},
	get validateSchema() {
		const validateSchema = require("./validateSchema");
		return validateSchema;
	},
	get version() {
		return /** @type {string} */ (require("../package.json").version);
	},

	get cli() {
		return require("./cli");
	},
	get AutomaticPrefetchPlugin() {
		return require("./AutomaticPrefetchPlugin");
	},
	get AsyncDependenciesBlock() {
		return require("./AsyncDependenciesBlock");
	},
	get BannerPlugin() {
		return require("./BannerPlugin");
	},
	get Cache() {
		return require("./Cache");
	},
	get Chunk() {
		return require("./Chunk");
	},
	get ChunkGraph() {
		return require("./ChunkGraph");
	},
	get CleanPlugin() {
		return require("./CleanPlugin");
	},
	get Compilation() {
		return require("./Compilation");
	},
	get Compiler() {
		return require("./Compiler");
	},
	get ConcatenationScope() {
		return require("./ConcatenationScope");
	},
	get ContextExclusionPlugin() {
		return require("./ContextExclusionPlugin");
	},
	get ContextReplacementPlugin() {
		return require("./ContextReplacementPlugin");
	},
	get DefinePlugin() {
		return require("./DefinePlugin");
	},
	get DelegatedPlugin() {
		return require("./DelegatedPlugin");
	},
	get Dependency() {
		return require("./Dependency");
	},
	get DllPlugin() {
		return require("./DllPlugin");
	},
	get DllReferencePlugin() {
		return require("./DllReferencePlugin");
	},
	get DynamicEntryPlugin() {
		return require("./DynamicEntryPlugin");
	},
	get EntryOptionPlugin() {
		return require("./EntryOptionPlugin");
	},
	get EntryPlugin() {
		return require("./EntryPlugin");
	},
	get EnvironmentPlugin() {
		return require("./EnvironmentPlugin");
	},
	get EvalDevToolModulePlugin() {
		return require("./EvalDevToolModulePlugin");
	},
	get EvalSourceMapDevToolPlugin() {
		return require("./EvalSourceMapDevToolPlugin");
	},
	get ExternalModule() {
		return require("./ExternalModule");
	},
	get ExternalsPlugin() {
		return require("./ExternalsPlugin");
	},
	get Generator() {
		return require("./Generator");
	},
	get HotUpdateChunk() {
		return require("./HotUpdateChunk");
	},
	get HotModuleReplacementPlugin() {
		return require("./HotModuleReplacementPlugin");
	},
	get InitFragment() {
		return require("./InitFragment");
	},
	get IgnorePlugin() {
		return require("./IgnorePlugin");
	},
	get JavascriptModulesPlugin() {
		return util.deprecate(
			() => require("./javascript/JavascriptModulesPlugin"),
			"webpack.JavascriptModulesPlugin has moved to webpack.javascript.JavascriptModulesPlugin",
			"DEP_WEBPACK_JAVASCRIPT_MODULES_PLUGIN"
		)();
	},
	get LibManifestPlugin() {
		return require("./LibManifestPlugin");
	},
	get LibraryTemplatePlugin() {
		return util.deprecate(
			() => require("./LibraryTemplatePlugin"),
			"webpack.LibraryTemplatePlugin is deprecated and has been replaced by compilation.outputOptions.library or compilation.addEntry + passing a library option",
			"DEP_WEBPACK_LIBRARY_TEMPLATE_PLUGIN"
		)();
	},
	get LoaderOptionsPlugin() {
		return require("./LoaderOptionsPlugin");
	},
	get LoaderTargetPlugin() {
		return require("./LoaderTargetPlugin");
	},
	get Module() {
		return require("./Module");
	},
	get ModuleFilenameHelpers() {
		return require("./ModuleFilenameHelpers");
	},
	get ModuleGraph() {
		return require("./ModuleGraph");
	},
	get ModuleGraphConnection() {
		return require("./ModuleGraphConnection");
	},
	get NoEmitOnErrorsPlugin() {
		return require("./NoEmitOnErrorsPlugin");
	},
	get NormalModule() {
		return require("./NormalModule");
	},
	get NormalModuleReplacementPlugin() {
		return require("./NormalModuleReplacementPlugin");
	},
	get MultiCompiler() {
		return require("./MultiCompiler");
	},
	get OptimizationStages() {
		return require("./OptimizationStages");
	},
	get Parser() {
		return require("./Parser");
	},
	get PlatformPlugin() {
		return require("./PlatformPlugin");
	},
	get PrefetchPlugin() {
		return require("./PrefetchPlugin");
	},
	get ProgressPlugin() {
		return require("./ProgressPlugin");
	},
	get ProvidePlugin() {
		return require("./ProvidePlugin");
	},
	get RuntimeGlobals() {
		return require("./RuntimeGlobals");
	},
	get RuntimeModule() {
		return require("./RuntimeModule");
	},
	get SingleEntryPlugin() {
		return util.deprecate(
			() => require("./EntryPlugin"),
			"SingleEntryPlugin was renamed to EntryPlugin",
			"DEP_WEBPACK_SINGLE_ENTRY_PLUGIN"
		)();
	},
	get SourceMapDevToolPlugin() {
		return require("./SourceMapDevToolPlugin");
	},
	get Stats() {
		return require("./Stats");
	},
	get Template() {
		return require("./Template");
	},
	get UsageState() {
		return require("./ExportsInfo").UsageState;
	},
	get WatchIgnorePlugin() {
		return require("./WatchIgnorePlugin");
	},
	get WebpackError() {
		return require("./WebpackError");
	},
	get WebpackOptionsApply() {
		return require("./WebpackOptionsApply");
	},
	get WebpackOptionsDefaulter() {
		return util.deprecate(
			() => require("./WebpackOptionsDefaulter"),
			"webpack.WebpackOptionsDefaulter is deprecated and has been replaced by webpack.config.getNormalizedWebpackOptions and webpack.config.applyWebpackOptionsDefaults",
			"DEP_WEBPACK_OPTIONS_DEFAULTER"
		)();
	},
	// TODO webpack 6 deprecate
	get WebpackOptionsValidationError() {
		return require("schema-utils").ValidationError;
	},
	get ValidationError() {
		return require("schema-utils").ValidationError;
	},

	cache: {
		get MemoryCachePlugin() {
			return require("./cache/MemoryCachePlugin");
		}
	},

	config: {
		get getNormalizedWebpackOptions() {
			return require("./config/normalization").getNormalizedWebpackOptions;
		},
		get applyWebpackOptionsDefaults() {
			return require("./config/defaults").applyWebpackOptionsDefaults;
		}
	},

	dependencies: {
		get ModuleDependency() {
			return require("./dependencies/ModuleDependency");
		},
		get HarmonyImportDependency() {
			return require("./dependencies/HarmonyImportDependency");
		},
		get ConstDependency() {
			return require("./dependencies/ConstDependency");
		},
		get NullDependency() {
			return require("./dependencies/NullDependency");
		}
	},

	ids: {
		get ChunkModuleIdRangePlugin() {
			return require("./ids/ChunkModuleIdRangePlugin");
		},
		get NaturalModuleIdsPlugin() {
			return require("./ids/NaturalModuleIdsPlugin");
		},
		get OccurrenceModuleIdsPlugin() {
			return require("./ids/OccurrenceModuleIdsPlugin");
		},
		get NamedModuleIdsPlugin() {
			return require("./ids/NamedModuleIdsPlugin");
		},
		get DeterministicChunkIdsPlugin() {
			return require("./ids/DeterministicChunkIdsPlugin");
		},
		get DeterministicModuleIdsPlugin() {
			return require("./ids/DeterministicModuleIdsPlugin");
		},
		get NamedChunkIdsPlugin() {
			return require("./ids/NamedChunkIdsPlugin");
		},
		get OccurrenceChunkIdsPlugin() {
			return require("./ids/OccurrenceChunkIdsPlugin");
		},
		get HashedModuleIdsPlugin() {
			return require("./ids/HashedModuleIdsPlugin");
		}
	},

	javascript: {
		get EnableChunkLoadingPlugin() {
			return require("./javascript/EnableChunkLoadingPlugin");
		},
		get JavascriptModulesPlugin() {
			return require("./javascript/JavascriptModulesPlugin");
		},
		get JavascriptParser() {
			return require("./javascript/JavascriptParser");
		}
	},

	optimize: {
		get AggressiveMergingPlugin() {
			return require("./optimize/AggressiveMergingPlugin");
		},
		get AggressiveSplittingPlugin() {
			return util.deprecate(
				() => require("./optimize/AggressiveSplittingPlugin"),
				"AggressiveSplittingPlugin is deprecated in favor of SplitChunksPlugin",
				"DEP_WEBPACK_AGGRESSIVE_SPLITTING_PLUGIN"
			)();
		},
		get InnerGraph() {
			return require("./optimize/InnerGraph");
		},
		get LimitChunkCountPlugin() {
			return require("./optimize/LimitChunkCountPlugin");
		},
		get MinChunkSizePlugin() {
			return require("./optimize/MinChunkSizePlugin");
		},
		get ModuleConcatenationPlugin() {
			return require("./optimize/ModuleConcatenationPlugin");
		},
		get RealContentHashPlugin() {
			return require("./optimize/RealContentHashPlugin");
		},
		get RuntimeChunkPlugin() {
			return require("./optimize/RuntimeChunkPlugin");
		},
		get SideEffectsFlagPlugin() {
			return require("./optimize/SideEffectsFlagPlugin");
		},
		get SplitChunksPlugin() {
			return require("./optimize/SplitChunksPlugin");
		}
	},

	runtime: {
		get GetChunkFilenameRuntimeModule() {
			return require("./runtime/GetChunkFilenameRuntimeModule");
		},
		get LoadScriptRuntimeModule() {
			return require("./runtime/LoadScriptRuntimeModule");
		}
	},

	prefetch: {
		get ChunkPrefetchPreloadPlugin() {
			return require("./prefetch/ChunkPrefetchPreloadPlugin");
		}
	},

	web: {
		get FetchCompileAsyncWasmPlugin() {
			return require("./web/FetchCompileAsyncWasmPlugin");
		},
		get FetchCompileWasmPlugin() {
			return require("./web/FetchCompileWasmPlugin");
		},
		get JsonpChunkLoadingRuntimeModule() {
			return require("./web/JsonpChunkLoadingRuntimeModule");
		},
		get JsonpTemplatePlugin() {
			return require("./web/JsonpTemplatePlugin");
		}
	},

	webworker: {
		get WebWorkerTemplatePlugin() {
			return require("./webworker/WebWorkerTemplatePlugin");
		}
	},

	node: {
		get NodeEnvironmentPlugin() {
			return require("./node/NodeEnvironmentPlugin");
		},
		get NodeSourcePlugin() {
			return require("./node/NodeSourcePlugin");
		},
		get NodeTargetPlugin() {
			return require("./node/NodeTargetPlugin");
		},
		get NodeTemplatePlugin() {
			return require("./node/NodeTemplatePlugin");
		},
		get ReadFileCompileWasmPlugin() {
			return require("./node/ReadFileCompileWasmPlugin");
		}
	},

	electron: {
		get ElectronTargetPlugin() {
			return require("./electron/ElectronTargetPlugin");
		}
	},

	wasm: {
		get AsyncWebAssemblyModulesPlugin() {
			return require("./wasm-async/AsyncWebAssemblyModulesPlugin");
		},
		get EnableWasmLoadingPlugin() {
			return require("./wasm/EnableWasmLoadingPlugin");
		}
	},

	library: {
		get AbstractLibraryPlugin() {
			return require("./library/AbstractLibraryPlugin");
		},
		get EnableLibraryPlugin() {
			return require("./library/EnableLibraryPlugin");
		}
	},

	container: {
		get ContainerPlugin() {
			return require("./container/ContainerPlugin");
		},
		get ContainerReferencePlugin() {
			return require("./container/ContainerReferencePlugin");
		},
		get ModuleFederationPlugin() {
			return require("./container/ModuleFederationPlugin");
		},
		get scope() {
			return require("./container/options").scope;
		}
	},

	sharing: {
		get ConsumeSharedPlugin() {
			return require("./sharing/ConsumeSharedPlugin");
		},
		get ProvideSharedPlugin() {
			return require("./sharing/ProvideSharedPlugin");
		},
		get SharePlugin() {
			return require("./sharing/SharePlugin");
		},
		get scope() {
			return require("./container/options").scope;
		}
	},

	debug: {
		get ProfilingPlugin() {
			return require("./debug/ProfilingPlugin");
		}
	},

	util: {
		get createHash() {
			return require("./util/createHash");
		},
		get comparators() {
			return require("./util/comparators");
		},
		get runtime() {
			return require("./util/runtime");
		},
		get serialization() {
			return require("./util/serialization");
		},
		get cleverMerge() {
			return require("./util/cleverMerge").cachedCleverMerge;
		},
		get LazySet() {
			return require("./util/LazySet");
		},
		get compileBooleanMatcher() {
			return require("./util/compileBooleanMatcher");
		}
	},

	get sources() {
		return require("webpack-sources");
	},

	experiments: {
		schemes: {
			get HttpUriPlugin() {
				return require("./schemes/HttpUriPlugin");
			}
		},
		ids: {
			get SyncModuleIdsPlugin() {
				return require("./ids/SyncModuleIdsPlugin");
			}
		}
	}
});


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { ConcatSource, PrefixSource, RawSource } = require("webpack-sources");
const { RuntimeGlobals } = require("..");
const HotUpdateChunk = require("../HotUpdateChunk");
const Template = require("../Template");
const { getCompilationHooks } = require("./JavascriptModulesPlugin");
const {
	generateEntryStartup,
	updateHashForEntryStartup
} = require("./StartupHelpers");

/** @typedef {import("../Compiler")} Compiler */

class ArrayPushCallbackChunkFormatPlugin {
	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.thisCompilation.tap(
			"ArrayPushCallbackChunkFormatPlugin",
			compilation => {
				compilation.hooks.additionalChunkRuntimeRequirements.tap(
					"ArrayPushCallbackChunkFormatPlugin",
					(chunk, set, { chunkGraph }) => {
						if (chunk.hasRuntime()) return;
						if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
							set.add(RuntimeGlobals.onChunksLoaded);
							set.add(RuntimeGlobals.require);
						}
						set.add(RuntimeGlobals.chunkCallback);
					}
				);
				const hooks = getCompilationHooks(compilation);
				hooks.renderChunk.tap(
					"ArrayPushCallbackChunkFormatPlugin",
					(modules, renderContext) => {
						const { chunk, chunkGraph, runtimeTemplate } = renderContext;
						const hotUpdateChunk =
							chunk instanceof HotUpdateChunk ? chunk : null;
						const globalObject = runtimeTemplate.globalObject;
						const source = new ConcatSource();
						const runtimeModules =
							chunkGraph.getChunkRuntimeModulesInOrder(chunk);
						if (hotUpdateChunk) {
							const hotUpdateGlobal =
								runtimeTemplate.outputOptions.hotUpdateGlobal;
							source.add(
								`${globalObject}[${JSON.stringify(hotUpdateGlobal)}](`
							);
							source.add(`${JSON.stringify(chunk.id)},`);
							source.add(modules);
							if (runtimeModules.length > 0) {
								source.add(",\n");
								const runtimePart = Template.renderChunkRuntimeModules(
									runtimeModules,
									renderContext
								);
								source.add(runtimePart);
							}
							source.add(")");
						} else {
							const chunkLoadingGlobal =
								runtimeTemplate.outputOptions.chunkLoadingGlobal;
							source.add(
								`(${globalObject}[${JSON.stringify(
									chunkLoadingGlobal
								)}] = ${globalObject}[${JSON.stringify(
									chunkLoadingGlobal
								)}] || []).push([`
							);
							source.add(`${JSON.stringify(chunk.ids)},`);
							source.add(modules);
							const entries = Array.from(
								chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
							);
							if (runtimeModules.length > 0 || entries.length > 0) {
								const runtime = new ConcatSource(
									(runtimeTemplate.supportsArrowFunction()
										? `${RuntimeGlobals.require} =>`
										: `function(${RuntimeGlobals.require})`) +
										" { // webpackRuntimeModules\n"
								);
								if (runtimeModules.length > 0) {
									runtime.add(
										Template.renderRuntimeModules(runtimeModules, {
											...renderContext,
											codeGenerationResults: compilation.codeGenerationResults
										})
									);
								}
								if (entries.length > 0) {
									const startupSource = new RawSource(
										generateEntryStartup(
											chunkGraph,
											runtimeTemplate,
											entries,
											chunk,
											true
										)
									);
									runtime.add(
										hooks.renderStartup.call(
											startupSource,
											entries[entries.length - 1][0],
											{
												...renderContext,
												inlined: false
											}
										)
									);
									if (
										chunkGraph
											.getChunkRuntimeRequirements(chunk)
											.has(RuntimeGlobals.returnExportsFromRuntime)
									) {
										runtime.add(`return ${RuntimeGlobals.exports};\n`);
									}
								}
								runtime.add("}\n");
								source.add(",\n");
								source.add(new PrefixSource("/******/ ", runtime));
							}
							source.add("])");
						}
						return source;
					}
				);
				hooks.chunkHash.tap(
					"ArrayPushCallbackChunkFormatPlugin",
					(chunk, hash, { chunkGraph, runtimeTemplate }) => {
						if (chunk.hasRuntime()) return;
						hash.update(
							`ArrayPushCallbackChunkFormatPlugin1${runtimeTemplate.outputOptions.chunkLoadingGlobal}${runtimeTemplate.outputOptions.hotUpdateGlobal}${runtimeTemplate.globalObject}`
						);
						const entries = Array.from(
							chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
						);
						updateHashForEntryStartup(hash, chunkGraph, entries, chunk);
					}
				);
			}
		);
	}
}

module.exports = ArrayPushCallbackChunkFormatPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

/** @typedef {import("estree").Node} Node */
/** @typedef {import("./JavascriptParser").Range} Range */
/** @typedef {import("./JavascriptParser").VariableInfoInterface} VariableInfoInterface */

const TypeUnknown = 0;
const TypeUndefined = 1;
const TypeNull = 2;
const TypeString = 3;
const TypeNumber = 4;
const TypeBoolean = 5;
const TypeRegExp = 6;
const TypeConditional = 7;
const TypeArray = 8;
const TypeConstArray = 9;
const TypeIdentifier = 10;
const TypeWrapped = 11;
const TypeTemplateString = 12;
const TypeBigInt = 13;

class BasicEvaluatedExpression {
	constructor() {
		this.type = TypeUnknown;
		/** @type {Range | undefined} */
		this.range = undefined;
		/** @type {boolean} */
		this.falsy = false;
		/** @type {boolean} */
		this.truthy = false;
		/** @type {boolean | undefined} */
		this.nullish = undefined;
		/** @type {boolean} */
		this.sideEffects = true;
		/** @type {boolean | undefined} */
		this.bool = undefined;
		/** @type {number | undefined} */
		this.number = undefined;
		/** @type {bigint | undefined} */
		this.bigint = undefined;
		/** @type {RegExp | undefined} */
		this.regExp = undefined;
		/** @type {string | undefined} */
		this.string = undefined;
		/** @type {BasicEvaluatedExpression[] | undefined} */
		this.quasis = undefined;
		/** @type {BasicEvaluatedExpression[] | undefined} */
		this.parts = undefined;
		/** @type {any[] | undefined} */
		this.array = undefined;
		/** @type {BasicEvaluatedExpression[] | undefined} */
		this.items = undefined;
		/** @type {BasicEvaluatedExpression[] | undefined} */
		this.options = undefined;
		/** @type {BasicEvaluatedExpression | undefined | null} */
		this.prefix = undefined;
		/** @type {BasicEvaluatedExpression | undefined | null} */
		this.postfix = undefined;
		/** @type {BasicEvaluatedExpression[] | undefined} */
		this.wrappedInnerExpressions = undefined;
		/** @type {string | VariableInfoInterface | undefined} */
		this.identifier = undefined;
		/** @type {string | VariableInfoInterface | undefined} */
		this.rootInfo = undefined;
		/** @type {(() => string[]) | undefined} */
		this.getMembers = undefined;
		/** @type {(() => boolean[]) | undefined} */
		this.getMembersOptionals = undefined;
		/** @type {(() => Range[]) | undefined} */
		this.getMemberRanges = undefined;
		/** @type {Node | undefined} */
		this.expression = undefined;
	}

	isUnknown() {
		return this.type === TypeUnknown;
	}

	isNull() {
		return this.type === TypeNull;
	}

	isUndefined() {
		return this.type === TypeUndefined;
	}

	isString() {
		return this.type === TypeString;
	}

	isNumber() {
		return this.type === TypeNumber;
	}

	isBigInt() {
		return this.type === TypeBigInt;
	}

	isBoolean() {
		return this.type === TypeBoolean;
	}

	isRegExp() {
		return this.type === TypeRegExp;
	}

	isConditional() {
		return this.type === TypeConditional;
	}

	isArray() {
		return this.type === TypeArray;
	}

	isConstArray() {
		return this.type === TypeConstArray;
	}

	isIdentifier() {
		return this.type === TypeIdentifier;
	}

	isWrapped() {
		return this.type === TypeWrapped;
	}

	isTemplateString() {
		return this.type === TypeTemplateString;
	}

	/**
	 * Is expression a primitive or an object type value?
	 * @returns {boolean | undefined} true: primitive type, false: object type, undefined: unknown/runtime-defined
	 */
	isPrimitiveType() {
		switch (this.type) {
			case TypeUndefined:
			case TypeNull:
			case TypeString:
			case TypeNumber:
			case TypeBoolean:
			case TypeBigInt:
			case TypeWrapped:
			case TypeTemplateString:
				return true;
			case TypeRegExp:
			case TypeArray:
			case TypeConstArray:
				return false;
			default:
				return undefined;
		}
	}

	/**
	 * Is expression a runtime or compile-time value?
	 * @returns {boolean} true: compile time value, false: runtime value
	 */
	isCompileTimeValue() {
		switch (this.type) {
			case TypeUndefined:
			case TypeNull:
			case TypeString:
			case TypeNumber:
			case TypeBoolean:
			case TypeRegExp:
			case TypeConstArray:
			case TypeBigInt:
				return true;
			default:
				return false;
		}
	}

	/**
	 * Gets the compile-time value of the expression
	 * @returns {any} the javascript value
	 */
	asCompileTimeValue() {
		switch (this.type) {
			case TypeUndefined:
				return undefined;
			case TypeNull:
				return null;
			case TypeString:
				return this.string;
			case TypeNumber:
				return this.number;
			case TypeBoolean:
				return this.bool;
			case TypeRegExp:
				return this.regExp;
			case TypeConstArray:
				return this.array;
			case TypeBigInt:
				return this.bigint;
			default:
				throw new Error(
					"asCompileTimeValue must only be called for compile-time values"
				);
		}
	}

	isTruthy() {
		return this.truthy;
	}

	isFalsy() {
		return this.falsy;
	}

	isNullish() {
		return this.nullish;
	}

	/**
	 * Can this expression have side effects?
	 * @returns {boolean} false: never has side effects
	 */
	couldHaveSideEffects() {
		return this.sideEffects;
	}

	/**
	 * Creates a boolean representation of this evaluated expression.
	 * @returns {boolean | undefined} true: truthy, false: falsy, undefined: unknown
	 */
	asBool() {
		if (this.truthy) return true;
		if (this.falsy || this.nullish) return false;
		if (this.isBoolean()) return this.bool;
		if (this.isNull()) return false;
		if (this.isUndefined()) return false;
		if (this.isString()) return this.string !== "";
		if (this.isNumber()) return this.number !== 0;
		if (this.isBigInt()) return this.bigint !== BigInt(0);
		if (this.isRegExp()) return true;
		if (this.isArray()) return true;
		if (this.isConstArray()) return true;
		if (this.isWrapped()) {
			return (this.prefix && this.prefix.asBool()) ||
				(this.postfix && this.postfix.asBool())
				? true
				: undefined;
		}
		if (this.isTemplateString()) {
			const str = this.asString();
			if (typeof str === "string") return str !== "";
		}
		return undefined;
	}

	/**
	 * Creates a nullish coalescing representation of this evaluated expression.
	 * @returns {boolean | undefined} true: nullish, false: not nullish, undefined: unknown
	 */
	asNullish() {
		const nullish = this.isNullish();

		if (nullish === true || this.isNull() || this.isUndefined()) return true;

		if (nullish === false) return false;
		if (this.isTruthy()) return false;
		if (this.isBoolean()) return false;
		if (this.isString()) return false;
		if (this.isNumber()) return false;
		if (this.isBigInt()) return false;
		if (this.isRegExp()) return false;
		if (this.isArray()) return false;
		if (this.isConstArray()) return false;
		if (this.isTemplateString()) return false;
		if (this.isRegExp()) return false;

		return undefined;
	}

	/**
	 * Creates a string representation of this evaluated expression.
	 * @returns {string | undefined} the string representation or undefined if not possible
	 */
	asString() {
		if (this.isBoolean()) return `${this.bool}`;
		if (this.isNull()) return "null";
		if (this.isUndefined()) return "undefined";
		if (this.isString()) return this.string;
		if (this.isNumber()) return `${this.number}`;
		if (this.isBigInt()) return `${this.bigint}`;
		if (this.isRegExp()) return `${this.regExp}`;
		if (this.isArray()) {
			let array = [];
			for (const item of /** @type {BasicEvaluatedExpression[]} */ (
				this.items
			)) {
				const itemStr = item.asString();
				if (itemStr === undefined) return undefined;
				array.push(itemStr);
			}
			return `${array}`;
		}
		if (this.isConstArray()) return `${this.array}`;
		if (this.isTemplateString()) {
			let str = "";
			for (const part of /** @type {BasicEvaluatedExpression[]} */ (
				this.parts
			)) {
				const partStr = part.asString();
				if (partStr === undefined) return undefined;
				str += partStr;
			}
			return str;
		}
		return undefined;
	}

	/**
	 * @param {string} string value
	 * @returns {BasicEvaluatedExpression} basic evaluated expression
	 */
	setString(string) {
		this.type = TypeString;
		this.string = string;
		this.sideEffects = false;
		return this;
	}

	setUndefined() {
		this.type = TypeUndefined;
		this.sideEffects = false;
		return this;
	}

	setNull() {
		this.type = TypeNull;
		this.sideEffects = false;
		return this;
	}

	/**
	 * Set's the value of this expression to a number
	 * @param {number} number number to set
	 * @returns {this} this
	 */
	setNumber(number) {
		this.type = TypeNumber;
		this.number = number;
		this.sideEffects = false;
		return this;
	}

	/**
	 * Set's the value of this expression to a BigInt
	 * @param {bigint} bigint bigint to set
	 * @returns {this} this
	 */
	setBigInt(bigint) {
		this.type = TypeBigInt;
		this.bigint = bigint;
		this.sideEffects = false;
		return this;
	}

	/**
	 * Set's the value of this expression to a boolean
	 * @param {boolean} bool boolean to set
	 * @returns {this} this
	 */
	setBoolean(bool) {
		this.type = TypeBoolean;
		this.bool = bool;
		this.sideEffects = false;
		return this;
	}

	/**
	 * Set's the value of this expression to a regular expression
	 * @param {RegExp} regExp regular expression to set
	 * @returns {this} this
	 */
	setRegExp(regExp) {
		this.type = TypeRegExp;
		this.regExp = regExp;
		this.sideEffects = false;
		return this;
	}

	/**
	 * Set's the value of this expression to a particular identifier and its members.
	 *
	 * @param {string | VariableInfoInterface} identifier identifier to set
	 * @param {string | VariableInfoInterface} rootInfo root info
	 * @param {() => string[]} getMembers members
	 * @param {() => boolean[]=} getMembersOptionals optional members
	 * @param {() => Range[]=} getMemberRanges ranges of progressively increasing sub-expressions
	 * @returns {this} this
	 */
	setIdentifier(
		identifier,
		rootInfo,
		getMembers,
		getMembersOptionals,
		getMemberRanges
	) {
		this.type = TypeIdentifier;
		this.identifier = identifier;
		this.rootInfo = rootInfo;
		this.getMembers = getMembers;
		this.getMembersOptionals = getMembersOptionals;
		this.getMemberRanges = getMemberRanges;
		this.sideEffects = true;
		return this;
	}

	/**
	 * Wraps an array of expressions with a prefix and postfix expression.
	 *
	 * @param {BasicEvaluatedExpression | null | undefined} prefix Expression to be added before the innerExpressions
	 * @param {BasicEvaluatedExpression | null | undefined} postfix Expression to be added after the innerExpressions
	 * @param {BasicEvaluatedExpression[] | undefined} innerExpressions Expressions to be wrapped
	 * @returns {this} this
	 */
	setWrapped(prefix, postfix, innerExpressions) {
		this.type = TypeWrapped;
		this.prefix = prefix;
		this.postfix = postfix;
		this.wrappedInnerExpressions = innerExpressions;
		this.sideEffects = true;
		return this;
	}

	/**
	 * Stores the options of a conditional expression.
	 *
	 * @param {BasicEvaluatedExpression[]} options optional (consequent/alternate) expressions to be set
	 * @returns {this} this
	 */
	setOptions(options) {
		this.type = TypeConditional;
		this.options = options;
		this.sideEffects = true;
		return this;
	}

	/**
	 * Adds options to a conditional expression.
	 *
	 * @param {BasicEvaluatedExpression[]} options optional (consequent/alternate) expressions to be added
	 * @returns {this} this
	 */
	addOptions(options) {
		if (!this.options) {
			this.type = TypeConditional;
			this.options = [];
			this.sideEffects = true;
		}
		for (const item of options) {
			this.options.push(item);
		}
		return this;
	}

	/**
	 * Set's the value of this expression to an array of expressions.
	 *
	 * @param {BasicEvaluatedExpression[]} items expressions to set
	 * @returns {this} this
	 */
	setItems(items) {
		this.type = TypeArray;
		this.items = items;
		this.sideEffects = items.some(i => i.couldHaveSideEffects());
		return this;
	}

	/**
	 * Set's the value of this expression to an array of strings.
	 *
	 * @param {string[]} array array to set
	 * @returns {this} this
	 */
	setArray(array) {
		this.type = TypeConstArray;
		this.array = array;
		this.sideEffects = false;
		return this;
	}

	/**
	 * Set's the value of this expression to a processed/unprocessed template string. Used
	 * for evaluating TemplateLiteral expressions in the JavaScript Parser.
	 *
	 * @param {BasicEvaluatedExpression[]} quasis template string quasis
	 * @param {BasicEvaluatedExpression[]} parts template string parts
	 * @param {"cooked" | "raw"} kind template string kind
	 * @returns {this} this
	 */
	setTemplateString(quasis, parts, kind) {
		this.type = TypeTemplateString;
		this.quasis = quasis;
		this.parts = parts;
		this.templateStringKind = kind;
		this.sideEffects = parts.some(p => p.sideEffects);
		return this;
	}

	setTruthy() {
		this.falsy = false;
		this.truthy = true;
		this.nullish = false;
		return this;
	}

	setFalsy() {
		this.falsy = true;
		this.truthy = false;
		return this;
	}

	/**
	 * Set's the value of the expression to nullish.
	 *
	 * @param {boolean} value true, if the expression is nullish
	 * @returns {this} this
	 */
	setNullish(value) {
		this.nullish = value;

		if (value) return this.setFalsy();

		return this;
	}

	/**
	 * Set's the range for the expression.
	 *
	 * @param {[number, number]} range range to set
	 * @returns {this} this
	 */
	setRange(range) {
		this.range = range;
		return this;
	}

	/**
	 * Set whether or not the expression has side effects.
	 *
	 * @param {boolean} sideEffects true, if the expression has side effects
	 * @returns {this} this
	 */
	setSideEffects(sideEffects = true) {
		this.sideEffects = sideEffects;
		return this;
	}

	/**
	 * Set the expression node for the expression.
	 *
	 * @param {Node | undefined} expression expression
	 * @returns {this} this
	 */
	setExpression(expression) {
		this.expression = expression;
		return this;
	}
}

/**
 * @param {string} flags regexp flags
 * @returns {boolean} is valid flags
 */
BasicEvaluatedExpression.isValidRegExpFlags = flags => {
	const len = flags.length;

	if (len === 0) return true;
	if (len > 4) return false;

	// cspell:word gimy
	let remaining = 0b0000; // bit per RegExp flag: gimy

	for (let i = 0; i < len; i++)
		switch (flags.charCodeAt(i)) {
			case 103 /* g */:
				if (remaining & 0b1000) return false;
				remaining |= 0b1000;
				break;
			case 105 /* i */:
				if (remaining & 0b0100) return false;
				remaining |= 0b0100;
				break;
			case 109 /* m */:
				if (remaining & 0b0010) return false;
				remaining |= 0b0010;
				break;
			case 121 /* y */:
				if (remaining & 0b0001) return false;
				remaining |= 0b0001;
				break;
			default:
				return false;
		}

	return true;
};

module.exports = BasicEvaluatedExpression;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const Entrypoint = require("../Entrypoint");

/** @typedef {import("../Chunk")} Chunk */

/**
 * @param {Entrypoint} entrypoint a chunk group
 * @param {(Chunk | null)=} excludedChunk1 current chunk which is excluded
 * @param {(Chunk | null)=} excludedChunk2 runtime chunk which is excluded
 * @returns {Set<Chunk>} chunks
 */
const getAllChunks = (entrypoint, excludedChunk1, excludedChunk2) => {
	const queue = new Set([entrypoint]);
	const chunks = new Set();
	for (const entrypoint of queue) {
		for (const chunk of entrypoint.chunks) {
			if (chunk === excludedChunk1) continue;
			if (chunk === excludedChunk2) continue;
			chunks.add(chunk);
		}
		for (const parent of entrypoint.parentsIterable) {
			if (parent instanceof Entrypoint) queue.add(parent);
		}
	}
	return chunks;
};
exports.getAllChunks = getAllChunks;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const { ConcatSource, RawSource } = require("webpack-sources");
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const {
	getChunkFilenameTemplate,
	getCompilationHooks
} = require("./JavascriptModulesPlugin");
const {
	generateEntryStartup,
	updateHashForEntryStartup
} = require("./StartupHelpers");

/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Entrypoint")} Entrypoint */

class CommonJsChunkFormatPlugin {
	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.thisCompilation.tap(
			"CommonJsChunkFormatPlugin",
			compilation => {
				compilation.hooks.additionalChunkRuntimeRequirements.tap(
					"CommonJsChunkFormatPlugin",
					(chunk, set, { chunkGraph }) => {
						if (chunk.hasRuntime()) return;
						if (chunkGraph.getNumberOfEntryModules(chunk) > 0) {
							set.add(RuntimeGlobals.require);
							set.add(RuntimeGlobals.startupEntrypoint);
							set.add(RuntimeGlobals.externalInstallChunk);
						}
					}
				);
				const hooks = getCompilationHooks(compilation);
				hooks.renderChunk.tap(
					"CommonJsChunkFormatPlugin",
					(modules, renderContext) => {
						const { chunk, chunkGraph, runtimeTemplate } = renderContext;
						const source = new ConcatSource();
						source.add(`exports.id = ${JSON.stringify(chunk.id)};\n`);
						source.add(`exports.ids = ${JSON.stringify(chunk.ids)};\n`);
						source.add(`exports.modules = `);
						source.add(modules);
						source.add(";\n");
						const runtimeModules =
							chunkGraph.getChunkRuntimeModulesInOrder(chunk);
						if (runtimeModules.length > 0) {
							source.add("exports.runtime =\n");
							source.add(
								Template.renderChunkRuntimeModules(
									runtimeModules,
									renderContext
								)
							);
						}
						const entries = Array.from(
							chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
						);
						if (entries.length > 0) {
							const runtimeChunk =
								/** @type {Entrypoint} */
								(entries[0][1]).getRuntimeChunk();
							const currentOutputName = compilation
								.getPath(
									getChunkFilenameTemplate(chunk, compilation.outputOptions),
									{
										chunk,
										contentHashType: "javascript"
									}
								)
								.split("/");
							const runtimeOutputName = compilation
								.getPath(
									getChunkFilenameTemplate(
										runtimeChunk,
										compilation.outputOptions
									),
									{
										chunk: /** @type {Chunk} */ (runtimeChunk),
										contentHashType: "javascript"
									}
								)
								.split("/");

							// remove filename, we only need the directory
							currentOutputName.pop();

							// remove common parts
							while (
								currentOutputName.length > 0 &&
								runtimeOutputName.length > 0 &&
								currentOutputName[0] === runtimeOutputName[0]
							) {
								currentOutputName.shift();
								runtimeOutputName.shift();
							}

							// create final path
							const runtimePath =
								(currentOutputName.length > 0
									? "../".repeat(currentOutputName.length)
									: "./") + runtimeOutputName.join("/");

							const entrySource = new ConcatSource();
							entrySource.add(
								`(${
									runtimeTemplate.supportsArrowFunction()
										? "() => "
										: "function() "
								}{\n`
							);
							entrySource.add("var exports = {};\n");
							entrySource.add(source);
							entrySource.add(";\n\n// load runtime\n");
							entrySource.add(
								`var ${RuntimeGlobals.require} = require(${JSON.stringify(
									runtimePath
								)});\n`
							);
							entrySource.add(
								`${RuntimeGlobals.externalInstallChunk}(exports);\n`
							);
							const startupSource = new RawSource(
								generateEntryStartup(
									chunkGraph,
									runtimeTemplate,
									entries,
									chunk,
									false
								)
							);
							entrySource.add(
								hooks.renderStartup.call(
									startupSource,
									entries[entries.length - 1][0],
									{
										...renderContext,
										inlined: false
									}
								)
							);
							entrySource.add("\n})()");
							return entrySource;
						}
						return source;
					}
				);
				hooks.chunkHash.tap(
					"CommonJsChunkFormatPlugin",
					(chunk, hash, { chunkGraph }) => {
						if (chunk.hasRuntime()) return;
						hash.update("CommonJsChunkFormatPlugin");
						hash.update("1");
						const entries = Array.from(
							chunkGraph.getChunkEntryModulesWithChunkGroupIterable(chunk)
						);
						updateHashForEntryStartup(hash, chunkGraph, entries, chunk);
					}
				);
			}
		);
	}
}

module.exports = CommonJsChunkFormatPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

/** @typedef {import("../../declarations/WebpackOptions").ChunkLoadingType} ChunkLoadingType */
/** @typedef {import("../Compiler")} Compiler */

/** @type {WeakMap<Compiler, Set<ChunkLoadingType>>} */
const enabledTypes = new WeakMap();

/**
 * @param {Compiler} compiler compiler
 * @returns {Set<ChunkLoadingType>} enabled types
 */
const getEnabledTypes = compiler => {
	let set = enabledTypes.get(compiler);
	if (set === undefined) {
		set = new Set();
		enabledTypes.set(compiler, set);
	}
	return set;
};

class EnableChunkLoadingPlugin {
	/**
	 * @param {ChunkLoadingType} type library type that should be available
	 */
	constructor(type) {
		this.type = type;
	}

	/**
	 * @param {Compiler} compiler the compiler instance
	 * @param {ChunkLoadingType} type type of library
	 * @returns {void}
	 */
	static setEnabled(compiler, type) {
		getEnabledTypes(compiler).add(type);
	}

	/**
	 * @param {Compiler} compiler the compiler instance
	 * @param {ChunkLoadingType} type type of library
	 * @returns {void}
	 */
	static checkEnabled(compiler, type) {
		if (!getEnabledTypes(compiler).has(type)) {
			throw new Error(
				`Chunk loading type "${type}" is not enabled. ` +
					"EnableChunkLoadingPlugin need to be used to enable this type of chunk loading. " +
					'This usually happens through the "output.enabledChunkLoadingTypes" option. ' +
					'If you are using a function as entry which sets "chunkLoading", you need to add all potential chunk loading types to "output.enabledChunkLoadingTypes". ' +
					"These types are enabled: " +
					Array.from(getEnabledTypes(compiler)).join(", ")
			);
		}
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		const { type } = this;

		// Only enable once
		const enabled = getEnabledTypes(compiler);
		if (enabled.has(type)) return;
		enabled.add(type);

		if (typeof type === "string") {
			switch (type) {
				case "jsonp": {
					const JsonpChunkLoadingPlugin = require("../web/JsonpChunkLoadingPlugin");
					new JsonpChunkLoadingPlugin().apply(compiler);
					break;
				}
				case "import-scripts": {
					const ImportScriptsChunkLoadingPlugin = require("../webworker/ImportScriptsChunkLoadingPlugin");
					new ImportScriptsChunkLoadingPlugin().apply(compiler);
					break;
				}
				case "require": {
					//@ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
					const CommonJsChunkLoadingPlugin = require("../node/CommonJsChunkLoadingPlugin");
					new CommonJsChunkLoadingPlugin({
						asyncChunkLoading: false
					}).apply(compiler);
					break;
				}
				case "async-node": {
					//@ts-expect-error https://github.com/microsoft/TypeScript/issues/41697
					const CommonJsChunkLoadingPlugin = require("../node/CommonJsChunkLoadingPlugin");
					new CommonJsChunkLoadingPlugin({
						asyncChunkLoading: true
					}).apply(compiler);
					break;
				}
				case "import": {
					const ModuleChunkLoadingPlugin = require("../esm/ModuleChunkLoadingPlugin");
					new ModuleChunkLoadingPlugin().apply(compiler);
					break;
				}
				case "universal":
					// TODO implement universal chunk loading
					throw new Error("Universal Chunk Loading is not implemented yet");
				default:
					throw new Error(`Unsupported chunk loading type ${type}.
Plugins which provide custom chunk loading types must call EnableChunkLoadingPlugin.setEnabled(compiler, type) to disable this error.`);
			}
		} else {
			// TODO support plugin instances here
			// apply them to the compiler
		}
	}
}

module.exports = EnableChunkLoadingPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Tobias Koppers @sokra
*/

"use strict";

const util = require("util");
const { RawSource, ReplaceSource } = require("webpack-sources");
const Generator = require("../Generator");
const InitFragment = require("../InitFragment");
const HarmonyCompatibilityDependency = require("../dependencies/HarmonyCompatibilityDependency");

/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../DependenciesBlock")} DependenciesBlock */
/** @typedef {import("../Dependency")} Dependency */
/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../Module").ConcatenationBailoutReasonContext} ConcatenationBailoutReasonContext */
/** @typedef {import("../NormalModule")} NormalModule */
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */

// TODO: clean up this file
// replace with newer constructs

const deprecatedGetInitFragments = util.deprecate(
	(template, dependency, templateContext) =>
		template.getInitFragments(dependency, templateContext),
	"DependencyTemplate.getInitFragment is deprecated (use apply(dep, source, { initFragments }) instead)",
	"DEP_WEBPACK_JAVASCRIPT_GENERATOR_GET_INIT_FRAGMENTS"
);

const TYPES = new Set(["javascript"]);

class JavascriptGenerator extends Generator {
	/**
	 * @param {NormalModule} module fresh module
	 * @returns {Set<string>} available types (do not mutate)
	 */
	getTypes(module) {
		return TYPES;
	}

	/**
	 * @param {NormalModule} module the module
	 * @param {string=} type source type
	 * @returns {number} estimate size of the module
	 */
	getSize(module, type) {
		const originalSource = module.originalSource();
		if (!originalSource) {
			return 39;
		}
		return originalSource.size();
	}

	/**
	 * @param {NormalModule} module module for which the bailout reason should be determined
	 * @param {ConcatenationBailoutReasonContext} context context
	 * @returns {string | undefined} reason why this module can't be concatenated, undefined when it can be concatenated
	 */
	getConcatenationBailoutReason(module, context) {
		// Only harmony modules are valid for optimization
		if (
			!module.buildMeta ||
			module.buildMeta.exportsType !== "namespace" ||
			module.presentationalDependencies === undefined ||
			!module.presentationalDependencies.some(
				d => d instanceof HarmonyCompatibilityDependency
			)
		) {
			return "Module is not an ECMAScript module";
		}

		// Some expressions are not compatible with module concatenation
		// because they may produce unexpected results. The plugin bails out
		// if some were detected upfront.
		if (module.buildInfo && module.buildInfo.moduleConcatenationBailout) {
			return `Module uses ${module.buildInfo.moduleConcatenationBailout}`;
		}
	}

	/**
	 * @param {NormalModule} module module for which the code should be generated
	 * @param {GenerateContext} generateContext context for generate
	 * @returns {Source} generated code
	 */
	generate(module, generateContext) {
		const originalSource = module.originalSource();
		if (!originalSource) {
			return new RawSource("throw new Error('No source available');");
		}

		const source = new ReplaceSource(originalSource);
		const initFragments = [];

		this.sourceModule(module, initFragments, source, generateContext);

		return InitFragment.addToSource(source, initFragments, generateContext);
	}

	/**
	 * @param {Module} module the module to generate
	 * @param {InitFragment[]} initFragments mutable list of init fragments
	 * @param {ReplaceSource} source the current replace source which can be modified
	 * @param {GenerateContext} generateContext the generateContext
	 * @returns {void}
	 */
	sourceModule(module, initFragments, source, generateContext) {
		for (const dependency of module.dependencies) {
			this.sourceDependency(
				module,
				dependency,
				initFragments,
				source,
				generateContext
			);
		}

		if (module.presentationalDependencies !== undefined) {
			for (const dependency of module.presentationalDependencies) {
				this.sourceDependency(
					module,
					dependency,
					initFragments,
					source,
					generateContext
				);
			}
		}

		for (const childBlock of module.blocks) {
			this.sourceBlock(
				module,
				childBlock,
				initFragments,
				source,
				generateContext
			);
		}
	}

	/**
	 * @param {Module} module the module to generate
	 * @param {DependenciesBlock} block the dependencies block which will be processed
	 * @param {InitFragment[]} initFragments mutable list of init fragments
	 * @param {ReplaceSource} source the current replace source which can be modified
	 * @param {GenerateContext} generateContext the generateContext
	 * @returns {void}
	 */
	sourceBlock(module, block, initFragments, source, generateContext) {
		for (const dependency of block.dependencies) {
			this.sourceDependency(
				module,
				dependency,
				initFragments,
				source,
				generateContext
			);
		}

		for (const childBlock of block.blocks) {
			this.sourceBlock(
				module,
				childBlock,
				initFragments,
				source,
				generateContext
			);
		}
	}

	/**
	 * @param {Module} module the current module
	 * @param {Dependency} dependency the dependency to generate
	 * @param {InitFragment[]} initFragments mutable list of init fragments
	 * @param {ReplaceSource} source the current replace source which can be modified
	 * @param {GenerateContext} generateContext the render context
	 * @returns {void}
	 */
	sourceDependency(module, dependency, initFragments, source, generateContext) {
		const constructor = /** @type {new (...args: any[]) => Dependency} */ (
			dependency.constructor
		);
		const template = generateContext.dependencyTemplates.get(constructor);
		if (!template) {
			throw new Error(
				"No template for dependency: " + dependency.constructor.name
			);
		}

		let chunkInitFragments;

		const templateContext = {
			runtimeTemplate: generateContext.runtimeTemplate,
			dependencyTemplates: generateContext.dependencyTemplates,
			moduleGraph: generateContext.moduleGraph,
			chunkGraph: generateContext.chunkGraph,
			module,
			runtime: generateContext.runtime,
			runtimeRequirements: generateContext.runtimeRequirements,
			concatenationScope: generateContext.concatenationScope,
			codeGenerationResults: generateContext.codeGenerationResults,
			initFragments,
			get chunkInitFragments() {
				if (!chunkInitFragments) {
					const data = generateContext.getData();
					chunkInitFragments = data.get("chunkInitFragments");
					if (!chunkInitFragments) {
						chunkInitFragments = [];
						data.set("chunkInitFragments", chunkInitFragments);
					}
				}

				return chunkInitFragments;
			}
		};

		template.apply(dependency, source, templateContext);

		// TODO remove in webpack 6
		if ("getInitFragments" in template) {
			const fragments = deprecatedGetInitFragments(
				template,
				dependency,
				templateContext
			);

			if (fragments) {
				for (const fragment of fragments) {
					initFragments.push(fragment);
				}
			}
		}
	}
}

module.exports = JavascriptGenerator;