code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");

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

class CompatGetDefaultExportRuntimeModule extends HelperRuntimeModule {
	constructor() {
		super("compat get default export");
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate } = compilation;
		const fn = RuntimeGlobals.compatGetDefaultExport;
		return Template.asString([
			"// getDefaultExport function for compatibility with non-harmony modules",
			`${fn} = ${runtimeTemplate.basicFunction("module", [
				"var getter = module && module.__esModule ?",
				Template.indent([
					`${runtimeTemplate.returningFunction("module['default']")} :`,
					`${runtimeTemplate.returningFunction("module")};`
				]),
				`${RuntimeGlobals.definePropertyGetters}(getter, { a: getter });`,
				"return getter;"
			])};`
		]);
	}
}

module.exports = CompatGetDefaultExportRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");

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

class CompatRuntimeModule extends RuntimeModule {
	constructor() {
		super("compat", RuntimeModule.STAGE_ATTACH);
		this.fullHash = true;
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
		const chunk = /** @type {Chunk} */ (this.chunk);
		const {
			runtimeTemplate,
			mainTemplate,
			moduleTemplates,
			dependencyTemplates
		} = compilation;
		const bootstrap = mainTemplate.hooks.bootstrap.call(
			"",
			chunk,
			compilation.hash || "XXXX",
			moduleTemplates.javascript,
			dependencyTemplates
		);
		const localVars = mainTemplate.hooks.localVars.call(
			"",
			chunk,
			compilation.hash || "XXXX"
		);
		const requireExtensions = mainTemplate.hooks.requireExtensions.call(
			"",
			chunk,
			compilation.hash || "XXXX"
		);
		const runtimeRequirements = chunkGraph.getTreeRuntimeRequirements(chunk);
		let requireEnsure = "";
		if (runtimeRequirements.has(RuntimeGlobals.ensureChunk)) {
			const requireEnsureHandler = mainTemplate.hooks.requireEnsure.call(
				"",
				chunk,
				compilation.hash || "XXXX",
				"chunkId"
			);
			if (requireEnsureHandler) {
				requireEnsure = `${
					RuntimeGlobals.ensureChunkHandlers
				}.compat = ${runtimeTemplate.basicFunction(
					"chunkId, promises",
					requireEnsureHandler
				)};`;
			}
		}
		return [bootstrap, localVars, requireEnsure, requireExtensions]
			.filter(Boolean)
			.join("\n");
	}

	/**
	 * @returns {boolean} true, if the runtime module should get it's own scope
	 */
	shouldIsolate() {
		// We avoid isolating this to have better backward-compat
		return false;
	}
}

module.exports = CompatRuntimeModule;

license: mit


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");

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

class CreateFakeNamespaceObjectRuntimeModule extends HelperRuntimeModule {
	constructor() {
		super("create fake namespace object");
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate } = compilation;
		const fn = RuntimeGlobals.createFakeNamespaceObject;
		return Template.asString([
			`var getProto = Object.getPrototypeOf ? ${runtimeTemplate.returningFunction(
				"Object.getPrototypeOf(obj)",
				"obj"
			)} : ${runtimeTemplate.returningFunction("obj.__proto__", "obj")};`,
			"var leafPrototypes;",
			"// create a fake namespace object",
			"// mode & 1: value is a module id, require it",
			"// mode & 2: merge all properties of value into the ns",
			"// mode & 4: return value when already ns object",
			"// mode & 16: return value when it's Promise-like",
			"// mode & 8|1: behave like require",
			// Note: must be a function (not arrow), because this is used in body!
			`${fn} = function(value, mode) {`,
			Template.indent([
				`if(mode & 1) value = this(value);`,
				`if(mode & 8) return value;`,
				"if(typeof value === 'object' && value) {",
				Template.indent([
					"if((mode & 4) && value.__esModule) return value;",
					"if((mode & 16) && typeof value.then === 'function') return value;"
				]),
				"}",
				"var ns = Object.create(null);",
				`${RuntimeGlobals.makeNamespaceObject}(ns);`,
				"var def = {};",
				"leafPrototypes = leafPrototypes || [null, getProto({}), getProto([]), getProto(getProto)];",
				"for(var current = mode & 2 && value; typeof current == 'object' && !~leafPrototypes.indexOf(current); current = getProto(current)) {",
				Template.indent([
					`Object.getOwnPropertyNames(current).forEach(${runtimeTemplate.expressionFunction(
						`def[key] = ${runtimeTemplate.returningFunction("value[key]", "")}`,
						"key"
					)});`
				]),
				"}",
				`def['default'] = ${runtimeTemplate.returningFunction("value", "")};`,
				`${RuntimeGlobals.definePropertyGetters}(ns, def);`,
				"return ns;"
			]),
			"};"
		]);
	}
}

module.exports = CreateFakeNamespaceObjectRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");

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

class CreateScriptRuntimeModule extends HelperRuntimeModule {
	constructor() {
		super("trusted types script");
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate, outputOptions } = compilation;
		const { trustedTypes } = outputOptions;
		const fn = RuntimeGlobals.createScript;

		return Template.asString(
			`${fn} = ${runtimeTemplate.returningFunction(
				trustedTypes
					? `${RuntimeGlobals.getTrustedTypesPolicy}().createScript(script)`
					: "script",
				"script"
			)};`
		);
	}
}

module.exports = CreateScriptRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");

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

class CreateScriptUrlRuntimeModule extends HelperRuntimeModule {
	constructor() {
		super("trusted types script url");
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate, outputOptions } = compilation;
		const { trustedTypes } = outputOptions;
		const fn = RuntimeGlobals.createScriptUrl;

		return Template.asString(
			`${fn} = ${runtimeTemplate.returningFunction(
				trustedTypes
					? `${RuntimeGlobals.getTrustedTypesPolicy}().createScriptURL(url)`
					: "url",
				"url"
			)};`
		);
	}
}

module.exports = CreateScriptUrlRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");

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

class DefinePropertyGettersRuntimeModule extends HelperRuntimeModule {
	constructor() {
		super("define property getters");
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate } = compilation;
		const fn = RuntimeGlobals.definePropertyGetters;
		return Template.asString([
			"// define getter functions for harmony exports",
			`${fn} = ${runtimeTemplate.basicFunction("exports, definition", [
				`for(var key in definition) {`,
				Template.indent([
					`if(${RuntimeGlobals.hasOwnProperty}(definition, key) && !${RuntimeGlobals.hasOwnProperty}(exports, key)) {`,
					Template.indent([
						"Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });"
					]),
					"}"
				]),
				"}"
			])};`
		]);
	}
}

module.exports = DefinePropertyGettersRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");

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

class EnsureChunkRuntimeModule extends RuntimeModule {
	/**
	 * @param {ReadOnlyRuntimeRequirements} runtimeRequirements runtime requirements
	 */
	constructor(runtimeRequirements) {
		super("ensure chunk");
		this.runtimeRequirements = runtimeRequirements;
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate } = compilation;
		// Check if there are non initial chunks which need to be imported using require-ensure
		if (this.runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers)) {
			const withFetchPriority = this.runtimeRequirements.has(
				RuntimeGlobals.hasFetchPriority
			);
			const handlers = RuntimeGlobals.ensureChunkHandlers;
			return Template.asString([
				`${handlers} = {};`,
				"// This file contains only the entry chunk.",
				"// The chunk loading function for additional chunks",
				`${RuntimeGlobals.ensureChunk} = ${runtimeTemplate.basicFunction(
					`chunkId${withFetchPriority ? ", fetchPriority" : ""}`,
					[
						`return Promise.all(Object.keys(${handlers}).reduce(${runtimeTemplate.basicFunction(
							"promises, key",
							[
								`${handlers}[key](chunkId, promises${
									withFetchPriority ? ", fetchPriority" : ""
								});`,
								"return promises;"
							]
						)}, []));`
					]
				)};`
			]);
		} else {
			// There ensureChunk is used somewhere in the tree, so we need an empty requireEnsure
			// function. This can happen with multiple entrypoints.
			return Template.asString([
				"// The chunk loading function for additional chunks",
				"// Since all referenced chunks are already included",
				"// in this file, this function is empty here.",
				`${RuntimeGlobals.ensureChunk} = ${runtimeTemplate.returningFunction(
					"Promise.resolve()"
				)};`
			]);
		}
	}
}

module.exports = EnsureChunkRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");
const { first } = require("../util/SetHelpers");

/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Compilation").AssetInfo} AssetInfo */
/** @typedef {import("../Compilation").PathData} PathData */

/** @typedef {function(PathData, AssetInfo=): string} FilenameFunction */

class GetChunkFilenameRuntimeModule extends RuntimeModule {
	/**
	 * @param {string} contentType the contentType to use the content hash for
	 * @param {string} name kind of filename
	 * @param {string} global function name to be assigned
	 * @param {function(Chunk): string | FilenameFunction} getFilenameForChunk functor to get the filename or function
	 * @param {boolean} allChunks when false, only async chunks are included
	 */
	constructor(contentType, name, global, getFilenameForChunk, allChunks) {
		super(`get ${name} chunk filename`);
		this.contentType = contentType;
		this.global = global;
		this.getFilenameForChunk = getFilenameForChunk;
		this.allChunks = allChunks;
		this.dependentHash = true;
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const { global, contentType, getFilenameForChunk, allChunks } = this;
		const compilation = /** @type {Compilation} */ (this.compilation);
		const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
		const chunk = /** @type {Chunk} */ (this.chunk);
		const { runtimeTemplate } = compilation;

		/** @type {Map<string | FilenameFunction, Set<Chunk>>} */
		const chunkFilenames = new Map();
		let maxChunks = 0;
		/** @type {string | undefined} */
		let dynamicFilename;

		/**
		 * @param {Chunk} c the chunk
		 * @returns {void}
		 */
		const addChunk = c => {
			const chunkFilename = getFilenameForChunk(c);
			if (chunkFilename) {
				let set = chunkFilenames.get(chunkFilename);
				if (set === undefined) {
					chunkFilenames.set(chunkFilename, (set = new Set()));
				}
				set.add(c);
				if (typeof chunkFilename === "string") {
					if (set.size < maxChunks) return;
					if (set.size === maxChunks) {
						if (
							chunkFilename.length <
							/** @type {string} */ (dynamicFilename).length
						) {
							return;
						}

						if (
							chunkFilename.length ===
							/** @type {string} */ (dynamicFilename).length
						) {
							if (chunkFilename < /** @type {string} */ (dynamicFilename)) {
								return;
							}
						}
					}
					maxChunks = set.size;
					dynamicFilename = chunkFilename;
				}
			}
		};

		/** @type {string[]} */
		const includedChunksMessages = [];
		if (allChunks) {
			includedChunksMessages.push("all chunks");
			for (const c of chunk.getAllReferencedChunks()) {
				addChunk(c);
			}
		} else {
			includedChunksMessages.push("async chunks");
			for (const c of chunk.getAllAsyncChunks()) {
				addChunk(c);
			}
			const includeEntries = chunkGraph
				.getTreeRuntimeRequirements(chunk)
				.has(RuntimeGlobals.ensureChunkIncludeEntries);
			if (includeEntries) {
				includedChunksMessages.push("sibling chunks for the entrypoint");
				for (const c of chunkGraph.getChunkEntryDependentChunksIterable(
					chunk
				)) {
					addChunk(c);
				}
			}
		}
		for (const entrypoint of chunk.getAllReferencedAsyncEntrypoints()) {
			addChunk(entrypoint.chunks[entrypoint.chunks.length - 1]);
		}

		/** @type {Map<string, Set<string | number | null>>} */
		const staticUrls = new Map();
		/** @type {Set<Chunk>} */
		const dynamicUrlChunks = new Set();

		/**
		 * @param {Chunk} c the chunk
		 * @param {string | FilenameFunction} chunkFilename the filename template for the chunk
		 * @returns {void}
		 */
		const addStaticUrl = (c, chunkFilename) => {
			/**
			 * @param {string | number} value a value
			 * @returns {string} string to put in quotes
			 */
			const unquotedStringify = value => {
				const str = `${value}`;
				if (str.length >= 5 && str === `${c.id}`) {
					// This is shorter and generates the same result
					return '" + chunkId + "';
				}
				const s = JSON.stringify(str);
				return s.slice(1, s.length - 1);
			};
			/**
			 * @param {string} value string
			 * @returns {function(number): string} string to put in quotes with length
			 */
			const unquotedStringifyWithLength = value => length =>
				unquotedStringify(`${value}`.slice(0, length));
			const chunkFilenameValue =
				typeof chunkFilename === "function"
					? JSON.stringify(
							chunkFilename({
								chunk: c,
								contentHashType: contentType
							})
						)
					: JSON.stringify(chunkFilename);
			const staticChunkFilename = compilation.getPath(chunkFilenameValue, {
				hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
				hashWithLength: length =>
					`" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`,
				chunk: {
					id: unquotedStringify(/** @type {number | string} */ (c.id)),
					hash: unquotedStringify(/** @type {string} */ (c.renderedHash)),
					hashWithLength: unquotedStringifyWithLength(
						/** @type {string} */ (c.renderedHash)
					),
					name: unquotedStringify(
						c.name || /** @type {number | string} */ (c.id)
					),
					contentHash: {
						[contentType]: unquotedStringify(c.contentHash[contentType])
					},
					contentHashWithLength: {
						[contentType]: unquotedStringifyWithLength(
							c.contentHash[contentType]
						)
					}
				},
				contentHashType: contentType
			});
			let set = staticUrls.get(staticChunkFilename);
			if (set === undefined) {
				staticUrls.set(staticChunkFilename, (set = new Set()));
			}
			set.add(c.id);
		};

		for (const [filename, chunks] of chunkFilenames) {
			if (filename !== dynamicFilename) {
				for (const c of chunks) addStaticUrl(c, filename);
			} else {
				for (const c of chunks) dynamicUrlChunks.add(c);
			}
		}

		/**
		 * @param {function(Chunk): string | number} fn function from chunk to value
		 * @returns {string} code with static mapping of results of fn
		 */
		const createMap = fn => {
			/** @type {Record<number | string, number | string>} */
			const obj = {};
			let useId = false;
			/** @type {number | string | undefined} */
			let lastKey;
			let entries = 0;
			for (const c of dynamicUrlChunks) {
				const value = fn(c);
				if (value === c.id) {
					useId = true;
				} else {
					obj[/** @type {number | string} */ (c.id)] = value;
					lastKey = /** @type {number | string} */ (c.id);
					entries++;
				}
			}
			if (entries === 0) return "chunkId";
			if (entries === 1) {
				return useId
					? `(chunkId === ${JSON.stringify(lastKey)} ? ${JSON.stringify(
							obj[/** @type {number | string} */ (lastKey)]
						)} : chunkId)`
					: JSON.stringify(obj[/** @type {number | string} */ (lastKey)]);
			}
			return useId
				? `(${JSON.stringify(obj)}[chunkId] || chunkId)`
				: `${JSON.stringify(obj)}[chunkId]`;
		};

		/**
		 * @param {function(Chunk): string | number} fn function from chunk to value
		 * @returns {string} code with static mapping of results of fn for including in quoted string
		 */
		const mapExpr = fn => {
			return `" + ${createMap(fn)} + "`;
		};

		/**
		 * @param {function(Chunk): string | number} fn function from chunk to value
		 * @returns {function(number): string} function which generates code with static mapping of results of fn for including in quoted string for specific length
		 */
		const mapExprWithLength = fn => length => {
			return `" + ${createMap(c => `${fn(c)}`.slice(0, length))} + "`;
		};

		const url =
			dynamicFilename &&
			compilation.getPath(JSON.stringify(dynamicFilename), {
				hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
				hashWithLength: length =>
					`" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`,
				chunk: {
					id: `" + chunkId + "`,
					hash: mapExpr(c => /** @type {string} */ (c.renderedHash)),
					hashWithLength: mapExprWithLength(
						c => /** @type {string} */ (c.renderedHash)
					),
					name: mapExpr(c => c.name || /** @type {number | string} */ (c.id)),
					contentHash: {
						[contentType]: mapExpr(c => c.contentHash[contentType])
					},
					contentHashWithLength: {
						[contentType]: mapExprWithLength(c => c.contentHash[contentType])
					}
				},
				contentHashType: contentType
			});

		return Template.asString([
			`// This function allow to reference ${includedChunksMessages.join(
				" and "
			)}`,
			`${global} = ${runtimeTemplate.basicFunction(
				"chunkId",

				staticUrls.size > 0
					? [
							"// return url for filenames not based on template",
							// it minimizes to `x===1?"...":x===2?"...":"..."`
							Template.asString(
								Array.from(staticUrls, ([url, ids]) => {
									const condition =
										ids.size === 1
											? `chunkId === ${JSON.stringify(first(ids))}`
											: `{${Array.from(
													ids,
													id => `${JSON.stringify(id)}:1`
												).join(",")}}[chunkId]`;
									return `if (${condition}) return ${url};`;
								})
							),
							"// return url for filenames based on template",
							`return ${url};`
						]
					: ["// return url for filenames based on template", `return ${url};`]
			)};`
		]);
	}
}

module.exports = GetChunkFilenameRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");

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

class GetFullHashRuntimeModule extends RuntimeModule {
	constructor() {
		super("getFullHash");
		this.fullHash = true;
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate } = compilation;
		return `${RuntimeGlobals.getFullHash} = ${runtimeTemplate.returningFunction(
			JSON.stringify(compilation.hash || "XXXX")
		)}`;
	}
}

module.exports = GetFullHashRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");

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

class GetMainFilenameRuntimeModule extends RuntimeModule {
	/**
	 * @param {string} name readable name
	 * @param {string} global global object binding
	 * @param {string} filename main file name
	 */
	constructor(name, global, filename) {
		super(`get ${name} filename`);
		this.global = global;
		this.filename = filename;
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const { global, filename } = this;
		const compilation = /** @type {Compilation} */ (this.compilation);
		const chunk = /** @type {Chunk} */ (this.chunk);
		const { runtimeTemplate } = compilation;
		const url = compilation.getPath(JSON.stringify(filename), {
			hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
			hashWithLength: length =>
				`" + ${RuntimeGlobals.getFullHash}().slice(0, ${length}) + "`,
			chunk,
			runtime: chunk.runtime
		});
		return Template.asString([
			`${global} = ${runtimeTemplate.returningFunction(url)};`
		]);
	}
}

module.exports = GetMainFilenameRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");

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

class GetTrustedTypesPolicyRuntimeModule extends HelperRuntimeModule {
	/**
	 * @param {ReadOnlyRuntimeRequirements} runtimeRequirements runtime requirements
	 */
	constructor(runtimeRequirements) {
		super("trusted types policy");
		this.runtimeRequirements = runtimeRequirements;
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate, outputOptions } = compilation;
		const { trustedTypes } = outputOptions;
		const fn = RuntimeGlobals.getTrustedTypesPolicy;
		const wrapPolicyCreationInTryCatch = trustedTypes
			? trustedTypes.onPolicyCreationFailure === "continue"
			: false;

		return Template.asString([
			"var policy;",
			`${fn} = ${runtimeTemplate.basicFunction("", [
				"// Create Trusted Type policy if Trusted Types are available and the policy doesn't exist yet.",
				"if (policy === undefined) {",
				Template.indent([
					"policy = {",
					Template.indent(
						[
							...(this.runtimeRequirements.has(RuntimeGlobals.createScript)
								? [
										`createScript: ${runtimeTemplate.returningFunction(
											"script",
											"script"
										)}`
									]
								: []),
							...(this.runtimeRequirements.has(RuntimeGlobals.createScriptUrl)
								? [
										`createScriptURL: ${runtimeTemplate.returningFunction(
											"url",
											"url"
										)}`
									]
								: [])
						].join(",\n")
					),
					"};",
					...(trustedTypes
						? [
								'if (typeof trustedTypes !== "undefined" && trustedTypes.createPolicy) {',
								Template.indent([
									...(wrapPolicyCreationInTryCatch ? ["try {"] : []),
									...[
										`policy = trustedTypes.createPolicy(${JSON.stringify(
											trustedTypes.policyName
										)}, policy);`
									].map(line =>
										wrapPolicyCreationInTryCatch ? Template.indent(line) : line
									),
									...(wrapPolicyCreationInTryCatch
										? [
												"} catch (e) {",
												Template.indent([
													`console.warn('Could not create trusted-types policy ${JSON.stringify(
														trustedTypes.policyName
													)}');`
												]),
												"}"
											]
										: [])
								]),
								"}"
							]
						: [])
				]),
				"}",
				"return policy;"
			])};`
		]);
	}
}

module.exports = GetTrustedTypesPolicyRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");

class GlobalRuntimeModule extends RuntimeModule {
	constructor() {
		super("global");
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		return Template.asString([
			`${RuntimeGlobals.global} = (function() {`,
			Template.indent([
				"if (typeof globalThis === 'object') return globalThis;",
				"try {",
				Template.indent(
					// This works in non-strict mode
					// or
					// This works if eval is allowed (see CSP)
					"return this || new Function('return this')();"
				),
				"} catch (e) {",
				Template.indent(
					// This works if the window reference is available
					"if (typeof window === 'object') return window;"
				),
				"}"
				// It can still be `undefined`, but nothing to do about it...
				// We return `undefined`, instead of nothing here, so it's
				// easier to handle this case:
				//   if (!global) { … }
			]),
			"})();"
		]);
	}
}

module.exports = GlobalRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Sergey Melyukov @smelukov
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");

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

class HasOwnPropertyRuntimeModule extends RuntimeModule {
	constructor() {
		super("hasOwnProperty shorthand");
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate } = compilation;

		return Template.asString([
			`${RuntimeGlobals.hasOwnProperty} = ${runtimeTemplate.returningFunction(
				"Object.prototype.hasOwnProperty.call(obj, prop)",
				"obj, prop"
			)}`
		]);
	}
}

module.exports = HasOwnPropertyRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

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

class HelperRuntimeModule extends RuntimeModule {
	/**
	 * @param {string} name a readable name
	 */
	constructor(name) {
		super(name);
	}
}

module.exports = HelperRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const { SyncWaterfallHook } = require("tapable");
const Compilation = require("../Compilation");
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");

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

/**
 * @typedef {object} LoadScriptCompilationHooks
 * @property {SyncWaterfallHook<[string, Chunk]>} createScript
 */

/** @type {WeakMap<Compilation, LoadScriptCompilationHooks>} */
const compilationHooksMap = new WeakMap();

class LoadScriptRuntimeModule extends HelperRuntimeModule {
	/**
	 * @param {Compilation} compilation the compilation
	 * @returns {LoadScriptCompilationHooks} hooks
	 */
	static getCompilationHooks(compilation) {
		if (!(compilation instanceof Compilation)) {
			throw new TypeError(
				"The 'compilation' argument must be an instance of Compilation"
			);
		}
		let hooks = compilationHooksMap.get(compilation);
		if (hooks === undefined) {
			hooks = {
				createScript: new SyncWaterfallHook(["source", "chunk"])
			};
			compilationHooksMap.set(compilation, hooks);
		}
		return hooks;
	}

	/**
	 * @param {boolean=} withCreateScriptUrl use create script url for trusted types
	 * @param {boolean=} withFetchPriority use `fetchPriority` attribute
	 */
	constructor(withCreateScriptUrl, withFetchPriority) {
		super("load script");
		this._withCreateScriptUrl = withCreateScriptUrl;
		this._withFetchPriority = withFetchPriority;
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate, outputOptions } = compilation;
		const {
			scriptType,
			chunkLoadTimeout: loadTimeout,
			crossOriginLoading,
			uniqueName,
			charset
		} = outputOptions;
		const fn = RuntimeGlobals.loadScript;

		const { createScript } =
			LoadScriptRuntimeModule.getCompilationHooks(compilation);

		const code = Template.asString([
			"script = document.createElement('script');",
			scriptType ? `script.type = ${JSON.stringify(scriptType)};` : "",
			charset ? "script.charset = 'utf-8';" : "",
			`script.timeout = ${/** @type {number} */ (loadTimeout) / 1000};`,
			`if (${RuntimeGlobals.scriptNonce}) {`,
			Template.indent(
				`script.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});`
			),
			"}",
			uniqueName
				? 'script.setAttribute("data-webpack", dataWebpackPrefix + key);'
				: "",
			this._withFetchPriority
				? Template.asString([
						"if(fetchPriority) {",
						Template.indent(
							'script.setAttribute("fetchpriority", fetchPriority);'
						),
						"}"
					])
				: "",
			`script.src = ${
				this._withCreateScriptUrl
					? `${RuntimeGlobals.createScriptUrl}(url)`
					: "url"
			};`,
			crossOriginLoading
				? crossOriginLoading === "use-credentials"
					? 'script.crossOrigin = "use-credentials";'
					: Template.asString([
							"if (script.src.indexOf(window.location.origin + '/') !== 0) {",
							Template.indent(
								`script.crossOrigin = ${JSON.stringify(crossOriginLoading)};`
							),
							"}"
						])
				: ""
		]);

		return Template.asString([
			"var inProgress = {};",
			uniqueName
				? `var dataWebpackPrefix = ${JSON.stringify(uniqueName + ":")};`
				: "// data-webpack is not used as build has no uniqueName",
			"// loadScript function to load a script via script tag",
			`${fn} = ${runtimeTemplate.basicFunction(
				`url, done, key, chunkId${
					this._withFetchPriority ? ", fetchPriority" : ""
				}`,
				[
					"if(inProgress[url]) { inProgress[url].push(done); return; }",
					"var script, needAttach;",
					"if(key !== undefined) {",
					Template.indent([
						'var scripts = document.getElementsByTagName("script");',
						"for(var i = 0; i < scripts.length; i++) {",
						Template.indent([
							"var s = scripts[i];",
							`if(s.getAttribute("src") == url${
								uniqueName
									? ' || s.getAttribute("data-webpack") == dataWebpackPrefix + key'
									: ""
							}) { script = s; break; }`
						]),
						"}"
					]),
					"}",
					"if(!script) {",
					Template.indent([
						"needAttach = true;",
						createScript.call(code, /** @type {Chunk} */ (this.chunk))
					]),
					"}",
					"inProgress[url] = [done];",
					"var onScriptComplete = " +
						runtimeTemplate.basicFunction(
							"prev, event",
							Template.asString([
								"// avoid mem leaks in IE.",
								"script.onerror = script.onload = null;",
								"clearTimeout(timeout);",
								"var doneFns = inProgress[url];",
								"delete inProgress[url];",
								"script.parentNode && script.parentNode.removeChild(script);",
								`doneFns && doneFns.forEach(${runtimeTemplate.returningFunction(
									"fn(event)",
									"fn"
								)});`,
								"if(prev) return prev(event);"
							])
						),
					`var timeout = setTimeout(onScriptComplete.bind(null, undefined, { type: 'timeout', target: script }), ${loadTimeout});`,
					"script.onerror = onScriptComplete.bind(null, script.onerror);",
					"script.onload = onScriptComplete.bind(null, script.onload);",
					"needAttach && document.head.appendChild(script);"
				]
			)};`
		]);
	}
}

module.exports = LoadScriptRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");

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

class MakeNamespaceObjectRuntimeModule extends HelperRuntimeModule {
	constructor() {
		super("make namespace object");
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate } = compilation;
		const fn = RuntimeGlobals.makeNamespaceObject;
		return Template.asString([
			"// define __esModule on exports",
			`${fn} = ${runtimeTemplate.basicFunction("exports", [
				"if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {",
				Template.indent([
					"Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });"
				]),
				"}",
				"Object.defineProperty(exports, '__esModule', { value: true });"
			])};`
		]);
	}
}

module.exports = MakeNamespaceObjectRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
	Author Ivan Kopeykin @vankop
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");

class NonceRuntimeModule extends RuntimeModule {
	constructor() {
		super("nonce", RuntimeModule.STAGE_ATTACH);
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		return `${RuntimeGlobals.scriptNonce} = undefined;`;
	}
}

module.exports = NonceRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");

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

class OnChunksLoadedRuntimeModule extends RuntimeModule {
	constructor() {
		super("chunk loaded");
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate } = compilation;
		return Template.asString([
			"var deferred = [];",
			`${RuntimeGlobals.onChunksLoaded} = ${runtimeTemplate.basicFunction(
				"result, chunkIds, fn, priority",
				[
					"if(chunkIds) {",
					Template.indent([
						"priority = priority || 0;",
						"for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];",
						"deferred[i] = [chunkIds, fn, priority];",
						"return;"
					]),
					"}",
					"var notFulfilled = Infinity;",
					"for (var i = 0; i < deferred.length; i++) {",
					Template.indent([
						runtimeTemplate.destructureArray(
							["chunkIds", "fn", "priority"],
							"deferred[i]"
						),
						"var fulfilled = true;",
						"for (var j = 0; j < chunkIds.length; j++) {",
						Template.indent([
							`if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(${
								RuntimeGlobals.onChunksLoaded
							}).every(${runtimeTemplate.returningFunction(
								`${RuntimeGlobals.onChunksLoaded}[key](chunkIds[j])`,
								"key"
							)})) {`,
							Template.indent(["chunkIds.splice(j--, 1);"]),
							"} else {",
							Template.indent([
								"fulfilled = false;",
								"if(priority < notFulfilled) notFulfilled = priority;"
							]),
							"}"
						]),
						"}",
						"if(fulfilled) {",
						Template.indent([
							"deferred.splice(i--, 1)",
							"var r = fn();",
							"if (r !== undefined) result = r;"
						]),
						"}"
					]),
					"}",
					"return result;"
				]
			)};`
		]);
	}
}

module.exports = OnChunksLoadedRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");

/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} OutputOptions */
/** @typedef {import("../Compilation")} Compilation */

class PublicPathRuntimeModule extends RuntimeModule {
	/**
	 * @param {OutputOptions["publicPath"]} publicPath public path
	 */
	constructor(publicPath) {
		super("publicPath", RuntimeModule.STAGE_BASIC);
		this.publicPath = publicPath;
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const { publicPath } = this;
		const compilation = /** @type {Compilation} */ (this.compilation);

		return `${RuntimeGlobals.publicPath} = ${JSON.stringify(
			compilation.getPath(publicPath || "", {
				hash: compilation.hash || "XXXX"
			})
		)};`;
	}
}

module.exports = PublicPathRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const HelperRuntimeModule = require("./HelperRuntimeModule");

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

class RelativeUrlRuntimeModule extends HelperRuntimeModule {
	constructor() {
		super("relative url");
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate } = compilation;
		return Template.asString([
			`${RuntimeGlobals.relativeUrl} = function RelativeURL(url) {`,
			Template.indent([
				'var realUrl = new URL(url, "x:/");',
				"var values = {};",
				"for (var key in realUrl) values[key] = realUrl[key];",
				"values.href = url;",
				'values.pathname = url.replace(/[?#].*/, "");',
				'values.origin = values.protocol = "";',
				`values.toString = values.toJSON = ${runtimeTemplate.returningFunction(
					"url"
				)};`,
				"for (var key in values) Object.defineProperty(this, key, { enumerable: true, configurable: true, value: values[key] });"
			]),
			"};",
			`${RuntimeGlobals.relativeUrl}.prototype = URL.prototype;`
		]);
	}
}

module.exports = RelativeUrlRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");

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

class RuntimeIdRuntimeModule extends RuntimeModule {
	constructor() {
		super("runtimeId");
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
		const chunk = /** @type {Chunk} */ (this.chunk);
		const runtime = chunk.runtime;
		if (typeof runtime !== "string")
			throw new Error("RuntimeIdRuntimeModule must be in a single runtime");
		const id = chunkGraph.getRuntimeId(runtime);
		return `${RuntimeGlobals.runtimeId} = ${JSON.stringify(id)};`;
	}
}

module.exports = RuntimeIdRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const StartupChunkDependenciesRuntimeModule = require("./StartupChunkDependenciesRuntimeModule");
const StartupEntrypointRuntimeModule = require("./StartupEntrypointRuntimeModule");

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

/**
 * @typedef {object} Options
 * @property {ChunkLoadingType} chunkLoading
 * @property {boolean=} asyncChunkLoading
 */

class StartupChunkDependenciesPlugin {
	/**
	 * @param {Options} options options
	 */
	constructor(options) {
		this.chunkLoading = options.chunkLoading;
		this.asyncChunkLoading =
			typeof options.asyncChunkLoading === "boolean"
				? options.asyncChunkLoading
				: true;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.thisCompilation.tap(
			"StartupChunkDependenciesPlugin",
			compilation => {
				const globalChunkLoading = compilation.outputOptions.chunkLoading;
				/**
				 * @param {Chunk} chunk chunk to check
				 * @returns {boolean} true, when the plugin is enabled for the chunk
				 */
				const isEnabledForChunk = chunk => {
					const options = chunk.getEntryOptions();
					const chunkLoading =
						options && options.chunkLoading !== undefined
							? options.chunkLoading
							: globalChunkLoading;
					return chunkLoading === this.chunkLoading;
				};
				compilation.hooks.additionalTreeRuntimeRequirements.tap(
					"StartupChunkDependenciesPlugin",
					(chunk, set, { chunkGraph }) => {
						if (!isEnabledForChunk(chunk)) return;
						if (chunkGraph.hasChunkEntryDependentChunks(chunk)) {
							set.add(RuntimeGlobals.startup);
							set.add(RuntimeGlobals.ensureChunk);
							set.add(RuntimeGlobals.ensureChunkIncludeEntries);
							compilation.addRuntimeModule(
								chunk,
								new StartupChunkDependenciesRuntimeModule(
									this.asyncChunkLoading
								)
							);
						}
					}
				);
				compilation.hooks.runtimeRequirementInTree
					.for(RuntimeGlobals.startupEntrypoint)
					.tap("StartupChunkDependenciesPlugin", (chunk, set) => {
						if (!isEnabledForChunk(chunk)) return;
						set.add(RuntimeGlobals.require);
						set.add(RuntimeGlobals.ensureChunk);
						set.add(RuntimeGlobals.ensureChunkIncludeEntries);
						compilation.addRuntimeModule(
							chunk,
							new StartupEntrypointRuntimeModule(this.asyncChunkLoading)
						);
					});
			}
		);
	}
}

module.exports = StartupChunkDependenciesPlugin;


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

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");
const Template = require("../Template");

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

class StartupChunkDependenciesRuntimeModule extends RuntimeModule {
	/**
	 * @param {boolean} asyncChunkLoading use async chunk loading
	 */
	constructor(asyncChunkLoading) {
		super("startup chunk dependencies", RuntimeModule.STAGE_TRIGGER);
		this.asyncChunkLoading = asyncChunkLoading;
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
		const chunk = /** @type {Chunk} */ (this.chunk);
		const chunkIds = Array.from(
			chunkGraph.getChunkEntryDependentChunksIterable(chunk)
		).map(chunk => {
			return chunk.id;
		});
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate } = compilation;
		return Template.asString([
			`var next = ${RuntimeGlobals.startup};`,
			`${RuntimeGlobals.startup} = ${runtimeTemplate.basicFunction(
				"",
				!this.asyncChunkLoading
					? chunkIds
							.map(
								id => `${RuntimeGlobals.ensureChunk}(${JSON.stringify(id)});`
							)
							.concat("return next();")
					: chunkIds.length === 1
						? `return ${RuntimeGlobals.ensureChunk}(${JSON.stringify(
								chunkIds[0]
							)}).then(next);`
						: chunkIds.length > 2
							? [
									// using map is shorter for 3 or more chunks
									`return Promise.all(${JSON.stringify(chunkIds)}.map(${
										RuntimeGlobals.ensureChunk
									}, ${RuntimeGlobals.require})).then(next);`
								]
							: [
									// calling ensureChunk directly is shorter for 0 - 2 chunks
									"return Promise.all([",
									Template.indent(
										chunkIds
											.map(
												id =>
													`${RuntimeGlobals.ensureChunk}(${JSON.stringify(id)})`
											)
											.join(",\n")
									),
									"]).then(next);"
								]
			)};`
		]);
	}
}

module.exports = StartupChunkDependenciesRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");

/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../MainTemplate")} MainTemplate */

class StartupEntrypointRuntimeModule extends RuntimeModule {
	/**
	 * @param {boolean} asyncChunkLoading use async chunk loading
	 */
	constructor(asyncChunkLoading) {
		super("startup entrypoint");
		this.asyncChunkLoading = asyncChunkLoading;
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { runtimeTemplate } = compilation;
		return `${
			RuntimeGlobals.startupEntrypoint
		} = ${runtimeTemplate.basicFunction("result, chunkIds, fn", [
			"// arguments: chunkIds, moduleId are deprecated",
			"var moduleId = chunkIds;",
			`if(!fn) chunkIds = result, fn = ${runtimeTemplate.returningFunction(
				`${RuntimeGlobals.require}(${RuntimeGlobals.entryModuleId} = moduleId)`
			)};`,
			...(this.asyncChunkLoading
				? [
						`return Promise.all(chunkIds.map(${RuntimeGlobals.ensureChunk}, ${
							RuntimeGlobals.require
						})).then(${runtimeTemplate.basicFunction("", [
							"var r = fn();",
							"return r === undefined ? result : r;"
						])})`
					]
				: [
						`chunkIds.map(${RuntimeGlobals.ensureChunk}, ${RuntimeGlobals.require})`,
						"var r = fn();",
						"return r === undefined ? result : r;"
					])
		])}`;
	}
}

module.exports = StartupEntrypointRuntimeModule;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

const RuntimeGlobals = require("../RuntimeGlobals");
const RuntimeModule = require("../RuntimeModule");

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

class SystemContextRuntimeModule extends RuntimeModule {
	constructor() {
		super("__system_context__");
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		return `${RuntimeGlobals.systemContext} = __system_context__;`;
	}
}

module.exports = SystemContextRuntimeModule;


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

"use strict";

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

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

// data URL scheme: "data:text/javascript;charset=utf-8;base64,some-string"
// http://www.ietf.org/rfc/rfc2397.txt
const URIRegEx = /^data:([^;,]+)?((?:;[^;,]+)*?)(?:;(base64))?,(.*)$/i;

/**
 * @param {string} uri data URI
 * @returns {Buffer|null} decoded data
 */
const decodeDataURI = uri => {
	const match = URIRegEx.exec(uri);
	if (!match) return null;

	const isBase64 = match[3];
	const body = match[4];

	if (isBase64) {
		return Buffer.from(body, "base64");
	}

	// CSS allows to use `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" style="stroke: rgb(223,224,225); stroke-width: 2px; fill: none; stroke-dasharray: 6px 3px" /></svg>`
	// so we return original body if we can't `decodeURIComponent`
	try {
		return Buffer.from(decodeURIComponent(body), "ascii");
	} catch (_) {
		return Buffer.from(body, "ascii");
	}
};

class DataUriPlugin {
	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.compilation.tap(
			"DataUriPlugin",
			(compilation, { normalModuleFactory }) => {
				normalModuleFactory.hooks.resolveForScheme
					.for("data")
					.tap("DataUriPlugin", resourceData => {
						const match = URIRegEx.exec(resourceData.resource);
						if (match) {
							resourceData.data.mimetype = match[1] || "";
							resourceData.data.parameters = match[2] || "";
							resourceData.data.encoding = match[3] || false;
							resourceData.data.encodedContent = match[4] || "";
						}
					});
				NormalModule.getCompilationHooks(compilation)
					.readResourceForScheme.for("data")
					.tap("DataUriPlugin", resource => decodeDataURI(resource));
			}
		);
	}
}

module.exports = DataUriPlugin;


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

"use strict";

const { URL, fileURLToPath } = require("url");
const { NormalModule } = require("..");

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

class FileUriPlugin {
	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.compilation.tap(
			"FileUriPlugin",
			(compilation, { normalModuleFactory }) => {
				normalModuleFactory.hooks.resolveForScheme
					.for("file")
					.tap("FileUriPlugin", resourceData => {
						const url = new URL(resourceData.resource);
						const path = fileURLToPath(url);
						const query = url.search;
						const fragment = url.hash;
						resourceData.path = path;
						resourceData.query = query;
						resourceData.fragment = fragment;
						resourceData.resource = path + query + fragment;
						return true;
					});
				const hooks = NormalModule.getCompilationHooks(compilation);
				hooks.readResource
					.for(undefined)
					.tapAsync("FileUriPlugin", (loaderContext, callback) => {
						const { resourcePath } = loaderContext;
						loaderContext.addDependency(resourcePath);
						loaderContext.fs.readFile(resourcePath, callback);
					});
			}
		);
	}
}

module.exports = FileUriPlugin;


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

"use strict";

const EventEmitter = require("events");
const { extname, basename } = require("path");
const { URL } = require("url");
const { createGunzip, createBrotliDecompress, createInflate } = require("zlib");
const NormalModule = require("../NormalModule");
const createSchemaValidation = require("../util/create-schema-validation");
const createHash = require("../util/createHash");
const { mkdirp, dirname, join } = require("../util/fs");
const memoize = require("../util/memoize");

/** @typedef {import("../../declarations/plugins/schemes/HttpUriPlugin").HttpUriPluginOptions} HttpUriPluginOptions */
/** @typedef {import("../Compiler")} Compiler */

const getHttp = memoize(() => require("http"));
const getHttps = memoize(() => require("https"));
const proxyFetch = (request, proxy) => (url, options, callback) => {
	const eventEmitter = new EventEmitter();
	const doRequest = socket =>
		request
			.get(url, { ...options, ...(socket && { socket }) }, callback)
			.on("error", eventEmitter.emit.bind(eventEmitter, "error"));

	if (proxy) {
		const { hostname: host, port } = new URL(proxy);

		getHttp()
			.request({
				host, // IP address of proxy server
				port, // port of proxy server
				method: "CONNECT",
				path: url.host
			})
			.on("connect", (res, socket) => {
				if (res.statusCode === 200) {
					// connected to proxy server
					doRequest(socket);
				}
			})
			.on("error", err => {
				eventEmitter.emit(
					"error",
					new Error(
						`Failed to connect to proxy server "${proxy}": ${err.message}`
					)
				);
			})
			.end();
	} else {
		doRequest();
	}

	return eventEmitter;
};

/** @type {(() => void)[] | undefined} */
let inProgressWrite = undefined;

const validate = createSchemaValidation(
	require("../../schemas/plugins/schemes/HttpUriPlugin.check.js"),
	() => require("../../schemas/plugins/schemes/HttpUriPlugin.json"),
	{
		name: "Http Uri Plugin",
		baseDataPath: "options"
	}
);

/**
 * @param {string} str path
 * @returns {string} safe path
 */
const toSafePath = str =>
	str
		.replace(/^[^a-zA-Z0-9]+|[^a-zA-Z0-9]+$/g, "")
		.replace(/[^a-zA-Z0-9._-]+/g, "_");

/**
 * @param {Buffer} content content
 * @returns {string} integrity
 */
const computeIntegrity = content => {
	const hash = createHash("sha512");
	hash.update(content);
	const integrity = "sha512-" + hash.digest("base64");
	return integrity;
};

/**
 * @param {Buffer} content content
 * @param {string} integrity integrity
 * @returns {boolean} true, if integrity matches
 */
const verifyIntegrity = (content, integrity) => {
	if (integrity === "ignore") return true;
	return computeIntegrity(content) === integrity;
};

/**
 * @param {string} str input
 * @returns {Record<string, string>} parsed
 */
const parseKeyValuePairs = str => {
	/** @type {Record<string, string>} */
	const result = {};
	for (const item of str.split(",")) {
		const i = item.indexOf("=");
		if (i >= 0) {
			const key = item.slice(0, i).trim();
			const value = item.slice(i + 1).trim();
			result[key] = value;
		} else {
			const key = item.trim();
			if (!key) continue;
			result[key] = key;
		}
	}
	return result;
};

/**
 * @param {string | undefined} cacheControl Cache-Control header
 * @param {number} requestTime timestamp of request
 * @returns {{storeCache: boolean, storeLock: boolean, validUntil: number}} Logic for storing in cache and lockfile cache
 */
const parseCacheControl = (cacheControl, requestTime) => {
	// When false resource is not stored in cache
	let storeCache = true;
	// When false resource is not stored in lockfile cache
	let storeLock = true;
	// Resource is only revalidated, after that timestamp and when upgrade is chosen
	let validUntil = 0;
	if (cacheControl) {
		const parsed = parseKeyValuePairs(cacheControl);
		if (parsed["no-cache"]) storeCache = storeLock = false;
		if (parsed["max-age"] && !isNaN(+parsed["max-age"])) {
			validUntil = requestTime + +parsed["max-age"] * 1000;
		}
		if (parsed["must-revalidate"]) validUntil = 0;
	}
	return {
		storeLock,
		storeCache,
		validUntil
	};
};

/**
 * @typedef {object} LockfileEntry
 * @property {string} resolved
 * @property {string} integrity
 * @property {string} contentType
 */

const areLockfileEntriesEqual = (a, b) => {
	return (
		a.resolved === b.resolved &&
		a.integrity === b.integrity &&
		a.contentType === b.contentType
	);
};

/**
 * @param {LockfileEntry} entry lockfile entry
 * @returns {`resolved: ${string}, integrity: ${string}, contentType: ${*}`} stringified entry
 */
const entryToString = entry => {
	return `resolved: ${entry.resolved}, integrity: ${entry.integrity}, contentType: ${entry.contentType}`;
};

class Lockfile {
	constructor() {
		this.version = 1;
		/** @type {Map<string, LockfileEntry | "ignore" | "no-cache">} */
		this.entries = new Map();
	}

	/**
	 * @param {string} content content of the lockfile
	 * @returns {Lockfile} lockfile
	 */
	static parse(content) {
		// TODO handle merge conflicts
		const data = JSON.parse(content);
		if (data.version !== 1)
			throw new Error(`Unsupported lockfile version ${data.version}`);
		const lockfile = new Lockfile();
		for (const key of Object.keys(data)) {
			if (key === "version") continue;
			const entry = data[key];
			lockfile.entries.set(
				key,
				typeof entry === "string"
					? entry
					: {
							resolved: key,
							...entry
						}
			);
		}
		return lockfile;
	}

	/**
	 * @returns {string} stringified lockfile
	 */
	toString() {
		let str = "{\n";
		const entries = Array.from(this.entries).sort(([a], [b]) =>
			a < b ? -1 : 1
		);
		for (const [key, entry] of entries) {
			if (typeof entry === "string") {
				str += `  ${JSON.stringify(key)}: ${JSON.stringify(entry)},\n`;
			} else {
				str += `  ${JSON.stringify(key)}: { `;
				if (entry.resolved !== key)
					str += `"resolved": ${JSON.stringify(entry.resolved)}, `;
				str += `"integrity": ${JSON.stringify(
					entry.integrity
				)}, "contentType": ${JSON.stringify(entry.contentType)} },\n`;
			}
		}
		str += `  "version": ${this.version}\n}\n`;
		return str;
	}
}

/**
 * @template R
 * @param {function(function(Error=, R=): void): void} fn function
 * @returns {function(function((Error | null)=, R=): void): void} cached function
 */
const cachedWithoutKey = fn => {
	let inFlight = false;
	/** @type {Error | undefined} */
	let cachedError = undefined;
	/** @type {R | undefined} */
	let cachedResult = undefined;
	/** @type {(function(Error=, R=): void)[] | undefined} */
	let cachedCallbacks = undefined;
	return callback => {
		if (inFlight) {
			if (cachedResult !== undefined) return callback(null, cachedResult);
			if (cachedError !== undefined) return callback(cachedError);
			if (cachedCallbacks === undefined) cachedCallbacks = [callback];
			else cachedCallbacks.push(callback);
			return;
		}
		inFlight = true;
		fn((err, result) => {
			if (err) cachedError = err;
			else cachedResult = result;
			const callbacks = cachedCallbacks;
			cachedCallbacks = undefined;
			callback(err, result);
			if (callbacks !== undefined) for (const cb of callbacks) cb(err, result);
		});
	};
};

/**
 * @template T
 * @template R
 * @param {function(T, function(Error=, R=): void): void} fn function
 * @param {function(T, function(Error=, R=): void): void=} forceFn function for the second try
 * @returns {(function(T, function((Error | null)=, R=): void): void) & { force: function(T, function((Error | null)=, R=): void): void }} cached function
 */
const cachedWithKey = (fn, forceFn = fn) => {
	/** @typedef {{ result?: R, error?: Error, callbacks?: (function((Error | null)=, R=): void)[], force?: true }} CacheEntry */
	/** @type {Map<T, CacheEntry>} */
	const cache = new Map();
	const resultFn = (arg, callback) => {
		const cacheEntry = cache.get(arg);
		if (cacheEntry !== undefined) {
			if (cacheEntry.result !== undefined)
				return callback(null, cacheEntry.result);
			if (cacheEntry.error !== undefined) return callback(cacheEntry.error);
			if (cacheEntry.callbacks === undefined) cacheEntry.callbacks = [callback];
			else cacheEntry.callbacks.push(callback);
			return;
		}
		/** @type {CacheEntry} */
		const newCacheEntry = {
			result: undefined,
			error: undefined,
			callbacks: undefined
		};
		cache.set(arg, newCacheEntry);
		fn(arg, (err, result) => {
			if (err) newCacheEntry.error = err;
			else newCacheEntry.result = result;
			const callbacks = newCacheEntry.callbacks;
			newCacheEntry.callbacks = undefined;
			callback(err, result);
			if (callbacks !== undefined) for (const cb of callbacks) cb(err, result);
		});
	};
	resultFn.force = (arg, callback) => {
		const cacheEntry = cache.get(arg);
		if (cacheEntry !== undefined && cacheEntry.force) {
			if (cacheEntry.result !== undefined)
				return callback(null, cacheEntry.result);
			if (cacheEntry.error !== undefined) return callback(cacheEntry.error);
			if (cacheEntry.callbacks === undefined) cacheEntry.callbacks = [callback];
			else cacheEntry.callbacks.push(callback);
			return;
		}
		/** @type {CacheEntry} */
		const newCacheEntry = {
			result: undefined,
			error: undefined,
			callbacks: undefined,
			force: true
		};
		cache.set(arg, newCacheEntry);
		forceFn(arg, (err, result) => {
			if (err) newCacheEntry.error = err;
			else newCacheEntry.result = result;
			const callbacks = newCacheEntry.callbacks;
			newCacheEntry.callbacks = undefined;
			callback(err, result);
			if (callbacks !== undefined) for (const cb of callbacks) cb(err, result);
		});
	};
	return resultFn;
};

class HttpUriPlugin {
	/**
	 * @param {HttpUriPluginOptions} options options
	 */
	constructor(options) {
		validate(options);
		this._lockfileLocation = options.lockfileLocation;
		this._cacheLocation = options.cacheLocation;
		this._upgrade = options.upgrade;
		this._frozen = options.frozen;
		this._allowedUris = options.allowedUris;
		this._proxy = options.proxy;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		const proxy =
			this._proxy || process.env["http_proxy"] || process.env["HTTP_PROXY"];
		const schemes = [
			{
				scheme: "http",
				fetch: proxyFetch(getHttp(), proxy)
			},
			{
				scheme: "https",
				fetch: proxyFetch(getHttps(), proxy)
			}
		];
		let lockfileCache;
		compiler.hooks.compilation.tap(
			"HttpUriPlugin",
			(compilation, { normalModuleFactory }) => {
				const intermediateFs = compiler.intermediateFileSystem;
				const fs = compilation.inputFileSystem;
				const cache = compilation.getCache("webpack.HttpUriPlugin");
				const logger = compilation.getLogger("webpack.HttpUriPlugin");
				/** @type {string} */
				const lockfileLocation =
					this._lockfileLocation ||
					join(
						intermediateFs,
						compiler.context,
						compiler.name
							? `${toSafePath(compiler.name)}.webpack.lock`
							: "webpack.lock"
					);
				/** @type {string | false} */
				const cacheLocation =
					this._cacheLocation !== undefined
						? this._cacheLocation
						: lockfileLocation + ".data";
				const upgrade = this._upgrade || false;
				const frozen = this._frozen || false;
				const hashFunction = "sha512";
				const hashDigest = "hex";
				const hashDigestLength = 20;
				const allowedUris = this._allowedUris;

				let warnedAboutEol = false;

				/** @type {Map<string, string>} */
				const cacheKeyCache = new Map();
				/**
				 * @param {string} url the url
				 * @returns {string} the key
				 */
				const getCacheKey = url => {
					const cachedResult = cacheKeyCache.get(url);
					if (cachedResult !== undefined) return cachedResult;
					const result = _getCacheKey(url);
					cacheKeyCache.set(url, result);
					return result;
				};

				/**
				 * @param {string} url the url
				 * @returns {string} the key
				 */
				const _getCacheKey = url => {
					const parsedUrl = new URL(url);
					const folder = toSafePath(parsedUrl.origin);
					const name = toSafePath(parsedUrl.pathname);
					const query = toSafePath(parsedUrl.search);
					let ext = extname(name);
					if (ext.length > 20) ext = "";
					const basename = ext ? name.slice(0, -ext.length) : name;
					const hash = createHash(hashFunction);
					hash.update(url);
					const digest = hash.digest(hashDigest).slice(0, hashDigestLength);
					return `${folder.slice(-50)}/${`${basename}${
						query ? `_${query}` : ""
					}`.slice(0, 150)}_${digest}${ext}`;
				};

				const getLockfile = cachedWithoutKey(
					/**
					 * @param {function((Error | null)=, Lockfile=): void} callback callback
					 * @returns {void}
					 */
					callback => {
						const readLockfile = () => {
							intermediateFs.readFile(lockfileLocation, (err, buffer) => {
								if (err && err.code !== "ENOENT") {
									compilation.missingDependencies.add(lockfileLocation);
									return callback(err);
								}
								compilation.fileDependencies.add(lockfileLocation);
								compilation.fileSystemInfo.createSnapshot(
									compiler.fsStartTime,
									buffer ? [lockfileLocation] : [],
									[],
									buffer ? [] : [lockfileLocation],
									{ timestamp: true },
									(err, snapshot) => {
										if (err) return callback(err);
										const lockfile = buffer
											? Lockfile.parse(buffer.toString("utf-8"))
											: new Lockfile();
										lockfileCache = {
											lockfile,
											snapshot
										};
										callback(null, lockfile);
									}
								);
							});
						};
						if (lockfileCache) {
							compilation.fileSystemInfo.checkSnapshotValid(
								lockfileCache.snapshot,
								(err, valid) => {
									if (err) return callback(err);
									if (!valid) return readLockfile();
									callback(null, lockfileCache.lockfile);
								}
							);
						} else {
							readLockfile();
						}
					}
				);

				/** @type {Map<string, LockfileEntry | "ignore" | "no-cache"> | undefined} */
				let lockfileUpdates = undefined;

				/**
				 * @param {Lockfile} lockfile lockfile instance
				 * @param {string} url url to store
				 * @param {LockfileEntry | "ignore" | "no-cache"} entry lockfile entry
				 */
				const storeLockEntry = (lockfile, url, entry) => {
					const oldEntry = lockfile.entries.get(url);
					if (lockfileUpdates === undefined) lockfileUpdates = new Map();
					lockfileUpdates.set(url, entry);
					lockfile.entries.set(url, entry);
					if (!oldEntry) {
						logger.log(`${url} added to lockfile`);
					} else if (typeof oldEntry === "string") {
						if (typeof entry === "string") {
							logger.log(`${url} updated in lockfile: ${oldEntry} -> ${entry}`);
						} else {
							logger.log(
								`${url} updated in lockfile: ${oldEntry} -> ${entry.resolved}`
							);
						}
					} else if (typeof entry === "string") {
						logger.log(
							`${url} updated in lockfile: ${oldEntry.resolved} -> ${entry}`
						);
					} else if (oldEntry.resolved !== entry.resolved) {
						logger.log(
							`${url} updated in lockfile: ${oldEntry.resolved} -> ${entry.resolved}`
						);
					} else if (oldEntry.integrity !== entry.integrity) {
						logger.log(`${url} updated in lockfile: content changed`);
					} else if (oldEntry.contentType !== entry.contentType) {
						logger.log(
							`${url} updated in lockfile: ${oldEntry.contentType} -> ${entry.contentType}`
						);
					} else {
						logger.log(`${url} updated in lockfile`);
					}
				};

				const storeResult = (lockfile, url, result, callback) => {
					if (result.storeLock) {
						storeLockEntry(lockfile, url, result.entry);
						if (!cacheLocation || !result.content)
							return callback(null, result);
						const key = getCacheKey(result.entry.resolved);
						const filePath = join(intermediateFs, cacheLocation, key);
						mkdirp(intermediateFs, dirname(intermediateFs, filePath), err => {
							if (err) return callback(err);
							intermediateFs.writeFile(filePath, result.content, err => {
								if (err) return callback(err);
								callback(null, result);
							});
						});
					} else {
						storeLockEntry(lockfile, url, "no-cache");
						callback(null, result);
					}
				};

				for (const { scheme, fetch } of schemes) {
					/**
					 *
					 * @param {string} url URL
					 * @param {string} integrity integrity
					 * @param {function((Error | null)=, { entry: LockfileEntry, content: Buffer, storeLock: boolean }=): void} callback callback
					 */
					const resolveContent = (url, integrity, callback) => {
						const handleResult = (err, result) => {
							if (err) return callback(err);
							if ("location" in result) {
								return resolveContent(
									result.location,
									integrity,
									(err, innerResult) => {
										if (err) return callback(err);
										callback(null, {
											entry: innerResult.entry,
											content: innerResult.content,
											storeLock: innerResult.storeLock && result.storeLock
										});
									}
								);
							} else {
								if (
									!result.fresh &&
									integrity &&
									result.entry.integrity !== integrity &&
									!verifyIntegrity(result.content, integrity)
								) {
									return fetchContent.force(url, handleResult);
								}
								return callback(null, {
									entry: result.entry,
									content: result.content,
									storeLock: result.storeLock
								});
							}
						};
						fetchContent(url, handleResult);
					};

					/** @typedef {{ storeCache: boolean, storeLock: boolean, validUntil: number, etag: string | undefined, fresh: boolean }} FetchResultMeta */
					/** @typedef {FetchResultMeta & { location: string }} RedirectFetchResult */
					/** @typedef {FetchResultMeta & { entry: LockfileEntry, content: Buffer }} ContentFetchResult */
					/** @typedef {RedirectFetchResult | ContentFetchResult} FetchResult */

					/**
					 * @param {string} url URL
					 * @param {FetchResult | RedirectFetchResult} cachedResult result from cache
					 * @param {function((Error | null)=, FetchResult=): void} callback callback
					 * @returns {void}
					 */
					const fetchContentRaw = (url, cachedResult, callback) => {
						const requestTime = Date.now();
						fetch(
							new URL(url),
							{
								headers: {
									"accept-encoding": "gzip, deflate, br",
									"user-agent": "webpack",
									"if-none-match": cachedResult
										? cachedResult.etag || null
										: null
								}
							},
							res => {
								const etag = res.headers["etag"];
								const location = res.headers["location"];
								const cacheControl = res.headers["cache-control"];
								const { storeLock, storeCache, validUntil } = parseCacheControl(
									cacheControl,
									requestTime
								);
								/**
								 * @param {Partial<Pick<FetchResultMeta, "fresh">> & (Pick<RedirectFetchResult, "location"> | Pick<ContentFetchResult, "content" | "entry">)} partialResult result
								 * @returns {void}
								 */
								const finishWith = partialResult => {
									if ("location" in partialResult) {
										logger.debug(
											`GET ${url} [${res.statusCode}] -> ${partialResult.location}`
										);
									} else {
										logger.debug(
											`GET ${url} [${res.statusCode}] ${Math.ceil(
												partialResult.content.length / 1024
											)} kB${!storeLock ? " no-cache" : ""}`
										);
									}
									const result = {
										...partialResult,
										fresh: true,
										storeLock,
										storeCache,
										validUntil,
										etag
									};
									if (!storeCache) {
										logger.log(
											`${url} can't be stored in cache, due to Cache-Control header: ${cacheControl}`
										);
										return callback(null, result);
									}
									cache.store(
										url,
										null,
										{
											...result,
											fresh: false
										},
										err => {
											if (err) {
												logger.warn(
													`${url} can't be stored in cache: ${err.message}`
												);
												logger.debug(err.stack);
											}
											callback(null, result);
										}
									);
								};
								if (res.statusCode === 304) {
									if (
										cachedResult.validUntil < validUntil ||
										cachedResult.storeLock !== storeLock ||
										cachedResult.storeCache !== storeCache ||
										cachedResult.etag !== etag
									) {
										return finishWith(cachedResult);
									} else {
										logger.debug(`GET ${url} [${res.statusCode}] (unchanged)`);
										return callback(null, {
											...cachedResult,
											fresh: true
										});
									}
								}
								if (
									location &&
									res.statusCode >= 301 &&
									res.statusCode <= 308
								) {
									const result = {
										location: new URL(location, url).href
									};
									if (
										!cachedResult ||
										!("location" in cachedResult) ||
										cachedResult.location !== result.location ||
										cachedResult.validUntil < validUntil ||
										cachedResult.storeLock !== storeLock ||
										cachedResult.storeCache !== storeCache ||
										cachedResult.etag !== etag
									) {
										return finishWith(result);
									} else {
										logger.debug(`GET ${url} [${res.statusCode}] (unchanged)`);
										return callback(null, {
											...result,
											fresh: true,
											storeLock,
											storeCache,
											validUntil,
											etag
										});
									}
								}
								const contentType = res.headers["content-type"] || "";
								const bufferArr = [];

								const contentEncoding = res.headers["content-encoding"];
								let stream = res;
								if (contentEncoding === "gzip") {
									stream = stream.pipe(createGunzip());
								} else if (contentEncoding === "br") {
									stream = stream.pipe(createBrotliDecompress());
								} else if (contentEncoding === "deflate") {
									stream = stream.pipe(createInflate());
								}

								stream.on("data", chunk => {
									bufferArr.push(chunk);
								});

								stream.on("end", () => {
									if (!res.complete) {
										logger.log(`GET ${url} [${res.statusCode}] (terminated)`);
										return callback(new Error(`${url} request was terminated`));
									}

									const content = Buffer.concat(bufferArr);

									if (res.statusCode !== 200) {
										logger.log(`GET ${url} [${res.statusCode}]`);
										return callback(
											new Error(
												`${url} request status code = ${
													res.statusCode
												}\n${content.toString("utf-8")}`
											)
										);
									}

									const integrity = computeIntegrity(content);
									const entry = { resolved: url, integrity, contentType };

									finishWith({
										entry,
										content
									});
								});
							}
						).on("error", err => {
							logger.log(`GET ${url} (error)`);
							err.message += `\nwhile fetching ${url}`;
							callback(err);
						});
					};

					const fetchContent = cachedWithKey(
						/**
						 * @param {string} url URL
						 * @param {function((Error | null)=, { validUntil: number, etag?: string, entry: LockfileEntry, content: Buffer, fresh: boolean } | { validUntil: number, etag?: string, location: string, fresh: boolean }=): void} callback callback
						 * @returns {void}
						 */ (url, callback) => {
							cache.get(url, null, (err, cachedResult) => {
								if (err) return callback(err);
								if (cachedResult) {
									const isValid = cachedResult.validUntil >= Date.now();
									if (isValid) return callback(null, cachedResult);
								}
								fetchContentRaw(url, cachedResult, callback);
							});
						},
						(url, callback) => fetchContentRaw(url, undefined, callback)
					);

					const isAllowed = uri => {
						for (const allowed of allowedUris) {
							if (typeof allowed === "string") {
								if (uri.startsWith(allowed)) return true;
							} else if (typeof allowed === "function") {
								if (allowed(uri)) return true;
							} else {
								if (allowed.test(uri)) return true;
							}
						}
						return false;
					};

					const getInfo = cachedWithKey(
						/**
						 * @param {string} url the url
						 * @param {function((Error | null)=, { entry: LockfileEntry, content: Buffer }=): void} callback callback
						 * @returns {void}
						 */
						(url, callback) => {
							if (!isAllowed(url)) {
								return callback(
									new Error(
										`${url} doesn't match the allowedUris policy. These URIs are allowed:\n${allowedUris
											.map(uri => ` - ${uri}`)
											.join("\n")}`
									)
								);
							}
							getLockfile((err, lockfile) => {
								if (err) return callback(err);
								const entryOrString = lockfile.entries.get(url);
								if (!entryOrString) {
									if (frozen) {
										return callback(
											new Error(
												`${url} has no lockfile entry and lockfile is frozen`
											)
										);
									}
									resolveContent(url, null, (err, result) => {
										if (err) return callback(err);
										storeResult(lockfile, url, result, callback);
									});
									return;
								}
								if (typeof entryOrString === "string") {
									const entryTag = entryOrString;
									resolveContent(url, null, (err, result) => {
										if (err) return callback(err);
										if (!result.storeLock || entryTag === "ignore")
											return callback(null, result);
										if (frozen) {
											return callback(
												new Error(
													`${url} used to have ${entryTag} lockfile entry and has content now, but lockfile is frozen`
												)
											);
										}
										if (!upgrade) {
											return callback(
												new Error(
													`${url} used to have ${entryTag} lockfile entry and has content now.
This should be reflected in the lockfile, so this lockfile entry must be upgraded, but upgrading is not enabled.
Remove this line from the lockfile to force upgrading.`
												)
											);
										}
										storeResult(lockfile, url, result, callback);
									});
									return;
								}
								let entry = entryOrString;
								const doFetch = lockedContent => {
									resolveContent(url, entry.integrity, (err, result) => {
										if (err) {
											if (lockedContent) {
												logger.warn(
													`Upgrade request to ${url} failed: ${err.message}`
												);
												logger.debug(err.stack);
												return callback(null, {
													entry,
													content: lockedContent
												});
											}
											return callback(err);
										}
										if (!result.storeLock) {
											// When the lockfile entry should be no-cache
											// we need to update the lockfile
											if (frozen) {
												return callback(
													new Error(
														`${url} has a lockfile entry and is no-cache now, but lockfile is frozen\nLockfile: ${entryToString(
															entry
														)}`
													)
												);
											}
											storeResult(lockfile, url, result, callback);
											return;
										}
										if (!areLockfileEntriesEqual(result.entry, entry)) {
											// When the lockfile entry is outdated
											// we need to update the lockfile
											if (frozen) {
												return callback(
													new Error(
														`${url} has an outdated lockfile entry, but lockfile is frozen\nLockfile: ${entryToString(
															entry
														)}\nExpected: ${entryToString(result.entry)}`
													)
												);
											}
											storeResult(lockfile, url, result, callback);
											return;
										}
										if (!lockedContent && cacheLocation) {
											// When the lockfile cache content is missing
											// we need to update the lockfile
											if (frozen) {
												return callback(
													new Error(
														`${url} is missing content in the lockfile cache, but lockfile is frozen\nLockfile: ${entryToString(
															entry
														)}`
													)
												);
											}
											storeResult(lockfile, url, result, callback);
											return;
										}
										return callback(null, result);
									});
								};
								if (cacheLocation) {
									// When there is a lockfile cache
									// we read the content from there
									const key = getCacheKey(entry.resolved);
									const filePath = join(intermediateFs, cacheLocation, key);
									fs.readFile(filePath, (err, result) => {
										const content = /** @type {Buffer} */ (result);
										if (err) {
											if (err.code === "ENOENT") return doFetch();
											return callback(err);
										}
										const continueWithCachedContent = result => {
											if (!upgrade) {
												// When not in upgrade mode, we accept the result from the lockfile cache
												return callback(null, { entry, content });
											}
											return doFetch(content);
										};
										if (!verifyIntegrity(content, entry.integrity)) {
											let contentWithChangedEol;
											let isEolChanged = false;
											try {
												contentWithChangedEol = Buffer.from(
													content.toString("utf-8").replace(/\r\n/g, "\n")
												);
												isEolChanged = verifyIntegrity(
													contentWithChangedEol,
													entry.integrity
												);
											} catch (e) {
												// ignore
											}
											if (isEolChanged) {
												if (!warnedAboutEol) {
													const explainer = `Incorrect end of line sequence was detected in the lockfile cache.
The lockfile cache is protected by integrity checks, so any external modification will lead to a corrupted lockfile cache.
When using git make sure to configure .gitattributes correctly for the lockfile cache:
  **/*webpack.lock.data/** -text
This will avoid that the end of line sequence is changed by git on Windows.`;
													if (frozen) {
														logger.error(explainer);
													} else {
														logger.warn(explainer);
														logger.info(
															"Lockfile cache will be automatically fixed now, but when lockfile is frozen this would result in an error."
														);
													}
													warnedAboutEol = true;
												}
												if (!frozen) {
													// "fix" the end of line sequence of the lockfile content
													logger.log(
														`${filePath} fixed end of line sequence (\\r\\n instead of \\n).`
													);
													intermediateFs.writeFile(
														filePath,
														contentWithChangedEol,
														err => {
															if (err) return callback(err);
															continueWithCachedContent(contentWithChangedEol);
														}
													);
													return;
												}
											}
											if (frozen) {
												return callback(
													new Error(
														`${
															entry.resolved
														} integrity mismatch, expected content with integrity ${
															entry.integrity
														} but got ${computeIntegrity(content)}.
Lockfile corrupted (${
															isEolChanged
																? "end of line sequence was unexpectedly changed"
																: "incorrectly merged? changed by other tools?"
														}).
Run build with un-frozen lockfile to automatically fix lockfile.`
													)
												);
											} else {
												// "fix" the lockfile entry to the correct integrity
												// the content has priority over the integrity value
												entry = {
													...entry,
													integrity: computeIntegrity(content)
												};
												storeLockEntry(lockfile, url, entry);
											}
										}
										continueWithCachedContent(result);
									});
								} else {
									doFetch();
								}
							});
						}
					);

					const respondWithUrlModule = (url, resourceData, callback) => {
						getInfo(url.href, (err, result) => {
							if (err) return callback(err);
							resourceData.resource = url.href;
							resourceData.path = url.origin + url.pathname;
							resourceData.query = url.search;
							resourceData.fragment = url.hash;
							resourceData.context = new URL(
								".",
								result.entry.resolved
							).href.slice(0, -1);
							resourceData.data.mimetype = result.entry.contentType;
							callback(null, true);
						});
					};
					normalModuleFactory.hooks.resolveForScheme
						.for(scheme)
						.tapAsync(
							"HttpUriPlugin",
							(resourceData, resolveData, callback) => {
								respondWithUrlModule(
									new URL(resourceData.resource),
									resourceData,
									callback
								);
							}
						);
					normalModuleFactory.hooks.resolveInScheme
						.for(scheme)
						.tapAsync("HttpUriPlugin", (resourceData, data, callback) => {
							// Only handle relative urls (./xxx, ../xxx, /xxx, //xxx)
							if (
								data.dependencyType !== "url" &&
								!/^\.{0,2}\//.test(resourceData.resource)
							) {
								return callback();
							}
							respondWithUrlModule(
								new URL(resourceData.resource, data.context + "/"),
								resourceData,
								callback
							);
						});
					const hooks = NormalModule.getCompilationHooks(compilation);
					hooks.readResourceForScheme
						.for(scheme)
						.tapAsync("HttpUriPlugin", (resource, module, callback) => {
							return getInfo(resource, (err, result) => {
								if (err) return callback(err);
								module.buildInfo.resourceIntegrity = result.entry.integrity;
								callback(null, result.content);
							});
						});
					hooks.needBuild.tapAsync(
						"HttpUriPlugin",
						(module, context, callback) => {
							if (
								module.resource &&
								module.resource.startsWith(`${scheme}://`)
							) {
								getInfo(module.resource, (err, result) => {
									if (err) return callback(err);
									if (
										result.entry.integrity !==
										module.buildInfo.resourceIntegrity
									) {
										return callback(null, true);
									}
									callback();
								});
							} else {
								return callback();
							}
						}
					);
				}
				compilation.hooks.finishModules.tapAsync(
					"HttpUriPlugin",
					(modules, callback) => {
						if (!lockfileUpdates) return callback();
						const ext = extname(lockfileLocation);
						const tempFile = join(
							intermediateFs,
							dirname(intermediateFs, lockfileLocation),
							`.${basename(lockfileLocation, ext)}.${
								(Math.random() * 10000) | 0
							}${ext}`
						);

						const writeDone = () => {
							const nextOperation = inProgressWrite.shift();
							if (nextOperation) {
								nextOperation();
							} else {
								inProgressWrite = undefined;
							}
						};
						const runWrite = () => {
							intermediateFs.readFile(lockfileLocation, (err, buffer) => {
								if (err && err.code !== "ENOENT") {
									writeDone();
									return callback(err);
								}
								const lockfile = buffer
									? Lockfile.parse(buffer.toString("utf-8"))
									: new Lockfile();
								for (const [key, value] of lockfileUpdates) {
									lockfile.entries.set(key, value);
								}
								intermediateFs.writeFile(tempFile, lockfile.toString(), err => {
									if (err) {
										writeDone();
										return intermediateFs.unlink(tempFile, () => callback(err));
									}
									intermediateFs.rename(tempFile, lockfileLocation, err => {
										if (err) {
											writeDone();
											return intermediateFs.unlink(tempFile, () =>
												callback(err)
											);
										}
										writeDone();
										callback();
									});
								});
							});
						};
						if (inProgressWrite) {
							inProgressWrite.push(runWrite);
						} else {
							inProgressWrite = [];
							runWrite();
						}
					}
				);
			}
		);
	}
}

module.exports = HttpUriPlugin;


code:
/*
	MIT License http://www.opensource.org/licenses/mit-license.php
*/

"use strict";

/** @typedef {import("./ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("./ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */

class ArraySerializer {
	/**
	 * @template T
	 * @param {T[]} array array
	 * @param {ObjectSerializerContext} context context
	 */
	serialize(array, context) {
		context.write(array.length);
		for (const item of array) context.write(item);
	}

	/**
	 * @template T
	 * @param {ObjectDeserializerContext} context context
	 * @returns {T[]} array
	 */
	deserialize(context) {
		/** @type {number} */
		const length = context.read();
		/** @type {T[]} */
		const array = [];
		for (let i = 0; i < length; i++) {
			array.push(context.read());
		}
		return array;
	}
}

module.exports = ArraySerializer;