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

"use strict";

/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
/** @typedef {(string|number|undefined|[])[]} SemVerRange */

/**
 * @param {string} str version string
 * @returns {(string|number|undefined|[])[]} parsed version
 */
const parseVersion = str => {
	var splitAndConvert = function (str) {
		return str.split(".").map(function (item) {
			// eslint-disable-next-line eqeqeq
			return +item == item ? +item : item;
		});
	};
	var match = /^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(str);
	/** @type {(string|number|undefined|[])[]} */
	var ver = match[1] ? splitAndConvert(match[1]) : [];
	if (match[2]) {
		ver.length++;
		ver.push.apply(ver, splitAndConvert(match[2]));
	}
	if (match[3]) {
		ver.push([]);
		ver.push.apply(ver, splitAndConvert(match[3]));
	}
	return ver;
};
exports.parseVersion = parseVersion;

/* eslint-disable eqeqeq */
/**
 * @param {string} a version
 * @param {string} b version
 * @returns {boolean} true, iff a < b
 */
const versionLt = (a, b) => {
	// @ts-expect-error
	a = parseVersion(a);
	// @ts-expect-error
	b = parseVersion(b);
	var i = 0;
	for (;;) {
		// a       b  EOA     object  undefined  number  string
		// EOA        a == b  a < b   b < a      a < b   a < b
		// object     b < a   (0)     b < a      a < b   a < b
		// undefined  a < b   a < b   (0)        a < b   a < b
		// number     b < a   b < a   b < a      (1)     a < b
		// string     b < a   b < a   b < a      b < a   (1)
		// EOA end of array
		// (0) continue on
		// (1) compare them via "<"

		// Handles first row in table
		if (i >= a.length) return i < b.length && (typeof b[i])[0] != "u";

		var aValue = a[i];
		var aType = (typeof aValue)[0];

		// Handles first column in table
		if (i >= b.length) return aType == "u";

		var bValue = b[i];
		var bType = (typeof bValue)[0];

		if (aType == bType) {
			if (aType != "o" && aType != "u" && aValue != bValue) {
				return aValue < bValue;
			}
			i++;
		} else {
			// Handles remaining cases
			if (aType == "o" && bType == "n") return true;
			return bType == "s" || aType == "u";
		}
	}
};
/* eslint-enable eqeqeq */
exports.versionLt = versionLt;

/**
 * @param {string} str range string
 * @returns {SemVerRange} parsed range
 */
exports.parseRange = str => {
	const splitAndConvert = str => {
		return str
			.split(".")
			.map(item => (item !== "NaN" && `${+item}` === item ? +item : item));
	};
	// see https://docs.npmjs.com/misc/semver#range-grammar for grammar
	const parsePartial = str => {
		const match = /^([^-+]+)?(?:-([^+]+))?(?:\+(.+))?$/.exec(str);
		/** @type {(string|number|undefined|[])[]} */
		const ver = match[1] ? [0, ...splitAndConvert(match[1])] : [0];
		if (match[2]) {
			ver.length++;
			ver.push.apply(ver, splitAndConvert(match[2]));
		}

		// remove trailing any matchers
		let last = ver[ver.length - 1];
		while (
			ver.length &&
			(last === undefined || /^[*xX]$/.test(/** @type {string} */ (last)))
		) {
			ver.pop();
			last = ver[ver.length - 1];
		}

		return ver;
	};
	const toFixed = range => {
		if (range.length === 1) {
			// Special case for "*" is "x.x.x" instead of "="
			return [0];
		} else if (range.length === 2) {
			// Special case for "1" is "1.x.x" instead of "=1"
			return [1, ...range.slice(1)];
		} else if (range.length === 3) {
			// Special case for "1.2" is "1.2.x" instead of "=1.2"
			return [2, ...range.slice(1)];
		} else {
			return [range.length, ...range.slice(1)];
		}
	};
	const negate = range => {
		return [-range[0] - 1, ...range.slice(1)];
	};
	const parseSimple = str => {
		// simple       ::= primitive | partial | tilde | caret
		// primitive    ::= ( '<' | '>' | '>=' | '<=' | '=' | '!' ) ( ' ' ) * partial
		// tilde        ::= '~' ( ' ' ) * partial
		// caret        ::= '^' ( ' ' ) * partial
		const match = /^(\^|~|<=|<|>=|>|=|v|!)/.exec(str);
		const start = match ? match[0] : "";
		const remainder = parsePartial(
			start.length ? str.slice(start.length).trim() : str.trim()
		);
		switch (start) {
			case "^":
				if (remainder.length > 1 && remainder[1] === 0) {
					if (remainder.length > 2 && remainder[2] === 0) {
						return [3, ...remainder.slice(1)];
					}
					return [2, ...remainder.slice(1)];
				}
				return [1, ...remainder.slice(1)];
			case "~":
				if (remainder.length === 2 && remainder[0] === 0) {
					return [1, ...remainder.slice(1)];
				}
				return [2, ...remainder.slice(1)];
			case ">=":
				return remainder;
			case "=":
			case "v":
			case "":
				return toFixed(remainder);
			case "<":
				return negate(remainder);
			case ">": {
				// and( >=, not( = ) ) => >=, =, not, and
				const fixed = toFixed(remainder);
				// eslint-disable-next-line no-sparse-arrays
				return [, fixed, 0, remainder, 2];
			}
			case "<=":
				// or( <, = ) => <, =, or
				// eslint-disable-next-line no-sparse-arrays
				return [, toFixed(remainder), negate(remainder), 1];
			case "!": {
				// not =
				const fixed = toFixed(remainder);
				// eslint-disable-next-line no-sparse-arrays
				return [, fixed, 0];
			}
			default:
				throw new Error("Unexpected start value");
		}
	};
	const combine = (items, fn) => {
		if (items.length === 1) return items[0];
		const arr = [];
		for (const item of items.slice().reverse()) {
			if (0 in item) {
				arr.push(item);
			} else {
				arr.push(...item.slice(1));
			}
		}
		// eslint-disable-next-line no-sparse-arrays
		return [, ...arr, ...items.slice(1).map(() => fn)];
	};
	const parseRange = str => {
		// range      ::= hyphen | simple ( ' ' ( ' ' ) * simple ) * | ''
		// hyphen     ::= partial ( ' ' ) * ' - ' ( ' ' ) * partial
		const items = str.split(/\s+-\s+/);
		if (items.length === 1) {
			const items = str
				.trim()
				.split(/(?<=[-0-9A-Za-z])\s+/g)
				.map(parseSimple);
			return combine(items, 2);
		}
		const a = parsePartial(items[0]);
		const b = parsePartial(items[1]);
		// >=a <=b => and( >=a, or( <b, =b ) ) => >=a, <b, =b, or, and
		// eslint-disable-next-line no-sparse-arrays
		return [, toFixed(b), negate(b), 1, a, 2];
	};
	const parseLogicalOr = str => {
		// range-set  ::= range ( logical-or range ) *
		// logical-or ::= ( ' ' ) * '||' ( ' ' ) *
		const items = str.split(/\s*\|\|\s*/).map(parseRange);
		return combine(items, 1);
	};
	return parseLogicalOr(str);
};

/* eslint-disable eqeqeq */
const rangeToString = range => {
	var fixCount = range[0];
	var str = "";
	if (range.length === 1) {
		return "*";
	} else if (fixCount + 0.5) {
		str +=
			fixCount == 0
				? ">="
				: fixCount == -1
					? "<"
					: fixCount == 1
						? "^"
						: fixCount == 2
							? "~"
							: fixCount > 0
								? "="
								: "!=";
		var needDot = 1;
		for (var i = 1; i < range.length; i++) {
			var item = range[i];
			var t = (typeof item)[0];
			needDot--;
			str +=
				t == "u"
					? // undefined: prerelease marker, add an "-"
						"-"
					: // number or string: add the item, set flag to add an "." between two of them
						(needDot > 0 ? "." : "") + ((needDot = 2), item);
		}
		return str;
	} else {
		var stack = [];
		// eslint-disable-next-line no-redeclare
		for (var i = 1; i < range.length; i++) {
			// eslint-disable-next-line no-redeclare
			var item = range[i];
			stack.push(
				item === 0
					? "not(" + pop() + ")"
					: item === 1
						? "(" + pop() + " || " + pop() + ")"
						: item === 2
							? stack.pop() + " " + stack.pop()
							: rangeToString(item)
			);
		}
		return pop();
	}
	function pop() {
		return stack.pop().replace(/^\((.+)\)$/, "$1");
	}
};
/* eslint-enable eqeqeq */
exports.rangeToString = rangeToString;

/* eslint-disable eqeqeq */
/**
 * @param {SemVerRange} range version range
 * @param {string} version the version
 * @returns {boolean} if version satisfy the range
 */
const satisfy = (range, version) => {
	if (0 in range) {
		// @ts-expect-error
		version = parseVersion(version);
		var fixCount = /** @type {number} */ (range[0]);
		// when negated is set it swill set for < instead of >=
		var negated = fixCount < 0;
		if (negated) fixCount = -fixCount - 1;
		for (var i = 0, j = 1, isEqual = true; ; j++, i++) {
			// cspell:word nequal nequ

			// when isEqual = true:
			// range         version: EOA/object  undefined  number    string
			// EOA                    equal       block      big-ver   big-ver
			// undefined              bigger      next       big-ver   big-ver
			// number                 smaller     block      cmp       big-cmp
			// fixed number           smaller     block      cmp-fix   differ
			// string                 smaller     block      differ    cmp
			// fixed string           smaller     block      small-cmp cmp-fix

			// when isEqual = false:
			// range         version: EOA/object  undefined  number    string
			// EOA                    nequal      block      next-ver  next-ver
			// undefined              nequal      block      next-ver  next-ver
			// number                 nequal      block      next      next
			// fixed number           nequal      block      next      next   (this never happens)
			// string                 nequal      block      next      next
			// fixed string           nequal      block      next      next   (this never happens)

			// EOA end of array
			// equal (version is equal range):
			//   when !negated: return true,
			//   when negated: return false
			// bigger (version is bigger as range):
			//   when fixed: return false,
			//   when !negated: return true,
			//   when negated: return false,
			// smaller (version is smaller as range):
			//   when !negated: return false,
			//   when negated: return true
			// nequal (version is not equal range (> resp <)): return true
			// block (version is in different prerelease area): return false
			// differ (version is different from fixed range (string vs. number)): return false
			// next: continues to the next items
			// next-ver: when fixed: return false, continues to the next item only for the version, sets isEqual=false
			// big-ver: when fixed || negated: return false, continues to the next item only for the version, sets isEqual=false
			// next-nequ: continues to the next items, sets isEqual=false
			// cmp (negated === false): version < range => return false, version > range => next-nequ, else => next
			// cmp (negated === true): version > range => return false, version < range => next-nequ, else => next
			// cmp-fix: version == range => next, else => return false
			// big-cmp: when negated => return false, else => next-nequ
			// small-cmp: when negated => next-nequ, else => return false

			var rangeType = j < range.length ? (typeof range[j])[0] : "";

			var versionValue;
			var versionType;

			// Handles first column in both tables (end of version or object)
			if (
				i >= version.length ||
				((versionValue = version[i]),
				(versionType = (typeof versionValue)[0]) == "o")
			) {
				// Handles nequal
				if (!isEqual) return true;
				// Handles bigger
				if (rangeType == "u") return j > fixCount && !negated;
				// Handles equal and smaller: (range === EOA) XOR negated
				return (rangeType == "") != negated; // equal + smaller
			}

			// Handles second column in both tables (version = undefined)
			if (versionType == "u") {
				if (!isEqual || rangeType != "u") {
					return false;
				}
			}

			// switch between first and second table
			else if (isEqual) {
				// Handle diagonal
				if (rangeType == versionType) {
					if (j <= fixCount) {
						// Handles "cmp-fix" cases
						if (versionValue != range[j]) {
							return false;
						}
					} else {
						// Handles "cmp" cases
						if (negated ? versionValue > range[j] : versionValue < range[j]) {
							return false;
						}
						if (versionValue != range[j]) isEqual = false;
					}
				}

				// Handle big-ver
				else if (rangeType != "s" && rangeType != "n") {
					if (negated || j <= fixCount) return false;
					isEqual = false;
					j--;
				}

				// Handle differ, big-cmp and small-cmp
				else if (j <= fixCount || versionType < rangeType != negated) {
					return false;
				} else {
					isEqual = false;
				}
			} else {
				// Handles all "next-ver" cases in the second table
				if (rangeType != "s" && rangeType != "n") {
					isEqual = false;
					j--;
				}

				// next is applied by default
			}
		}
	}
	/** @type {(boolean | number)[]} */
	var stack = [];
	var p = stack.pop.bind(stack);
	// eslint-disable-next-line no-redeclare
	for (var i = 1; i < range.length; i++) {
		var item = /** @type {SemVerRange | 0 | 1 | 2} */ (range[i]);
		stack.push(
			item == 1
				? p() | p()
				: item == 2
					? p() & p()
					: item
						? satisfy(item, version)
						: !p()
		);
	}
	return !!p();
};
/* eslint-enable eqeqeq */
exports.satisfy = satisfy;

exports.stringifyHoley = json => {
	switch (typeof json) {
		case "undefined":
			return "";
		case "object":
			if (Array.isArray(json)) {
				let str = "[";
				for (let i = 0; i < json.length; i++) {
					if (i !== 0) str += ",";
					str += this.stringifyHoley(json[i]);
				}
				str += "]";
				return str;
			} else {
				return JSON.stringify(json);
			}
		default:
			return JSON.stringify(json);
	}
};

//#region runtime code: parseVersion
exports.parseVersionRuntimeCode = runtimeTemplate =>
	`var parseVersion = ${runtimeTemplate.basicFunction("str", [
		"// see webpack/lib/util/semver.js for original code",
		`var p=${runtimeTemplate.supportsArrowFunction() ? "p=>" : "function(p)"}{return p.split(".").map((${runtimeTemplate.supportsArrowFunction() ? "p=>" : "function(p)"}{return+p==p?+p:p}))},n=/^([^-+]+)?(?:-([^+]+))?(?:\\+(.+))?$/.exec(str),r=n[1]?p(n[1]):[];return n[2]&&(r.length++,r.push.apply(r,p(n[2]))),n[3]&&(r.push([]),r.push.apply(r,p(n[3]))),r;`
	])}`;
//#endregion

//#region runtime code: versionLt
exports.versionLtRuntimeCode = runtimeTemplate =>
	`var versionLt = ${runtimeTemplate.basicFunction("a, b", [
		"// see webpack/lib/util/semver.js for original code",
		'a=parseVersion(a),b=parseVersion(b);for(var r=0;;){if(r>=a.length)return r<b.length&&"u"!=(typeof b[r])[0];var e=a[r],n=(typeof e)[0];if(r>=b.length)return"u"==n;var t=b[r],f=(typeof t)[0];if(n!=f)return"o"==n&&"n"==f||("s"==f||"u"==n);if("o"!=n&&"u"!=n&&e!=t)return e<t;r++}'
	])}`;
//#endregion

//#region runtime code: rangeToString
exports.rangeToStringRuntimeCode = runtimeTemplate =>
	`var rangeToString = ${runtimeTemplate.basicFunction("range", [
		"// see webpack/lib/util/semver.js for original code",
		'var r=range[0],n="";if(1===range.length)return"*";if(r+.5){n+=0==r?">=":-1==r?"<":1==r?"^":2==r?"~":r>0?"=":"!=";for(var e=1,a=1;a<range.length;a++){e--,n+="u"==(typeof(t=range[a]))[0]?"-":(e>0?".":"")+(e=2,t)}return n}var g=[];for(a=1;a<range.length;a++){var t=range[a];g.push(0===t?"not("+o()+")":1===t?"("+o()+" || "+o()+")":2===t?g.pop()+" "+g.pop():rangeToString(t))}return o();function o(){return g.pop().replace(/^\\((.+)\\)$/,"$1")}'
	])}`;
//#endregion

//#region runtime code: satisfy
exports.satisfyRuntimeCode = runtimeTemplate =>
	`var satisfy = ${runtimeTemplate.basicFunction("range, version", [
		"// see webpack/lib/util/semver.js for original code",
		'if(0 in range){version=parseVersion(version);var e=range[0],r=e<0;r&&(e=-e-1);for(var n=0,i=1,a=!0;;i++,n++){var f,s,g=i<range.length?(typeof range[i])[0]:"";if(n>=version.length||"o"==(s=(typeof(f=version[n]))[0]))return!a||("u"==g?i>e&&!r:""==g!=r);if("u"==s){if(!a||"u"!=g)return!1}else if(a)if(g==s)if(i<=e){if(f!=range[i])return!1}else{if(r?f>range[i]:f<range[i])return!1;f!=range[i]&&(a=!1)}else if("s"!=g&&"n"!=g){if(r||i<=e)return!1;a=!1,i--}else{if(i<=e||s<g!=r)return!1;a=!1}else"s"!=g&&"n"!=g&&(a=!1,i--)}}var t=[],o=t.pop.bind(t);for(n=1;n<range.length;n++){var u=range[n];t.push(1==u?o()|o():2==u?o()&o():u?satisfy(u,version):!o())}return!!o();'
	])}`;
//#endregion


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

"use strict";

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

/** @typedef {import("../serialization/BinaryMiddleware").MEASURE_END_OPERATION_TYPE} MEASURE_END_OPERATION */
/** @typedef {import("../serialization/BinaryMiddleware").MEASURE_START_OPERATION_TYPE} MEASURE_START_OPERATION */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectDeserializerContext} ObjectDeserializerContext */
/** @typedef {import("../serialization/ObjectMiddleware").ObjectSerializerContext} ObjectSerializerContext */
/** @typedef {import("../serialization/Serializer")} Serializer */
/** @typedef {typeof import("../util/Hash")} Hash */
/** @typedef {import("../util/fs").IntermediateFileSystem} IntermediateFileSystem */

const getBinaryMiddleware = memoize(() =>
	require("../serialization/BinaryMiddleware")
);
const getObjectMiddleware = memoize(() =>
	require("../serialization/ObjectMiddleware")
);
const getSingleItemMiddleware = memoize(() =>
	require("../serialization/SingleItemMiddleware")
);
const getSerializer = memoize(() => require("../serialization/Serializer"));
const getSerializerMiddleware = memoize(() =>
	require("../serialization/SerializerMiddleware")
);

const getBinaryMiddlewareInstance = memoize(
	() => new (getBinaryMiddleware())()
);

const registerSerializers = memoize(() => {
	require("./registerExternalSerializer");

	// Load internal paths with a relative require
	// This allows bundling all internal serializers
	const internalSerializables = require("./internalSerializables");
	getObjectMiddleware().registerLoader(/^webpack\/lib\//, req => {
		const loader = internalSerializables[req.slice("webpack/lib/".length)];
		if (loader) {
			loader();
		} else {
			console.warn(`${req} not found in internalSerializables`);
		}
		return true;
	});
});

/** @type {Serializer} */
let buffersSerializer;

// Expose serialization API
module.exports = {
	get register() {
		return getObjectMiddleware().register;
	},
	get registerLoader() {
		return getObjectMiddleware().registerLoader;
	},
	get registerNotSerializable() {
		return getObjectMiddleware().registerNotSerializable;
	},
	get NOT_SERIALIZABLE() {
		return getObjectMiddleware().NOT_SERIALIZABLE;
	},
	/** @type {MEASURE_START_OPERATION} */
	get MEASURE_START_OPERATION() {
		return getBinaryMiddleware().MEASURE_START_OPERATION;
	},
	/** @type {MEASURE_END_OPERATION} */
	get MEASURE_END_OPERATION() {
		return getBinaryMiddleware().MEASURE_END_OPERATION;
	},
	/**
	 * @returns {Serializer} buffer serializer
	 */
	get buffersSerializer() {
		if (buffersSerializer !== undefined) return buffersSerializer;
		registerSerializers();
		const Serializer = getSerializer();
		const binaryMiddleware = getBinaryMiddlewareInstance();
		const SerializerMiddleware = getSerializerMiddleware();
		const SingleItemMiddleware = getSingleItemMiddleware();
		return (buffersSerializer = new Serializer([
			new SingleItemMiddleware(),
			new (getObjectMiddleware())(context => {
				if (context.write) {
					context.writeLazy = value => {
						context.write(
							SerializerMiddleware.createLazy(value, binaryMiddleware)
						);
					};
				}
			}, "md4"),
			binaryMiddleware
		]));
	},
	/**
	 * @param {IntermediateFileSystem} fs filesystem
	 * @param {string | Hash} hashFunction hash function to use
	 * @returns {Serializer} file serializer
	 */
	createFileSerializer: (fs, hashFunction) => {
		registerSerializers();
		const Serializer = getSerializer();
		const FileMiddleware = require("../serialization/FileMiddleware");
		const fileMiddleware = new FileMiddleware(fs, hashFunction);
		const binaryMiddleware = getBinaryMiddlewareInstance();
		const SerializerMiddleware = getSerializerMiddleware();
		const SingleItemMiddleware = getSingleItemMiddleware();
		return new Serializer([
			new SingleItemMiddleware(),
			new (getObjectMiddleware())(context => {
				if (context.write) {
					context.writeLazy = value => {
						context.write(
							SerializerMiddleware.createLazy(value, binaryMiddleware)
						);
					};
					context.writeSeparate = (value, options) => {
						const lazy = SerializerMiddleware.createLazy(
							value,
							fileMiddleware,
							options
						);
						context.write(lazy);
						return lazy;
					};
				}
			}, hashFunction),
			binaryMiddleware,
			fileMiddleware
		]);
	}
};

license: mit


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

"use strict";

/**
 * @typedef {object} GroupOptions
 * @property {boolean=} groupChildren
 * @property {boolean=} force
 * @property {number=} targetGroupCount
 */

/**
 * @template T
 * @template R
 * @typedef {object} GroupConfig
 * @property {function(T): string[]} getKeys
 * @property {function(string, (R | T)[], T[]): R} createGroup
 * @property {function(string, T[]): GroupOptions=} getOptions
 */

/**
 * @template T
 * @template R
 * @typedef {object} ItemWithGroups
 * @property {T} item
 * @property {Set<Group<T, R>>} groups
 */

/**
 * @template T
 * @template R
 * @typedef {{ config: GroupConfig<T, R>, name: string, alreadyGrouped: boolean, items: Set<ItemWithGroups<T, R>> | undefined }} Group
 */

/**
 * @template T
 * @template R
 * @param {T[]} items the list of items
 * @param {GroupConfig<T, R>[]} groupConfigs configuration
 * @returns {(R | T)[]} grouped items
 */
const smartGrouping = (items, groupConfigs) => {
	/** @type {Set<ItemWithGroups<T, R>>} */
	const itemsWithGroups = new Set();
	/** @type {Map<string, Group<T, R>>} */
	const allGroups = new Map();
	for (const item of items) {
		/** @type {Set<Group<T, R>>} */
		const groups = new Set();
		for (let i = 0; i < groupConfigs.length; i++) {
			const groupConfig = groupConfigs[i];
			const keys = groupConfig.getKeys(item);
			if (keys) {
				for (const name of keys) {
					const key = `${i}:${name}`;
					let group = allGroups.get(key);
					if (group === undefined) {
						allGroups.set(
							key,
							(group = {
								config: groupConfig,
								name,
								alreadyGrouped: false,
								items: undefined
							})
						);
					}
					groups.add(group);
				}
			}
		}
		itemsWithGroups.add({
			item,
			groups
		});
	}
	/**
	 * @param {Set<ItemWithGroups<T, R>>} itemsWithGroups input items with groups
	 * @returns {(T | R)[]} groups items
	 */
	const runGrouping = itemsWithGroups => {
		const totalSize = itemsWithGroups.size;
		for (const entry of itemsWithGroups) {
			for (const group of entry.groups) {
				if (group.alreadyGrouped) continue;
				const items = group.items;
				if (items === undefined) {
					group.items = new Set([entry]);
				} else {
					items.add(entry);
				}
			}
		}
		/** @type {Map<Group<T, R>, { items: Set<ItemWithGroups<T, R>>, options: GroupOptions | false | undefined, used: boolean }>} */
		const groupMap = new Map();
		for (const group of allGroups.values()) {
			if (group.items) {
				const items = group.items;
				group.items = undefined;
				groupMap.set(group, {
					items,
					options: undefined,
					used: false
				});
			}
		}
		/** @type {(T | R)[]} */
		const results = [];
		for (;;) {
			/** @type {Group<T, R> | undefined} */
			let bestGroup = undefined;
			let bestGroupSize = -1;
			let bestGroupItems = undefined;
			let bestGroupOptions = undefined;
			for (const [group, state] of groupMap) {
				const { items, used } = state;
				let options = state.options;
				if (options === undefined) {
					const groupConfig = group.config;
					state.options = options =
						(groupConfig.getOptions &&
							groupConfig.getOptions(
								group.name,
								Array.from(items, ({ item }) => item)
							)) ||
						false;
				}

				const force = options && options.force;
				if (!force) {
					if (bestGroupOptions && bestGroupOptions.force) continue;
					if (used) continue;
					if (items.size <= 1 || totalSize - items.size <= 1) {
						continue;
					}
				}
				const targetGroupCount = (options && options.targetGroupCount) || 4;
				let sizeValue = force
					? items.size
					: Math.min(
							items.size,
							(totalSize * 2) / targetGroupCount +
								itemsWithGroups.size -
								items.size
						);
				if (
					sizeValue > bestGroupSize ||
					(force && (!bestGroupOptions || !bestGroupOptions.force))
				) {
					bestGroup = group;
					bestGroupSize = sizeValue;
					bestGroupItems = items;
					bestGroupOptions = options;
				}
			}
			if (bestGroup === undefined) {
				break;
			}
			const items = new Set(bestGroupItems);
			const options = bestGroupOptions;

			const groupChildren = !options || options.groupChildren !== false;

			for (const item of items) {
				itemsWithGroups.delete(item);
				// Remove all groups that items have from the map to not select them again
				for (const group of item.groups) {
					const state = groupMap.get(group);
					if (state !== undefined) {
						state.items.delete(item);
						if (state.items.size === 0) {
							groupMap.delete(group);
						} else {
							state.options = undefined;
							if (groupChildren) {
								state.used = true;
							}
						}
					}
				}
			}
			groupMap.delete(bestGroup);

			const key = bestGroup.name;
			const groupConfig = bestGroup.config;

			const allItems = Array.from(items, ({ item }) => item);

			bestGroup.alreadyGrouped = true;
			const children = groupChildren ? runGrouping(items) : allItems;
			bestGroup.alreadyGrouped = false;

			results.push(groupConfig.createGroup(key, children, allItems));
		}
		for (const { item } of itemsWithGroups) {
			results.push(item);
		}
		return results;
	};
	return runGrouping(itemsWithGroups);
};

module.exports = smartGrouping;


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

"use strict";

/** @typedef {import("webpack-sources").Source} Source */

/** @type {WeakMap<Source, WeakMap<Source, boolean>>} */
const equalityCache = new WeakMap();

/**
 * @param {Source} a a source
 * @param {Source} b another source
 * @returns {boolean} true, when both sources are equal
 */
const _isSourceEqual = (a, b) => {
	// prefer .buffer(), it's called anyway during emit
	/** @type {Buffer|string} */
	let aSource = typeof a.buffer === "function" ? a.buffer() : a.source();
	/** @type {Buffer|string} */
	let bSource = typeof b.buffer === "function" ? b.buffer() : b.source();
	if (aSource === bSource) return true;
	if (typeof aSource === "string" && typeof bSource === "string") return false;
	if (!Buffer.isBuffer(aSource)) aSource = Buffer.from(aSource, "utf-8");
	if (!Buffer.isBuffer(bSource)) bSource = Buffer.from(bSource, "utf-8");
	return aSource.equals(bSource);
};

/**
 * @param {Source} a a source
 * @param {Source} b another source
 * @returns {boolean} true, when both sources are equal
 */
const isSourceEqual = (a, b) => {
	if (a === b) return true;
	const cache1 = equalityCache.get(a);
	if (cache1 !== undefined) {
		const result = cache1.get(b);
		if (result !== undefined) return result;
	}
	const result = _isSourceEqual(a, b);
	if (cache1 !== undefined) {
		cache1.set(b, result);
	} else {
		const map = new WeakMap();
		map.set(b, result);
		equalityCache.set(a, map);
	}
	const cache2 = equalityCache.get(b);
	if (cache2 !== undefined) {
		cache2.set(a, result);
	} else {
		const map = new WeakMap();
		map.set(a, result);
		equalityCache.set(b, map);
	}
	return result;
};
exports.isSourceEqual = isSourceEqual;


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

"use strict";

const { validate } = require("schema-utils");

/* cSpell:disable */
const DID_YOU_MEAN = {
	rules: "module.rules",
	loaders: "module.rules or module.rules.*.use",
	query: "module.rules.*.options (BREAKING CHANGE since webpack 5)",
	noParse: "module.noParse",
	filename: "output.filename or module.rules.*.generator.filename",
	file: "output.filename",
	chunkFilename: "output.chunkFilename",
	chunkfilename: "output.chunkFilename",
	ecmaVersion:
		"output.environment (output.ecmaVersion was a temporary configuration option during webpack 5 beta)",
	ecmaversion:
		"output.environment (output.ecmaVersion was a temporary configuration option during webpack 5 beta)",
	ecma: "output.environment (output.ecmaVersion was a temporary configuration option during webpack 5 beta)",
	path: "output.path",
	pathinfo: "output.pathinfo",
	pathInfo: "output.pathinfo",
	jsonpFunction: "output.chunkLoadingGlobal (BREAKING CHANGE since webpack 5)",
	chunkCallbackName:
		"output.chunkLoadingGlobal (BREAKING CHANGE since webpack 5)",
	jsonpScriptType: "output.scriptType (BREAKING CHANGE since webpack 5)",
	hotUpdateFunction: "output.hotUpdateGlobal (BREAKING CHANGE since webpack 5)",
	splitChunks: "optimization.splitChunks",
	immutablePaths: "snapshot.immutablePaths",
	managedPaths: "snapshot.managedPaths",
	maxModules: "stats.modulesSpace (BREAKING CHANGE since webpack 5)",
	hashedModuleIds:
		'optimization.moduleIds: "hashed" (BREAKING CHANGE since webpack 5)',
	namedChunks:
		'optimization.chunkIds: "named" (BREAKING CHANGE since webpack 5)',
	namedModules:
		'optimization.moduleIds: "named" (BREAKING CHANGE since webpack 5)',
	occurrenceOrder:
		'optimization.chunkIds: "size" and optimization.moduleIds: "size" (BREAKING CHANGE since webpack 5)',
	automaticNamePrefix:
		"optimization.splitChunks.[cacheGroups.*].idHint (BREAKING CHANGE since webpack 5)",
	noEmitOnErrors:
		"optimization.emitOnErrors (BREAKING CHANGE since webpack 5: logic is inverted to avoid negative flags)",
	Buffer:
		"to use the ProvidePlugin to process the Buffer variable to modules as polyfill\n" +
		"BREAKING CHANGE: webpack 5 no longer provided Node.js polyfills by default.\n" +
		"Note: if you are using 'node.Buffer: false', you can just remove that as this is the default behavior now.\n" +
		"To provide a polyfill to modules use:\n" +
		'new ProvidePlugin({ Buffer: ["buffer", "Buffer"] }) and npm install buffer.',
	process:
		"to use the ProvidePlugin to process the process variable to modules as polyfill\n" +
		"BREAKING CHANGE: webpack 5 no longer provided Node.js polyfills by default.\n" +
		"Note: if you are using 'node.process: false', you can just remove that as this is the default behavior now.\n" +
		"To provide a polyfill to modules use:\n" +
		'new ProvidePlugin({ process: "process" }) and npm install buffer.'
};

const REMOVED = {
	concord:
		"BREAKING CHANGE: resolve.concord has been removed and is no longer available.",
	devtoolLineToLine:
		"BREAKING CHANGE: output.devtoolLineToLine has been removed and is no longer available."
};
/* cSpell:enable */

/**
 * @param {Parameters<typeof validate>[0]} schema a json schema
 * @param {Parameters<typeof validate>[1]} options the options that should be validated
 * @param {Parameters<typeof validate>[2]=} validationConfiguration configuration for generating errors
 * @returns {void}
 */
const validateSchema = (schema, options, validationConfiguration) => {
	validate(
		schema,
		options,
		validationConfiguration || {
			name: "Webpack",
			postFormatter: (formattedError, error) => {
				const children = error.children;
				if (
					children &&
					children.some(
						child =>
							child.keyword === "absolutePath" &&
							child.dataPath === ".output.filename"
					)
				) {
					return `${formattedError}\nPlease use output.path to specify absolute path and output.filename for the file name.`;
				}

				if (
					children &&
					children.some(
						child =>
							child.keyword === "pattern" && child.dataPath === ".devtool"
					)
				) {
					return (
						`${formattedError}\n` +
						"BREAKING CHANGE since webpack 5: The devtool option is more strict.\n" +
						"Please strictly follow the order of the keywords in the pattern."
					);
				}

				if (error.keyword === "additionalProperties") {
					const params =
						/** @type {import("ajv").AdditionalPropertiesParams} */ (
							error.params
						);
					if (
						Object.prototype.hasOwnProperty.call(
							DID_YOU_MEAN,
							params.additionalProperty
						)
					) {
						return `${formattedError}\nDid you mean ${
							DID_YOU_MEAN[
								/** @type {keyof DID_YOU_MEAN} */ (params.additionalProperty)
							]
						}?`;
					}

					if (
						Object.prototype.hasOwnProperty.call(
							REMOVED,
							params.additionalProperty
						)
					) {
						return `${formattedError}\n${
							REMOVED[/** @type {keyof REMOVED} */ (params.additionalProperty)]
						}?`;
					}

					if (!error.dataPath) {
						if (params.additionalProperty === "debug") {
							return (
								`${formattedError}\n` +
								"The 'debug' property was removed in webpack 2.0.0.\n" +
								"Loaders should be updated to allow passing this option via loader options in module.rules.\n" +
								"Until loaders are updated one can use the LoaderOptionsPlugin to switch loaders into debug mode:\n" +
								"plugins: [\n" +
								"  new webpack.LoaderOptionsPlugin({\n" +
								"    debug: true\n" +
								"  })\n" +
								"]"
							);
						}

						if (params.additionalProperty) {
							return (
								`${formattedError}\n` +
								"For typos: please correct them.\n" +
								"For loader options: webpack >= v2.0.0 no longer allows custom properties in configuration.\n" +
								"  Loaders should be updated to allow passing options via loader options in module.rules.\n" +
								"  Until loaders are updated one can use the LoaderOptionsPlugin to pass these options to the loader:\n" +
								"  plugins: [\n" +
								"    new webpack.LoaderOptionsPlugin({\n" +
								"      // test: /\\.xxx$/, // may apply this only for some modules\n" +
								"      options: {\n" +
								`        ${params.additionalProperty}: …\n` +
								"      }\n" +
								"    })\n" +
								"  ]"
							);
						}
					}
				}

				return formattedError;
			}
		}
	);
};
module.exports = validateSchema;


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("../Compilation")} Compilation */

/**
 * @typedef {object} AsyncWasmLoadingRuntimeModuleOptions
 * @property {function(string): string} generateLoadBinaryCode
 * @property {boolean} supportsStreaming
 */

class AsyncWasmLoadingRuntimeModule extends RuntimeModule {
	/**
	 * @param {AsyncWasmLoadingRuntimeModuleOptions} options options
	 */
	constructor({ generateLoadBinaryCode, supportsStreaming }) {
		super("wasm loading", RuntimeModule.STAGE_NORMAL);
		this.generateLoadBinaryCode = generateLoadBinaryCode;
		this.supportsStreaming = supportsStreaming;
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const compilation = /** @type {Compilation} */ (this.compilation);
		const chunk = /** @type {Chunk} */ (this.chunk);
		const { outputOptions, runtimeTemplate } = compilation;
		const fn = RuntimeGlobals.instantiateWasm;
		const wasmModuleSrcPath = compilation.getPath(
			JSON.stringify(outputOptions.webassemblyModuleFilename),
			{
				hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
				hashWithLength: length =>
					`" + ${RuntimeGlobals.getFullHash}}().slice(0, ${length}) + "`,
				module: {
					id: '" + wasmModuleId + "',
					hash: `" + wasmModuleHash + "`,
					hashWithLength(length) {
						return `" + wasmModuleHash.slice(0, ${length}) + "`;
					}
				},
				runtime: chunk.runtime
			}
		);

		const loader = this.generateLoadBinaryCode(wasmModuleSrcPath);
		const fallback = [
			`.then(${runtimeTemplate.returningFunction("x.arrayBuffer()", "x")})`,
			`.then(${runtimeTemplate.returningFunction(
				"WebAssembly.instantiate(bytes, importsObj)",
				"bytes"
			)})`,
			`.then(${runtimeTemplate.returningFunction(
				"Object.assign(exports, res.instance.exports)",
				"res"
			)})`
		];
		const getStreaming = () => {
			const concat = (/** @type {string[]} */ ...text) => text.join("");
			return [
				`var req = ${loader};`,
				`var fallback = ${runtimeTemplate.returningFunction(
					Template.asString(["req", Template.indent(fallback)])
				)};`,
				concat(
					"return req.then(",
					runtimeTemplate.basicFunction("res", [
						`if (typeof WebAssembly.instantiateStreaming === "function") {`,
						Template.indent([
							"return WebAssembly.instantiateStreaming(res, importsObj)",
							Template.indent([
								".then(",
								Template.indent([
									runtimeTemplate.returningFunction(
										"Object.assign(exports, res.instance.exports)",
										"res"
									) + ",",
									runtimeTemplate.basicFunction("e", [
										`if(res.headers.get("Content-Type") !== "application/wasm") {`,
										Template.indent([
											'console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\\n", e);',
											"return fallback();"
										]),
										"}",
										"throw e;"
									])
								]),
								");"
							])
						]),
						"}",
						"return fallback();"
					]),
					");"
				)
			];
		};

		return `${fn} = ${runtimeTemplate.basicFunction(
			"exports, wasmModuleId, wasmModuleHash, importsObj",
			this.supportsStreaming
				? getStreaming()
				: [`return ${loader}`, Template.indent(fallback) + ";"]
		)};`;
	}
}

module.exports = AsyncWasmLoadingRuntimeModule;


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

"use strict";

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

/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
/** @typedef {import("../NormalModule")} NormalModule */

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

/**
 * @typedef {object} AsyncWebAssemblyGeneratorOptions
 * @property {boolean} [mangleImports] mangle imports
 */

class AsyncWebAssemblyGenerator extends Generator {
	/**
	 * @param {AsyncWebAssemblyGeneratorOptions} options options
	 */
	constructor(options) {
		super();
		this.options = options;
	}

	/**
	 * @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 0;
		}
		return originalSource.size();
	}

	/**
	 * @param {NormalModule} module module for which the code should be generated
	 * @param {GenerateContext} generateContext context for generate
	 * @returns {Source} generated code
	 */
	generate(module, generateContext) {
		return /** @type {Source} */ (module.originalSource());
	}
}

module.exports = AsyncWebAssemblyGenerator;


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

"use strict";

const { RawSource } = require("webpack-sources");
const Generator = require("../Generator");
const InitFragment = require("../InitFragment");
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");

/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} OutputOptions */
/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../NormalModule")} NormalModule */
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */

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

/**
 * @typedef {{ request: string, importVar: string }} ImportObjRequestItem
 */

class AsyncWebAssemblyJavascriptGenerator extends Generator {
	/**
	 * @param {OutputOptions["webassemblyModuleFilename"]} filenameTemplate template for the WebAssembly module filename
	 */
	constructor(filenameTemplate) {
		super();
		this.filenameTemplate = filenameTemplate;
	}

	/**
	 * @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) {
		return 40 + module.dependencies.length * 10;
	}

	/**
	 * @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 {
			runtimeTemplate,
			chunkGraph,
			moduleGraph,
			runtimeRequirements,
			runtime
		} = generateContext;
		runtimeRequirements.add(RuntimeGlobals.module);
		runtimeRequirements.add(RuntimeGlobals.moduleId);
		runtimeRequirements.add(RuntimeGlobals.exports);
		runtimeRequirements.add(RuntimeGlobals.instantiateWasm);
		/** @type {InitFragment<InitFragment<string>>[]} */
		const initFragments = [];
		/** @type {Map<Module, ImportObjRequestItem>} */
		const depModules = new Map();
		/** @type {Map<string, WebAssemblyImportDependency[]>} */
		const wasmDepsByRequest = new Map();
		for (const dep of module.dependencies) {
			if (dep instanceof WebAssemblyImportDependency) {
				const module = /** @type {Module} */ (moduleGraph.getModule(dep));
				if (!depModules.has(module)) {
					depModules.set(module, {
						request: dep.request,
						importVar: `WEBPACK_IMPORTED_MODULE_${depModules.size}`
					});
				}
				let list = wasmDepsByRequest.get(dep.request);
				if (list === undefined) {
					list = [];
					wasmDepsByRequest.set(dep.request, list);
				}
				list.push(dep);
			}
		}

		/** @type {Array<string>} */
		const promises = [];

		const importStatements = Array.from(
			depModules,
			([importedModule, { request, importVar }]) => {
				if (moduleGraph.isAsync(importedModule)) {
					promises.push(importVar);
				}
				return runtimeTemplate.importStatement({
					update: false,
					module: importedModule,
					chunkGraph,
					request,
					originModule: module,
					importVar,
					runtimeRequirements
				});
			}
		);
		const importsCode = importStatements.map(([x]) => x).join("");
		const importsCompatCode = importStatements.map(([_, x]) => x).join("");

		const importObjRequestItems = Array.from(
			wasmDepsByRequest,
			([request, deps]) => {
				const exportItems = deps.map(dep => {
					const importedModule =
						/** @type {Module} */
						(moduleGraph.getModule(dep));
					const importVar =
						/** @type {ImportObjRequestItem} */
						(depModules.get(importedModule)).importVar;
					return `${JSON.stringify(
						dep.name
					)}: ${runtimeTemplate.exportFromImport({
						moduleGraph,
						module: importedModule,
						request,
						exportName: dep.name,
						originModule: module,
						asiSafe: true,
						isCall: false,
						callContext: false,
						defaultInterop: true,
						importVar,
						initFragments,
						runtime,
						runtimeRequirements
					})}`;
				});
				return Template.asString([
					`${JSON.stringify(request)}: {`,
					Template.indent(exportItems.join(",\n")),
					"}"
				]);
			}
		);

		const importsObj =
			importObjRequestItems.length > 0
				? Template.asString([
						"{",
						Template.indent(importObjRequestItems.join(",\n")),
						"}"
					])
				: undefined;

		const instantiateCall =
			`${RuntimeGlobals.instantiateWasm}(${module.exportsArgument}, ${
				module.moduleArgument
			}.id, ${JSON.stringify(
				chunkGraph.getRenderedModuleHash(module, runtime)
			)}` + (importsObj ? `, ${importsObj})` : `)`);

		if (promises.length > 0)
			runtimeRequirements.add(RuntimeGlobals.asyncModule);

		const source = new RawSource(
			promises.length > 0
				? Template.asString([
						`var __webpack_instantiate__ = ${runtimeTemplate.basicFunction(
							`[${promises.join(", ")}]`,
							`${importsCompatCode}return ${instantiateCall};`
						)}`,
						`${RuntimeGlobals.asyncModule}(${
							module.moduleArgument
						}, async ${runtimeTemplate.basicFunction(
							"__webpack_handle_async_dependencies__, __webpack_async_result__",
							[
								"try {",
								importsCode,
								`var __webpack_async_dependencies__ = __webpack_handle_async_dependencies__([${promises.join(
									", "
								)}]);`,
								`var [${promises.join(
									", "
								)}] = __webpack_async_dependencies__.then ? (await __webpack_async_dependencies__)() : __webpack_async_dependencies__;`,
								`${importsCompatCode}await ${instantiateCall};`,
								"__webpack_async_result__();",
								"} catch(e) { __webpack_async_result__(e); }"
							]
						)}, 1);`
					])
				: `${importsCode}${importsCompatCode}module.exports = ${instantiateCall};`
		);

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

module.exports = AsyncWebAssemblyJavascriptGenerator;


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

"use strict";

const { SyncWaterfallHook } = require("tapable");
const Compilation = require("../Compilation");
const Generator = require("../Generator");
const { tryRunOrWebpackError } = require("../HookWebpackError");
const { WEBASSEMBLY_MODULE_TYPE_ASYNC } = require("../ModuleTypeConstants");
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
const { compareModulesByIdentifier } = require("../util/comparators");
const memoize = require("../util/memoize");

/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} OutputOptions */
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../CodeGenerationResults")} CodeGenerationResults */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../ModuleGraph")} ModuleGraph */
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
/** @typedef {import("../Template").RenderManifestEntry} RenderManifestEntry */
/** @typedef {import("../Template").RenderManifestOptions} RenderManifestOptions */
/** @typedef {import("../WebpackError")} WebpackError */

const getAsyncWebAssemblyGenerator = memoize(() =>
	require("./AsyncWebAssemblyGenerator")
);
const getAsyncWebAssemblyJavascriptGenerator = memoize(() =>
	require("./AsyncWebAssemblyJavascriptGenerator")
);
const getAsyncWebAssemblyParser = memoize(() =>
	require("./AsyncWebAssemblyParser")
);

/**
 * @typedef {object} WebAssemblyRenderContext
 * @property {Chunk} chunk the chunk
 * @property {DependencyTemplates} dependencyTemplates the dependency templates
 * @property {RuntimeTemplate} runtimeTemplate the runtime template
 * @property {ModuleGraph} moduleGraph the module graph
 * @property {ChunkGraph} chunkGraph the chunk graph
 * @property {CodeGenerationResults} codeGenerationResults results of code generation
 */

/**
 * @typedef {object} CompilationHooks
 * @property {SyncWaterfallHook<[Source, Module, WebAssemblyRenderContext]>} renderModuleContent
 */

/**
 * @typedef {object} AsyncWebAssemblyModulesPluginOptions
 * @property {boolean} [mangleImports] mangle imports
 */

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

const PLUGIN_NAME = "AsyncWebAssemblyModulesPlugin";

class AsyncWebAssemblyModulesPlugin {
	/**
	 * @param {Compilation} compilation the compilation
	 * @returns {CompilationHooks} the attached 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 = {
				renderModuleContent: new SyncWaterfallHook([
					"source",
					"module",
					"renderContext"
				])
			};
			compilationHooksMap.set(compilation, hooks);
		}
		return hooks;
	}

	/**
	 * @param {AsyncWebAssemblyModulesPluginOptions} options options
	 */
	constructor(options) {
		this.options = options;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.compilation.tap(
			PLUGIN_NAME,
			(compilation, { normalModuleFactory }) => {
				const hooks =
					AsyncWebAssemblyModulesPlugin.getCompilationHooks(compilation);
				compilation.dependencyFactories.set(
					WebAssemblyImportDependency,
					normalModuleFactory
				);

				normalModuleFactory.hooks.createParser
					.for(WEBASSEMBLY_MODULE_TYPE_ASYNC)
					.tap(PLUGIN_NAME, () => {
						const AsyncWebAssemblyParser = getAsyncWebAssemblyParser();

						return new AsyncWebAssemblyParser();
					});
				normalModuleFactory.hooks.createGenerator
					.for(WEBASSEMBLY_MODULE_TYPE_ASYNC)
					.tap(PLUGIN_NAME, () => {
						const AsyncWebAssemblyJavascriptGenerator =
							getAsyncWebAssemblyJavascriptGenerator();
						const AsyncWebAssemblyGenerator = getAsyncWebAssemblyGenerator();

						return Generator.byType({
							javascript: new AsyncWebAssemblyJavascriptGenerator(
								compilation.outputOptions.webassemblyModuleFilename
							),
							webassembly: new AsyncWebAssemblyGenerator(this.options)
						});
					});

				compilation.hooks.renderManifest.tap(
					"WebAssemblyModulesPlugin",
					(result, options) => {
						const { moduleGraph, chunkGraph, runtimeTemplate } = compilation;
						const {
							chunk,
							outputOptions,
							dependencyTemplates,
							codeGenerationResults
						} = options;

						for (const module of chunkGraph.getOrderedChunkModulesIterable(
							chunk,
							compareModulesByIdentifier
						)) {
							if (module.type === WEBASSEMBLY_MODULE_TYPE_ASYNC) {
								const filenameTemplate =
									/** @type {NonNullable<OutputOptions["webassemblyModuleFilename"]>} */
									(outputOptions.webassemblyModuleFilename);

								result.push({
									render: () =>
										this.renderModule(
											module,
											{
												chunk,
												dependencyTemplates,
												runtimeTemplate,
												moduleGraph,
												chunkGraph,
												codeGenerationResults
											},
											hooks
										),
									filenameTemplate,
									pathOptions: {
										module,
										runtime: chunk.runtime,
										chunkGraph
									},
									auxiliary: true,
									identifier: `webassemblyAsyncModule${chunkGraph.getModuleId(
										module
									)}`,
									hash: chunkGraph.getModuleHash(module, chunk.runtime)
								});
							}
						}

						return result;
					}
				);
			}
		);
	}

	/**
	 * @param {Module} module the rendered module
	 * @param {WebAssemblyRenderContext} renderContext options object
	 * @param {CompilationHooks} hooks hooks
	 * @returns {Source} the newly generated source from rendering
	 */
	renderModule(module, renderContext, hooks) {
		const { codeGenerationResults, chunk } = renderContext;
		try {
			const moduleSource = codeGenerationResults.getSource(
				module,
				chunk.runtime,
				"webassembly"
			);
			return tryRunOrWebpackError(
				() =>
					hooks.renderModuleContent.call(moduleSource, module, renderContext),
				"AsyncWebAssemblyModulesPlugin.getCompilationHooks().renderModuleContent"
			);
		} catch (e) {
			/** @type {WebpackError} */ (e).module = module;
			throw e;
		}
	}
}

module.exports = AsyncWebAssemblyModulesPlugin;


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

"use strict";

const t = require("@webassemblyjs/ast");
const { decode } = require("@webassemblyjs/wasm-parser");
const EnvironmentNotSupportAsyncWarning = require("../EnvironmentNotSupportAsyncWarning");
const Parser = require("../Parser");
const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");

/** @typedef {import("../Module").BuildInfo} BuildInfo */
/** @typedef {import("../Module").BuildMeta} BuildMeta */
/** @typedef {import("../Parser").ParserState} ParserState */
/** @typedef {import("../Parser").PreparsedAst} PreparsedAst */

const decoderOpts = {
	ignoreCodeSection: true,
	ignoreDataSection: true,

	// this will avoid having to lookup with identifiers in the ModuleContext
	ignoreCustomNameSection: true
};

class WebAssemblyParser extends Parser {
	/**
	 * @param {{}=} options parser options
	 */
	constructor(options) {
		super();
		this.hooks = Object.freeze({});
		this.options = options;
	}

	/**
	 * @param {string | Buffer | PreparsedAst} source the source to parse
	 * @param {ParserState} state the parser state
	 * @returns {ParserState} the parser state
	 */
	parse(source, state) {
		if (!Buffer.isBuffer(source)) {
			throw new Error("WebAssemblyParser input must be a Buffer");
		}

		// flag it as async module
		const buildInfo = /** @type {BuildInfo} */ (state.module.buildInfo);
		buildInfo.strict = true;
		const BuildMeta = /** @type {BuildMeta} */ (state.module.buildMeta);
		BuildMeta.exportsType = "namespace";
		BuildMeta.async = true;
		EnvironmentNotSupportAsyncWarning.check(
			state.module,
			state.compilation.runtimeTemplate,
			"asyncWebAssembly"
		);

		// parse it
		const program = decode(source, decoderOpts);
		const module = program.body[0];
		/** @type {Array<string>} */
		const exports = [];
		t.traverse(module, {
			ModuleExport({ node }) {
				exports.push(node.name);
			},

			ModuleImport({ node }) {
				const dep = new WebAssemblyImportDependency(
					node.module,
					node.name,
					node.descr,
					false
				);

				state.module.addDependency(dep);
			}
		});

		state.module.addDependency(new StaticExportsDependency(exports, false));

		return state;
	}
}

module.exports = WebAssemblyParser;


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

"use strict";

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

module.exports = class UnsupportedWebAssemblyFeatureError extends WebpackError {
	/** @param {string} message Error message */
	constructor(message) {
		super(message);
		this.name = "UnsupportedWebAssemblyFeatureError";
		this.hideStack = true;
	}
};


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 { compareModulesByIdentifier } = require("../util/comparators");
const WebAssemblyUtils = require("./WebAssemblyUtils");

/** @typedef {import("@webassemblyjs/ast").Signature} Signature */
/** @typedef {import("../Chunk")} Chunk */
/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../Compilation")} Compilation */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../Module").ReadOnlyRuntimeRequirements} ReadOnlyRuntimeRequirements */
/** @typedef {import("../ModuleGraph")} ModuleGraph */
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */

// TODO webpack 6 remove the whole folder

// Get all wasm modules
/**
 * @param {ModuleGraph} moduleGraph the module graph
 * @param {ChunkGraph} chunkGraph the chunk graph
 * @param {Chunk} chunk the chunk
 * @returns {Module[]} all wasm modules
 */
const getAllWasmModules = (moduleGraph, chunkGraph, chunk) => {
	const wasmModules = chunk.getAllAsyncChunks();
	const array = [];
	for (const chunk of wasmModules) {
		for (const m of chunkGraph.getOrderedChunkModulesIterable(
			chunk,
			compareModulesByIdentifier
		)) {
			if (m.type.startsWith("webassembly")) {
				array.push(m);
			}
		}
	}

	return array;
};

/**
 * generates the import object function for a module
 * @param {ChunkGraph} chunkGraph the chunk graph
 * @param {Module} module the module
 * @param {boolean | undefined} mangle mangle imports
 * @param {string[]} declarations array where declarations are pushed to
 * @param {RuntimeSpec} runtime the runtime
 * @returns {string} source code
 */
const generateImportObject = (
	chunkGraph,
	module,
	mangle,
	declarations,
	runtime
) => {
	const moduleGraph = chunkGraph.moduleGraph;
	/** @type {Map<string, string | number>} */
	const waitForInstances = new Map();
	const properties = [];
	const usedWasmDependencies = WebAssemblyUtils.getUsedDependencies(
		moduleGraph,
		module,
		mangle
	);
	for (const usedDep of usedWasmDependencies) {
		const dep = usedDep.dependency;
		const importedModule = moduleGraph.getModule(dep);
		const exportName = dep.name;
		const usedName =
			importedModule &&
			moduleGraph
				.getExportsInfo(importedModule)
				.getUsedName(exportName, runtime);
		const description = dep.description;
		const direct = dep.onlyDirectImport;

		const module = usedDep.module;
		const name = usedDep.name;

		if (direct) {
			const instanceVar = `m${waitForInstances.size}`;
			waitForInstances.set(
				instanceVar,
				chunkGraph.getModuleId(/** @type {Module} */ (importedModule))
			);
			properties.push({
				module,
				name,
				value: `${instanceVar}[${JSON.stringify(usedName)}]`
			});
		} else {
			const params =
				/** @type {Signature} */
				(description.signature).params.map(
					(param, k) => "p" + k + param.valtype
				);

			const mod = `${RuntimeGlobals.moduleCache}[${JSON.stringify(
				chunkGraph.getModuleId(/** @type {Module} */ (importedModule))
			)}]`;
			const modExports = `${mod}.exports`;

			const cache = `wasmImportedFuncCache${declarations.length}`;
			declarations.push(`var ${cache};`);

			const modCode =
				/** @type {Module} */
				(importedModule).type.startsWith("webassembly")
					? `${mod} ? ${modExports}[${JSON.stringify(usedName)}] : `
					: "";

			properties.push({
				module,
				name,
				value: Template.asString([
					modCode + `function(${params}) {`,
					Template.indent([
						`if(${cache} === undefined) ${cache} = ${modExports};`,
						`return ${cache}[${JSON.stringify(usedName)}](${params});`
					]),
					"}"
				])
			});
		}
	}

	let importObject;
	if (mangle) {
		importObject = [
			"return {",
			Template.indent([
				properties.map(p => `${JSON.stringify(p.name)}: ${p.value}`).join(",\n")
			]),
			"};"
		];
	} else {
		/** @type {Map<string, Array<{ name: string, value: string }>>} */
		const propertiesByModule = new Map();
		for (const p of properties) {
			let list = propertiesByModule.get(p.module);
			if (list === undefined) {
				propertiesByModule.set(p.module, (list = []));
			}
			list.push(p);
		}
		importObject = [
			"return {",
			Template.indent([
				Array.from(propertiesByModule, ([module, list]) => {
					return Template.asString([
						`${JSON.stringify(module)}: {`,
						Template.indent([
							list.map(p => `${JSON.stringify(p.name)}: ${p.value}`).join(",\n")
						]),
						"}"
					]);
				}).join(",\n")
			]),
			"};"
		];
	}

	const moduleIdStringified = JSON.stringify(chunkGraph.getModuleId(module));
	if (waitForInstances.size === 1) {
		const moduleId = Array.from(waitForInstances.values())[0];
		const promise = `installedWasmModules[${JSON.stringify(moduleId)}]`;
		const variable = Array.from(waitForInstances.keys())[0];
		return Template.asString([
			`${moduleIdStringified}: function() {`,
			Template.indent([
				`return promiseResolve().then(function() { return ${promise}; }).then(function(${variable}) {`,
				Template.indent(importObject),
				"});"
			]),
			"},"
		]);
	} else if (waitForInstances.size > 0) {
		const promises = Array.from(
			waitForInstances.values(),
			id => `installedWasmModules[${JSON.stringify(id)}]`
		).join(", ");
		const variables = Array.from(
			waitForInstances.keys(),
			(name, i) => `${name} = array[${i}]`
		).join(", ");
		return Template.asString([
			`${moduleIdStringified}: function() {`,
			Template.indent([
				`return promiseResolve().then(function() { return Promise.all([${promises}]); }).then(function(array) {`,
				Template.indent([`var ${variables};`, ...importObject]),
				"});"
			]),
			"},"
		]);
	} else {
		return Template.asString([
			`${moduleIdStringified}: function() {`,
			Template.indent(importObject),
			"},"
		]);
	}
};

/**
 * @typedef {object} WasmChunkLoadingRuntimeModuleOptions
 * @property {(path: string) => string} generateLoadBinaryCode
 * @property {boolean} [supportsStreaming]
 * @property {boolean} [mangleImports]
 * @property {ReadOnlyRuntimeRequirements} runtimeRequirements
 */

class WasmChunkLoadingRuntimeModule extends RuntimeModule {
	/**
	 * @param {WasmChunkLoadingRuntimeModuleOptions} options options
	 */
	constructor({
		generateLoadBinaryCode,
		supportsStreaming,
		mangleImports,
		runtimeRequirements
	}) {
		super("wasm chunk loading", RuntimeModule.STAGE_ATTACH);
		this.generateLoadBinaryCode = generateLoadBinaryCode;
		this.supportsStreaming = supportsStreaming;
		this.mangleImports = mangleImports;
		this._runtimeRequirements = runtimeRequirements;
	}

	/**
	 * @returns {string | null} runtime code
	 */
	generate() {
		const fn = RuntimeGlobals.ensureChunkHandlers;
		const withHmr = this._runtimeRequirements.has(
			RuntimeGlobals.hmrDownloadUpdateHandlers
		);
		const compilation = /** @type {Compilation} */ (this.compilation);
		const { moduleGraph, outputOptions } = compilation;
		const chunkGraph = /** @type {ChunkGraph} */ (this.chunkGraph);
		const chunk = /** @type {Chunk} */ (this.chunk);
		const wasmModules = getAllWasmModules(moduleGraph, chunkGraph, chunk);
		const { mangleImports } = this;
		/** @type {string[]} */
		const declarations = [];
		const importObjects = wasmModules.map(module => {
			return generateImportObject(
				chunkGraph,
				module,
				mangleImports,
				declarations,
				chunk.runtime
			);
		});
		const chunkModuleIdMap = chunkGraph.getChunkModuleIdMap(chunk, m =>
			m.type.startsWith("webassembly")
		);
		/**
		 * @param {string} content content
		 * @returns {string} created import object
		 */
		const createImportObject = content =>
			mangleImports
				? `{ ${JSON.stringify(WebAssemblyUtils.MANGLED_MODULE)}: ${content} }`
				: content;
		const wasmModuleSrcPath = compilation.getPath(
			JSON.stringify(outputOptions.webassemblyModuleFilename),
			{
				hash: `" + ${RuntimeGlobals.getFullHash}() + "`,
				hashWithLength: length =>
					`" + ${RuntimeGlobals.getFullHash}}().slice(0, ${length}) + "`,
				module: {
					id: '" + wasmModuleId + "',
					hash: `" + ${JSON.stringify(
						chunkGraph.getChunkModuleRenderedHashMap(chunk, m =>
							m.type.startsWith("webassembly")
						)
					)}[chunkId][wasmModuleId] + "`,
					hashWithLength(length) {
						return `" + ${JSON.stringify(
							chunkGraph.getChunkModuleRenderedHashMap(
								chunk,
								m => m.type.startsWith("webassembly"),
								length
							)
						)}[chunkId][wasmModuleId] + "`;
					}
				},
				runtime: chunk.runtime
			}
		);

		const stateExpression = withHmr
			? `${RuntimeGlobals.hmrRuntimeStatePrefix}_wasm`
			: undefined;

		return Template.asString([
			"// object to store loaded and loading wasm modules",
			`var installedWasmModules = ${
				stateExpression ? `${stateExpression} = ${stateExpression} || ` : ""
			}{};`,
			"",
			// This function is used to delay reading the installed wasm module promises
			// by a microtask. Sorting them doesn't help because there are edge cases where
			// sorting is not possible (modules splitted into different chunks).
			// So we not even trying and solve this by a microtask delay.
			"function promiseResolve() { return Promise.resolve(); }",
			"",
			Template.asString(declarations),
			"var wasmImportObjects = {",
			Template.indent(importObjects),
			"};",
			"",
			`var wasmModuleMap = ${JSON.stringify(
				chunkModuleIdMap,
				undefined,
				"\t"
			)};`,
			"",
			"// object with all WebAssembly.instance exports",
			`${RuntimeGlobals.wasmInstances} = {};`,
			"",
			"// Fetch + compile chunk loading for webassembly",
			`${fn}.wasm = function(chunkId, promises) {`,
			Template.indent([
				"",
				`var wasmModules = wasmModuleMap[chunkId] || [];`,
				"",
				"wasmModules.forEach(function(wasmModuleId, idx) {",
				Template.indent([
					"var installedWasmModuleData = installedWasmModules[wasmModuleId];",
					"",
					'// a Promise means "currently loading" or "already loaded".',
					"if(installedWasmModuleData)",
					Template.indent(["promises.push(installedWasmModuleData);"]),
					"else {",
					Template.indent([
						`var importObject = wasmImportObjects[wasmModuleId]();`,
						`var req = ${this.generateLoadBinaryCode(wasmModuleSrcPath)};`,
						"var promise;",
						this.supportsStreaming
							? Template.asString([
									"if(importObject && typeof importObject.then === 'function' && typeof WebAssembly.compileStreaming === 'function') {",
									Template.indent([
										"promise = Promise.all([WebAssembly.compileStreaming(req), importObject]).then(function(items) {",
										Template.indent([
											`return WebAssembly.instantiate(items[0], ${createImportObject(
												"items[1]"
											)});`
										]),
										"});"
									]),
									"} else if(typeof WebAssembly.instantiateStreaming === 'function') {",
									Template.indent([
										`promise = WebAssembly.instantiateStreaming(req, ${createImportObject(
											"importObject"
										)});`
									])
								])
							: Template.asString([
									"if(importObject && typeof importObject.then === 'function') {",
									Template.indent([
										"var bytesPromise = req.then(function(x) { return x.arrayBuffer(); });",
										"promise = Promise.all([",
										Template.indent([
											"bytesPromise.then(function(bytes) { return WebAssembly.compile(bytes); }),",
											"importObject"
										]),
										"]).then(function(items) {",
										Template.indent([
											`return WebAssembly.instantiate(items[0], ${createImportObject(
												"items[1]"
											)});`
										]),
										"});"
									])
								]),
						"} else {",
						Template.indent([
							"var bytesPromise = req.then(function(x) { return x.arrayBuffer(); });",
							"promise = bytesPromise.then(function(bytes) {",
							Template.indent([
								`return WebAssembly.instantiate(bytes, ${createImportObject(
									"importObject"
								)});`
							]),
							"});"
						]),
						"}",
						"promises.push(installedWasmModules[wasmModuleId] = promise.then(function(res) {",
						Template.indent([
							`return ${RuntimeGlobals.wasmInstances}[wasmModuleId] = (res.instance || res).exports;`
						]),
						"}));"
					]),
					"}"
				]),
				"});"
			]),
			"};"
		]);
	}
}

module.exports = WasmChunkLoadingRuntimeModule;


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

"use strict";

const formatLocation = require("../formatLocation");
const UnsupportedWebAssemblyFeatureError = require("./UnsupportedWebAssemblyFeatureError");

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

class WasmFinalizeExportsPlugin {
	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.compilation.tap("WasmFinalizeExportsPlugin", compilation => {
			compilation.hooks.finishModules.tap(
				"WasmFinalizeExportsPlugin",
				modules => {
					for (const module of modules) {
						// 1. if a WebAssembly module
						if (module.type.startsWith("webassembly") === true) {
							const jsIncompatibleExports =
								/** @type {BuildMeta} */
								(module.buildMeta).jsIncompatibleExports;

							if (jsIncompatibleExports === undefined) {
								continue;
							}

							for (const connection of compilation.moduleGraph.getIncomingConnections(
								module
							)) {
								// 2. is active and referenced by a non-WebAssembly module
								if (
									connection.isTargetActive(undefined) &&
									/** @type {Module} */
									(connection.originModule).type.startsWith("webassembly") ===
										false
								) {
									const referencedExports =
										compilation.getDependencyReferencedExports(
											/** @type {Dependency} */ (connection.dependency),
											undefined
										);

									for (const info of referencedExports) {
										const names = Array.isArray(info) ? info : info.name;
										if (names.length === 0) continue;
										const name = names[0];
										if (typeof name === "object") continue;
										// 3. and uses a func with an incompatible JS signature
										if (
											Object.prototype.hasOwnProperty.call(
												jsIncompatibleExports,
												name
											)
										) {
											// 4. error
											const error = new UnsupportedWebAssemblyFeatureError(
												`Export "${name}" with ${jsIncompatibleExports[name]} can only be used for direct wasm to wasm dependencies\n` +
													`It's used from ${
														/** @type {Module} */
														(connection.originModule).readableIdentifier(
															compilation.requestShortener
														)
													} at ${formatLocation(
														/** @type {Dependency} */ (connection.dependency)
															.loc
													)}.`
											);
											error.module = module;
											compilation.errors.push(error);
										}
									}
								}
							}
						}
					}
				}
			);
		});
	}
}

module.exports = WasmFinalizeExportsPlugin;


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

"use strict";

const { RawSource } = require("webpack-sources");
const Generator = require("../Generator");
const WebAssemblyUtils = require("./WebAssemblyUtils");

const t = require("@webassemblyjs/ast");
const { moduleContextFromModuleAST } = require("@webassemblyjs/ast");
const { editWithAST, addWithAST } = require("@webassemblyjs/wasm-edit");
const { decode } = require("@webassemblyjs/wasm-parser");

const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency");

/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../ModuleGraph")} ModuleGraph */
/** @typedef {import("../NormalModule")} NormalModule */
/** @typedef {import("../RuntimeTemplate")} RuntimeTemplate */
/** @typedef {import("../util/runtime").RuntimeSpec} RuntimeSpec */
/** @typedef {import("./WebAssemblyUtils").UsedWasmDependency} UsedWasmDependency */
/** @typedef {import("@webassemblyjs/ast").Instruction} Instruction */
/** @typedef {import("@webassemblyjs/ast").ModuleImport} ModuleImport */
/** @typedef {import("@webassemblyjs/ast").ModuleExport} ModuleExport */
/** @typedef {import("@webassemblyjs/ast").Global} Global */
/**
 * @template T
 * @typedef {import("@webassemblyjs/ast").NodePath<T>} NodePath
 */

/**
 * @typedef {(buf: ArrayBuffer) => ArrayBuffer} ArrayBufferTransform
 */

/**
 * @template T
 * @param {((prev: ArrayBuffer) => ArrayBuffer)[]} fns transforms
 * @returns {Function} composed transform
 */
const compose = (...fns) => {
	return fns.reduce(
		(prevFn, nextFn) => {
			return value => nextFn(prevFn(value));
		},
		value => value
	);
};

/**
 * Removes the start instruction
 *
 * @param {object} state state
 * @param {object} state.ast Module's ast
 * @returns {ArrayBufferTransform} transform
 */
const removeStartFunc = state => bin => {
	return editWithAST(state.ast, bin, {
		Start(path) {
			path.remove();
		}
	});
};

/**
 * Get imported globals
 *
 * @param {object} ast Module's AST
 * @returns {t.ModuleImport[]} - nodes
 */
const getImportedGlobals = ast => {
	/** @type {t.ModuleImport[]} */
	const importedGlobals = [];

	t.traverse(ast, {
		ModuleImport({ node }) {
			if (t.isGlobalType(node.descr)) {
				importedGlobals.push(node);
			}
		}
	});

	return importedGlobals;
};

/**
 * Get the count for imported func
 *
 * @param {object} ast Module's AST
 * @returns {number} - count
 */
const getCountImportedFunc = ast => {
	let count = 0;

	t.traverse(ast, {
		ModuleImport({ node }) {
			if (t.isFuncImportDescr(node.descr)) {
				count++;
			}
		}
	});

	return count;
};

/**
 * Get next type index
 *
 * @param {object} ast Module's AST
 * @returns {t.Index} - index
 */
const getNextTypeIndex = ast => {
	const typeSectionMetadata = t.getSectionMetadata(ast, "type");

	if (typeSectionMetadata === undefined) {
		return t.indexLiteral(0);
	}

	return t.indexLiteral(typeSectionMetadata.vectorOfSize.value);
};

/**
 * Get next func index
 *
 * The Func section metadata provide information for implemented funcs
 * in order to have the correct index we shift the index by number of external
 * functions.
 *
 * @param {object} ast Module's AST
 * @param {number} countImportedFunc number of imported funcs
 * @returns {t.Index} - index
 */
const getNextFuncIndex = (ast, countImportedFunc) => {
	const funcSectionMetadata = t.getSectionMetadata(ast, "func");

	if (funcSectionMetadata === undefined) {
		return t.indexLiteral(0 + countImportedFunc);
	}

	const vectorOfSize = funcSectionMetadata.vectorOfSize.value;

	return t.indexLiteral(vectorOfSize + countImportedFunc);
};

/**
 * Creates an init instruction for a global type
 * @param {t.GlobalType} globalType the global type
 * @returns {t.Instruction} init expression
 */
const createDefaultInitForGlobal = globalType => {
	if (globalType.valtype[0] === "i") {
		// create NumberLiteral global initializer
		return t.objectInstruction("const", globalType.valtype, [
			t.numberLiteralFromRaw(66)
		]);
	} else if (globalType.valtype[0] === "f") {
		// create FloatLiteral global initializer
		return t.objectInstruction("const", globalType.valtype, [
			t.floatLiteral(66, false, false, "66")
		]);
	} else {
		throw new Error("unknown type: " + globalType.valtype);
	}
};

/**
 * Rewrite the import globals:
 * - removes the ModuleImport instruction
 * - injects at the same offset a mutable global of the same type
 *
 * Since the imported globals are before the other global declarations, our
 * indices will be preserved.
 *
 * Note that globals will become mutable.
 *
 * @param {object} state transformation state
 * @param {object} state.ast Module's ast
 * @param {t.Instruction[]} state.additionalInitCode list of addition instructions for the init function
 * @returns {ArrayBufferTransform} transform
 */
const rewriteImportedGlobals = state => bin => {
	const additionalInitCode = state.additionalInitCode;
	/** @type {Array<t.Global>} */
	const newGlobals = [];

	bin = editWithAST(state.ast, bin, {
		ModuleImport(path) {
			if (t.isGlobalType(path.node.descr)) {
				const globalType = /** @type {TODO} */ (path.node.descr);

				globalType.mutability = "var";

				const init = [
					createDefaultInitForGlobal(globalType),
					t.instruction("end")
				];

				newGlobals.push(t.global(globalType, init));

				path.remove();
			}
		},

		// in order to preserve non-imported global's order we need to re-inject
		// those as well
		/**
		 * @param {NodePath<Global>} path path
		 */
		Global(path) {
			const { node } = path;
			const [init] = node.init;

			if (init.id === "get_global") {
				node.globalType.mutability = "var";

				const initialGlobalIdx = init.args[0];

				node.init = [
					createDefaultInitForGlobal(node.globalType),
					t.instruction("end")
				];

				additionalInitCode.push(
					/**
					 * get_global in global initializer only works for imported globals.
					 * They have the same indices as the init params, so use the
					 * same index.
					 */
					t.instruction("get_local", [initialGlobalIdx]),
					t.instruction("set_global", [t.indexLiteral(newGlobals.length)])
				);
			}

			newGlobals.push(node);

			path.remove();
		}
	});

	// Add global declaration instructions
	return addWithAST(state.ast, bin, newGlobals);
};

/**
 * Rewrite the export names
 * @param {object} state state
 * @param {object} state.ast Module's ast
 * @param {Module} state.module Module
 * @param {ModuleGraph} state.moduleGraph module graph
 * @param {Set<string>} state.externalExports Module
 * @param {RuntimeSpec} state.runtime runtime
 * @returns {ArrayBufferTransform} transform
 */
const rewriteExportNames =
	({ ast, moduleGraph, module, externalExports, runtime }) =>
	bin => {
		return editWithAST(ast, bin, {
			/**
			 * @param {NodePath<ModuleExport>} path path
			 */
			ModuleExport(path) {
				const isExternal = externalExports.has(path.node.name);
				if (isExternal) {
					path.remove();
					return;
				}
				const usedName = moduleGraph
					.getExportsInfo(module)
					.getUsedName(path.node.name, runtime);
				if (!usedName) {
					path.remove();
					return;
				}
				path.node.name = /** @type {string} */ (usedName);
			}
		});
	};

/**
 * Mangle import names and modules
 * @param {object} state state
 * @param {object} state.ast Module's ast
 * @param {Map<string, UsedWasmDependency>} state.usedDependencyMap mappings to mangle names
 * @returns {ArrayBufferTransform} transform
 */
const rewriteImports =
	({ ast, usedDependencyMap }) =>
	bin => {
		return editWithAST(ast, bin, {
			/**
			 * @param {NodePath<ModuleImport>} path path
			 */
			ModuleImport(path) {
				const result = usedDependencyMap.get(
					path.node.module + ":" + path.node.name
				);

				if (result !== undefined) {
					path.node.module = result.module;
					path.node.name = result.name;
				}
			}
		});
	};

/**
 * Add an init function.
 *
 * The init function fills the globals given input arguments.
 *
 * @param {object} state transformation state
 * @param {object} state.ast Module's ast
 * @param {t.Identifier} state.initFuncId identifier of the init function
 * @param {t.Index} state.startAtFuncOffset index of the start function
 * @param {t.ModuleImport[]} state.importedGlobals list of imported globals
 * @param {t.Instruction[]} state.additionalInitCode list of addition instructions for the init function
 * @param {t.Index} state.nextFuncIndex index of the next function
 * @param {t.Index} state.nextTypeIndex index of the next type
 * @returns {ArrayBufferTransform} transform
 */
const addInitFunction =
	({
		ast,
		initFuncId,
		startAtFuncOffset,
		importedGlobals,
		additionalInitCode,
		nextFuncIndex,
		nextTypeIndex
	}) =>
	bin => {
		const funcParams = importedGlobals.map(importedGlobal => {
			// used for debugging
			const id = t.identifier(
				`${importedGlobal.module}.${importedGlobal.name}`
			);

			return t.funcParam(
				/** @type {string} */ (importedGlobal.descr.valtype),
				id
			);
		});

		/** @type {Instruction[]} */
		const funcBody = [];
		importedGlobals.forEach((importedGlobal, index) => {
			const args = [t.indexLiteral(index)];
			const body = [
				t.instruction("get_local", args),
				t.instruction("set_global", args)
			];

			funcBody.push(...body);
		});

		if (typeof startAtFuncOffset === "number") {
			funcBody.push(
				t.callInstruction(t.numberLiteralFromRaw(startAtFuncOffset))
			);
		}

		for (const instr of additionalInitCode) {
			funcBody.push(instr);
		}

		funcBody.push(t.instruction("end"));

		/** @type {string[]} */
		const funcResults = [];

		// Code section
		const funcSignature = t.signature(funcParams, funcResults);
		const func = t.func(initFuncId, funcSignature, funcBody);

		// Type section
		const functype = t.typeInstruction(undefined, funcSignature);

		// Func section
		const funcindex = t.indexInFuncSection(nextTypeIndex);

		// Export section
		const moduleExport = t.moduleExport(
			initFuncId.value,
			t.moduleExportDescr("Func", nextFuncIndex)
		);

		return addWithAST(ast, bin, [func, moduleExport, funcindex, functype]);
	};

/**
 * Extract mangle mappings from module
 * @param {ModuleGraph} moduleGraph module graph
 * @param {Module} module current module
 * @param {boolean | undefined} mangle mangle imports
 * @returns {Map<string, UsedWasmDependency>} mappings to mangled names
 */
const getUsedDependencyMap = (moduleGraph, module, mangle) => {
	/** @type {Map<string, UsedWasmDependency>} */
	const map = new Map();
	for (const usedDep of WebAssemblyUtils.getUsedDependencies(
		moduleGraph,
		module,
		mangle
	)) {
		const dep = usedDep.dependency;
		const request = dep.request;
		const exportName = dep.name;
		map.set(request + ":" + exportName, usedDep);
	}
	return map;
};

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

/**
 * @typedef {object} WebAssemblyGeneratorOptions
 * @property {boolean} [mangleImports] mangle imports
 */

class WebAssemblyGenerator extends Generator {
	/**
	 * @param {WebAssemblyGeneratorOptions} options options
	 */
	constructor(options) {
		super();
		this.options = options;
	}

	/**
	 * @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 0;
		}
		return originalSource.size();
	}

	/**
	 * @param {NormalModule} module module for which the code should be generated
	 * @param {GenerateContext} generateContext context for generate
	 * @returns {Source} generated code
	 */
	generate(module, { moduleGraph, runtime }) {
		const bin = /** @type {Source} */ (module.originalSource()).source();

		const initFuncId = t.identifier("");

		// parse it
		const ast = decode(bin, {
			ignoreDataSection: true,
			ignoreCodeSection: true,
			ignoreCustomNameSection: true
		});

		const moduleContext = moduleContextFromModuleAST(ast.body[0]);

		const importedGlobals = getImportedGlobals(ast);
		const countImportedFunc = getCountImportedFunc(ast);
		const startAtFuncOffset = moduleContext.getStart();
		const nextFuncIndex = getNextFuncIndex(ast, countImportedFunc);
		const nextTypeIndex = getNextTypeIndex(ast);

		const usedDependencyMap = getUsedDependencyMap(
			moduleGraph,
			module,
			this.options.mangleImports
		);
		const externalExports = new Set(
			module.dependencies
				.filter(d => d instanceof WebAssemblyExportImportedDependency)
				.map(d => {
					const wasmDep = /** @type {WebAssemblyExportImportedDependency} */ (
						d
					);
					return wasmDep.exportName;
				})
		);

		/** @type {t.Instruction[]} */
		const additionalInitCode = [];

		const transform = compose(
			rewriteExportNames({
				ast,
				moduleGraph,
				module,
				externalExports,
				runtime
			}),

			removeStartFunc({ ast }),

			rewriteImportedGlobals({ ast, additionalInitCode }),

			rewriteImports({
				ast,
				usedDependencyMap
			}),

			addInitFunction({
				ast,
				initFuncId,
				importedGlobals,
				additionalInitCode,
				startAtFuncOffset,
				nextFuncIndex,
				nextTypeIndex
			})
		);

		const newBin = transform(bin);

		const newBuf = Buffer.from(newBin);

		return new RawSource(newBuf);
	}
}

module.exports = WebAssemblyGenerator;


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

"use strict";

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

/** @typedef {import("../ChunkGraph")} ChunkGraph */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../ModuleGraph")} ModuleGraph */
/** @typedef {import("../RequestShortener")} RequestShortener */

/**
 * @param {Module} module module to get chains from
 * @param {ModuleGraph} moduleGraph the module graph
 * @param {ChunkGraph} chunkGraph the chunk graph
 * @param {RequestShortener} requestShortener to make readable identifiers
 * @returns {string[]} all chains to the module
 */
const getInitialModuleChains = (
	module,
	moduleGraph,
	chunkGraph,
	requestShortener
) => {
	const queue = [
		{ head: module, message: module.readableIdentifier(requestShortener) }
	];
	/** @type {Set<string>} */
	const results = new Set();
	/** @type {Set<string>} */
	const incompleteResults = new Set();
	/** @type {Set<Module>} */
	const visitedModules = new Set();

	for (const chain of queue) {
		const { head, message } = chain;
		let final = true;
		/** @type {Set<Module>} */
		const alreadyReferencedModules = new Set();
		for (const connection of moduleGraph.getIncomingConnections(head)) {
			const newHead = connection.originModule;
			if (newHead) {
				if (!chunkGraph.getModuleChunks(newHead).some(c => c.canBeInitial()))
					continue;
				final = false;
				if (alreadyReferencedModules.has(newHead)) continue;
				alreadyReferencedModules.add(newHead);
				const moduleName = newHead.readableIdentifier(requestShortener);
				const detail = connection.explanation
					? ` (${connection.explanation})`
					: "";
				const newMessage = `${moduleName}${detail} --> ${message}`;
				if (visitedModules.has(newHead)) {
					incompleteResults.add(`... --> ${newMessage}`);
					continue;
				}
				visitedModules.add(newHead);
				queue.push({
					head: newHead,
					message: newMessage
				});
			} else {
				final = false;
				const newMessage = connection.explanation
					? `(${connection.explanation}) --> ${message}`
					: message;
				results.add(newMessage);
			}
		}
		if (final) {
			results.add(message);
		}
	}
	for (const result of incompleteResults) {
		results.add(result);
	}
	return Array.from(results);
};

module.exports = class WebAssemblyInInitialChunkError extends WebpackError {
	/**
	 * @param {Module} module WASM module
	 * @param {ModuleGraph} moduleGraph the module graph
	 * @param {ChunkGraph} chunkGraph the chunk graph
	 * @param {RequestShortener} requestShortener request shortener
	 */
	constructor(module, moduleGraph, chunkGraph, requestShortener) {
		const moduleChains = getInitialModuleChains(
			module,
			moduleGraph,
			chunkGraph,
			requestShortener
		);
		const message = `WebAssembly module is included in initial chunk.
This is not allowed, because WebAssembly download and compilation must happen asynchronous.
Add an async split point (i. e. import()) somewhere between your entrypoint and the WebAssembly module:
${moduleChains.map(s => `* ${s}`).join("\n")}`;

		super(message);
		this.name = "WebAssemblyInInitialChunkError";
		this.hideStack = true;
		this.module = module;
	}
};


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

"use strict";

const { RawSource } = require("webpack-sources");
const { UsageState } = require("../ExportsInfo");
const Generator = require("../Generator");
const InitFragment = require("../InitFragment");
const RuntimeGlobals = require("../RuntimeGlobals");
const Template = require("../Template");
const ModuleDependency = require("../dependencies/ModuleDependency");
const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency");
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");

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

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

class WebAssemblyJavascriptGenerator 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) {
		return 95 + module.dependencies.length * 5;
	}

	/**
	 * @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 {
			runtimeTemplate,
			moduleGraph,
			chunkGraph,
			runtimeRequirements,
			runtime
		} = generateContext;
		/** @type {InitFragment<InitFragment<string>>[]} */
		const initFragments = [];

		const exportsInfo = moduleGraph.getExportsInfo(module);

		let needExportsCopy = false;
		const importedModules = new Map();
		const initParams = [];
		let index = 0;
		for (const dep of module.dependencies) {
			const moduleDep =
				dep && dep instanceof ModuleDependency ? dep : undefined;
			if (moduleGraph.getModule(dep)) {
				let importData = importedModules.get(moduleGraph.getModule(dep));
				if (importData === undefined) {
					importedModules.set(
						moduleGraph.getModule(dep),
						(importData = {
							importVar: `m${index}`,
							index,
							request: (moduleDep && moduleDep.userRequest) || undefined,
							names: new Set(),
							reexports: []
						})
					);
					index++;
				}
				if (dep instanceof WebAssemblyImportDependency) {
					importData.names.add(dep.name);
					if (dep.description.type === "GlobalType") {
						const exportName = dep.name;
						const importedModule = moduleGraph.getModule(dep);

						if (importedModule) {
							const usedName = moduleGraph
								.getExportsInfo(importedModule)
								.getUsedName(exportName, runtime);
							if (usedName) {
								initParams.push(
									runtimeTemplate.exportFromImport({
										moduleGraph,
										module: importedModule,
										request: dep.request,
										importVar: importData.importVar,
										originModule: module,
										exportName: dep.name,
										asiSafe: true,
										isCall: false,
										callContext: null,
										defaultInterop: true,
										initFragments,
										runtime,
										runtimeRequirements
									})
								);
							}
						}
					}
				}
				if (dep instanceof WebAssemblyExportImportedDependency) {
					importData.names.add(dep.name);
					const usedName = moduleGraph
						.getExportsInfo(module)
						.getUsedName(dep.exportName, runtime);
					if (usedName) {
						runtimeRequirements.add(RuntimeGlobals.exports);
						const exportProp = `${module.exportsArgument}[${JSON.stringify(
							usedName
						)}]`;
						const defineStatement = Template.asString([
							`${exportProp} = ${runtimeTemplate.exportFromImport({
								moduleGraph,
								module: /** @type {Module} */ (moduleGraph.getModule(dep)),
								request: dep.request,
								importVar: importData.importVar,
								originModule: module,
								exportName: dep.name,
								asiSafe: true,
								isCall: false,
								callContext: null,
								defaultInterop: true,
								initFragments,
								runtime,
								runtimeRequirements
							})};`,
							`if(WebAssembly.Global) ${exportProp} = ` +
								`new WebAssembly.Global({ value: ${JSON.stringify(
									dep.valueType
								)} }, ${exportProp});`
						]);
						importData.reexports.push(defineStatement);
						needExportsCopy = true;
					}
				}
			}
		}
		const importsCode = Template.asString(
			Array.from(
				importedModules,
				([module, { importVar, request, reexports }]) => {
					const importStatement = runtimeTemplate.importStatement({
						module,
						chunkGraph,
						request,
						importVar,
						originModule: module,
						runtimeRequirements
					});
					return importStatement[0] + importStatement[1] + reexports.join("\n");
				}
			)
		);

		const copyAllExports =
			exportsInfo.otherExportsInfo.getUsed(runtime) === UsageState.Unused &&
			!needExportsCopy;

		// need these globals
		runtimeRequirements.add(RuntimeGlobals.module);
		runtimeRequirements.add(RuntimeGlobals.moduleId);
		runtimeRequirements.add(RuntimeGlobals.wasmInstances);
		if (exportsInfo.otherExportsInfo.getUsed(runtime) !== UsageState.Unused) {
			runtimeRequirements.add(RuntimeGlobals.makeNamespaceObject);
			runtimeRequirements.add(RuntimeGlobals.exports);
		}
		if (!copyAllExports) {
			runtimeRequirements.add(RuntimeGlobals.exports);
		}

		// create source
		const source = new RawSource(
			[
				'"use strict";',
				"// Instantiate WebAssembly module",
				`var wasmExports = ${RuntimeGlobals.wasmInstances}[${module.moduleArgument}.id];`,

				exportsInfo.otherExportsInfo.getUsed(runtime) !== UsageState.Unused
					? `${RuntimeGlobals.makeNamespaceObject}(${module.exportsArgument});`
					: "",

				// this must be before import for circular dependencies
				"// export exports from WebAssembly module",
				copyAllExports
					? `${module.moduleArgument}.exports = wasmExports;`
					: "for(var name in wasmExports) " +
						`if(name) ` +
						`${module.exportsArgument}[name] = wasmExports[name];`,
				"// exec imports from WebAssembly module (for esm order)",
				importsCode,
				"",
				"// exec wasm module",
				`wasmExports[""](${initParams.join(", ")})`
			].join("\n")
		);
		return InitFragment.addToSource(source, initFragments, generateContext);
	}
}

module.exports = WebAssemblyJavascriptGenerator;


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

"use strict";

const Generator = require("../Generator");
const { WEBASSEMBLY_MODULE_TYPE_SYNC } = require("../ModuleTypeConstants");
const WebAssemblyExportImportedDependency = require("../dependencies/WebAssemblyExportImportedDependency");
const WebAssemblyImportDependency = require("../dependencies/WebAssemblyImportDependency");
const { compareModulesByIdentifier } = require("../util/comparators");
const memoize = require("../util/memoize");
const WebAssemblyInInitialChunkError = require("./WebAssemblyInInitialChunkError");

/** @typedef {import("webpack-sources").Source} Source */
/** @typedef {import("../../declarations/WebpackOptions").OutputNormalized} OutputOptions */
/** @typedef {import("../Compiler")} Compiler */
/** @typedef {import("../Module")} Module */
/** @typedef {import("../ModuleTemplate")} ModuleTemplate */
/** @typedef {import("../javascript/JavascriptModulesPlugin").RenderContext} RenderContext */

const getWebAssemblyGenerator = memoize(() =>
	require("./WebAssemblyGenerator")
);
const getWebAssemblyJavascriptGenerator = memoize(() =>
	require("./WebAssemblyJavascriptGenerator")
);
const getWebAssemblyParser = memoize(() => require("./WebAssemblyParser"));

const PLUGIN_NAME = "WebAssemblyModulesPlugin";

/**
 * @typedef {object} WebAssemblyModulesPluginOptions
 * @property {boolean} [mangleImports] mangle imports
 */

class WebAssemblyModulesPlugin {
	/**
	 * @param {WebAssemblyModulesPluginOptions} options options
	 */
	constructor(options) {
		this.options = options;
	}

	/**
	 * Apply the plugin
	 * @param {Compiler} compiler the compiler instance
	 * @returns {void}
	 */
	apply(compiler) {
		compiler.hooks.compilation.tap(
			PLUGIN_NAME,
			(compilation, { normalModuleFactory }) => {
				compilation.dependencyFactories.set(
					WebAssemblyImportDependency,
					normalModuleFactory
				);

				compilation.dependencyFactories.set(
					WebAssemblyExportImportedDependency,
					normalModuleFactory
				);

				normalModuleFactory.hooks.createParser
					.for(WEBASSEMBLY_MODULE_TYPE_SYNC)
					.tap(PLUGIN_NAME, () => {
						const WebAssemblyParser = getWebAssemblyParser();

						return new WebAssemblyParser();
					});

				normalModuleFactory.hooks.createGenerator
					.for(WEBASSEMBLY_MODULE_TYPE_SYNC)
					.tap(PLUGIN_NAME, () => {
						const WebAssemblyJavascriptGenerator =
							getWebAssemblyJavascriptGenerator();
						const WebAssemblyGenerator = getWebAssemblyGenerator();

						return Generator.byType({
							javascript: new WebAssemblyJavascriptGenerator(),
							webassembly: new WebAssemblyGenerator(this.options)
						});
					});

				compilation.hooks.renderManifest.tap(PLUGIN_NAME, (result, options) => {
					const { chunkGraph } = compilation;
					const { chunk, outputOptions, codeGenerationResults } = options;

					for (const module of chunkGraph.getOrderedChunkModulesIterable(
						chunk,
						compareModulesByIdentifier
					)) {
						if (module.type === WEBASSEMBLY_MODULE_TYPE_SYNC) {
							const filenameTemplate =
								/** @type {NonNullable<OutputOptions["webassemblyModuleFilename"]>} */
								(outputOptions.webassemblyModuleFilename);

							result.push({
								render: () =>
									codeGenerationResults.getSource(
										module,
										chunk.runtime,
										"webassembly"
									),
								filenameTemplate,
								pathOptions: {
									module,
									runtime: chunk.runtime,
									chunkGraph
								},
								auxiliary: true,
								identifier: `webassemblyModule${chunkGraph.getModuleId(
									module
								)}`,
								hash: chunkGraph.getModuleHash(module, chunk.runtime)
							});
						}
					}

					return result;
				});

				compilation.hooks.afterChunks.tap(PLUGIN_NAME, () => {
					const chunkGraph = compilation.chunkGraph;
					const initialWasmModules = new Set();
					for (const chunk of compilation.chunks) {
						if (chunk.canBeInitial()) {
							for (const module of chunkGraph.getChunkModulesIterable(chunk)) {
								if (module.type === WEBASSEMBLY_MODULE_TYPE_SYNC) {
									initialWasmModules.add(module);
								}
							}
						}
					}
					for (const module of initialWasmModules) {
						compilation.errors.push(
							new WebAssemblyInInitialChunkError(
								module,
								compilation.moduleGraph,
								compilation.chunkGraph,
								compilation.requestShortener
							)
						);
					}
				});
			}
		);
	}
}

module.exports = WebAssemblyModulesPlugin;